Skip to content

Instantly share code, notes, and snippets.

@maticzav
Last active April 6, 2019 12:19
Show Gist options
  • Save maticzav/bf7165b78d1b3aa6fb179c7deeb82945 to your computer and use it in GitHub Desktop.
Save maticzav/bf7165b78d1b3aa6fb179c7deeb82945 to your computer and use it in GitHub Desktop.
TicTacToe game written in Elm
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