Anonymous user
Go Fish/Haskell: Difference between revisions
Fixing formatting from copy after Go Fish pages were branched out
(Created page with '{{collection|Go Fish}}Category:Haskell If possible, the AI will randomly select a rank known to be in the human's hand (a card in the AI's hand that the human has asked for b…') |
(Fixing formatting from copy after Go Fish pages were branched out) |
||
Line 2:
If possible, the AI will randomly select a rank known to be in the human's hand (a card in the AI's hand that the human has asked for before and the AI hasn't asked for before). If there are no known ranks, a rank is randomly selected from the AI's hand.
<lang haskell>
import IO
import Data.Map (Map)
import Data.Set (Set)
data Player = Player String (GameState -> IO Rank)
Line 16 ⟶ 17:
type PlayerState = (Hand, Set Rank, Set Rank)
type Hand = Map Rank (Set Suit)
deriving (Bounded, Enum, Eq, Ord, Show)
Jack | Queen | King | Ace
deriving (Bounded, Enum, Eq, Ord, Show)
hSetBuffering stdout NoBuffering >>
putStrLn "GO FISH\n\nDealing Cards" >>
initialGameState >>=
play (cycle [player, computer])
)
if score > oppScore then (name,score,oppScore) else (opp,oppScore,score)
where (score, oppScore) = (S.size books, S.size oppBooks)
putStr "Your cards: " >>
putStrLn (intercalate " " . map showCard $ handToCards hand) >>
Line 53 ⟶ 54:
where rankPrompt = putStr "Ask opponent for what rank? " >> getLine
liftM selectRank newStdGen >>= \rank ->
putStrLn ("Do you have any " ++ show rank ++ "s?") >>
return rank
where knowns = S.difference (S.intersection guesses oppHistory) history
guesses = M.keysSet hand
ranks = S.toList $ if S.null knowns then guesses else knowns
selectRank = (ranks !!) . fst . randomR (0, length ranks - 1)
if M.null hand
then if null deck
then return $! state
else putStrLn "Empty hand, forced draw" >>
let (newHand, newDeck) = draw hand deck
in normalizeBooks $ GS newDeck (newHand, b, hi) o
else getValidRank askRank state >>= \rank ->
exchangeCards state rank >>= \(newState, done) ->
normalizeBooks newState >>=
(if done then return else runPlayer askRank)
putStrLn m >> return (GS nd (nh, b, nhi) (noh, ob, ohi), done)
where (m, nh, noh, nd, done) = worker $ M.lookup rank opponentHand
nhi = S.insert rank hist
worker Nothing = ("Go fish", newHand, opponentHand, newDeck, True)
where (newHand, newDeck) = draw hand deck
worker (Just suits) = (message, newHand, newOppHand, deck, False)
where message = show (S.size suits) ++ " " ++ show rank ++ "(s)"
newHand = M.adjust (S.union suits) rank hand
newOppHand = M.delete rank opponentHand
(liftM (check hand) $ askRank state) $ putStrLn "Rank not in hand"
where check m v = M.lookup v m >>= Just . const v
mapM_ printRank (M.keys newBookRanks) >>
(return $! GS d (newHand, newBooks, hi) o)
where (newBookRanks, newHand) = M.partition ((==4) . S.size) hand
newBooks = S.union books $ M.keysSet newBookRanks
printRank r = putStrLn ("Rank " ++ show r ++ " was booked")
and [M.null hand, M.null oppHand, null deck]
where worker gen =
(GS deck (hand1, S.empty, S.empty) (hand2, S.empty, S.empty))
where (startDeck, _) = shuffle initialDeck gen
(hand1, deckMinusPlayerHand) = drawN 9 M.empty startDeck
(hand2, deck) = drawN 9 M.empty deckMinusPlayerHand
where worker = action >>= \result -> case result of
Nothing -> onFailure >> worker
Just value -> return $! value
'j' -> Just Jack
'q' -> Just Queen
Line 122 ⟶ 123:
'a' -> Just Ace
_ -> Nothing
where r = if rank > Ten then front rank else show (fromEnum rank + 2)
front v = [head $ show v]
where worker g l xs [] = (xs, g)
worker g l xs ys = worker newGen (l-1) (card : xs) (delete card ys)
where (index, newGen) = randomR (0,l-1) g
card = ys !! index
draw hand ((s,r):deck) = (M.insertWith S.union r (S.singleton s) hand, deck)
</lang>
|