-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgame.mjs
125 lines (107 loc) · 3.28 KB
/
game.mjs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Members.
const marks = {
EMPTY: '-',
X: 'X',
O: 'O',
};
export default class Game {
constructor (player1, player2) {
this._player1 = player1;
this._player2 = player2;
// Initialize the board.
this._board = new Array(9).fill(marks.EMPTY);
// Assign X and O to players.
// There's gotta be a better way to do this.
this._marksMap = new Map();
this._marksMap.set(marks.X, player1);
this._marksMap.set(marks.O, player2);
this._playersToMarks = new Map();
this._playersToMarks.set(player1, marks.X);
this._playersToMarks.set(player2, marks.O);
// Decide who goes first.
this._isP1sTurn = true;
}
get activePlayer () { return this._isP1sTurn ? this._player1 : this._player2; }
get gameState () { return this._board; }
get isOver() { return getWinnerMark(this._board) || isFull(this._board); }
get player1() { return { team: this._player1, token: this._playersToMarks.get(this._player1) }; }
get player2() { return { team: this._player2, token: this._playersToMarks.get(this._player2) }; }
get result () {
if (!this.isOver) {
return undefined;
}
// If we don't have a winner, it's a tie.
const isTie = !this.winningPlayer;
return {
isTie,
winner: this.winningPlayer,
loser: (this.winningPlayer.socketId === this._player1.socketId) ? this._player2 : this._player1,
}
}
get winnerMark () { return getWinnerMark(this._board); }
get winningPlayer () {
const winnerMark = this.winnerMark;
if (this.winnerMark) {
return this._marksMap.get(winnerMark);
}
else {
return null;
}
}
advanceTurn () {
this._isP1sTurn = !this._isP1sTurn;
}
/**
* @param mark - the mark to place on the board.
* @param move - the index to place the mark.
*/
update (move) {
const mark = this._playersToMarks.get(this.activePlayer);
// Can only place mark in an empty square.
if (this._board[move] === marks.EMPTY) {
const newBoard = [...this._board];
newBoard[move] = mark;
this._board = newBoard;
}
// Advance the turn regardless - invalid moves result in forfeiture of turn.
this.advanceTurn();
}
};
const isFull = board => board.every(isNotEmpty);
const isNotEmpty = square => square !== marks.EMPTY;
const getWinnerMark = board => {
const topLeft = board[0];
const topMiddle = board[1];
const topRight = board[2];
const middleLeft = board[3];
const middleMiddle = board[4];
const middleRight = board[5];
const bottomLeft = board[6];
const bottomMiddle = board[7];
const bottomRight = board[8];
const winningCombinations = [
// Rows.
[topLeft, topMiddle, topRight],
[middleLeft, middleMiddle, middleRight],
[bottomLeft, bottomMiddle, bottomRight],
// Columns.
[topLeft, middleLeft, bottomLeft],
[topMiddle, middleMiddle, bottomMiddle],
[topRight, middleRight, bottomRight],
// Diagonals.
[topLeft, middleMiddle, bottomRight],
[bottomLeft, middleMiddle, topRight],
];
let winningMark = null;
winningCombinations.forEach(potential => {
// Is this a winner?
if (potential[0] !== marks.EMPTY &&
potential[0] === potential[1] &&
potential[1] === potential[2])
{
winningMark = potential[0];
return;
}
});
return winningMark;
}