Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
133
Task/Tic-tac-toe/F-Sharp/tic-tac-toe.fs
Normal file
133
Task/Tic-tac-toe/F-Sharp/tic-tac-toe.fs
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
type Brick =
|
||||
| Empty
|
||||
| Computer
|
||||
| User
|
||||
|
||||
let brickToString = function
|
||||
| Empty -> ' '
|
||||
| Computer -> 'X'
|
||||
| User -> 'O'
|
||||
|
||||
// y -> x -> Brick
|
||||
type Board = Map<int, Map<int, Brick> >
|
||||
|
||||
let emptyBoard =
|
||||
let emptyRow = Map.ofList [0,Empty; 1,Empty; 2,Empty]
|
||||
Map.ofList [0,emptyRow; 1,emptyRow; 2,emptyRow]
|
||||
|
||||
let get (b:Board) (x,y) = b.[y].[x]
|
||||
|
||||
let set player (b:Board) (x,y) : Board =
|
||||
let row = b.[y].Add(x, player)
|
||||
b.Add(y, row)
|
||||
|
||||
let winningPositions =
|
||||
[for x in [0..2] -> x,x] // first diagonal
|
||||
::[for x in [0..2] -> 2-x,x] // second diagonal
|
||||
::[for y in [0..2] do
|
||||
yield! [[for x in [0..2]->(y,x)]; // columns
|
||||
[for x in [0..2] -> (x,y)]]] // rows
|
||||
|
||||
let hasWon player board =
|
||||
List.exists
|
||||
(fun ps -> List.forall (fun pos -> get board pos = player) ps)
|
||||
winningPositions
|
||||
|
||||
let freeSpace board =
|
||||
[for x in 0..2 do
|
||||
for y in 0..2 do
|
||||
if get board (x,y) = Empty then yield x,y]
|
||||
|
||||
type Evaluation =
|
||||
| Win
|
||||
| Draw
|
||||
| Lose
|
||||
|
||||
let rec evaluate board move =
|
||||
let b2 = set Computer board move
|
||||
if hasWon Computer b2 then Win
|
||||
else
|
||||
match freeSpace b2 with
|
||||
| [] -> Draw
|
||||
| userChoices ->
|
||||
let b3s = List.map (set User b2) userChoices
|
||||
if List.exists (hasWon User) b3s then Lose
|
||||
elif List.exists (fun b3 -> bestOutcome b3 = Lose) b3s
|
||||
then Lose
|
||||
elif List.exists (fun b3 -> bestOutcome b3 = Draw) b3s
|
||||
then Draw
|
||||
else Win
|
||||
|
||||
and findBestChoice b =
|
||||
match freeSpace b with
|
||||
| [] -> ((-1,-1), Draw)
|
||||
| choices ->
|
||||
match List.tryFind (fun c -> evaluate b c = Win) choices with
|
||||
| Some c -> (c, Win)
|
||||
| None -> match List.tryFind (fun c -> evaluate b c = Draw) choices with
|
||||
| Some c -> (c, Draw)
|
||||
| None -> (List.head choices, Lose)
|
||||
|
||||
and bestOutcome b = snd (findBestChoice b)
|
||||
|
||||
let bestChoice b = fst (findBestChoice b)
|
||||
|
||||
let computerPlay b = set Computer b (bestChoice b)
|
||||
|
||||
let printBoard b =
|
||||
printfn " | A | B | C |"
|
||||
printfn "---+---+---+---+"
|
||||
for y in 0..2 do
|
||||
printfn " %d | %c | %c | %c |"
|
||||
(3-y)
|
||||
(get b (0,y) |> brickToString)
|
||||
(get b (1,y) |> brickToString)
|
||||
(get b (2,y) |> brickToString)
|
||||
printfn "---+---+---+---+"
|
||||
|
||||
let rec userPlay b =
|
||||
printfn "Which field do you play? (format: a1)"
|
||||
let input = System.Console.ReadLine()
|
||||
if input.Length <> 2
|
||||
|| input.[0] < 'a' || input.[0] > 'c'
|
||||
|| input.[1] < '1' || input.[1] > '3' then
|
||||
printfn "illegal input"
|
||||
userPlay b
|
||||
else
|
||||
let x = int(input.[0]) - int('a')
|
||||
let y = 2 - int(input.[1]) + int('1')
|
||||
if get b (x,y) <> Empty then
|
||||
printfn "Field is not free."
|
||||
userPlay b
|
||||
else
|
||||
set User b (x,y)
|
||||
|
||||
let rec gameLoop b player =
|
||||
if freeSpace b = [] then
|
||||
printfn "Game over. Draw."
|
||||
elif player = Computer then
|
||||
printfn "Computer plays..."
|
||||
let b2 = computerPlay b
|
||||
printBoard b2
|
||||
if hasWon Computer b2 then
|
||||
printfn "Game over. I have won."
|
||||
else
|
||||
gameLoop b2 User
|
||||
elif player = User then
|
||||
let b2 = userPlay b
|
||||
printBoard b2
|
||||
if hasWon User b2 then
|
||||
printfn "Game over. You have won."
|
||||
else
|
||||
gameLoop b2 Computer
|
||||
|
||||
// randomly choose an element of a list
|
||||
let choose =
|
||||
let rnd = new System.Random()
|
||||
fun (xs:_ list) -> xs.[rnd.Next(xs.Length)]
|
||||
|
||||
// play first brick randomly
|
||||
printfn "Computer starts."
|
||||
let b = set Computer emptyBoard (choose (freeSpace emptyBoard))
|
||||
printBoard b
|
||||
gameLoop b User
|
||||
Loading…
Add table
Add a link
Reference in a new issue