From 8d9186963fa591898102b7d2e11a137183caca2d Mon Sep 17 00:00:00 2001 From: Tibo De Peuter Date: Tue, 15 Nov 2022 09:28:10 +0100 Subject: [PATCH] #16 Fix --- lib/Patience.hs | 26 ++++++++++ lib/PatienceBoard.hs | 114 +++++++++++++++++++++++++++++++++---------- 2 files changed, 113 insertions(+), 27 deletions(-) create mode 100644 lib/Patience.hs diff --git a/lib/Patience.hs b/lib/Patience.hs new file mode 100644 index 0000000..021da57 --- /dev/null +++ b/lib/Patience.hs @@ -0,0 +1,26 @@ +module Patience +( playPatience +) where + +import PatienceBoard +import PatienceRenderer + +import Graphics.Gloss (green, play) + +--------------------------------------------------------------------- +-- Single module to play patience. -- +-- Includes all logic and rendering. -- +--------------------------------------------------------------------- + +----------------------------- Constants ------------------------------ + +-- Framerate of the game +type FPS = Int + +--------------------------------------------------------------------- + +-- Play a game of patience. +playPatience :: FPS -> IO() +playPatience fps = do play window green fps initGame render handleInputs step + where window = getWindow + step _ g = g diff --git a/lib/PatienceBoard.hs b/lib/PatienceBoard.hs index 63f9eac..492f375 100644 --- a/lib/PatienceBoard.hs +++ b/lib/PatienceBoard.hs @@ -90,6 +90,45 @@ initGame = Game { selector = initSelector } +------------------- Coordinate to Card conversion -------------------- + +-- Check if a coordinate is in the pile. +isInPile :: Coordinate -> Bool +isInPile = (pileCoord == ) + +-- Check if a coordinate is in an endingStack. +isInEnding :: Coordinate -> Bool +isInEnding (x, y) = leftBound && rightBound && yCheck + where leftBound = fst endingStacksCoord <= x + rightBound = x < amountOfGameStacks + yCheck = y == snd endingStacksCoord + +-- Check if a coordinate is in a GameStack. +isInGame :: Coordinate -> Game -> Bool +isInGame (x, y) g = horizontalCheck && verticalCheck + where horizontalCheck = leftBound && rightBound + verticalCheck = upBound && downBound + leftBound = fst gameStacksCoord <= x + rightBound = x < amountOfGameStacks + upBound = y <= snd gameStacksCoord + downBound = negate y < length (gameStacks (board g) !! x) + +-- Based on a coordinate, return a stack. +getStackFromCoord :: Game -> Coordinate -> Stack +getStackFromCoord game (x, y) + | isInPile (x, y) = pile $ board game + | isInEnding (x, y) = endingStacks (board game) !! (x - (amountOfGameStacks - amountOfEndingStacks)) + | isInGame (x, y) game = gameStacks (board game) !! x + | otherwise = pile $ board game + +-- Based on a coordinate, return a card. +getCardFromCoord :: Game -> Coordinate -> Card +getCardFromCoord game (x, y) + | isInPile (x, y) = head $ pile (board game) + | isInEnding (x, y) = head $ endingStacks (board game) !! (x - (amountOfGameStacks - amountOfEndingStacks)) + | isInGame (x, y) game = (gameStacks (board game) !! x ) !! negate y + | otherwise = (NoneType, NoneValue, Hidden) + --------------------------- Change cards ----------------------------- -- Show the first of a stack of cards. @@ -98,9 +137,10 @@ showFirst [] = [] showFirst (c:cs) = showCard c : cs -- Rotate the pile n times. -rotatePile :: Board -> Board -rotatePile b = b { pile = tail ++ head } - where (head,tail) = splitAt rotateStep $ pile b +rotatePile :: Game -> Game +rotatePile g@Game{ board = b } = g{ board = rotatedBoard } + where rotatedBoard = b{ pile = tail ++ head } + (head, tail) = splitAt rotateStep $ pile b -- Check if a card can be placed ontop of a gameStack. canPlayOn :: Card -> Stack -> Bool @@ -135,29 +175,45 @@ moveToES from to where (diff,removed) = splitAt 1 from added = diff ++ to +-- Switch a stack for another stack in a list of stacks. +switchStack :: [Stack] -> Int -> Stack -> [Stack] +switchStack ss index new = front ++ new:back + where (front, back') = splitAt index ss + back = tail back' + +-- Swap a stack in the Game for another stack. +updateStack :: Game -> Coordinate -> Stack -> Game +updateStack game (x, y) new + | isInEnding (x, y) = let originalBoard = board game + index = x - (amountOfGameStacks - amountOfEndingStacks) + newStack = switchStack (endingStacks originalBoard) index new + updatedBoard = originalBoard{ endingStacks = newStack } + in game{ board = updatedBoard } + | isInPile (x, y) = let originalBoard = board game + updatedBoard = originalBoard{ pile = new } + in game{ board = updatedBoard } + | otherwise = let originalBoard = board game + stackNr = x + index = negate y + newGameStacks = switchStack (gameStacks originalBoard) stackNr new + updatedBoard = originalBoard{ gameStacks = newGameStacks } + in game{ board = updatedBoard } + +-- Move a card from Coordinate to Coordinate. +moveCard :: Game -> Coordinate -> Coordinate -> Game +moveCard game (x, y) (a, b) + | isInEnding (a, b) = let fromStack = getStackFromCoord game (x, y) + toStack = getStackFromCoord game (a, b) + (removed, added) = moveToES fromStack toStack + -- Swapping to old stack. + applyFirst = updateStack game (x, y) removed + -- Swapping the new stack. + result = updateStack applyFirst (a, b) added + in result + | otherwise = game + ------------------------------ Input --------------------------------- --- Check if a coordinate is in the pile. -isInPile :: Coordinate -> Bool -isInPile = (pileCoord == ) - --- Check if a coordinate is in an endingStack. -isInEnding :: Coordinate -> Bool -isInEnding (x, y) = leftBound && rightBound && yCheck - where leftBound = fst endingStacksCoord <= x - rightBound = x < amountOfGameStacks - yCheck = y == snd endingStacksCoord - --- Check if a coordinate is in a GameStack. -isInGame :: Coordinate -> Game -> Bool -isInGame (x, y) g = horizontalCheck && verticalCheck - where horizontalCheck = leftBound && rightBound - verticalCheck = upBound && downBound - leftBound = fst gameStacksCoord <= x - rightBound = x < amountOfGameStacks - upBound = y <= snd gameStacksCoord - downBound = negate y < length (gameStacks (board g) !! x) - -- Check if moving in a direction is legal. isLegalMove :: Direction -> Game -> Bool isLegalMove dir g = isInPile coord || isInEnding coord || isInGame coord g @@ -169,9 +225,12 @@ moveSelector dir g@Game{ selector = s } | isLegalMove dir g = g{ selector = move dir s } | otherwise = g --- Toggle selector. (Wrapper) +-- Toggle selector. If a card was already selected, try to move it. toggleSelector :: Game -> Game -toggleSelector g@Game{ selector = s } = g{ selector = toggleSelection s } +toggleSelector g@Game{ selector = s@Selector{ selected = Nothing } } = toggled + where toggled = g{ selector = toggleSelection s } +toggleSelector g@Game{ selector = s@Selector{ selected = Just coord } } = moved + where moved = moveCard g{ selector = toggleSelection s } (getSelected s) (position s) -- Handle all the inputs necessary for patience. handleInputs :: Event -> Game -> Game @@ -181,5 +240,6 @@ handleInputs = composeInputHandler [ handleLeft (moveSelector L), handleRight (moveSelector R), - handleSpace toggleSelector + handleSpace toggleSelector, + handleEnter rotatePile ]