forked from porkchop/lc-connect4
-
Notifications
You must be signed in to change notification settings - Fork 0
/
game.js
144 lines (120 loc) · 4.22 KB
/
game.js
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
var _ = require('lodash');
function Game(params) {
params = params || {};
this.id = params.id;
this.player1 = params.player1;
this.player2 = params.player2;
this.winner = null;
this.player1PlayAgain = false;
this.player2PlayAgain = false;
this.match_key = params.matchKey;
// this.server_key = params.key
// this.server_api_key = params.apiKey
// this.server_secret = params.apiSecret
// We need to store the leetcoin userids
// this.player1leetcoinKey = params.player1leetcoinKey;
// this.player2leetcoinKey = params.player2leetcoinKey;
this.nRows = params.nRows || 6;
this.nColumns = params.nColumns || 7;
this.nInARow = params.nInARow || 4;
this.reset();
}
Game.prototype.reset = function() {
var self = this;
this.board = _.times(this.nColumns, function() {
return [];
});
this.draw = false;
this.turn = 'player1';
this.winner = null;
this.winVector = null;
this.player1PlayAgain = this.player2PlayAgain = false;
}
Game.prototype.isGameOver = function() {
return !!this.draw || !!this.winner;
}
Game.prototype.move = function(playerId, col) {
if(this.isGameOver() // round already over
|| col < 0 // out of bounds
|| col >= this.nColumns
|| (playerId !== this.player1.id && playerId !== this.player2.id) // isn't an active player
|| playerId != this[this.turn].id // not this player's turn
// || !(this.player1leetcoinKey && this.player2leetcoinKey) // both players have not yet been activated at leetcoin
|| this.board[col].length === this.nRows) // column is already full
return false; // invalid move
var column = this.board[col];
column.push(playerId === this.player1.id ? 'X' : 'O');
var win = this.winVector = this.checkWinAt(column.length - 1, col);
if(win) {
var coord1 = win[0]
, playerPiece = this.board[coord1[0]][coord1[1]];
this.winner = playerPiece === 'X' ? this.player1.id : this.player2.id;
}
else {
this.draw = this.checkFull();
if(!this.draw) this.turn = this.turn === 'player1' ? 'player2' : 'player1';
}
return true;
}
/**
* Lower left corner is 0,0
* m == row
* n == column
*/
Game.prototype.checkWinAt = function(m, n) {
var directions = [[1,1],[1,0],[1,-1],[0,1]]
, nInARow = this.nInARow
, nRows = this.nRows
, nColumns = this.nColumns
, board = this.board;
for(var dindex in directions) {
var direction = directions[dindex]
, nextContent
, lastContent
, solution = []
, i = 0
, dn = direction[0]
, dm = direction[1];
// First back up to find the beginning of the connected chain behind me, if it's not me
lastContent = board[n + i * dn][m + i * dm];
nextContent = board[n + (i-1) * dn] && board[n + (i-1) * dn][m + (i-1) * dm];
while(!!lastContent && lastContent === nextContent) {
i--;
lastContent = board[n + i * dn][m + i * dm];
nextContent = board[n + (i-1) * dn] && board[n + (i-1) * dn][m + (i-1) * dm];
}
// Now go forward to get the max connected line in this direction
do {
lastContent = board[n + i * dn][m + i * dm];
solution.push([n + i * dn, m + i * dm]);
nextContent = board[n + (i+1) * dn] && board[n + (i+1) * dn][m + (i+1) * dm];
} while(++i < nInARow && !!lastContent && lastContent === nextContent);
if(solution.length === nInARow) return solution;
}
}
Game.prototype.checkFull = function() {
var nRows = this.nRows;
return _.all(this.board, function(col) {
return col.length === nRows;
});
}
Game.prototype.wireSafe = function() {
return {
id: this.id,
player1: this.player1 && this.player1.id,
player2: this.player2 && this.player2.id,
player1PlayAgain: this.player1PlayAgain,
player2PlayAgain: this.player2PlayAgain,
winner: this.winner,
player1leetcoinKey: this.player1leetcoinKey,
player2leetcoinKey: this.player2leetcoinKey,
board: this.board,
nRows: this.nRows,
nColumns: this.nColumns,
draw: this.draw,
turn: this.turn,
nInARow: this.nInARow,
winVector: this.winVector
};
}
module.exports = Game;