Go Fish/Julia

From Rosetta Code
Revision as of 19:19, 3 February 2019 by Wherrera (talk | contribs) (Created page with "<lang julia>import Base.show const sorteddeck = reshape([string(r == 'T' ? "10" : r) * s for r in "23456789TJQKA", s in "♣♦♥♠"], 52) const maxdecklen = length(sortedd...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

<lang julia>import Base.show

const sorteddeck = reshape([string(r == 'T' ? "10" : r) * s for r in "23456789TJQKA", s in "♣♦♥♠"], 52) const maxdecklen = length(sorteddeck)

isvaliddeck(a) = (s = Vector{UInt8}(unique(a)); (a == s && all(x -> 0 < x <= 52, s)))

mutable struct Deck

   cards::Vector{UInt8}
   Deck(a) = if isvaliddeck(a) new(a) else throw("bad deck constructor $a") end

end

suitrank(crd) = divrem((crd - 1), 13) .+ 1 cardsuit(crd) = suitrank(crd)[1] cardrank(crd) = suitrank(crd)[2] shuffledeck!(d) = shuffle!(d.cards)

ascards(d::Deck) = [sorteddeck[i] for i in d.cards] Base.show(io::IO, d::Deck) = show(io, join(ascards(d), " ")) byrank(d::Deck) = filter(d -> !isempty(d.cards),

   [Deck(d.cards[findall(x -> cardrank(x) == n, d.cards)]) for n in 1:13])

printbyrank(d) = foreach(println, byrank(d))

function deal!(d::Deck, hlen)

   if hlen < length(d.cards)
       hand = Deck(d.cards[1:hlen])
       d.cards = d.cards[hlen+1:end]
   else
       hand = Deck(d.cards)
       empty!(d.cards)
   end
   return hand

end

function queryprompt(query, choices, choicetxt="")

   carr = map(x -> uppercase(strip(string(x))), collect(choices))
   while true
       print(query, " ", choicetxt == "" ? carr : choicetxt, ": ")
       choice = uppercase(strip(readline(stdin)))
       if choice in carr
           return choice
       end
       println()
   end

end

function gofish()

   ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A"]
   displayplayer(d, l, cl) = println("Player hand is $d. \nYour score is $(length(l)) books.",
       " Computer score is $(length(cl)) books.")
   discardfrom!(a, d) = (dis = Deck(a.cards); d.cards = filter(x -> !(x in a.cards), d.cards); dis)
   books!(d, l) = (b = [discardfrom!(a, d) for a in byrank(d) if length(a.cards) == 4]; append!(l, b); b)
   function cardswithrank(rankstring, d)
       r = indexin([rankstring], ranks)[1]
       if r == nothing
           return []::Vector{Int}
       else
           arr = findall(x -> cardrank(x) == r, d.cards)
       end
       d.cards[arr]
   end


   function moverank!(rnk, srcdeck, dstdeck)
       arr = cardswithrank(rnk, srcdeck)
       srcdeck.cards = sort(filter(x -> !(x in arr), srcdeck.cards))
       dstdeck.cards = sort(unique(append!(dstdeck.cards, arr)))
   end
   function drawacard!(d, maindeck, display=true)
       if isempty(maindeck.cards)
           println("Draw pile is empty.")
           return
       end
       crd = popfirst!(maindeck.cards)
       d = sort(push!(d.cards, crd))
       if display
           println("You drew a ", Deck([crd]))
       end
   end
   function playerasks!(d, plaid, claid, cdeck, maindeck)
       choice = ""
       while true
           if isempty(cdeck.cards)
               drawacard!(cdeck, maindeck, false)
           end
           if isempty(d.cards)
               drawacard!(d, maindeck)
           end
           if isempty(d.cards)
               return
           end
           displayplayer(d, plaid, claid)
           choice = queryprompt("Your turn. Rank you request? ", ranks)
           if isempty(cardswithrank(choice, d))
               println("You cannot ask for \"$choice\" cards since you have none.")
               continue
           end
           println("You want the \"$choice\" cards.")
           if (n = length(cardswithrank(choice, cdeck))) > 0
               moverank!(choice, cdeck, d)
               println("Computer gives you $n of the \"$choice\" cards.")
               choice = queryprompt("Ask computer for cards again? ", ["Y", "N"])
               if choice == "N"
                   break
               end
           else
               println("Sorry, computer does not have any of those cards.")
               break
           end
       end
   end
   function playerdiscards!(pd, plaid)
       choice = queryprompt("Discard cards? ", ["Y","N"])
       if choice == "Y"
           bks = books!(pd, plaid)
           println(length(bks) > 0 ? "Books: $(join(map(ascards, bks), ", ")))" : "No new books.")
       end
   end
   function computerasks!(cdeck, claid, pdeck, maindeck)
       choice = ""
       while true
           if isempty(pdeck.cards)
               drawacard!(pdeck, maindeck)
           end
           if isempty(cdeck.cards)
               drawacard!(pdeck, maindeck, false)
           end
           if isempty(cdeck.cards)
               return
           end
           groups = byrank(cdeck)
           wmost = sort(byrank(cdeck), lt = (x, y) -> length(x.cards) < length(y.cards))[end]
           wants = vcat(map(g -> g.cards, groups), [wmost.cards], [wmost.cards], [wmost.cards]) 
           choice = ranks[rank(rand(wants)[1])]
           println("Computer asks you for \"$choice\" cards.")
           if (n = length(cardswithrank(choice, pdeck))) > 0
               moverank!(choice, pdeck, cdeck)
               println("Computer accepts $n \"$choice\" cards from you.")
           else
               println("Computer cannot get those cards from you.")
               return
           end
       end
   end
   function computerdiscards!(cdec, claid)
       bks = books!(cdec, claid)
       if length(bks) > 0
           println("Computer new books: ", join(map(ascards, bks), ", "))
       end
   end
   fishd = Deck(shuffle(collect(1:52)))
   println("------------GO FISH GAME------------\n\nDealing:")
   pdeck = deal!(fishd, 9)
   cdeck = deal!(fishd, 9)
   println("You are dealt $pdeck.")
   plaid = Vector{Deck}()
   claid = Vector{Deck}()
   while sum(length, [pdeck.cards, cdeck.cards, fishd.cards]) > 0
       playerasks!(pdeck, plaid, claid, cdeck, fishd)
       playerdiscards!(pdeck, plaid)
       drawacard!(pdeck, fishd)
       computerasks!(cdeck, claid, pdeck, fishd)
       computerdiscards!(cdeck, claid)
       drawacard!(cdeck, fishd, false)
   end
   pscore = length(plaid)
   cscore = length(claid)
   println("Player has taken out $pscore books, and computer has taken out $cscore books.")
   println(pscore > cscore ? "Player wins." : pscore < cscore ? "Computer wins." : "Tied game.")

end

gofish() </lang>