Skip to content

Commit

Permalink
Refactor update (#42)
Browse files Browse the repository at this point in the history
* finished creation of Game module

* we should commit this
  • Loading branch information
tkshill authored Nov 4, 2020
1 parent 5f1763d commit 78e684a
Show file tree
Hide file tree
Showing 6 changed files with 479 additions and 348 deletions.
7 changes: 4 additions & 3 deletions elm.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
"elm/browser": "1.0.2",
"elm/core": "1.0.5",
"elm/html": "1.0.0",
"elm/random": "1.0.0",
"elm/svg": "1.0.1",
"elm/url": "1.0.0",
"elm-community/list-extra": "8.2.4",
"mdgriffith/elm-ui": "1.1.7"
"mdgriffith/elm-ui": "1.1.7",
"mgold/elm-nonempty-list": "4.1.0"
},
"indirect": {
"elm/json": "1.1.3",
Expand All @@ -29,8 +31,7 @@
"avh4/elm-fifo": "1.0.4",
"elm/bytes": "1.0.8",
"elm/file": "1.0.5",
"elm/http": "2.0.0",
"elm/random": "1.0.0"
"elm/http": "2.0.0"
}
}
}
281 changes: 281 additions & 0 deletions src/Game.elm
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
module Game exposing
( Cell
, GameStatus(..)
, Model(..)
, Msg(..)
, Player(..)
, Turn(..)
, currentStatus
, gameboard
, init
, nameToString
, pieceToString
, playerToString
, remainingPieces
, update
)

import Dict
import Game.Board as Board
exposing
( Board
, BoardStatus(..)
)
import Game.Core exposing (Cellname(..), Gamepiece)
import Helpers exposing (andThen, map, noCmds, withCmd)
import List.Nonempty as Listn
import Process
import Random
import Shared exposing (Model)
import Task



-- DOMAIN


type Player
= Human
| Computer


type alias ActivePlayer =
Player


type alias Winner =
Player


type alias Cell =
{ name : Cellname
, status : Maybe Gamepiece
}


type alias ChosenPiece =
Gamepiece


type GeneratorOptions
= GetGamepiece
| GetCell


type Turn
= ChoosingPiece
| ChoosingCellToPlay ChosenPiece


type GameStatus
= InPlay ActivePlayer Turn
| Won Winner
| Draw


type Model
= Model { board : Board, status : GameStatus }



-- INIT


initStatus : GameStatus
initStatus =
InPlay Human ChoosingPiece


init : Model
init =
Model { board = Board.init, status = initStatus }



-- Msg


type Msg
= HumanSelectedPiece Gamepiece
| HumanSelectedCell Cellname
| RestartWanted
| ComputerSelectedCell Cellname
| ComputerSelectedPiece Gamepiece
| NoOp



-- UPDATE


update : Msg -> Model -> ( Model, Cmd Msg )
update msg (Model model) =
case ( msg, model.status ) of
( HumanSelectedPiece piece, InPlay Human ChoosingPiece ) ->
Model model
|> noCmds
|> map (nextPlayerStartsPlaying Human piece)
|> withCmd (wait 2)
|> andThen (computerChooses GetCell)

( ComputerSelectedCell name, InPlay Computer (ChoosingCellToPlay piece) ) ->
Model model
|> noCmds
|> map (playerMakesPlay name piece)
|> andThen (checkForWin Computer)

( ComputerSelectedPiece piece, InPlay Computer ChoosingPiece ) ->
Model model
|> noCmds
|> map (nextPlayerStartsPlaying Computer piece)

( HumanSelectedCell name, InPlay Human (ChoosingCellToPlay piece) ) ->
Model model
|> noCmds
|> map (playerMakesPlay name piece)
|> andThen (checkForWin Human)

( RestartWanted, _ ) ->
init |> noCmds

( NoOp, _ ) ->
Model model |> noCmds

_ ->
Model model |> noCmds


nextPlayerStartsPlaying : ActivePlayer -> Gamepiece -> Model -> Model
nextPlayerStartsPlaying player piece (Model model) =
Model { model | status = InPlay (switch player) (ChoosingCellToPlay piece) }


computerChooses : GeneratorOptions -> Model -> ( Model, Cmd Msg )
computerChooses opt (Model model) =
let
helper : (a -> Msg) -> List a -> ( Model, Cmd Msg )
helper msg lst =
lst
|> Listn.fromList
|> Maybe.map
(\items ->
( Model model, Random.generate msg (Listn.sample items) )
)
|> Maybe.withDefault (Model model |> noCmds)
in
case opt of
GetCell ->
Board.openCells model.board
|> helper ComputerSelectedCell

GetGamepiece ->
Board.unPlayedPieces model.board
|> helper ComputerSelectedPiece


playerMakesPlay : Cellname -> Gamepiece -> Model -> Model
playerMakesPlay name piece (Model model) =
let
newBoard =
Board.update name piece model.board
in
Model { model | board = newBoard }


checkForWin : ActivePlayer -> Model -> ( Model, Cmd Msg )
checkForWin player (Model ({ board, status } as model)) =
case ( player, Board.status board ) of
( Computer, CanContinue ) ->
Model model
|> noCmds
|> map (playerStartsChoosing Computer)
|> withCmd (wait 2)
|> andThen (computerChooses GetGamepiece)

( Human, CanContinue ) ->
Model model
|> noCmds
|> map (playerStartsChoosing Human)

( _, MatchFound ) ->
Model { model | status = Won player }
|> noCmds

( _, Full ) ->
Model { model | status = Draw } |> noCmds


playerStartsChoosing : Player -> Model -> Model
playerStartsChoosing player (Model model) =
Model { model | status = InPlay player ChoosingPiece }



-- Cmd Msg


type Seconds
= Seconds Int


wait : Int -> Cmd Msg
wait i =
delay (Seconds i) NoOp


delay : Seconds -> Msg -> Cmd Msg
delay (Seconds time) msg =
Process.sleep (toFloat <| time * 1000)
|> Task.andThen (always <| Task.succeed msg)
|> Task.perform identity



-- UTILITY


switch : ActivePlayer -> ActivePlayer
switch player =
if player == Human then
Computer

else
Human


gameboard : Model -> (Cellname -> Cell)
gameboard (Model model) =
\name ->
Board.playedPieces model.board
|> Dict.get (Board.nameToString name)
|> Cell name


remainingPieces : Model -> List Gamepiece
remainingPieces (Model model) =
Board.unPlayedPieces model.board


currentStatus : Model -> GameStatus
currentStatus (Model model) =
model.status


playerToString : Player -> String
playerToString player =
case player of
Human ->
"Human"

Computer ->
"Computer"


nameToString : Cellname -> String
nameToString =
Board.nameToString


pieceToString : Gamepiece -> String
pieceToString =
Board.pieceToString
Loading

0 comments on commit 78e684a

Please sign in to comment.