Skip to content

Commit

Permalink
feat: docs and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
kyranet committed Sep 19, 2020
1 parent 1e98fd7 commit c94e219
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 3 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,5 +49,6 @@
"streambuf": "cpp",
"thread": "cpp",
"typeinfo": "cpp"
}
},
"C_Cpp.default.includePath": ["/usr/include/node", "${workspaceFolder}/include", "${workspaceFolder}/node_modules/node-addon-api"]
}
25 changes: 25 additions & 0 deletions src/games/TicTacToe.cc
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ namespace TicTacToe
TicTacToe::ai_results min(ai_board &board, int_fast8_t remaining, int_fast8_t alpha, int_fast8_t beta) noexcept;
TicTacToe::ai_results max(ai_board &board, int_fast8_t remaining, int_fast8_t alpha, int_fast8_t beta) noexcept;

// Maximum is Players::Machine
TicTacToe::ai_results max(ai_board &board, int_fast8_t remaining, int_fast8_t alpha, int_fast8_t beta) noexcept
{
const auto winner = status(board);
Expand All @@ -71,22 +72,33 @@ namespace TicTacToe
if (remaining == 0)
return {0, -1};

// Possible values for maxv are:
// -1 - loss
// 0 - a tie
// 1 - win
//
// We're initially setting it to -2 as worse than the worst case:
int_fast8_t maxv = -2;
int_fast8_t posi = -1;

for (int_fast8_t i = 0; i < static_cast<int_fast8_t>(board.size()); ++i)
{
if (board[i] == Players::Unset)
{
// On the empty field player Machine makes a move and calls Min
// That's one branch of the game tree:
board[i] = Players::Machine;

const auto m = TicTacToe::min(board, remaining - 1, alpha, beta).points;

// Fixing the maxv value if needed:
if (m > maxv)
{
maxv = m;
posi = i;
}

// Setting back the field to empty:
board[i] = Players::Unset;

if (maxv >= beta)
Expand All @@ -104,6 +116,7 @@ namespace TicTacToe
return {maxv, posi};
}

// Minimum is Players::Player
TicTacToe::ai_results min(ai_board &board, int_fast8_t remaining, int_fast8_t alpha, int_fast8_t beta) noexcept
{
const auto winner = status(board);
Expand All @@ -116,22 +129,33 @@ namespace TicTacToe
if (remaining == 0)
return {0, -1};

// Possible values for minv are:
// -1 - win
// 0 - a tie
// 1 - loss
//
// We're initially setting it to 2 as worse than the worst case:
int_fast8_t minv = 2;
int_fast8_t posi = -1;

for (int_fast8_t i = 0; i < static_cast<int_fast8_t>(board.size()); ++i)
{
if (board[i] == Players::Unset)
{
// On the empty field player Player makes a move and calls Max
// That's one branch of the game tree:
board[i] = Players::Player;

const auto m = TicTacToe::max(board, remaining - 1, alpha, beta).points;

// Fixing the minv value if needed:
if (m < minv)
{
minv = m;
posi = i;
}

// Setting back the field to empty:
board[i] = Players::Unset;

if (minv <= alpha)
Expand All @@ -149,6 +173,7 @@ namespace TicTacToe
return {minv, posi};
}

// Returns the optimal move from the AI, -1 if no move was possible.
int_fast8_t position(ai_board &board, int_fast8_t remaining) noexcept
{
// If remaining is 9, then the board is empty.
Expand Down
74 changes: 72 additions & 2 deletions tests/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,78 @@
import { ticTacToe } from '../lib/main';

describe('TicTacToe', () => {
test('Do something, Kyra fill this in', () => {
expect(ticTacToe(new Uint8Array([0, 0, 1, 1, 2, 1, 2, 2, 0]))).toEqual(1);
test('GIVEN no args THEN throws TypeError', () => {
// @ts-expect-error
expect(() => ticTacToe()).toThrow('data must be a typed array');
});

test('GIVEN null THEN throws TypeError', () => {
expect(() => ticTacToe(null)).toThrow('data must be a typed array');
});

test('GIVEN array THEN throws TypeError', () => {
// @ts-expect-error
expect(() => ticTacToe([0, 0, 0, 0, 0, 0, 0, 0, 0])).toThrow('data must be a typed array');
});

test('GIVEN Uint8Array with too little elements THEN throws TypeError', () => {
expect(() => ticTacToe(new Uint8Array([0, 0, 0, 0, 0, 0]))).toThrow('data must have exactly 9 numbers');
});

test('GIVEN Uint8Array with too many elements THEN throws TypeError', () => {
expect(() => ticTacToe(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))).toThrow('data must have exactly 9 numbers');
});

test('GIVEN empty board THEN returns 4', () => {
expect(ticTacToe(new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0]))).toEqual(4);
});

test('GIVEN possible horizontal row (0..2) THEN returns 2', () => {
expect(ticTacToe(new Uint8Array([2, 2, 0, 1, 1, 0, 0, 0, 0]))).toEqual(2);
});

test('GIVEN possible horizontal row (3..5) THEN returns 5', () => {
expect(ticTacToe(new Uint8Array([0, 0, 0, 2, 2, 0, 1, 1, 0]))).toEqual(5);
});

test('GIVEN possible horizontal row (6..8) THEN returns 4', () => {
expect(ticTacToe(new Uint8Array([0, 0, 0, 1, 0, 1, 2, 2, 0]))).toEqual(4);
});

test('GIVEN possible vertical row (0) THEN returns 4', () => {
expect(ticTacToe(new Uint8Array([0, 1, 2, 0, 0, 2, 0, 1, 0]))).toEqual(4);
});

test('GIVEN possible vertical row (1) THEN returns 7', () => {
expect(ticTacToe(new Uint8Array([0, 2, 0, 0, 2, 0, 1, 0, 1]))).toEqual(7);
});

test('GIVEN possible vertical row (2) THEN returns 3', () => {
expect(ticTacToe(new Uint8Array([1, 0, 2, 0, 0, 2, 1, 0, 0]))).toEqual(3);
});

test('GIVEN ascending diagonal (0) THEN returns 2', () => {
expect(ticTacToe(new Uint8Array([1, 0, 0, 0, 2, 0, 2, 1, 0]))).toEqual(2);
});

test('GIVEN ascending diagonal (1) THEN returns 4', () => {
expect(ticTacToe(new Uint8Array([1, 0, 2, 0, 0, 0, 2, 0, 1]))).toEqual(4);
});

test('GIVEN ascending diagonal (2) THEN returns 6', () => {
expect(ticTacToe(new Uint8Array([1, 0, 2, 1, 2, 0, 0, 0, 0]))).toEqual(6);
});

test('GIVEN descending diagonal (0) THEN returns 0', () => {
expect(ticTacToe(new Uint8Array([0, 0, 0, 1, 2, 0, 1, 0, 2]))).toEqual(0);
});

test('GIVEN descending diagonal (1) THEN returns 4', () => {
expect(ticTacToe(new Uint8Array([2, 0, 1, 0, 0, 0, 1, 0, 2]))).toEqual(4);
});

test('GIVEN descending diagonal (2) THEN returns 8', () => {
expect(ticTacToe(new Uint8Array([2, 0, 0, 0, 2, 0, 1, 1, 0]))).toEqual(8);
});
});

Expand Down

0 comments on commit c94e219

Please sign in to comment.