Skip to content

Instantly share code, notes, and snippets.

@bryanedds
Last active August 13, 2016 11:07
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save bryanedds/87788350203a6a0527d9 to your computer and use it in GitHub Desktop.
Save bryanedds/87788350203a6a0527d9 to your computer and use it in GitHub Desktop.
/// A tic-tac-toe piece, or the absence thereof.
type Piece = U | X | O
/// Tic-tac-toe board position.
type Position = { X : int; Y : int }
[<AutoOpen>]
module GameModule =
/// A tic-tac-toe game implemented as a Pure ADT.
type Game =
private
{ FirstPlayerTurn : bool
Board : Map<Position, Piece> }
[<RequireQualifiedAccess; CompilationRepresentation (CompilationRepresentationFlags.ModuleSuffix)>]
module Game =
let private ownsDiagonalA piece game =
List.fold (fun s i -> s && game.Board.[{ X = i; Y = i}] = piece) true [0 .. 2]
let private ownsDiagonalB piece game =
List.fold (fun s i -> s && game.Board.[{ X = i; Y = 2 - i}] = piece) true [0 .. 2]
let private ownsDiagonal piece game =
ownsDiagonalA piece game ||
ownsDiagonalB piece game
let private ownsHorizontalAt y piece game =
List.fold (fun s x -> s && Map.find { X = x; Y = y} game.Board = piece) true [0 .. 2]
let private ownsVerticalAt x piece game =
List.fold (fun s y -> s && Map.find { X = x; Y = y} game.Board = piece) true [0 .. 2]
let private ownsHorizontal piece game =
List.fold (fun s y -> s || ownsHorizontalAt y piece game) false [0 .. 2]
let private ownsVertical piece game =
List.fold (fun s x -> s || ownsVerticalAt x piece game) false [0 .. 2]
let private ownsLine piece game =
ownsDiagonal piece game ||
ownsHorizontal piece game ||
ownsVertical piece game
/// Get the current winner, or U if none.
let getWinner game =
if ownsLine X game then X
elif ownsLine O game then O
else U
/// Try to place a piece on the board at the given position.
let tryPlace position game =
match getWinner game with
| U ->
match Map.tryFind position game.Board with
| Some piece ->
match piece with
| U ->
let board = Map.add position (if game.FirstPlayerTurn then X else O) game.Board
let firstPlayerTurn = not game.FirstPlayerTurn
Some { game with Board = board; FirstPlayerTurn = firstPlayerTurn }
| X | O -> None
| None -> None
| X | O -> None
/// Make tic-tac-toe game.
let make () =
let board =
Map.ofList
[for x in 0 .. 2 do
for y in 0 .. 2 do
yield ({ X = x; Y = y }, U)]
{ Board = board; FirstPlayerTurn = true }
let [<EntryPoint>] main _ =
let game = Game.make ()
let game = Game.tryPlace { X = 0; Y = 0 } game |> Option.get
let game = Game.tryPlace { X = 1; Y = 0 } game |> Option.get
let game = Game.tryPlace { X = 1; Y = 1 } game |> Option.get
let game = Game.tryPlace { X = 0; Y = 1 } game |> Option.get
let game = Game.tryPlace { X = 2; Y = 2 } game |> Option.get
printfn "Winner is %A!" <| Game.getWinner game
0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment