diff --git a/exercises/practice/state-of-tic-tac-toe/.meta/Example.fs b/exercises/practice/state-of-tic-tac-toe/.meta/Example.fs index 34c9bc78f..bfdac5647 100644 --- a/exercises/practice/state-of-tic-tac-toe/.meta/Example.fs +++ b/exercises/practice/state-of-tic-tac-toe/.meta/Example.fs @@ -16,12 +16,14 @@ type Board = Cell [,] let won (player: Cell) (board: Board) = let winning = [| player; player; player |] - Array.init 3 (fun i -> board[i, i]) = winning || - Array.init 3 (fun i -> board[i, 2 - i]) = winning - || Array.init 3 (fun i -> board[i, *]) |> Array.contains winning - || Array.init 3 (fun i -> board[*, i]) |> Array.contains winning - -let gameState (board: Board) = + Array.init 3 (fun i -> board[i, i]) = winning + || Array.init 3 (fun i -> board[i, 2 - i]) = winning + || Array.init 3 (fun i -> board[i, *]) + |> Array.contains winning + || Array.init 3 (fun i -> board[*, i]) + |> Array.contains winning + +let gamestate (board: Board) = let numCells cell = board |> Seq.cast diff --git a/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.fs b/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.fs index da839d6dc..fa21fcdf7 100644 --- a/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.fs +++ b/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToe.fs @@ -3,5 +3,5 @@ module StateOfTicTacToe // TODO: define the 'EndGameState' type // TODO: define the 'GameError' type -let gameState board = +let gamestate board = failwith "Please implement the 'gameState' function" diff --git a/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToeTests.fs b/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToeTests.fs index 5e0e9a4dd..15b38eb52 100644 --- a/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToeTests.fs +++ b/exercises/practice/state-of-tic-tac-toe/StateOfTicTacToeTests.fs @@ -7,328 +7,244 @@ open StateOfTicTacToe [] let ``Finished game where X won via left column victory`` () = - let board = - array2D [ - [ 'X'; 'O'; 'O' ] - [ 'X'; ' '; ' ' ] - [ 'X'; ' '; ' ' ] - ] - + let board = + array2D [ ['X'; 'O'; 'O']; + ['X'; ' '; ' ']; + ['X'; ' '; ' '] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where X won via middle column victory`` () = - let board = - array2D [ - [ 'O'; 'X'; 'O' ] - [ ' '; 'X'; ' ' ] - [ ' '; 'X'; ' ' ] - ] - + let board = + array2D [ ['O'; 'X'; 'O']; + [' '; 'X'; ' ']; + [' '; 'X'; ' '] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where X won via right column victory`` () = - let board = - array2D [ - [ 'O'; 'O'; 'X' ] - [ ' '; ' '; 'X' ] - [ ' '; ' '; 'X' ] - ] - + let board = + array2D [ ['O'; 'O'; 'X']; + [' '; ' '; 'X']; + [' '; ' '; 'X'] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where O won via left column victory`` () = - let board = - array2D [ - [ 'O'; 'X'; 'X' ] - [ 'O'; 'X'; ' ' ] - [ 'O'; ' '; ' ' ] - ] - + let board = + array2D [ ['O'; 'X'; 'X']; + ['O'; 'X'; ' ']; + ['O'; ' '; ' '] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where O won via middle column victory`` () = - let board = - array2D [ - [ 'X'; 'O'; 'X' ] - [ ' '; 'O'; 'X' ] - [ ' '; 'O'; ' ' ] - ] - + let board = + array2D [ ['X'; 'O'; 'X']; + [' '; 'O'; 'X']; + [' '; 'O'; ' '] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where O won via right column victory`` () = - let board = - array2D [ - [ 'X'; 'X'; 'O' ] - [ ' '; 'X'; 'O' ] - [ ' '; ' '; 'O' ] - ] - + let board = + array2D [ ['X'; 'X'; 'O']; + [' '; 'X'; 'O']; + [' '; ' '; 'O'] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where X won via top row victory`` () = - let board = - array2D [ - [ 'X'; 'X'; 'X' ] - [ 'X'; 'O'; 'O' ] - [ 'O'; ' '; ' ' ] - ] - + let board = + array2D [ ['X'; 'X'; 'X']; + ['X'; 'O'; 'O']; + ['O'; ' '; ' '] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where X won via middle row victory`` () = - let board = - array2D [ - [ 'O'; ' '; ' ' ] - [ 'X'; 'X'; 'X' ] - [ ' '; 'O'; ' ' ] - ] - + let board = + array2D [ ['O'; ' '; ' ']; + ['X'; 'X'; 'X']; + [' '; 'O'; ' '] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where X won via bottom row victory`` () = - let board = - array2D [ - [ ' '; 'O'; 'O' ] - [ 'O'; ' '; 'X' ] - [ 'X'; 'X'; 'X' ] - ] - + let board = + array2D [ [' '; 'O'; 'O']; + ['O'; ' '; 'X']; + ['X'; 'X'; 'X'] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where O won via top row victory`` () = - let board = - array2D [ - [ 'O'; 'O'; 'O' ] - [ 'X'; 'X'; 'O' ] - [ 'X'; 'X'; ' ' ] - ] - + let board = + array2D [ ['O'; 'O'; 'O']; + ['X'; 'X'; 'O']; + ['X'; 'X'; ' '] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where O won via middle row victory`` () = - let board = - array2D [ - [ 'X'; 'X'; ' ' ] - [ 'O'; 'O'; 'O' ] - [ 'X'; ' '; ' ' ] - ] - + let board = + array2D [ ['X'; 'X'; ' ']; + ['O'; 'O'; 'O']; + ['X'; ' '; ' '] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where O won via bottom row victory`` () = - let board = - array2D [ - [ 'X'; 'O'; 'X' ] - [ ' '; 'X'; 'X' ] - [ 'O'; 'O'; 'O' ] - ] - + let board = + array2D [ ['X'; 'O'; 'X']; + [' '; 'X'; 'X']; + ['O'; 'O'; 'O'] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where X won via falling diagonal victory`` () = - let board = - array2D [ - [ 'X'; 'O'; 'O' ] - [ ' '; 'X'; ' ' ] - [ ' '; ' '; 'X' ] - ] - + let board = + array2D [ ['X'; 'O'; 'O']; + [' '; 'X'; ' ']; + [' '; ' '; 'X'] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where X won via rising diagonal victory`` () = - let board = - array2D [ - [ 'O'; ' '; 'X' ] - [ 'O'; 'X'; ' ' ] - [ 'X'; ' '; ' ' ] - ] - + let board = + array2D [ ['O'; ' '; 'X']; + ['O'; 'X'; ' ']; + ['X'; ' '; ' '] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where O won via falling diagonal victory`` () = - let board = - array2D [ - [ 'O'; 'X'; 'X' ] - [ 'O'; 'O'; 'X' ] - [ 'X'; ' '; 'O' ] - ] - + let board = + array2D [ ['O'; 'X'; 'X']; + ['O'; 'O'; 'X']; + ['X'; ' '; 'O'] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where O won via rising diagonal victory`` () = - let board = - array2D [ - [ ' '; ' '; 'O' ] - [ ' '; 'O'; 'X' ] - [ 'O'; 'X'; 'X' ] - ] - + let board = + array2D [ [' '; ' '; 'O']; + [' '; 'O'; 'X']; + ['O'; 'X'; 'X'] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where X won via a row and a column victory`` () = - let board = - array2D [ - [ 'X'; 'X'; 'X' ] - [ 'X'; 'O'; 'O' ] - [ 'X'; 'O'; 'O' ] - ] - + let board = + array2D [ ['X'; 'X'; 'X']; + ['X'; 'O'; 'O']; + ['X'; 'O'; 'O'] ] let expected: Result = Ok Win - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Finished game where X won via two diagonal victories`` () = - let board = - array2D [ - [ 'X'; 'O'; 'X' ] - [ 'O'; 'X'; 'O' ] - [ 'X'; 'O'; 'X' ] - ] - - let expected: Result = Ok Win - gameState board |> should equal expected - -[] -let ``A draw`` () = - let board = - array2D [ - [ 'X'; 'O'; 'X' ] - [ 'X'; 'X'; 'O' ] - [ 'O'; 'X'; 'O' ] - ] - + let board = + array2D [ ['X'; 'O'; 'X']; + ['O'; 'X'; 'O']; + ['X'; 'O'; 'X'] ] + let expected: Result = Ok Win + gamestate board |> should equal expected + +[] +let ``Draw`` () = + let board = + array2D [ ['X'; 'O'; 'X']; + ['X'; 'X'; 'O']; + ['O'; 'X'; 'O'] ] let expected: Result = Ok Draw - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Another draw`` () = - let board = - array2D [ - [ 'X'; 'X'; 'O' ] - [ 'O'; 'X'; 'X' ] - [ 'X'; 'O'; 'O' ] - ] - + let board = + array2D [ ['X'; 'X'; 'O']; + ['O'; 'X'; 'X']; + ['X'; 'O'; 'O'] ] let expected: Result = Ok Draw - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Ongoing game: one move in`` () = - let board = - array2D [ - [ ' '; ' '; ' ' ] - [ 'X'; ' '; ' ' ] - [ ' '; ' '; ' ' ] - ] - + let board = + array2D [ [' '; ' '; ' ']; + ['X'; ' '; ' ']; + [' '; ' '; ' '] ] let expected: Result = Ok Ongoing - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Ongoing game: two moves in`` () = - let board = - array2D [ - [ 'O'; ' '; ' ' ] - [ ' '; 'X'; ' ' ] - [ ' '; ' '; ' ' ] - ] - + let board = + array2D [ ['O'; ' '; ' ']; + [' '; 'X'; ' ']; + [' '; ' '; ' '] ] let expected: Result = Ok Ongoing - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Ongoing game: five moves in`` () = - let board = - array2D [ - [ 'X'; ' '; ' ' ] - [ ' '; 'X'; 'O' ] - [ 'O'; 'X'; ' ' ] - ] - + let board = + array2D [ ['X'; ' '; ' ']; + [' '; 'X'; 'O']; + ['O'; 'X'; ' '] ] let expected: Result = Ok Ongoing - gameState board |> should equal expected + gamestate board |> should equal expected -[] +[] let ``Invalid board: X went twice`` () = - let board = - array2D [ - [ 'X'; 'X'; ' ' ] - [ ' '; ' '; ' ' ] - [ ' '; ' '; ' ' ] - ] - - let expected: Result = Error ConsecutiveMovesBySamePlayer - gameState board - |> should equal expected - -[] + let board = + array2D [ ['X'; 'X'; ' ']; + [' '; ' '; ' ']; + [' '; ' '; ' '] ] + let expected: Result = Error "Wrong turn order: X went twice" + gamestate board |> should equal expected + +[] let ``Invalid board: O started`` () = - let board = - array2D [ - [ 'O'; 'O'; 'X' ] - [ ' '; ' '; ' ' ] - [ ' '; ' '; ' ' ] - ] - - let expected: Result = Error WrongPlayerStarted - gameState board - |> should equal expected - -[] + let board = + array2D [ ['O'; 'O'; 'X']; + [' '; ' '; ' ']; + [' '; ' '; ' '] ] + let expected: Result = Error "Wrong turn order: O started" + gamestate board |> should equal expected + +[] let ``Invalid board: X won and O kept playing`` () = - let board = - array2D [ - [ 'X'; 'X'; 'X' ] - [ 'O'; 'O'; 'O' ] - [ ' '; ' '; ' ' ] - ] - - let expected: Result = Error MoveMadeAfterGameWasDone - gameState board - |> should equal expected - -[] + let board = + array2D [ ['X'; 'X'; 'X']; + ['O'; 'O'; 'O']; + [' '; ' '; ' '] ] + let expected: Result = Error "Impossible board: game should have ended after the game was won" + gamestate board |> should equal expected + +[] let ``Invalid board: players kept playing after a win`` () = - let board = - array2D [ - [ 'X'; 'X'; 'X' ] - [ 'O'; 'O'; 'O' ] - [ 'X'; 'O'; 'X' ] - ] + let board = + array2D [ ['X'; 'X'; 'X']; + ['O'; 'O'; 'O']; + ['X'; 'O'; 'X'] ] + let expected: Result = Error "Impossible board: game should have ended after the game was won" + gamestate board |> should equal expected - let expected: Result = Error MoveMadeAfterGameWasDone - gameState board - |> should equal expected diff --git a/generators/Generators.fs b/generators/Generators.fs index 3c3d9b005..ef644f042 100644 --- a/generators/Generators.fs +++ b/generators/Generators.fs @@ -2080,6 +2080,20 @@ type KillerSudokuHelper() = type StateOfTicTacToe() = inherit ExerciseGenerator() + override _.PropertiesWithIdentifier _ = [ "board"; "expected" ] + + override _.IdentifierTypeAnnotation(_, key, _) = + if key = "expected" then Some "Result" else None + + override _.RenderInput(_, _, value) = + let rows = value |> Seq.map (fun row -> row.ToString().ToCharArray() |> List.ofArray |> List.map (fun c -> $"'{c}'") |> Obj.render) + Collection.renderMultiLine "array2D [" "]" rows + + override _.RenderExpected(_, _, value) = + match value.SelectToken "error" with + | null -> $"Ok {String.upperCaseFirst (value.ToString())}" + | error -> $"Error \"%s{string error}\"" + type Satellite() = inherit ExerciseGenerator()