Last active
June 5, 2019 19:15
-
-
Save bryanedds/245b7e23ed2c7c112ea8ba7f43cf5405 to your computer and use it in GitHub Desktop.
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
/// 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 } | |
/// The game data abstraction. | |
abstraction Game = | |
{ FirstPlayerTurn : bool | |
Board : Map<Position, Piece> } | |
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