module Checkers.Types where import Data.Maybe -- A coordinate represents a square on the board, it is a pair of integers (x,y). -- The board is 0-indexed, where (_,0) is the top row of the board, and (0,_) is -- the leftmost column. type Coord = (Int,Int) type PieceState = [Coord] -- A move is a list of coordinates, tracing the path travelled by a piece, -- where one keeps track of whether or not the piece is a Pawn or King -- using the PorK datatype below. -- The list is "in the right order", e.g. [firstSquare, secondSquare, ...] data PorK a = P a | K a deriving (Show,Eq, Read) type Move = [PorK Coord] -- Simple moves or jumpmoves data SMorJM a = SM a |JM a | EndM deriving (Show, Eq) -- It is either red/black's turn, or the game has finished. data Status = RedPlayer | BlackPlayer | GameOver deriving (Eq,Show) -- Gamestate is a record with all the data for the state of a game. data GameState = GameState { blackPieces :: PieceState -- coordinate of black pieces , redPieces :: PieceState -- coordinate of red pieces , blackKings :: PieceState -- coordinate of black kings , redKings :: PieceState -- coordinate of red kings , status :: Status -- red/black move or gameover , message :: String -- illegal move messge , history :: [Move]} -- history of moves made (most recent first!) -- Your job is to write functions: -- moves:: GameState -> ([Move],[Move]) -- to generate all the possible moves from a state -- separated into the simple moves and the jump moves. -- apply_move:: Move -> GameState -> GameSTate -- to apply a move to generate the next state -- ai_move_red, ai_move_black:: GameState -> Move -- the ai chooses a move for the red or black player from a state ... -- A player is either an AI or Human: an AI has its move generated by a function -- which given a state chooses a Move, while a Human must get information from -- the user. data PlayerType = AI (GameState -> Move) | Human -- The GameConfig type defines the configurations possible for a checkers game. -- This includes the apply_move function, the two players (AI or human), and -- the start state of the game. data GameConfig = GameConfig { movemaker :: Move -> GameState -> GameState , blackMove :: PlayerType , redMove :: PlayerType , state :: GameState} -- "Show" for the game state ... instance Show GameState where show g = concatN ("":x:y:"":xs) where x = show (status g) y = "Message:"++message g xs = printBoard g printBoard :: GameState -> [String] printBoard b = ((" "++(concat [show n++" "|n <-[0..7]])): (" "++['_'|_<-[0..15]]): [printHLine y b | y <- [0..7]]) ++ [(" "++['^'|_<-[0..17]])] printHLine :: Int -> GameState -> String printHLine y b = " "++(show y) ++ " |" ++[printSquare (x,y) b | x <- [0..7], _ <- [0,1]]++"|" printSquare :: Coord -> GameState -> Char printSquare xy b | xy `elem` (redPieces b) = 'r' | xy `elem` (redKings b) = 'R' | xy `elem` (blackPieces b) = 'b' | xy `elem` (blackKings b) = 'B' | otherwise = '_' concatN :: [String] -> String concatN [] = "\n" concatN (x:xs) = x++('\n':concatN xs) -- The initial game state initialGameState :: GameState initialGameState = GameState { blackPieces = blackInit , redPieces = redInit , blackKings = [] , redKings = [] , status = RedPlayer , message = "" , history = []} blackInit :: [Coord] blackInit = [ (1,0), (3,0), (5,0), (7,0) , (0,1), (2,1), (4,1), (6,1) , (1,2), (3,2), (5,2), (7,2)] redInit :: [Coord] redInit = [ (0,7), (2,7), (4,7), (6,7) , (1,6), (3,6), (5,6), (7,6) , (0,5), (2,5), (4,5), (6,5)]