|
|
|
@ -14,33 +14,57 @@ void t.test("Serialize / deserialize", async (t) => { |
|
|
|
|
void t.test("Empty state", async (t) => { |
|
|
|
|
t.equal(BoardgameState.fromSerialized(""), null); |
|
|
|
|
t.equal(BoardgameState.fromSerialized(null), null); |
|
|
|
|
t.equal(BoardgameState.fromSerialized(".."), null); |
|
|
|
|
t.equal(BoardgameState.fromSerialized("..."), null); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("1x1 state (incompletely serialized)", async (t) => { |
|
|
|
|
const state = BoardgameState.fromSerialized("1x1"); |
|
|
|
|
t.ok(state); |
|
|
|
|
t.equal(state?.serialize(), "1x1.."); |
|
|
|
|
t.equal(state?.serialize(), "1x1..."); |
|
|
|
|
t.equal(state?.rows, 1); |
|
|
|
|
t.equal(state?.columns, 1); |
|
|
|
|
t.matchOnlyStrict(state?.autoPlayers, new Set()); |
|
|
|
|
t.equal(state?.currentPlayer, null); |
|
|
|
|
t.equal(state?.currentPlayerName, ""); |
|
|
|
|
t.equal(state?.board, null); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("1x1 state with empty board", async (t) => { |
|
|
|
|
const state = createAndCheckBoardgameState(t, "1x1.."); |
|
|
|
|
const state = createAndCheckBoardgameState(t, "1x1..."); |
|
|
|
|
t.equal(state?.rows, 1); |
|
|
|
|
t.equal(state?.columns, 1); |
|
|
|
|
t.matchOnlyStrict(state?.autoPlayers, new Set()); |
|
|
|
|
t.equal(state?.currentPlayer, null); |
|
|
|
|
t.equal(state?.currentPlayerName, ""); |
|
|
|
|
t.equal(state?.board, null); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("1x1 state with empty board and one autoplayer", async (t) => { |
|
|
|
|
const state = createAndCheckBoardgameState(t, "1x1.X.."); |
|
|
|
|
t.equal(state?.rows, 1); |
|
|
|
|
t.equal(state?.columns, 1); |
|
|
|
|
t.matchOnlyStrict(state?.autoPlayers, new Set([Player.X])); |
|
|
|
|
t.equal(state?.currentPlayer, null); |
|
|
|
|
t.equal(state?.currentPlayerName, ""); |
|
|
|
|
t.equal(state?.board, null); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("1x1 state with empty board and one duplicated autoplayer", async (t) => { |
|
|
|
|
const state = BoardgameState.fromSerialized("1x1.OOO.."); |
|
|
|
|
t.equal(state?.serialize(), "1x1.O.."); |
|
|
|
|
t.equal(state?.rows, 1); |
|
|
|
|
t.equal(state?.columns, 1); |
|
|
|
|
t.matchOnlyStrict(state?.autoPlayers, new Set([Player.O])); |
|
|
|
|
t.equal(state?.currentPlayer, null); |
|
|
|
|
t.equal(state?.currentPlayerName, ""); |
|
|
|
|
t.equal(state?.board, null); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("1x1 board with started game", async (t) => { |
|
|
|
|
const state = createAndCheckBoardgameState(t, "1x1.X._"); |
|
|
|
|
const state = createAndCheckBoardgameState(t, "1x1..X._"); |
|
|
|
|
t.equal(state?.rows, 1); |
|
|
|
|
t.equal(state?.columns, 1); |
|
|
|
|
t.matchOnlyStrict(state?.autoPlayers, new Set()); |
|
|
|
|
t.equal(state?.currentPlayer, Player.X); |
|
|
|
|
t.equal(state?.currentPlayerName, "X"); |
|
|
|
|
t.equal(state?.board?.hasRow(0), true); |
|
|
|
@ -51,9 +75,10 @@ void t.test("Serialize / deserialize", async (t) => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("1x2 board with first move", async (t) => { |
|
|
|
|
const state = createAndCheckBoardgameState(t, "1x2.O._X"); |
|
|
|
|
const state = createAndCheckBoardgameState(t, "1x2..O._X"); |
|
|
|
|
t.equal(state?.rows, 1); |
|
|
|
|
t.equal(state?.columns, 2); |
|
|
|
|
t.matchOnlyStrict(state?.autoPlayers, new Set()); |
|
|
|
|
t.equal(state?.currentPlayer, Player.O); |
|
|
|
|
t.equal(state?.currentPlayerName, "O"); |
|
|
|
|
t.equal(state?.board?.get(0, 0), SquareState.Unoccupied); |
|
|
|
@ -63,9 +88,10 @@ void t.test("Serialize / deserialize", async (t) => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("2x1 board with first move", async (t) => { |
|
|
|
|
const state = createAndCheckBoardgameState(t, "2x1.O._|X"); |
|
|
|
|
const state = createAndCheckBoardgameState(t, "2x1..O._|X"); |
|
|
|
|
t.equal(state?.rows, 2); |
|
|
|
|
t.equal(state?.columns, 1); |
|
|
|
|
t.matchOnlyStrict(state?.autoPlayers, new Set()); |
|
|
|
|
t.equal(state?.currentPlayer, Player.O); |
|
|
|
|
t.equal(state?.currentPlayerName, "O"); |
|
|
|
|
t.equal(state?.board?.get(0, 0), SquareState.Unoccupied); |
|
|
|
@ -73,12 +99,37 @@ void t.test("Serialize / deserialize", async (t) => { |
|
|
|
|
t.equal(state?.board?.hasSquare(0, 1), false); |
|
|
|
|
t.equal(state?.board?.hasRow(2), false); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("2x1 board with first move and two autoplayers", async (t) => { |
|
|
|
|
const state = createAndCheckBoardgameState(t, "2x1.XO.O._|X"); |
|
|
|
|
t.equal(state?.rows, 2); |
|
|
|
|
t.equal(state?.columns, 1); |
|
|
|
|
t.matchOnlyStrict(state?.autoPlayers, new Set([Player.X, Player.O])); |
|
|
|
|
t.equal(state?.currentPlayer, Player.O); |
|
|
|
|
t.equal(state?.currentPlayerName, "O"); |
|
|
|
|
t.equal(state?.board?.get(0, 0), SquareState.Unoccupied); |
|
|
|
|
t.equal(state?.board?.get(1, 0), SquareState.X); |
|
|
|
|
t.equal(state?.board?.hasSquare(0, 1), false); |
|
|
|
|
t.equal(state?.board?.hasRow(2), false); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("Error handling", async (t) => { |
|
|
|
|
t.throws(() => BoardgameState.fromSerialized("0..."), { |
|
|
|
|
message: "Incorrect dimensions", |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
const state = BoardgameState.fromSerialized("1x1.abc.."); |
|
|
|
|
t.equal(state?.serialize(), "1x1..."); |
|
|
|
|
t.matchOnlyStrict(state?.autoPlayers, new Set()); |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("Empty state creation", async (t) => { |
|
|
|
|
void t.test("0x0 board", async (t) => { |
|
|
|
|
const state = BoardgameState.createWithoutBoard(0, 0); |
|
|
|
|
t.equal(state.serialize(), "0x0.."); |
|
|
|
|
t.equal(state.serialize(), "0x0..."); |
|
|
|
|
t.equal(state.rows, 0); |
|
|
|
|
t.equal(state.columns, 0); |
|
|
|
|
t.equal(state.currentPlayer, null); |
|
|
|
@ -88,7 +139,7 @@ void t.test("Empty state creation", async (t) => { |
|
|
|
|
|
|
|
|
|
void t.test("1x0 board", async (t) => { |
|
|
|
|
const state = BoardgameState.createWithoutBoard(1, 0); |
|
|
|
|
t.equal(state.serialize(), "1x0.."); |
|
|
|
|
t.equal(state.serialize(), "1x0..."); |
|
|
|
|
t.equal(state.rows, 1); |
|
|
|
|
t.equal(state.columns, 0); |
|
|
|
|
t.equal(state.currentPlayer, null); |
|
|
|
@ -98,7 +149,7 @@ void t.test("Empty state creation", async (t) => { |
|
|
|
|
|
|
|
|
|
void t.test("1x1 board", async (t) => { |
|
|
|
|
const state = BoardgameState.createWithoutBoard(1, 1); |
|
|
|
|
t.equal(state.serialize(), "1x1.."); |
|
|
|
|
t.equal(state.serialize(), "1x1..."); |
|
|
|
|
t.equal(state.rows, 1); |
|
|
|
|
t.equal(state.columns, 1); |
|
|
|
|
t.equal(state.currentPlayer, null); |
|
|
|
@ -108,26 +159,20 @@ void t.test("Empty state creation", async (t) => { |
|
|
|
|
|
|
|
|
|
void t.test("1x2 board", async (t) => { |
|
|
|
|
const state = BoardgameState.createWithoutBoard(1, 2); |
|
|
|
|
t.equal(state.serialize(), "1x2.."); |
|
|
|
|
t.equal(state.serialize(), "1x2..."); |
|
|
|
|
t.equal(state.rows, 1); |
|
|
|
|
t.equal(state.columns, 2); |
|
|
|
|
t.equal(state.currentPlayer, null); |
|
|
|
|
t.equal(state.currentPlayerName, ""); |
|
|
|
|
t.equal(state.board, null); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("Error handling", async (t) => { |
|
|
|
|
t.throws(() => BoardgameState.fromSerialized("0.."), { |
|
|
|
|
message: "Incorrect dimensions", |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("withEmptyBoard", async (t) => { |
|
|
|
|
void t.test("On 0x0 board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "0x0.."); |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "0x0..."); |
|
|
|
|
const newState = oldState?.withEmptyBoard(); |
|
|
|
|
t.equal(newState?.serialize(), "0x0.X."); |
|
|
|
|
t.equal(newState?.serialize(), "0x0..X."); |
|
|
|
|
t.equal(newState?.rows, 0); |
|
|
|
|
t.equal(newState?.columns, 0); |
|
|
|
|
t.equal(newState?.currentPlayer, Player.X); |
|
|
|
@ -136,9 +181,9 @@ void t.test("withEmptyBoard", async (t) => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("On 0x1 board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "0x1.."); |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "0x1..."); |
|
|
|
|
const newState = oldState?.withEmptyBoard(); |
|
|
|
|
t.equal(newState?.serialize(), "0x1.X."); |
|
|
|
|
t.equal(newState?.serialize(), "0x1..X."); |
|
|
|
|
t.equal(newState?.rows, 0); |
|
|
|
|
t.equal(newState?.columns, 1); |
|
|
|
|
t.equal(newState?.currentPlayer, Player.X); |
|
|
|
@ -147,9 +192,9 @@ void t.test("withEmptyBoard", async (t) => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("On 1x0 board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "1x0.."); |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "1x0..."); |
|
|
|
|
const newState = oldState?.withEmptyBoard(); |
|
|
|
|
t.equal(newState?.serialize(), "1x0.X."); |
|
|
|
|
t.equal(newState?.serialize(), "1x0..X."); |
|
|
|
|
t.equal(newState?.rows, 1); |
|
|
|
|
t.equal(newState?.columns, 0); |
|
|
|
|
t.equal(newState?.currentPlayer, Player.X); |
|
|
|
@ -158,9 +203,9 @@ void t.test("withEmptyBoard", async (t) => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("On 1x1 board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "1x1.."); |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "1x1..."); |
|
|
|
|
const newState = oldState?.withEmptyBoard(); |
|
|
|
|
t.equal(newState?.serialize(), "1x1.X._"); |
|
|
|
|
t.equal(newState?.serialize(), "1x1..X._"); |
|
|
|
|
t.equal(newState?.rows, 1); |
|
|
|
|
t.equal(newState?.columns, 1); |
|
|
|
|
t.equal(newState?.currentPlayer, Player.X); |
|
|
|
@ -169,9 +214,9 @@ void t.test("withEmptyBoard", async (t) => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("On 1x2 board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "1x2.."); |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "1x2..."); |
|
|
|
|
const newState = oldState?.withEmptyBoard(); |
|
|
|
|
t.equal(newState?.serialize(), "1x2.X.__"); |
|
|
|
|
t.equal(newState?.serialize(), "1x2..X.__"); |
|
|
|
|
t.equal(newState?.rows, 1); |
|
|
|
|
t.equal(newState?.columns, 2); |
|
|
|
|
t.equal(newState?.currentPlayer, Player.X); |
|
|
|
@ -180,9 +225,9 @@ void t.test("withEmptyBoard", async (t) => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("On 2x1 board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "2x1.."); |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "2x1..."); |
|
|
|
|
const newState = oldState?.withEmptyBoard(); |
|
|
|
|
t.equal(newState?.serialize(), "2x1.X._|_"); |
|
|
|
|
t.equal(newState?.serialize(), "2x1..X._|_"); |
|
|
|
|
t.equal(newState?.rows, 2); |
|
|
|
|
t.equal(newState?.columns, 1); |
|
|
|
|
t.equal(newState?.currentPlayer, Player.X); |
|
|
|
@ -191,12 +236,95 @@ void t.test("withEmptyBoard", async (t) => { |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("withAutoPlayer", async (t) => { |
|
|
|
|
void t.test("On uninitialized board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "2x3..."); |
|
|
|
|
|
|
|
|
|
const newStateX = oldState?.withAutoPlayer(Player.X); |
|
|
|
|
t.equal(newStateX?.serialize(), "2x3.X.."); |
|
|
|
|
t.matchOnlyStrict(newStateX?.autoPlayers, new Set([Player.X])); |
|
|
|
|
|
|
|
|
|
const newStateO = oldState?.withAutoPlayer(Player.O); |
|
|
|
|
t.equal(newStateO?.serialize(), "2x3.O.."); |
|
|
|
|
t.matchOnlyStrict(newStateO?.autoPlayers, new Set([Player.O])); |
|
|
|
|
|
|
|
|
|
const newStateXO = newStateX?.withAutoPlayer(Player.O); |
|
|
|
|
t.equal(newStateXO?.serialize(), "2x3.XO.."); |
|
|
|
|
t.matchOnlyStrict(newStateXO?.autoPlayers, new Set([Player.X, Player.O])); |
|
|
|
|
|
|
|
|
|
const newStateOO = newStateO?.withAutoPlayer(Player.O); |
|
|
|
|
t.equal(newStateOO?.serialize(), "2x3.O.."); |
|
|
|
|
t.matchOnlyStrict(newStateOO?.autoPlayers, new Set([Player.O])); |
|
|
|
|
}); |
|
|
|
|
void t.test("On 2x3 board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "2x3..X.__X|O__"); |
|
|
|
|
|
|
|
|
|
const newStateX = oldState?.withAutoPlayer(Player.X); |
|
|
|
|
t.equal(newStateX?.serialize(), "2x3.X.X.__X|O__"); |
|
|
|
|
t.matchOnlyStrict(newStateX?.autoPlayers, new Set([Player.X])); |
|
|
|
|
|
|
|
|
|
const newStateO = oldState?.withAutoPlayer(Player.O); |
|
|
|
|
t.equal(newStateO?.serialize(), "2x3.O.X.__X|O__"); |
|
|
|
|
t.matchOnlyStrict(newStateO?.autoPlayers, new Set([Player.O])); |
|
|
|
|
|
|
|
|
|
const newStateXO = newStateX?.withAutoPlayer(Player.O); |
|
|
|
|
t.equal(newStateXO?.serialize(), "2x3.XO.X.__X|O__"); |
|
|
|
|
t.matchOnlyStrict(newStateXO?.autoPlayers, new Set([Player.X, Player.O])); |
|
|
|
|
|
|
|
|
|
const newStateOO = newStateO?.withAutoPlayer(Player.O); |
|
|
|
|
t.equal(newStateOO?.serialize(), "2x3.O.X.__X|O__"); |
|
|
|
|
t.matchOnlyStrict(newStateOO?.autoPlayers, new Set([Player.O])); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("withoutAutoPlayer", async (t) => { |
|
|
|
|
void t.test("On uninitialized board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "2x3.XO.."); |
|
|
|
|
|
|
|
|
|
const newStateX = oldState?.withoutAutoPlayer(Player.O); |
|
|
|
|
t.equal(newStateX?.serialize(), "2x3.X.."); |
|
|
|
|
t.matchOnlyStrict(newStateX?.autoPlayers, new Set([Player.X])); |
|
|
|
|
|
|
|
|
|
const newStateO = oldState?.withoutAutoPlayer(Player.X); |
|
|
|
|
t.equal(newStateO?.serialize(), "2x3.O.."); |
|
|
|
|
t.matchOnlyStrict(newStateO?.autoPlayers, new Set([Player.O])); |
|
|
|
|
|
|
|
|
|
const newStateNone = newStateX?.withoutAutoPlayer(Player.X); |
|
|
|
|
t.equal(newStateNone?.serialize(), "2x3..."); |
|
|
|
|
t.matchOnlyStrict(newStateNone?.autoPlayers, new Set()); |
|
|
|
|
|
|
|
|
|
const newStateOO = newStateO?.withoutAutoPlayer(Player.X); |
|
|
|
|
t.equal(newStateOO?.serialize(), "2x3.O.."); |
|
|
|
|
t.matchOnlyStrict(newStateOO?.autoPlayers, new Set([Player.O])); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("On 2x3 board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "2x3.XO.X.__X|O__"); |
|
|
|
|
|
|
|
|
|
const newStateX = oldState?.withoutAutoPlayer(Player.O); |
|
|
|
|
t.equal(newStateX?.serialize(), "2x3.X.X.__X|O__"); |
|
|
|
|
t.matchOnlyStrict(newStateX?.autoPlayers, new Set([Player.X])); |
|
|
|
|
|
|
|
|
|
const newStateO = oldState?.withoutAutoPlayer(Player.X); |
|
|
|
|
t.equal(newStateO?.serialize(), "2x3.O.X.__X|O__"); |
|
|
|
|
t.matchOnlyStrict(newStateO?.autoPlayers, new Set([Player.O])); |
|
|
|
|
|
|
|
|
|
const newStateNone = newStateX?.withoutAutoPlayer(Player.X); |
|
|
|
|
t.equal(newStateNone?.serialize(), "2x3..X.__X|O__"); |
|
|
|
|
t.matchOnlyStrict(newStateNone?.autoPlayers, new Set()); |
|
|
|
|
|
|
|
|
|
const newStateOO = newStateO?.withoutAutoPlayer(Player.X); |
|
|
|
|
t.equal(newStateOO?.serialize(), "2x3.O.X.__X|O__"); |
|
|
|
|
t.matchOnlyStrict(newStateOO?.autoPlayers, new Set([Player.O])); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("withMove", async (t) => { |
|
|
|
|
void t.test("On 2x3 board", async (t) => { |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "2x3.X.___|___"); |
|
|
|
|
const oldState = createAndCheckBoardgameState(t, "2x3..X.___|___"); |
|
|
|
|
|
|
|
|
|
const firstMoveState = oldState?.withMove(0, 1); |
|
|
|
|
t.equal(firstMoveState?.serialize(), "2x3.O._X_|___"); |
|
|
|
|
t.equal(firstMoveState?.serialize(), "2x3..O._X_|___"); |
|
|
|
|
t.equal(firstMoveState?.rows, 2); |
|
|
|
|
t.equal(firstMoveState?.columns, 3); |
|
|
|
|
t.equal(firstMoveState?.currentPlayer, Player.O); |
|
|
|
@ -204,7 +332,7 @@ void t.test("withMove", async (t) => { |
|
|
|
|
t.equal(firstMoveState?.board?.serialize(), "_X_|___"); |
|
|
|
|
|
|
|
|
|
const secondMoveState = firstMoveState?.withMove(1, 2); |
|
|
|
|
t.equal(secondMoveState?.serialize(), "2x3.X._X_|__O"); |
|
|
|
|
t.equal(secondMoveState?.serialize(), "2x3..X._X_|__O"); |
|
|
|
|
t.equal(secondMoveState?.rows, 2); |
|
|
|
|
t.equal(secondMoveState?.columns, 3); |
|
|
|
|
t.equal(secondMoveState?.currentPlayer, Player.X); |
|
|
|
@ -213,7 +341,7 @@ void t.test("withMove", async (t) => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("Error handling", async () => { |
|
|
|
|
const unstartedBoard = createAndCheckBoardgameState(t, "1x1.."); |
|
|
|
|
const unstartedBoard = createAndCheckBoardgameState(t, "1x1..."); |
|
|
|
|
t.throws(() => unstartedBoard?.withMove(0, 0), { |
|
|
|
|
message: "Game is not started", |
|
|
|
|
}); |
|
|
|
@ -222,17 +350,17 @@ void t.test("withMove", async (t) => { |
|
|
|
|
|
|
|
|
|
void t.test("Sample usage scenario", async (t) => { |
|
|
|
|
const noBoardState = BoardgameState.createWithoutBoard(2, 3); |
|
|
|
|
t.equal(noBoardState.serialize(), "2x3.."); |
|
|
|
|
t.equal(noBoardState.serialize(), "2x3..."); |
|
|
|
|
|
|
|
|
|
const gameStartedState = noBoardState.withEmptyBoard(); |
|
|
|
|
t.equal(gameStartedState.serialize(), "2x3.X.___|___"); |
|
|
|
|
t.equal(gameStartedState.serialize(), "2x3..X.___|___"); |
|
|
|
|
|
|
|
|
|
const firstMoveState = gameStartedState.withMove(0, 1); |
|
|
|
|
t.equal(firstMoveState.serialize(), "2x3.O._X_|___"); |
|
|
|
|
t.equal(firstMoveState.serialize(), "2x3..O._X_|___"); |
|
|
|
|
|
|
|
|
|
const secondMoveState = firstMoveState.withMove(1, 2); |
|
|
|
|
t.equal(secondMoveState.serialize(), "2x3.X._X_|__O"); |
|
|
|
|
t.equal(secondMoveState.serialize(), "2x3..X._X_|__O"); |
|
|
|
|
|
|
|
|
|
const thirdMoveState = secondMoveState.withMove(1, 0); |
|
|
|
|
t.equal(thirdMoveState.serialize(), "2x3.O._X_|X_O"); |
|
|
|
|
t.equal(thirdMoveState.serialize(), "2x3..O._X_|X_O"); |
|
|
|
|
}); |
|
|
|
|