Created
February 9, 2024 22:40
-
-
Save Frityet/83db3e2b4ae5e39e7bad5975731cb73a 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
// tic tac toe in F# | |
open System | |
module TicTacToe = | |
type Player = X | O | |
type Cell = Empty | Checked of Player | |
type Board = Cell list list | |
let cellToString cell = | |
match cell with | |
| Empty -> " " | |
| Checked X -> "X" | |
| Checked O -> "O" | |
let nextPlayer prev = match prev with | X -> O | O -> X | |
let boardToString board = | |
board |> List.map (fun x -> x |> List.map cellToString |> String.concat " | ") |> String.concat "\n--+---+--\n" | |
let markPart x y board player = | |
let row = board |> List.item y | |
let newRow = row |> List.mapi (fun i cell -> if i = x then Checked player else cell) | |
List.mapi (fun i row -> if i = y then newRow else row) board | |
type Input = Move of int * int | Exit | |
let rec readMove () = | |
let line = Console.ReadLine() | |
match line with | |
| "exit" -> Exit | |
| _ -> | |
let parts = line.Split ' ' | |
if parts.Length <> 2 then | |
printfn "Invalid input, please try again." | |
readMove () | |
else | |
let x = Int32.Parse parts.[0] | |
let y = Int32.Parse parts.[1] | |
if x >= 0 && x <= 2 && y >= 0 && y <= 2 then | |
Move(x, y) | |
else | |
printfn "Invalid coordinates, please try again." | |
readMove () | |
let checkRow row = | |
match row with | |
| [Checked p1; Checked p2; Checked p3] when p1 = p2 && p2 = p3 -> true | |
| _ -> false | |
let checkColumn board i = | |
checkRow (board |> List.map (fun row -> List.item i row)) | |
let checkDiagonals (board: Board) = | |
let diag1 = [board.[0].[0]; board.[1].[1]; board.[2].[2]] | |
let diag2 = [board.[0].[2]; board.[1].[1]; board.[2].[0]] | |
checkRow diag1 || checkRow diag2 | |
let checkState board = | |
let rows = board |> List.map checkRow | |
let cols = [0..2] |> List.map (checkColumn board) | |
let diags = checkDiagonals board | |
(rows |> List.exists (fun x -> x)) || (cols |> List.exists (fun x -> x)) || diags | |
let rec main player board = | |
printfn "%s" (boardToString board) | |
printfn "Player %s" (cellToString (Checked player)) | |
printf "Enter the coordinates of your move (x y), or 'exit' to stop the game: " | |
let mov = readMove () | |
match mov with | |
| Exit -> | |
printf "Goodbye!" | |
() | |
| Move(x, y) -> | |
let newBoard = markPart x y board player | |
if checkState newBoard then | |
printfn "Player %s wins!" (cellToString (Checked player)) | |
() | |
else | |
main (nextPlayer player) newBoard |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment