Skip to content

Instantly share code, notes, and snippets.

@johnomarkid
Created May 22, 2016 06:40
Show Gist options
  • Save johnomarkid/b2a0eece875f5f7f725a3482ed0b05e3 to your computer and use it in GitHub Desktop.
Save johnomarkid/b2a0eece875f5f7f725a3482ed0b05e3 to your computer and use it in GitHub Desktop.
module GameLogic exposing (..)
import Model exposing (..)
-- Helpers
createScoreboard : Mark -> Board -> List (List Int)
createScoreboard mark board =
(List.map2
(\row items ->
List.map2
(\col item ->
if item == mark then
1
else
0
)
[0..((List.length board) - 1)]
items
)
[0..((List.length board) - 1)]
board
)
listToStatus : List Int -> Status
listToStatus items =
if (List.sum items) == (List.length items) then
Win
else
Ongoing
get : Int -> List a -> a
get n xs =
List.head (List.drop n xs)
|> fromJust
fromJust : Maybe a -> a
fromJust x =
case x of
Just y ->
y
Nothing ->
Debug.crash "error: fromJust Nothing"
invertScoreboard : List (List a) -> List (List a)
invertScoreboard board =
List.map (\i -> List.map (\row -> get i row) board) [0..((List.length board) - 1)]
invertUpVertical : List (List number) -> List number
invertUpVertical board =
let
boardLength =
((List.length board) - 1)
in
List.map2
(\row index ->
if (get (boardLength - index) row) == 1 then
1
else
0
)
board
[0..boardLength]
invertDownVertical : List (List number) -> List number
invertDownVertical board =
List.map2
(\row index ->
if (get (0 + index) row) == 1 then
1
else
0
)
board
[0..((List.length board) - 1)]
-- randLocation : Model -> ( Location, Model )
-- randLocation model =
-- let
-- randRange =
-- int 0 ((List.length model.board) - 1)
--
-- rowResult =
-- generate randRange model.randSeed
--
-- colResult =
-- generate randRange (snd rowResult)
--
-- -- use new seed from rowResult
-- location =
-- ( (fst rowResult), (fst colResult) )
--
-- newSeed =
-- snd colResult
--
-- newModel =
-- { model | randSeed = newSeed }
--
-- markAtLocation =
-- get (fst location) model.board
-- |> get (snd location)
-- in
-- if markAtLocation == NA then
-- ( location, newModel )
-- else
-- randLocation newModel
-- Core Gameplay
checkWin : Model -> Model
checkWin model =
let
-- if sum of row = 3 for items that match mark
scoreBoard =
createScoreboard model.turn model.board
checkRow =
scoreBoard
|> List.map listToStatus
checkCol =
scoreBoard
|> invertScoreboard
|> List.map listToStatus
checkUpVertical =
scoreBoard
|> invertUpVertical
|> listToStatus
checkDownVertical =
scoreBoard
|> invertDownVertical
|> listToStatus
status =
List.append checkRow checkCol
|> (\v -> checkUpVertical :: v)
|> (\v -> checkDownVertical :: v)
|> List.member Win
|> (\v ->
(if v == True then
Win
else
Ongoing
)
)
-- tie if moves = 0 and no win above
remainingMoves =
createScoreboard NA model.board
|> List.map List.sum
|> List.sum
newStatus =
case remainingMoves == 0 of
True ->
if status == Ongoing then
Tie
else
status
False ->
status
in
{ model | status = newStatus }
updateSquare : Location -> Model -> Model
updateSquare location model =
let
newBoard =
(List.map2
(\x row ->
List.map2
(\y item ->
if ( x, y ) == location then
model.turn
else
item
)
[0..model.boardSize]
row
)
[0..model.boardSize]
model.board
)
in
{ model | board = newBoard }
changeTurn : Model -> Model
changeTurn model =
let
newTurn =
case model.turn of
X ->
O
O ->
X
NA ->
NA
in
{ model | turn = newTurn }
module Main exposing (..)
import Html.App as Html
import Html exposing (..)
import Html.Events exposing (onClick)
import Html.Attributes exposing (..)
import Model exposing (..)
import GameLogic exposing (updateSquare, checkWin, changeTurn)
-- Helper
markToString : Mark -> String
markToString mark =
case mark of
X ->
"X"
O ->
"O"
NA ->
""
--Update
type Msg
= NoOp
| Reset
| IncreaseBoard
| Turn Location
update : Msg -> Model -> Model
update msg model =
case msg of
NoOp ->
model
Reset ->
initialModel 2
IncreaseBoard ->
initialModel (model.boardSize + 1)
Turn location ->
let
newModel =
updateSquare location model
|> checkWin
|> (\aModel -> changeTurn aModel)
|> (\bModel ->
-- this is a recursive call to update for the cpu move if turn == O
-- can't call this if someone has won because causes infinite loop
if bModel.status /= Ongoing then
changeTurn bModel
else
(if bModel.turn == O then
-- let
-- ( loc, newModel ) =
-- randLocation bModel
-- in
--update (Turn loc) newModel
bModel -- temporary
else
bModel
)
)
in
newModel
-- View
squareView : Int -> Int -> Mark -> Html Msg
squareView rowNum colNum mark =
let
location =
( rowNum, colNum )
action =
if mark == NA then
(Turn location)
else
NoOp
in
div [ onClick action
, style [("width", "50px"), ("height", "50px"), ("background-color", "gray"), ("border", "1px solid black"), ("justify-content", "center"), ("align-items", "center") ,("display", "flex")]]
[text (markToString mark)]
rowView : Int -> Int -> List Mark -> Html Msg
rowView bs rowNum items =
let
squares =
List.map2 (squareView rowNum) [0..bs] items
in
div [style [("display", "flex")]] squares
view : Model -> Html Msg
view model =
let
board =
if model.status == Ongoing then
div []
(List.map2 (rowView model.boardSize) [0..model.boardSize] model.board)
else
div [] [text "Play again!"]
buttons =
div [] [
button [onClick Reset] [text "Reset Game"]
, button [onClick IncreaseBoard] [text "Increase Board Size"]]
statusMessage =
(case model.status of
Win ->
(markToString model.turn) ++ " Wins!"
Tie ->
"It's a Tie!"
Ongoing ->
"Game is ongoing."
)
in
div [] [board, buttons, div [] [text statusMessage]]
main: Program Never
main =
Html.beginnerProgram { model = (initialModel 2), view = view, update = update }
module Model exposing (..)
type alias Model =
{ board : Board
, turn : Mark
, status : Status
, boardSize : Int
}
initialModel : Int -> Model
initialModel bs =
{ board = initialBoard bs
, turn = X
, status = Ongoing
, boardSize = bs
}
type alias Board =
List (List Mark)
initialBoard : Int -> Board
initialBoard numRows =
let
returnNum _ =
NA
in
List.map (\i -> List.map returnNum [0..numRows]) [0..numRows]
type Status
= Ongoing
| Tie
| Win
type Mark
= X
| O
| NA
type alias Location =
( Int, Int )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment