Skip to content

Commit

Permalink
added connect4.js
Browse files Browse the repository at this point in the history
  • Loading branch information
jonjones320 committed Dec 29, 2023
1 parent 92194bd commit 9354019
Showing 1 changed file with 177 additions and 0 deletions.
177 changes: 177 additions & 0 deletions connect4.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/** Connect Four
*
* Player 1 and 2 alternate turns. On each turn, a piece is dropped down a
* column until a player gets four-in-a-row (horiz, vert, or diag) or until
* board fills (tie)
*/

class Game {
constructor(player1, player2) {
this.WIDTH = 6
this.HEIGHT = 7;
this.players = [player1, player2];
this.currPlayer = player1; // active player: 1 or 2
this.makeBoard();
this.makeHtmlBoard();
let gameOver = false;
}

/** makeBoard: create in-JS board structure:
* board = array of rows, each row is array of cells (board[y][x])
*/
makeBoard() {
this.board = []; // array of rows, each row is array of cells (board[y][x])
for (let y = 0; y < this.HEIGHT; y++) {
this.board.push(Array.from({ length: this.WIDTH }));
}
}

/** makeHtmlBoard: make HTML table and row of column tops. */

makeHtmlBoard() {
const board = document.getElementById('board');

const top = document.createElement('tr'); // make column tops (clickable area for adding a piece to that column)
top.setAttribute('id', 'column-top');

this.bindClick = this.handleClick.bind(this)
top.addEventListener('click', this.bindClick);

for (let x = 0; x < this.WIDTH; x++) {
const headCell = document.createElement('td');
headCell.setAttribute('id', x);
top.append(headCell);
}

board.append(top);

// make main part of board
for (let y = 1; y < this.HEIGHT; y++) {
const row = document.createElement('tr');

for (let x = 0; x < this.WIDTH; x++) {
const cell = document.createElement('td');
cell.setAttribute('id', `${y}-${x}`);
row.append(cell);
}

board.append(row);
}
}

/** findSpotForCol: given column x, return top empty y (null if filled) */
findSpotForCol(x) {
for (let y = this.HEIGHT - 1; y >= 0; y--) {
if (!this.board[y][x]) {
return y;
}
}
return null;
}

/** placeInTable: update DOM to place piece into HTML table of board */
placeInTable(y, x) {
const piece = document.createElement('div');
piece.classList.add('piece');
// piece.classList.add(`p${this.currPlayer}`);
piece.style.backgroundColor = `${this.currPlayer.color}`
piece.style.top = -50 * (y + 2);

const spot = document.getElementById(`${y}-${x}`);
spot.append(piece);
}

/** endGame: announce game end */

endGame(msg) {
alert(msg);
const topRow = document.querySelector("#column-top");
topRow.removeEventListener('click', this.bindClick);
}

/** handleClick: handle click of column top to play piece */

handleClick(evt) {
// get x from ID of clicked cell
const x = +evt.target.id;

// get next spot in column (if none, ignore click)
const y = this.findSpotForCol(x);
if (y === null) {
return;
}

this.board[y][x] = this.currPlayer;
this.placeInTable(y, x);

// check for win
if (this.checkForWin()) {
this.gameOver = true;
return this.endGame(`The ${this.currPlayer.color} player won!`);
}

// check for tie
if (this.board.every(row => row.every(cell => cell))) {
this.gameOver = true;
return this.endGame('Tie!');
}
// place piece in board and add to HTML table

// switch players
this.currPlayer = this.currPlayer === this.players[0] ? this.players[1] : this.players[0];
}

/** checkForWin: check board cell-by-cell for "does a win start here?" */

checkForWin() {
// Check four cells to see if they're all color of current player
// - cells: list of four (y, x) cells
// - returns true if all are legal coordinates & all match currPlayer

const _win = cells =>
cells.every(
([y, x]) =>
y >= 0 &&
y < this.HEIGHT &&
x >= 0 &&
x < this.WIDTH &&
this.board[y][x] === this.currPlayer
);

for (let y = 0; y < this.HEIGHT; y++) {
for (let x = 0; x < this.WIDTH; x++) {
// get "check list" of 4 cells (starting here) for each of the different
// ways to win
const horiz = [[y, x], [y, x + 1], [y, x + 2], [y, x + 3]];
const vert = [[y, x], [y + 1, x], [y + 2, x], [y + 3, x]];
const diagDR = [[y, x], [y + 1, x + 1], [y + 2, x + 2], [y + 3, x + 3]];
const diagDL = [[y, x], [y + 1, x - 1], [y + 2, x - 2], [y + 3, x - 3]];

// find winner (only checking each win-possibility as needed)
if (_win(horiz) || _win(vert) || _win(diagDR) || _win(diagDL)) {
return true;
}
}
}
}
}

class Player {
constructor(color) {
this.color = color;
}}

document.querySelector('#startBtn').addEventListener('click', (event) => {
event.preventDefault();

// Assign each player their input color.
const player1 = new Player(document.querySelector('#p1Color').value);
const player2 = new Player(document.querySelector('#p2Color').value);

// Reset the board each time "Start" is clicked.
const board = document.getElementById('board');
board.innerHTML = "";

new Game(player1, player2);
}
);

0 comments on commit 9354019

Please sign in to comment.