Implement basic board types/functions
This commit is contained in:
parent
2b64fe2a0b
commit
0fe8205ed9
8 changed files with 140 additions and 35 deletions
10
package.yaml
10
package.yaml
|
|
@ -13,6 +13,10 @@ dependencies:
|
||||||
- random
|
- random
|
||||||
- array
|
- array
|
||||||
- text
|
- text
|
||||||
|
- mtl
|
||||||
|
- extra
|
||||||
|
- display
|
||||||
|
- binary
|
||||||
|
|
||||||
library:
|
library:
|
||||||
source-dirs:
|
source-dirs:
|
||||||
|
|
@ -24,13 +28,13 @@ executable:
|
||||||
main: Main.hs
|
main: Main.hs
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
spec:
|
numberspec-test:
|
||||||
main: "Spec.hs"
|
main: "Main.hs"
|
||||||
ghc-options: "-threaded -O0"
|
ghc-options: "-threaded -O0"
|
||||||
source-dirs:
|
source-dirs:
|
||||||
- src
|
|
||||||
- test
|
- test
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
- hspec >= 2.1.8
|
- hspec >= 2.1.8
|
||||||
- QuickCheck
|
- QuickCheck
|
||||||
|
- numbersquare
|
||||||
|
|
|
||||||
13
src/Game.hs
13
src/Game.hs
|
|
@ -1,7 +1,8 @@
|
||||||
module Game where
|
module Game where
|
||||||
|
|
||||||
import Data.Text
|
import Data.Text
|
||||||
import Types
|
import Types.GameBoard
|
||||||
|
import Types.GameMode (GameMode)
|
||||||
|
|
||||||
newtype PlayerName = MkPlayerName Text
|
newtype PlayerName = MkPlayerName Text
|
||||||
deriving (Eq, Show, Ord)
|
deriving (Eq, Show, Ord)
|
||||||
|
|
@ -12,14 +13,10 @@ data PlayerState = MkPlayerState
|
||||||
}
|
}
|
||||||
deriving (Eq, Show)
|
deriving (Eq, Show)
|
||||||
|
|
||||||
data GameState = MkGameState
|
data GameState mode = MkGameState
|
||||||
{ board :: GameBoard
|
{ board :: GameBoard mode
|
||||||
, players :: PlayerState
|
, players :: PlayerState
|
||||||
}
|
}
|
||||||
deriving (Eq, Show)
|
|
||||||
|
|
||||||
newRandomBoard :: Int -> Int -> IO GameBoard
|
newGame :: (GameMode mode) => mode -> [PlayerName] -> IO (GameState mode)
|
||||||
newRandomBoard width height = undefined
|
|
||||||
|
|
||||||
newGame :: [PlayerName] -> IO GameState
|
|
||||||
newGame = undefined
|
newGame = undefined
|
||||||
|
|
|
||||||
19
src/Types.hs
19
src/Types.hs
|
|
@ -1,19 +0,0 @@
|
||||||
{-# LANGUAGE NamedFieldPuns #-}
|
|
||||||
|
|
||||||
module Types where
|
|
||||||
|
|
||||||
import Data.Array
|
|
||||||
import Data.Array.Base (genArray)
|
|
||||||
|
|
||||||
data GameBoard = MkGameBoard
|
|
||||||
{ width :: Int
|
|
||||||
, height :: Int
|
|
||||||
, board :: Array (Int, Int) (Maybe Int)
|
|
||||||
}
|
|
||||||
deriving (Show, Eq)
|
|
||||||
|
|
||||||
mkEmptyBoard :: Int -> Int -> GameBoard
|
|
||||||
mkEmptyBoard width height = MkGameBoard{width, height, board}
|
|
||||||
where
|
|
||||||
board :: Array (Int, Int) (Maybe Int)
|
|
||||||
board = genArray ((0, 0), (width - 1, height - 1)) (const Nothing)
|
|
||||||
3
src/Types/BoardPosition.hs
Normal file
3
src/Types/BoardPosition.hs
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module Types.BoardPosition where
|
||||||
|
|
||||||
|
type BoardPosition = (Int, Int)
|
||||||
61
src/Types/GameBoard.hs
Normal file
61
src/Types/GameBoard.hs
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE UndecidableInstances #-}
|
||||||
|
|
||||||
|
module Types.GameBoard where
|
||||||
|
|
||||||
|
import Data.Array
|
||||||
|
import Data.Binary.Builder (append)
|
||||||
|
import Data.Maybe (mapMaybe)
|
||||||
|
import Display (Display, display)
|
||||||
|
import System.Random.Stateful (RandomGen)
|
||||||
|
import Types.BoardPosition
|
||||||
|
import Types.GameMode
|
||||||
|
|
||||||
|
data GameBoard mode = MkGameBoard
|
||||||
|
{ width :: Int
|
||||||
|
, height :: Int
|
||||||
|
, board :: Array BoardPosition (Maybe (Tile mode))
|
||||||
|
, gameMode :: mode
|
||||||
|
}
|
||||||
|
|
||||||
|
clear :: (GameMode mode) => GameBoard mode -> BoardPosition -> BoardPosition -> Bool
|
||||||
|
clear = undefined
|
||||||
|
|
||||||
|
selectCheck :: (GameMode mode) => GameBoard mode -> BoardPosition -> BoardPosition -> Bool
|
||||||
|
selectCheck board@MkGameBoard{gameMode} topLeft bottomRight =
|
||||||
|
check gameMode (select board topLeft bottomRight)
|
||||||
|
|
||||||
|
select :: (GameMode mode) => GameBoard mode -> BoardPosition -> BoardPosition -> [Tile mode]
|
||||||
|
select MkGameBoard{board} topLeft bottomRight =
|
||||||
|
mapMaybe (board !) (range (topLeft, bottomRight))
|
||||||
|
|
||||||
|
-- TODO: rewrite this with monadic RNG
|
||||||
|
newRandomBoard :: (RandomGen g, GameMode mode) => g -> mode -> Int -> Int -> (GameBoard mode, g)
|
||||||
|
newRandomBoard rng gameMode width height =
|
||||||
|
(MkGameBoard{width, height, gameMode, board = array (low, high) cellAssocList}, nextRng)
|
||||||
|
where
|
||||||
|
low = (0, 0)
|
||||||
|
high = (width - 1, height - 1)
|
||||||
|
(cellAssocList, nextRng) =
|
||||||
|
foldl'
|
||||||
|
( \(cur, rng') -> \ix ->
|
||||||
|
let (res, next) = gen gameMode rng' in ((ix, Just res) : cur, next)
|
||||||
|
)
|
||||||
|
([], rng)
|
||||||
|
ixs
|
||||||
|
ixs = range (low, high)
|
||||||
|
|
||||||
|
instance (Display (Tile mode)) => Display (GameBoard mode) where
|
||||||
|
display MkGameBoard{width, height, board} =
|
||||||
|
foldl' (\c -> \row -> c `append` displayRow row `append` "\n") "" [0 .. height - 1]
|
||||||
|
where
|
||||||
|
displayCell row col = case board ! (row, col) of Nothing -> " "; Just t -> display t
|
||||||
|
displayRow row =
|
||||||
|
foldl'
|
||||||
|
( \c -> \col ->
|
||||||
|
c `append` (displayCell row col) `append` " "
|
||||||
|
)
|
||||||
|
""
|
||||||
|
[0 .. width - 1]
|
||||||
37
src/Types/GameMode.hs
Normal file
37
src/Types/GameMode.hs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
|
||||||
|
module Types.GameMode where
|
||||||
|
|
||||||
|
import Data.Bifunctor (Bifunctor (first))
|
||||||
|
import Data.Kind (Type)
|
||||||
|
import Display
|
||||||
|
import System.Random.Stateful (Random (randomR), RandomGen)
|
||||||
|
|
||||||
|
{- | The type of game that is being played.
|
||||||
|
|
||||||
|
This typeclass carries information about how to check whether a set
|
||||||
|
of elements satisfies the condition for a valid move. For example,
|
||||||
|
in the 'SumTo n' mode, a valid move is a set of elements (Ints)
|
||||||
|
that sums up to 'n'.
|
||||||
|
-}
|
||||||
|
class (Display (Tile t), Show (Tile t), Eq (Tile t), Eq t, Show t) => GameMode t where
|
||||||
|
data Tile t :: Type
|
||||||
|
check :: t -> [Tile t] -> Bool
|
||||||
|
gen :: (RandomGen g) => t -> g -> (Tile t, g)
|
||||||
|
|
||||||
|
data SumTo = MkSumTo Int
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
instance GameMode SumTo where
|
||||||
|
data Tile SumTo = IntTile Int deriving (Eq, Show)
|
||||||
|
|
||||||
|
check (MkSumTo n) [] = n == 0
|
||||||
|
check (MkSumTo n) lst = n == sum (map toInt lst)
|
||||||
|
where
|
||||||
|
toInt (IntTile a) = a
|
||||||
|
gen (MkSumTo n) = first IntTile . randomR (1, n)
|
||||||
|
|
||||||
|
instance Display (Tile SumTo) where
|
||||||
|
display (IntTile x) = display x
|
||||||
7
test/Main.hs
Normal file
7
test/Main.hs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
module Main where
|
||||||
|
|
||||||
|
import Spec
|
||||||
|
import Test.Hspec
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = hspec spec
|
||||||
25
test/Spec.hs
25
test/Spec.hs
|
|
@ -1,9 +1,24 @@
|
||||||
module Main where
|
{-# LANGUAGE BlockArguments #-}
|
||||||
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
|
module Spec where
|
||||||
|
|
||||||
|
import Data.Array (array)
|
||||||
|
import Display (Display (display), displayText)
|
||||||
import Test.Hspec
|
import Test.Hspec
|
||||||
|
import Types.GameBoard
|
||||||
|
import Types.GameMode (SumTo (MkSumTo), Tile (IntTile))
|
||||||
|
|
||||||
spec :: Spec
|
spec :: Spec
|
||||||
spec = undefined
|
spec = describe "gameboard" do
|
||||||
|
it "displays correctly" do
|
||||||
main :: IO ()
|
let tiles =
|
||||||
main = hspec spec
|
array
|
||||||
|
((0, 0), (1, 1))
|
||||||
|
[ ((0, 0), Just $ IntTile 1)
|
||||||
|
, ((0, 1), Just $ IntTile 2)
|
||||||
|
, ((1, 0), Just $ IntTile 3)
|
||||||
|
, ((1, 1), Just $ IntTile 4)
|
||||||
|
]
|
||||||
|
gameBoard = MkGameBoard{width = 2, height = 2, gameMode = MkSumTo 10, board = tiles}
|
||||||
|
displayText gameBoard `shouldBe` "1 2 \n3 4 \n"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue