Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save willkessler/84c47163c4789b32d00efd29a6621ee0 to your computer and use it in GitHub Desktop.
Save willkessler/84c47163c4789b32d00efd29a6621ee0 to your computer and use it in GitHub Desktop.
connect4 game
console.log('Welcome to connect4!', "\n");
var connect4Obj = {
board: new Array(), // this will be a two dimensional array
boardWidth : 7,
boardHeight : 5,
player1Piece : 'X',
player2Piece : 'O',
requiredToWin: 4,
constructWinnerSubstr: function(piece) {
return new Array(this.requiredToWin + 1).join( piece );
},
// Build the player board
buildBoard: function(width,height) {
console.log('Building board.');
for (var i = 0; i < height; ++i) {
var row = Array();
for (var j = 0; j < width; ++j) {
row.push('*');
}
this.board.push(row);
}
},
printBoard: function() {
for (var i = 0; i < this.board.length; ++i) {
var rowStr = this.board[i].join(' ');
console.log(rowStr);
}
},
// Place a piece in the top of the board. Have it "fall" downwards until it can no longer fall. This simply means
// find the first spot it will fit starting from the last row. Return true if piece placed successfully, false
// if there was no spot it could fit
placePiece: function(column, piece) {
for (var i = this.boardHeight - 1; i >= 0; --i) {
if (this.board[i][column] == '*') {
this.board[i][column] = piece;
return true;
}
}
return false;
},
checkForWinnerInString: function(singleRow) {
var player1Winner = this.constructWinnerSubstr(this.player1Piece);
var player2Winner = this.constructWinnerSubstr(this.player2Piece);
if (singleRow.indexOf(player1Winner) > -1) {
console.log('Winner is player 1 using \'X\'!');
this.printBoard();
return true; // we have a winner
} else if (singleRow.indexOf(player2Winner) > -1) {
console.log('Winner is player 2 using \'O\'!');
this.printBoard();
return true; // we have a winner
}
//console.log('No winner yet!');
return false; // no winner thus far
},
constructDiagStrLLUR: function(startRow, startCol) {
//console.log('starting at row:', startRow, ' col:', startCol);
var diagStr = '';
var rowCheck = startRow;
var colCheck = startCol;
while (rowCheck > -1 && colCheck < this.boardWidth) {
//console.log(rowCheck,colCheck);
diagStr += this.board[rowCheck][colCheck];
rowCheck--;
colCheck++;
}
//console.log('diagstr from constructDiagStr=' + diagStr);
return diagStr;
},
constructDiagStrULLR: function(startRow, startCol) {
//console.log('starting at row:', startRow, ' col:', startCol);
var diagStr = '';
var rowCheck = startRow;
var colCheck = startCol;
while (rowCheck < this.boardHeight && colCheck < this.boardWidth) {
//console.log(rowCheck,colCheck);
diagStr += this.board[rowCheck][colCheck];
rowCheck++;
colCheck++;
}
//console.log('diagstr from constructDiagStr=' + diagStr);
return diagStr;
},
// Scan for horizontal 4 in a row, vertical 4 in a row, and diagonal 4 in a row of the same kind.
// To be cute, we can check using string concat (might be faster than generic iterative scanning since
// substr is a C func under the covers). Trickier for diagonal winners...
checkForWinner: function() {
// Construct string for horizontal check
for (var i = 0; i < this.boardHeight; ++i) {
var singleRow = '';
for (var j = 0; j < this.boardWidth; ++j) {
singleRow += this.board[i][j];
}
//console.log('Horizontal winner check:' , singleRow);
if (this.checkForWinnerInString(singleRow)) {
console.log('winner found in a row');
return true;
}
}
// Construct string for vertical check
for (var i = 0; i < this.boardWidth; ++i) {
var singleRow = '';
for (var j = 0; j < this.boardHeight; ++j) {
singleRow += this.board[j][i];
}
//console.log('Vertical winner check:' , singleRow);
if (this.checkForWinnerInString(singleRow)) {
console.log('winner found in a column');
return true;
}
}
// Now that I've written these two it could be refactored to one routine since rows and cols and the limits just reverse.
//console.log('check for LLUR');
// Construct string for diagonal check for diagonals from lower left->upper right (LLUR)
var startRow = this.requiredToWin - 1;
var startCol = 0;
while (startCol < this.boardWidth - this.requiredToWin + 1) {
var diagStr = this.constructDiagStrLLUR(startRow,startCol);
if (this.checkForWinnerInString(diagStr)) {
console.log('winner found in a LLUR diagonal');
return true;
}
var checkRow = startRow + 1;
startRow = Math.min(checkRow, this.boardHeight - 1);
if (checkRow > this.boardHeight - 1) {
startCol++;
}
}
//console.log('check for ULLR');
// Construct string for diagonal check for diagonals from upper left -> lower right (ULLR)
var startRow = 0;
var startCol = this.requiredToWin - 1;
while (startRow < this.boardHeight - this.requiredToWin + 1) {
var diagStr = this.constructDiagStrULLR(startRow,startCol);
if (this.checkForWinnerInString(diagStr)) {
console.log('winner found in a ULLR diagonal');
return true;
}
var checkCol = startCol - 1;
startCol = Math.max(0, checkCol);
if (startCol == 0) {
startRow++;
}
}
return false;
},
pickRandomPlayerPiece: function() {
var playerId = Math.floor(Math.random() * 2);
return (playerId == 0 ? this.player1Piece : this.player2Piece);
},
findFreeSpot: function() {
var startSpot = Math.floor(Math.random() * this.boardWidth);
var check = (startSpot + 1) % this.boardWidth ;
while (check != startSpot) {
if (this.board[0][check] == '*') {
//console.log('found free spot at check=',check);
return(check);
}
check = (check + 1) % this.boardWidth;
}
return -1;
},
playGame: function() {
this.buildBoard(this.boardWidth,this.boardHeight);
// Fill in a vertical column of X's
//for (var i = 0; i < 4; ++i ) {
// this.placePiece(2, 'X');
// }
// Fill in moves until the board is full (ie placePiece returns false), checking for winners along the way
var freeSpot;
while ((freeSpot = this.findFreeSpot()) > -1) {
this.placePiece(freeSpot, this.pickRandomPlayerPiece());
this.printBoard();
console.log("\n");
if (this.checkForWinner()) {
break;
}
}
}
};
connect4Obj.playGame();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment