|
|
|
@ -1,6 +1,8 @@ |
|
|
|
|
import t from "tap"; |
|
|
|
|
import t, { Test } from "tap"; |
|
|
|
|
|
|
|
|
|
import { ExpectedOutcome, FinalOutcome } from "./datatypes.ts"; |
|
|
|
|
import { Board } from "./board.ts"; |
|
|
|
|
import { ExpectedOutcome, FinalOutcome, Opponent, Player } from "./datatypes.ts"; |
|
|
|
|
import { createOpponent } from "./opponent.ts"; |
|
|
|
|
import { computeAllSolutions } from "./solver.ts"; |
|
|
|
|
import { rules } from "./tictactoe-rules.ts"; |
|
|
|
|
|
|
|
|
@ -142,3 +144,70 @@ void t.test("computeAllSolutions", async (t) => { |
|
|
|
|
"OO_|__X|_XX": { finalOutcome: FinalOutcome.WinO, movesLeft: 1 }, |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("createOpponent", async (t) => { |
|
|
|
|
const checkNextMove = ( |
|
|
|
|
t: Test, |
|
|
|
|
opponent: Opponent, |
|
|
|
|
currentBoardSerialized: string, |
|
|
|
|
currentPlayer: Player, |
|
|
|
|
expectedNextBoardSerialized: string, |
|
|
|
|
) => { |
|
|
|
|
t.equal( |
|
|
|
|
opponent.getNextMove(Board.fromSerialized(currentBoardSerialized), currentPlayer).serialize(), |
|
|
|
|
expectedNextBoardSerialized, |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
void t.test("1x5 board", async (t) => { |
|
|
|
|
const outcomes = computeAllSolutions(1, 5, rules); |
|
|
|
|
const opponent = createOpponent(outcomes); |
|
|
|
|
|
|
|
|
|
checkNextMove(t, opponent, "_____", Player.X, "X____"); |
|
|
|
|
checkNextMove(t, opponent, "X____", Player.O, "XO___"); |
|
|
|
|
checkNextMove(t, opponent, "XO___", Player.X, "XOX__"); |
|
|
|
|
checkNextMove(t, opponent, "XOX__", Player.O, "XOXO_"); |
|
|
|
|
checkNextMove(t, opponent, "XOXO_", Player.X, "XOXOX"); |
|
|
|
|
|
|
|
|
|
checkNextMove(t, opponent, "__X__", Player.O, "_OX__"); |
|
|
|
|
checkNextMove(t, opponent, "_OX__", Player.X, "XOX__"); |
|
|
|
|
checkNextMove(t, opponent, "XOX__", Player.O, "XOXO_"); |
|
|
|
|
checkNextMove(t, opponent, "XOXO_", Player.X, "XOXOX"); |
|
|
|
|
|
|
|
|
|
checkNextMove(t, opponent, "O_X__", Player.X, "O_XX_"); |
|
|
|
|
checkNextMove(t, opponent, "O_XX_", Player.O, "OOXX_"); |
|
|
|
|
checkNextMove(t, opponent, "OOXX_", Player.X, "OOXXX"); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("3x3 board", async (t) => { |
|
|
|
|
const outcomes = computeAllSolutions(3, 3, rules); |
|
|
|
|
const opponent = createOpponent(outcomes); |
|
|
|
|
|
|
|
|
|
checkNextMove(t, opponent, "___|___|___", Player.X, "X__|___|___"); |
|
|
|
|
checkNextMove(t, opponent, "X__|___|___", Player.O, "X__|_O_|___"); |
|
|
|
|
checkNextMove(t, opponent, "X__|_O_|___", Player.X, "XX_|_O_|___"); |
|
|
|
|
checkNextMove(t, opponent, "XX_|_O_|___", Player.O, "XXO|_O_|___"); |
|
|
|
|
checkNextMove(t, opponent, "XXO|_O_|___", Player.X, "XXO|_O_|X__"); |
|
|
|
|
checkNextMove(t, opponent, "XXO|_O_|X__", Player.O, "XXO|OO_|X__"); |
|
|
|
|
checkNextMove(t, opponent, "XXO|OO_|X__", Player.X, "XXO|OOX|X__"); |
|
|
|
|
checkNextMove(t, opponent, "XXO|OOX|X__", Player.O, "XXO|OOX|XO_"); |
|
|
|
|
checkNextMove(t, opponent, "XXO|OOX|XO_", Player.X, "XXO|OOX|XOX"); |
|
|
|
|
|
|
|
|
|
checkNextMove(t, opponent, "___|___|__X", Player.O, "___|_O_|__X"); |
|
|
|
|
checkNextMove(t, opponent, "___|_O_|__X", Player.X, "X__|_O_|__X"); |
|
|
|
|
checkNextMove(t, opponent, "X__|_O_|__X", Player.O, "XO_|_O_|__X"); |
|
|
|
|
checkNextMove(t, opponent, "XO_|_O_|__X", Player.X, "XO_|_O_|_XX"); |
|
|
|
|
checkNextMove(t, opponent, "XO_|_O_|_XX", Player.O, "XO_|_O_|OXX"); |
|
|
|
|
checkNextMove(t, opponent, "XO_|_O_|OXX", Player.X, "XOX|_O_|OXX"); |
|
|
|
|
checkNextMove(t, opponent, "XOX|_O_|OXX", Player.O, "XOX|_OO|OXX"); |
|
|
|
|
checkNextMove(t, opponent, "XOX|_OO|OXX", Player.X, "XOX|XOO|OXX"); |
|
|
|
|
|
|
|
|
|
checkNextMove(t, opponent, "XO_|___|___", Player.X, "XO_|X__|___"); |
|
|
|
|
checkNextMove(t, opponent, "XO_|X__|___", Player.O, "XO_|X__|O__"); |
|
|
|
|
checkNextMove(t, opponent, "XO_|X__|O__", Player.X, "XO_|XX_|O__"); |
|
|
|
|
checkNextMove(t, opponent, "XO_|XX_|O__", Player.O, "XOO|XX_|O__"); |
|
|
|
|
checkNextMove(t, opponent, "XOO|XX_|O__", Player.X, "XOO|XXX|O__"); |
|
|
|
|
|
|
|
|
|
checkNextMove(t, opponent, "XO_|XXO|O__", Player.X, "XO_|XXO|O_X"); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|