You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
4.2 KiB
154 lines
4.2 KiB
module Morra |
|
(runGame, Game(..), Player(..), PlayerType(..)) |
|
where |
|
|
|
import Data.Maybe (listToMaybe) |
|
import qualified Data.Map as M |
|
|
|
import Control.Monad (forever) |
|
import Control.Monad.Trans.State |
|
import Control.Monad.IO.Class |
|
import Control.Monad.Trans.Class |
|
|
|
import System.Exit (exitSuccess) |
|
import System.Random (randomRIO) |
|
import System.Console.ANSI |
|
import System.IO (hFlush, stdout) |
|
|
|
-- Two player game |
|
-- Player chooses 0-5 and number |
|
-- AI chooses 0-5 and number |
|
|
|
type Source = (Integer, Integer) |
|
type Table = M.Map Source Integer |
|
type Guesses = (Integer, Integer) |
|
|
|
data PlayerType = Human | AI Guesses Table deriving (Show, Eq) |
|
|
|
data Player = Player { |
|
pType :: PlayerType, |
|
score :: Integer |
|
} deriving (Show, Eq) |
|
|
|
data Game = Game { |
|
playerA :: Player, |
|
playerB :: Player, |
|
pointsToWin :: Integer |
|
} deriving (Show, Eq) |
|
|
|
-- type Score = (Integer, Integer) |
|
|
|
type GameState = StateT Game IO |
|
|
|
isPlayerWinner :: (Game -> Player) -> Game -> Bool |
|
isPlayerWinner p g = (score . p) g >= pointsToWin g |
|
|
|
endGameMsg :: Bool -> Bool -> IO () |
|
endGameMsg True True = putStrLn "Everybody is a winner!" >> exitSuccess |
|
endGameMsg True False = putStrLn "Player A is a winner!" >> exitSuccess |
|
endGameMsg False True = putStrLn "Player B is a winner!" >> exitSuccess |
|
endGameMsg _ _ = return () |
|
|
|
gameEnd :: GameState () |
|
gameEnd = do |
|
g <- get |
|
let pA = isPlayerWinner playerA g |
|
pB = isPlayerWinner playerB g |
|
liftIO $ endGameMsg pA pB |
|
return () |
|
|
|
handleHumanPlayer :: IO (Integer, Integer) |
|
handleHumanPlayer = do |
|
putStr "Fingers and total (f, t): " |
|
hFlush stdout |
|
s <- getLine |
|
clearScreen |
|
case fmap fst . listToMaybe . reads $ s of |
|
Nothing -> do |
|
putStrLn "Incorrect format." |
|
handleHumanPlayer |
|
Just a -> return a |
|
|
|
handleAIPlayer :: Guesses -> Table -> IO (Integer, Integer) |
|
handleAIPlayer g t = do |
|
f <- randomRIO (0,5) |
|
g <- case M.lookup g t of |
|
Nothing -> randomRIO (0, 5) |
|
Just n -> return n |
|
return (f, f + g) |
|
|
|
updateAI :: Player -> Integer -> Player |
|
updateAI p n = case pType p of |
|
Human -> p |
|
AI g@(g1, g2) t -> p { pType = AI g' t' } |
|
where g' = (g2, n) |
|
t' = M.insert g n t |
|
|
|
updateAIs :: (Integer, Integer) -> GameState () |
|
updateAIs (gA, gB) = do |
|
g <- get |
|
let pA = playerA g |
|
pB = playerB g |
|
pA' = updateAI pA gB |
|
pB' = updateAI pB gA |
|
g' = g { playerA = pA' } |
|
put $ g' { playerB = pB' } |
|
|
|
handlePlayer :: (Game -> Player) -> GameState (Integer, Integer) |
|
handlePlayer p = do |
|
g <- get |
|
let player = p g |
|
case pType player of |
|
Human -> liftIO handleHumanPlayer |
|
AI g t -> liftIO $ handleAIPlayer g t |
|
|
|
handleGuessPlayerA :: Integer -> Integer -> GameState () |
|
handleGuessPlayerA guess total = |
|
if (guess == total) |
|
then do |
|
g <- get |
|
let p = playerA g |
|
s = score p |
|
put $ g { playerA = (p { score = s + 1 })} |
|
liftIO $ putStrLn $ "PlayerA guessed correctly!" |
|
else return () |
|
|
|
handleGuessPlayerB :: Integer -> Integer -> GameState () |
|
handleGuessPlayerB guess total = |
|
if (guess == total) |
|
then do |
|
g <- get |
|
let p = playerB g |
|
s = score p |
|
put $ g { playerB = (p { score = s + 1 })} |
|
liftIO $ putStrLn $ "PlayerB guessed correctly!" |
|
else return () |
|
|
|
runGame :: GameState () |
|
runGame = forever $ do |
|
gameEnd |
|
liftIO $ putStrLn "Turn PlayerA" |
|
(f, g) <- handlePlayer playerA |
|
liftIO $ putStrLn "Turn PlayerB" |
|
(f', g') <- handlePlayer playerB |
|
let total = f + f' |
|
liftIO $ do |
|
putStrLn "==========================" |
|
putStr $ "PlayerA showed: " ++ show f |
|
putStrLn $ " and guessed: " ++ show g |
|
putStr $ "PlayerB showed: " ++ show f' |
|
putStrLn $ " and guessed: " ++ show g' |
|
putStrLn $ "Total was: " ++ show total |
|
putStrLn "==========================" |
|
handleGuessPlayerA g total |
|
handleGuessPlayerB g' total |
|
liftIO $ putStrLn "==========================" |
|
-- update any ai |
|
updateAIs (f, f') |
|
-- print the player status |
|
g <- get |
|
let pA = playerA g |
|
pB = playerB g |
|
liftIO $ do |
|
putStrLn $ "PlayerA: " ++ show pA |
|
putStrLn $ "PlayerB: " ++ show pB |