|
|
|
@ -1,7 +1,18 @@ |
|
|
|
|
import t from "tap"; |
|
|
|
|
|
|
|
|
|
import { getBoardOutcome, getSequenceOutcome } from "./solver.ts"; |
|
|
|
|
import { CurrentOutcome, SquareState } from "./types.ts"; |
|
|
|
|
import { |
|
|
|
|
computeAllSolutions, |
|
|
|
|
getBoardOutcome, |
|
|
|
|
getPreferredNextOutcome, |
|
|
|
|
getSequenceOutcome, |
|
|
|
|
} from "./solver.ts"; |
|
|
|
|
import { |
|
|
|
|
CurrentOutcome, |
|
|
|
|
ExpectedOutcome, |
|
|
|
|
FinalOutcome, |
|
|
|
|
Player, |
|
|
|
|
SquareState, |
|
|
|
|
} from "./datatypes.ts"; |
|
|
|
|
import { Board } from "./board.ts"; |
|
|
|
|
|
|
|
|
|
void t.test("getSequenceOutcome", async (t) => { |
|
|
|
@ -134,6 +145,15 @@ void t.test("getSequenceOutcome", async (t) => { |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("getBoardOutcome", async (t) => { |
|
|
|
|
void t.test("1x1 boards", async (t) => { |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome(Board.fromSerialized("_")), |
|
|
|
|
CurrentOutcome.Undecided, |
|
|
|
|
); |
|
|
|
|
t.equal(getBoardOutcome(Board.fromSerialized("X")), CurrentOutcome.Draw); |
|
|
|
|
t.equal(getBoardOutcome(Board.fromSerialized("O")), CurrentOutcome.Draw); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("2x2 boards", async (t) => { |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome(Board.fromSerialized("__|__")), |
|
|
|
@ -279,4 +299,391 @@ void t.test("getBoardOutcome", async (t) => { |
|
|
|
|
CurrentOutcome.WinX, |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("6x5 boards", async (t) => { |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome( |
|
|
|
|
Board.fromSerialized("_____|_____|_____|_____|_____|__XXX"), |
|
|
|
|
), |
|
|
|
|
CurrentOutcome.WinX, |
|
|
|
|
); |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome( |
|
|
|
|
Board.fromSerialized("_____|_____|_____|____X|____X|____X"), |
|
|
|
|
), |
|
|
|
|
CurrentOutcome.WinX, |
|
|
|
|
); |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome( |
|
|
|
|
Board.fromSerialized("_____|_____|_____|__X__|___X_|____X"), |
|
|
|
|
), |
|
|
|
|
CurrentOutcome.WinX, |
|
|
|
|
); |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome( |
|
|
|
|
Board.fromSerialized("_____|_____|_____|____X|___X_|__X__"), |
|
|
|
|
), |
|
|
|
|
CurrentOutcome.WinX, |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("5x6 boards", async (t) => { |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome( |
|
|
|
|
Board.fromSerialized("______|______|______|______|___XXX"), |
|
|
|
|
), |
|
|
|
|
CurrentOutcome.WinX, |
|
|
|
|
); |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome( |
|
|
|
|
Board.fromSerialized("______|______|_____X|_____X|_____X"), |
|
|
|
|
), |
|
|
|
|
CurrentOutcome.WinX, |
|
|
|
|
); |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome( |
|
|
|
|
Board.fromSerialized("______|______|___X__|____X_|_____X"), |
|
|
|
|
), |
|
|
|
|
CurrentOutcome.WinX, |
|
|
|
|
); |
|
|
|
|
t.equal( |
|
|
|
|
getBoardOutcome( |
|
|
|
|
Board.fromSerialized("______|______|_____X|____X_|___X__"), |
|
|
|
|
), |
|
|
|
|
CurrentOutcome.WinX, |
|
|
|
|
); |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("getPreferredNextOutcome", async (t) => { |
|
|
|
|
const nextOutcomes: ExpectedOutcome[] = [ |
|
|
|
|
{ finalOutcome: FinalOutcome.Draw, movesLeft: 100 }, |
|
|
|
|
{ finalOutcome: FinalOutcome.Draw, movesLeft: 150 }, |
|
|
|
|
{ finalOutcome: FinalOutcome.Draw, movesLeft: 50 }, |
|
|
|
|
{ finalOutcome: FinalOutcome.WinX, movesLeft: 60 }, |
|
|
|
|
{ finalOutcome: FinalOutcome.WinX, movesLeft: 160 }, |
|
|
|
|
{ finalOutcome: FinalOutcome.WinO, movesLeft: 40 }, |
|
|
|
|
{ finalOutcome: FinalOutcome.WinO, movesLeft: 140 }, |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes, Player.X), { |
|
|
|
|
finalOutcome: FinalOutcome.WinX, |
|
|
|
|
movesLeft: 60, |
|
|
|
|
}); |
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes, Player.O), { |
|
|
|
|
finalOutcome: FinalOutcome.WinO, |
|
|
|
|
movesLeft: 40, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes.slice(3), Player.X), { |
|
|
|
|
finalOutcome: FinalOutcome.WinX, |
|
|
|
|
movesLeft: 60, |
|
|
|
|
}); |
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes.slice(3), Player.O), { |
|
|
|
|
finalOutcome: FinalOutcome.WinO, |
|
|
|
|
movesLeft: 40, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes.slice(4), Player.X), { |
|
|
|
|
finalOutcome: FinalOutcome.WinX, |
|
|
|
|
movesLeft: 160, |
|
|
|
|
}); |
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes.slice(4), Player.O), { |
|
|
|
|
finalOutcome: FinalOutcome.WinO, |
|
|
|
|
movesLeft: 40, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes.slice(5), Player.X), { |
|
|
|
|
finalOutcome: FinalOutcome.WinO, |
|
|
|
|
movesLeft: 140, |
|
|
|
|
}); |
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes.slice(5), Player.O), { |
|
|
|
|
finalOutcome: FinalOutcome.WinO, |
|
|
|
|
movesLeft: 40, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes.slice(6), Player.X), { |
|
|
|
|
finalOutcome: FinalOutcome.WinO, |
|
|
|
|
movesLeft: 140, |
|
|
|
|
}); |
|
|
|
|
t.matchOnlyStrict(getPreferredNextOutcome(nextOutcomes.slice(6), Player.O), { |
|
|
|
|
finalOutcome: FinalOutcome.WinO, |
|
|
|
|
movesLeft: 140, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
t.matchOnlyStrict( |
|
|
|
|
getPreferredNextOutcome(nextOutcomes.slice(0, 5), Player.X), |
|
|
|
|
{ |
|
|
|
|
finalOutcome: FinalOutcome.WinX, |
|
|
|
|
movesLeft: 60, |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
t.matchOnlyStrict( |
|
|
|
|
getPreferredNextOutcome(nextOutcomes.slice(0, 5), Player.O), |
|
|
|
|
{ |
|
|
|
|
finalOutcome: FinalOutcome.Draw, |
|
|
|
|
movesLeft: 150, |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
t.matchOnlyStrict( |
|
|
|
|
getPreferredNextOutcome(nextOutcomes.slice(0, 3), Player.X), |
|
|
|
|
{ |
|
|
|
|
finalOutcome: FinalOutcome.Draw, |
|
|
|
|
movesLeft: 150, |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
t.matchOnlyStrict( |
|
|
|
|
getPreferredNextOutcome(nextOutcomes.slice(0, 3), Player.O), |
|
|
|
|
{ |
|
|
|
|
finalOutcome: FinalOutcome.Draw, |
|
|
|
|
movesLeft: 150, |
|
|
|
|
}, |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
t.throws(() => getPreferredNextOutcome([], Player.X), { |
|
|
|
|
message: "Could not find the best outcome out of 0 possible next outcomes", |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
void t.test("computeAllSolutions", async (t) => { |
|
|
|
|
const checkSolutionsComplete = ( |
|
|
|
|
rows: number, |
|
|
|
|
columns: number, |
|
|
|
|
expectedSolutions: Record<string, ExpectedOutcome>, |
|
|
|
|
) => { |
|
|
|
|
t.matchOnlyStrict( |
|
|
|
|
Object.fromEntries(computeAllSolutions(rows, columns).entries()), |
|
|
|
|
expectedSolutions, |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const checkSolutionsIncomplete = ( |
|
|
|
|
rows: number, |
|
|
|
|
columns: number, |
|
|
|
|
expectedSolutionsCount: number, |
|
|
|
|
expectedSolutionsIncomplete: Record<string, ExpectedOutcome>, |
|
|
|
|
) => { |
|
|
|
|
const allSolutions = computeAllSolutions(rows, columns); |
|
|
|
|
t.equal(allSolutions.size, expectedSolutionsCount); |
|
|
|
|
t.matchStrict( |
|
|
|
|
Object.fromEntries(allSolutions.entries()), |
|
|
|
|
expectedSolutionsIncomplete, |
|
|
|
|
); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
checkSolutionsComplete(0, 0, { |
|
|
|
|
"": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
checkSolutionsComplete(1, 0, { |
|
|
|
|
"": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
checkSolutionsComplete(1, 1, { |
|
|
|
|
_: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
X: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// making sure that we don't have any bugs that would manifest when width > height
|
|
|
|
|
checkSolutionsComplete(1, 3, { |
|
|
|
|
___: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
|
|
|
|
|
X__: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
_X_: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
__X: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
|
|
|
|
|
XO_: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
X_O: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
OX_: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
_XO: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
O_X: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
_OX: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
|
|
|
|
|
XOX: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
XXO: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
OXX: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// making sure that we don't have any bugs that would manifest when height > width
|
|
|
|
|
checkSolutionsComplete(3, 1, { |
|
|
|
|
"_|_|_": { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
|
|
|
|
|
"X|_|_": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"_|X|_": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"_|_|X": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
|
|
|
|
|
"X|O|_": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"X|_|O": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"O|X|_": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"_|X|O": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"O|_|X": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"_|O|X": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
|
|
|
|
|
"X|O|X": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
"X|X|O": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
"O|X|X": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// smallest possible board where X can win
|
|
|
|
|
checkSolutionsComplete(1, 5, { |
|
|
|
|
_____: { finalOutcome: FinalOutcome.Draw, movesLeft: 5 }, |
|
|
|
|
|
|
|
|
|
X____: { finalOutcome: FinalOutcome.Draw, movesLeft: 4 }, |
|
|
|
|
XO___: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
X_O__: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
X__O_: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
X___O: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
_X___: { finalOutcome: FinalOutcome.Draw, movesLeft: 4 }, |
|
|
|
|
OX___: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
_XO__: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
_X_O_: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
_X__O: { finalOutcome: FinalOutcome.WinX, movesLeft: 3 }, |
|
|
|
|
__X__: { finalOutcome: FinalOutcome.Draw, movesLeft: 4 }, |
|
|
|
|
O_X__: { finalOutcome: FinalOutcome.WinX, movesLeft: 3 }, |
|
|
|
|
_OX__: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
__XO_: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
__X_O: { finalOutcome: FinalOutcome.WinX, movesLeft: 3 }, |
|
|
|
|
___X_: { finalOutcome: FinalOutcome.Draw, movesLeft: 4 }, |
|
|
|
|
O__X_: { finalOutcome: FinalOutcome.WinX, movesLeft: 3 }, |
|
|
|
|
_O_X_: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
__OX_: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
___XO: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
____X: { finalOutcome: FinalOutcome.Draw, movesLeft: 4 }, |
|
|
|
|
O___X: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
_O__X: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
__O_X: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
___OX: { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
|
|
|
|
|
XOX__: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
XO_X_: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
XO__X: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
XXO__: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
X_OX_: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
X_O_X: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
XX_O_: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
X_XO_: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
X__OX: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
XX__O: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
X_X_O: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
X__XO: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
OXX__: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
OX_X_: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
OX__X: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
_XOX_: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
_XO_X: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
_XXO_: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
_X_OX: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
_XX_O: { finalOutcome: FinalOutcome.WinX, movesLeft: 2 }, |
|
|
|
|
_X_XO: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
O_XX_: { finalOutcome: FinalOutcome.WinX, movesLeft: 2 }, |
|
|
|
|
O_X_X: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
_OXX_: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
_OX_X: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
__XOX: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
__XXO: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
O__XX: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
_O_XX: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
__OXX: { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
|
|
|
|
|
XOXO_: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
XOX_O: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
XOOX_: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
XO_XO: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
XOO_X: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
XO_OX: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
XXOO_: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
XXO_O: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
X_OXO: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
X_OOX: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
XX_OO: { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
X_XOO: { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
OXXO_: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
OXX_O: { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
OXOX_: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
OX_XO: { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
OXO_X: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
OX_OX: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
_XOXO: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
_XOOX: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
_XXOO: { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
OOXX_: { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
O_XXO: { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
OOX_X: { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
O_XOX: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
_OXXO: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
_OXOX: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
OO_XX: { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
O_OXX: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
_OOXX: { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
|
|
|
|
|
XOXOX: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
XOXXO: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
XOOXX: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
XXOOX: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
XXOXO: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
XXXOO: { finalOutcome: FinalOutcome.WinX, movesLeft: 0 }, |
|
|
|
|
OXXOX: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
OXXXO: { finalOutcome: FinalOutcome.WinX, movesLeft: 0 }, |
|
|
|
|
OXOXX: { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
OOXXX: { finalOutcome: FinalOutcome.WinX, movesLeft: 0 }, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
checkSolutionsComplete(2, 2, { |
|
|
|
|
"__|__": { finalOutcome: FinalOutcome.Draw, movesLeft: 4 }, |
|
|
|
|
|
|
|
|
|
"X_|__": { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
"XO|__": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"X_|O_": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"X_|_O": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
|
|
|
|
|
"_X|__": { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
"OX|__": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"_X|O_": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"_X|_O": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
|
|
|
|
|
"__|X_": { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
"O_|X_": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"_O|X_": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"__|XO": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
|
|
|
|
|
"__|_X": { finalOutcome: FinalOutcome.Draw, movesLeft: 3 }, |
|
|
|
|
"O_|_X": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"_O|_X": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
"__|OX": { finalOutcome: FinalOutcome.Draw, movesLeft: 2 }, |
|
|
|
|
|
|
|
|
|
"XO|X_": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"XO|_X": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"XX|O_": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"X_|OX": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"XX|_O": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"X_|XO": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"OX|X_": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"OX|_X": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"_X|OX": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"_X|XO": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"O_|XX": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
"_O|XX": { finalOutcome: FinalOutcome.Draw, movesLeft: 1 }, |
|
|
|
|
|
|
|
|
|
"XO|XO": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
"XO|OX": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
"XX|OO": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
"OX|XO": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
"OX|OX": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
"OO|XX": { finalOutcome: FinalOutcome.Draw, movesLeft: 0 }, |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// number 5478 taken from https://math.stackexchange.com/a/613505
|
|
|
|
|
checkSolutionsIncomplete(3, 3, 5478, { |
|
|
|
|
"___|___|___": { finalOutcome: FinalOutcome.Draw, movesLeft: 9 }, |
|
|
|
|
"X__|___|___": { finalOutcome: FinalOutcome.Draw, movesLeft: 8 }, |
|
|
|
|
"_X_|___|___": { finalOutcome: FinalOutcome.Draw, movesLeft: 8 }, |
|
|
|
|
"___|_X_|___": { finalOutcome: FinalOutcome.Draw, movesLeft: 8 }, |
|
|
|
|
"XO_|___|___": { finalOutcome: FinalOutcome.WinX, movesLeft: 5 }, |
|
|
|
|
"X__|___|_O_": { finalOutcome: FinalOutcome.WinX, movesLeft: 5 }, |
|
|
|
|
"X_O|___|___": { finalOutcome: FinalOutcome.WinX, movesLeft: 5 }, |
|
|
|
|
"X__|___|__O": { finalOutcome: FinalOutcome.WinX, movesLeft: 5 }, |
|
|
|
|
"OO_|___|_XX": { finalOutcome: FinalOutcome.WinX, movesLeft: 1 }, |
|
|
|
|
"OO_|__X|_XX": { finalOutcome: FinalOutcome.WinO, movesLeft: 1 }, |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|