Last active
April 6, 2019 12:19
-
-
Save maticzav/bf7165b78d1b3aa6fb179c7deeb82945 to your computer and use it in GitHub Desktop.
TicTacToe game written in Elm
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Main exposing (main) | |
import Browser | |
import Html exposing (Html, button, div, table, td, text, tr) | |
import Html.Attributes exposing (disabled) | |
import Html.Events exposing (onClick) | |
import List | |
import Maybe | |
type alias Model = | |
{ board : Board | |
, player : Player | |
} | |
type alias Board = | |
List Position | |
type Position | |
= Position Int (Maybe Player) | |
type Player | |
= Cross | |
| Circle | |
--INIT | |
init : ( Model, Cmd Msg ) | |
init = | |
( Model initBoard Cross, Cmd.none ) | |
initBoard : Board | |
initBoard = | |
List.map (\n -> Position n Nothing) [ 0, 1, 2, 3, 4, 5, 6, 7, 8 ] | |
-- UPDATE | |
type Msg | |
= Reset | |
| Pick Int | |
update : Msg -> Model -> ( Model, Cmd Msg ) | |
update msg model = | |
case msg of | |
Reset -> | |
init | |
Pick position -> | |
let | |
board = | |
case getWinner model.board of | |
Just _ -> | |
initBoard | |
Nothing -> | |
model.board | |
newBoard = | |
List.map updatePosition board | |
updatePosition (Position location player) = | |
if location == position then | |
Position location (Just model.player) | |
else | |
Position location player | |
newPlayer = | |
notPlayer model.player | |
in | |
( { model | board = newBoard, player = newPlayer } | |
, Cmd.none | |
) | |
notPlayer : Player -> Player | |
notPlayer player = | |
case player of | |
Cross -> | |
Circle | |
Circle -> | |
Cross | |
getWinner : Board -> Maybe Player | |
getWinner board = | |
List.foldr | |
(\combination winner -> | |
case ( winner, checkCombination board combination ) of | |
( Just player, _ ) -> | |
Just player | |
( Nothing, Just player ) -> | |
Just player | |
( _, _ ) -> | |
Nothing | |
) | |
Nothing | |
winningCombinations | |
checkCombination : Board -> List Int -> Maybe Player | |
checkCombination board combination = | |
let | |
entries : List (Maybe Player) | |
entries = | |
combination | |
|> List.map (findPosition board) | |
|> List.map | |
(\entry -> | |
case entry of | |
Just (Position _ player) -> | |
player | |
Nothing -> | |
Nothing | |
) | |
in | |
case entries of | |
[ Just Circle, Just Circle, Just Circle ] -> | |
Just Circle | |
[ Just Cross, Just Cross, Just Cross ] -> | |
Just Cross | |
_ -> | |
Nothing | |
winningCombinations : List (List Int) | |
winningCombinations = | |
[ [ 0, 1, 2 ] | |
, [ 3, 4, 5 ] | |
, [ 6, 7, 8 ] | |
, [ 0, 3, 6 ] | |
, [ 1, 4, 7 ] | |
, [ 2, 5, 8 ] | |
, [ 0, 4, 8 ] | |
, [ 2, 4, 6 ] | |
] | |
find : (a -> Bool) -> List a -> Maybe a | |
find p list = | |
case list of | |
[] -> | |
Nothing | |
x :: xs -> | |
if p x then | |
Just x | |
else | |
find p xs | |
findPosition : Board -> Int -> Maybe Position | |
findPosition board location = | |
find (\(Position l _) -> l == location) board | |
-- VIEW | |
view : Model -> Browser.Document Msg | |
view model = | |
{ title = "Križci in krožci" | |
, body = | |
[ viewPlayer model.player | |
, viewBoard model.board | |
, viewWinner model.board | |
, viewReset | |
] | |
} | |
viewPlayer : Player -> Html Msg | |
viewPlayer player = | |
case player of | |
Cross -> | |
text "Križci na potezi" | |
Circle -> | |
text "Krožci na potezi" | |
viewBoard : Board -> Html Msg | |
viewBoard board = | |
let | |
format = | |
[ [ 0, 1, 2 ], [ 3, 4, 5 ], [ 6, 7, 8 ] ] | |
rows = | |
List.map (viewRow board) format | |
in | |
table [] rows | |
viewRow : Board -> List Int -> Html Msg | |
viewRow board row = | |
let | |
tiles = | |
List.map (viewTile board) row | |
in | |
tr [] tiles | |
viewTile : Board -> Int -> Html Msg | |
viewTile board location = | |
let | |
viewSymbol sym = | |
case sym of | |
Just Circle -> | |
text "O" | |
Just Cross -> | |
text "X" | |
Nothing -> | |
text " " | |
in | |
case findPosition board location of | |
Just (Position l player) -> | |
td [] | |
[ button | |
[ onClick (Pick l) | |
, disabled (player /= Nothing) | |
] | |
[ viewSymbol player ] | |
] | |
Nothing -> | |
td [] [] | |
viewWinner : Board -> Html Msg | |
viewWinner board = | |
case getWinner board of | |
Just Circle -> | |
text "Krožci so zmagali" | |
Just Cross -> | |
text "Križci so zmagali" | |
Nothing -> | |
text "Spremljamo zelo napeto igro!!!" | |
viewReset : Html Msg | |
viewReset = | |
div [] | |
[ text "Začni od začetka" | |
, button [ onClick Reset ] [ text "Ponastavi" ] | |
] | |
main : Program () Model Msg | |
main = | |
Browser.document | |
{ init = \_ -> init | |
, view = view | |
, update = update | |
, subscriptions = \_ -> Sub.none | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment