parent
7dc72ee211
commit
425bb6eee2
3 changed files with 44 additions and 44 deletions
|
@ -5,7 +5,7 @@ module Patience
|
||||||
import PatienceBoard
|
import PatienceBoard
|
||||||
import PatienceRenderer
|
import PatienceRenderer
|
||||||
|
|
||||||
import Graphics.Gloss (green, play)
|
import Graphics.Gloss (dim, green, play)
|
||||||
|
|
||||||
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
||||||
-- Single module to play patience. --
|
-- Single module to play patience. --
|
||||||
|
@ -21,6 +21,19 @@ type FPS = Int
|
||||||
|
|
||||||
-- Play a game of patience.
|
-- Play a game of patience.
|
||||||
playPatience :: FPS -> IO()
|
playPatience :: FPS -> IO()
|
||||||
playPatience fps = do play window green fps initGame render handleInputs step
|
playPatience fps = do play window bgcolor fps initGame render handleInputs step
|
||||||
where window = getWindow
|
where window = getWindow
|
||||||
step _ g = g
|
step _ g = g
|
||||||
|
bgcolor = dim green
|
||||||
|
|
||||||
|
---------------------------- Documentation ---------------------------
|
||||||
|
-- The structure of this project is based on the Model-View- --
|
||||||
|
-- Controller as known in Java. This clearly seperates different --
|
||||||
|
-- functionality from each other. I also tried to put as much --
|
||||||
|
-- functionality of the same thing into a single module. I always --
|
||||||
|
-- asked myself: "Could I use this piece of code in a different --
|
||||||
|
-- project?" If the answer was yes, there is now a module for it. --
|
||||||
|
-- -*- --
|
||||||
|
-- This block merely serves as a message to the person reviewing --
|
||||||
|
-- this code. --
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
|
@ -28,7 +28,7 @@ data Game = Game {
|
||||||
board :: Board,
|
board :: Board,
|
||||||
-- The selector
|
-- The selector
|
||||||
selector :: Selector
|
selector :: Selector
|
||||||
} deriving (Show)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
-- Representation of a Patience board
|
-- Representation of a Patience board
|
||||||
data Board = Board {
|
data Board = Board {
|
||||||
|
@ -38,7 +38,7 @@ data Board = Board {
|
||||||
endingStacks :: [Stack],
|
endingStacks :: [Stack],
|
||||||
-- Stack of cards that are not yet on the board
|
-- Stack of cards that are not yet on the board
|
||||||
pile :: Stack
|
pile :: Stack
|
||||||
} deriving (Show)
|
} deriving (Show, Eq)
|
||||||
|
|
||||||
-- The zones of the board. Represents either the pile, the endingStacks
|
-- The zones of the board. Represents either the pile, the endingStacks
|
||||||
-- or the gameStacks. It can also be out of the board.
|
-- or the gameStacks. It can also be out of the board.
|
||||||
|
@ -117,7 +117,7 @@ isInGame (x, y) g = horizontalCheck && verticalCheck
|
||||||
upBound = y <= snd gameStacksCoord
|
upBound = y <= snd gameStacksCoord
|
||||||
xStack = gameStacks (board g) !! x
|
xStack = gameStacks (board g) !! x
|
||||||
downBound = zero || negate y < length xStack
|
downBound = zero || negate y < length xStack
|
||||||
zero = y == 0 && length xStack == 0
|
zero = y == 0 && null xStack
|
||||||
|
|
||||||
-- Get the zone number from a coordinate.
|
-- Get the zone number from a coordinate.
|
||||||
getZoneFromCoord :: Game -> Coordinate -> Zone
|
getZoneFromCoord :: Game -> Coordinate -> Zone
|
||||||
|
@ -127,22 +127,6 @@ getZoneFromCoord game (x, y)
|
||||||
| isInGame (x, y) game = GS
|
| isInGame (x, y) game = GS
|
||||||
| otherwise = Out
|
| otherwise = Out
|
||||||
|
|
||||||
-- 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 -----------------------------
|
--------------------------- Change cards -----------------------------
|
||||||
|
|
||||||
-- Show the first of a stack of cards.
|
-- Show the first of a stack of cards.
|
||||||
|
@ -161,9 +145,9 @@ canPlayOn :: Stack -> Int -> Stack -> Bool
|
||||||
canPlayOn [] _ _ = False
|
canPlayOn [] _ _ = False
|
||||||
canPlayOn cs index [] = v1 == King && vis == Visible
|
canPlayOn cs index [] = v1 == King && vis == Visible
|
||||||
where (_,v1,vis) = cs !! index
|
where (_,v1,vis) = cs !! index
|
||||||
canPlayOn cs index ((t2,v2,_):_) = differentColor && predValue && visibility
|
canPlayOn cs index ((t2,v2,vis2):_) = differentColor && predValue && visibility
|
||||||
where (t1,v1,vis) = cs !! index
|
where (t1,v1,vis) = cs !! index
|
||||||
differentColor = t1 /= t2 && (fromEnum t1 + fromEnum t2) `elem` [1,2,4,5]
|
differentColor = not $ (t1,v1,vis) `matchColor` (t2,v2,vis2)
|
||||||
predValue = succ v1 == v2
|
predValue = succ v1 == v2
|
||||||
visibility = vis == Visible
|
visibility = vis == Visible
|
||||||
|
|
||||||
|
@ -194,7 +178,7 @@ moveGS2GS fromCoord toStackNr board
|
||||||
tempGS = switchStack oldGS fromStackNr (showFirst newFrom)
|
tempGS = switchStack oldGS fromStackNr (showFirst newFrom)
|
||||||
newGS = switchStack tempGS toStackNr newTo
|
newGS = switchStack tempGS toStackNr newTo
|
||||||
newBoard = board{ gameStacks = newGS }
|
newBoard = board{ gameStacks = newGS }
|
||||||
|
-- Move from a gameStack to an endingStack.
|
||||||
moveGS2ES :: Coordinate -> Int -> Board -> Board
|
moveGS2ES :: Coordinate -> Int -> Board -> Board
|
||||||
moveGS2ES fromCoord toIndex board
|
moveGS2ES fromCoord toIndex board
|
||||||
| canFinishOn from 0 to = newBoard
|
| canFinishOn from 0 to = newBoard
|
||||||
|
@ -236,6 +220,7 @@ moveP2GS _ toStackNr board
|
||||||
newGS = switchStack oldGS toStackNr newGSStack
|
newGS = switchStack oldGS toStackNr newGSStack
|
||||||
newBoard = board{ gameStacks = newGS, pile = newPile }
|
newBoard = board{ gameStacks = newGS, pile = newPile }
|
||||||
|
|
||||||
|
-- Move a card from an endingStack to a gameStack.
|
||||||
moveES2GS :: Coordinate -> Int -> Board -> Board
|
moveES2GS :: Coordinate -> Int -> Board -> Board
|
||||||
moveES2GS fromCoord toStackNr board
|
moveES2GS fromCoord toStackNr board
|
||||||
| canPlayOn from 0 to = newBoard
|
| canPlayOn from 0 to = newBoard
|
||||||
|
@ -264,6 +249,7 @@ getStackFromZone :: Game -> Zone -> Int -> Stack
|
||||||
getStackFromZone game Pile index = pile (board game)
|
getStackFromZone game Pile index = pile (board game)
|
||||||
getStackFromZone game ES index = endingStacks (board game) !! index
|
getStackFromZone game ES index = endingStacks (board game) !! index
|
||||||
getStackFromZone game GS index = gameStacks (board game) !! index
|
getStackFromZone game GS index = gameStacks (board game) !! index
|
||||||
|
getStackFromZone _ Out _ = []
|
||||||
|
|
||||||
-- Move between to zones with two indexes
|
-- Move between to zones with two indexes
|
||||||
getMoveFunction2 :: Zone -> Zone -> Coordinate -> Int -> Board -> Board
|
getMoveFunction2 :: Zone -> Zone -> Coordinate -> Int -> Board -> Board
|
||||||
|
@ -274,6 +260,7 @@ getMoveFunction2 GS ES coord index = moveGS2ES coord index
|
||||||
getMoveFunction2 ES GS coord index = moveES2GS coord index
|
getMoveFunction2 ES GS coord index = moveES2GS coord index
|
||||||
getMoveFunction2 _ _ _ _ = id
|
getMoveFunction2 _ _ _ _ = id
|
||||||
|
|
||||||
|
-- Tranform the index based on the zone.
|
||||||
transformIndex :: Zone -> Int -> Int
|
transformIndex :: Zone -> Int -> Int
|
||||||
transformIndex ES index = index - (amountOfGameStacks - amountOfEndingStacks)
|
transformIndex ES index = index - (amountOfGameStacks - amountOfEndingStacks)
|
||||||
transformIndex Pile _ = 0
|
transformIndex Pile _ = 0
|
||||||
|
@ -316,11 +303,13 @@ toggleSelector g@Game{ selector = s@Selector{ selected = Just coord } } = moved
|
||||||
-- Handle all the inputs necessary for patience.
|
-- Handle all the inputs necessary for patience.
|
||||||
handleInputs :: Event -> Game -> Game
|
handleInputs :: Event -> Game -> Game
|
||||||
handleInputs = composeInputHandler [
|
handleInputs = composeInputHandler [
|
||||||
|
-- Selector movement
|
||||||
handleUp (moveSelector U),
|
handleUp (moveSelector U),
|
||||||
handleDown (moveSelector D),
|
handleDown (moveSelector D),
|
||||||
handleLeft (moveSelector L),
|
handleLeft (moveSelector L),
|
||||||
handleRight (moveSelector R),
|
handleRight (moveSelector R),
|
||||||
|
-- Selection handling
|
||||||
handleSpace toggleSelector,
|
handleSpace toggleSelector,
|
||||||
|
-- Pile rotation
|
||||||
handleEnter rotatePile
|
handleEnter rotatePile
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,6 +3,7 @@ module PatienceRenderer
|
||||||
, getWindow
|
, getWindow
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import CardDeck
|
||||||
import PatienceBoard
|
import PatienceBoard
|
||||||
import Selector
|
import Selector
|
||||||
|
|
||||||
|
@ -32,16 +33,6 @@ stackDistance = 10
|
||||||
zoneDistance :: Float
|
zoneDistance :: Float
|
||||||
zoneDistance = 25
|
zoneDistance = 25
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
|
||||||
|
|
||||||
-- Render the GameStacks zone.
|
|
||||||
renderGS :: Board -> Picture
|
|
||||||
renderGS = renderStacks stackDistance (negate cardDistance) . gameStacks
|
|
||||||
|
|
||||||
-- Render the EndingStacks zone.
|
|
||||||
renderES :: Board -> Picture
|
|
||||||
renderES = renderStacks stackDistance 0 . endingStacks
|
|
||||||
|
|
||||||
-- X axis render difference for EndingStacks
|
-- X axis render difference for EndingStacks
|
||||||
esXDiff :: Float
|
esXDiff :: Float
|
||||||
esXDiff = fromIntegral esX * cardDistance
|
esXDiff = fromIntegral esX * cardDistance
|
||||||
|
@ -53,10 +44,6 @@ esYDiff :: Float
|
||||||
esYDiff = fromIntegral esY * (zoneDistance + cardHeight)
|
esYDiff = fromIntegral esY * (zoneDistance + cardHeight)
|
||||||
where (_, esY) = endingStacksCoord
|
where (_, esY) = endingStacksCoord
|
||||||
|
|
||||||
-- Render the Pile zone.
|
|
||||||
renderPile :: Board -> Picture
|
|
||||||
renderPile = renderStack 0 . pile
|
|
||||||
|
|
||||||
-- X axis render difference for Pile
|
-- X axis render difference for Pile
|
||||||
pileXDiff :: Float
|
pileXDiff :: Float
|
||||||
pileXDiff = 0
|
pileXDiff = 0
|
||||||
|
@ -65,6 +52,20 @@ pileXDiff = 0
|
||||||
pileYDiff :: Float
|
pileYDiff :: Float
|
||||||
pileYDiff = esYDiff
|
pileYDiff = esYDiff
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
-- Render the GameStacks zone.
|
||||||
|
renderGS :: Board -> Picture
|
||||||
|
renderGS = renderStacks stackDistance (negate cardDistance) . gameStacks
|
||||||
|
|
||||||
|
-- Render the EndingStacks zone.
|
||||||
|
renderES :: Board -> Picture
|
||||||
|
renderES = renderStacks stackDistance 0 . endingStacks
|
||||||
|
|
||||||
|
-- Render the Pile zone.
|
||||||
|
renderPile :: Board -> Picture
|
||||||
|
renderPile = renderStack 0 . pile
|
||||||
|
|
||||||
-- Get the diff based on a coordinate because different 'zones' have
|
-- Get the diff based on a coordinate because different 'zones' have
|
||||||
-- different offsets.
|
-- different offsets.
|
||||||
getDiff :: Coordinate -> (Float, Float)
|
getDiff :: Coordinate -> (Float, Float)
|
||||||
|
@ -100,17 +101,14 @@ renderPSelector ps = compose [
|
||||||
(xd1, yd1) = getDiff (position ps)
|
(xd1, yd1) = getDiff (position ps)
|
||||||
(xd2, yd2) = getDiff $ getSelected ps
|
(xd2, yd2) = getDiff $ getSelected ps
|
||||||
|
|
||||||
getSelected :: Selector -> Coordinate
|
-- Render the patience game.
|
||||||
getSelected s@Selector{ selected = Just c } = c
|
|
||||||
getSelected s@Selector{ selected = Nothing } = (0,0)
|
|
||||||
|
|
||||||
render :: Game -> Picture
|
render :: Game -> Picture
|
||||||
render game = translate centerX centerY $ compose [
|
render game = translate centerX centerY $ compose [
|
||||||
renderBoard $ board game,
|
renderBoard $ board game,
|
||||||
renderPSelector $ selector game
|
renderPSelector $ selector game
|
||||||
]
|
]
|
||||||
where centerX = negate $ (cardWidth + stackDistance) * (fromIntegral amountOfGameStacks - 1) / 2
|
where centerX = negate $ (cardWidth + stackDistance) * (fromIntegral amountOfGameStacks - 1) / 2
|
||||||
centerY = 0 -- TODO Different center
|
centerY = 0
|
||||||
|
|
||||||
-- The default window to play patience.
|
-- The default window to play patience.
|
||||||
getWindow :: Display
|
getWindow :: Display
|
||||||
|
|
Reference in a new issue