Skip to content

Connect Four Questions

I am trying to learn how to code by looking a solutions for previous codes and finding out what each part is doing to learn how to use them. I want to become a developer but I do not want to copy and paste everything , I want to actually know what is happening so I can code this myself. I can watch 100 videos but I have questions and I need help, hope someone out there can help me ….

I was wondering if someone could explain to me what is going on in the code below.

 * 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(p1, p2, height = 6, width = 7) {
    this.players = [p1, p2];
    this.height = height;
    this.width = width;
    this.currPlayer = p1;
    this.makeBoard();
    this.makeHtmlBoard();
    this.gameOver = false;
  }

  /** makeBoard: create in-JS board structure:
   *   board = array of rows, each row is array of cells  (board[y][x])
   */

**Question: So I believe that this is creating a board and making it empty by looping through it?**
 
 makeBoard() {
    this.board = [];
    for (let y = 0; y < this.height; y++) {
      this.board.push(Array.from({ length: this.width }));
    }
  }

  **Question: Is this grabbing the board element from the HTML Page? board.innerHtml is blank, however
didnt we just make a blank a board? Why do we need this?**

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

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

    // store a reference to the handleClick bound function 
    // so that we can remove the event listener correctly later
    this.handleGameClick = this.handleClick.bind(this);
    
    top.addEventListener("click", this.handleGameClick);

    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 = 0; 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) */

**Question: I have no idea what this line is doing**

  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 board */

**Question: Im not sure what place in table is doing, however I know the second line is creating a DIV on 
the table , third line is styling it, however the last three lines i need help with it.**

  placeInTable(y, x) {
    const piece = document.createElement('div');
    piece.classList.add('piece');
    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 top = document.querySelector("#column-top");
    top.removeEventListener("click", this.handleGameClick);
  }

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

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

The lines below, I have no idea how I could even think of this logic , please help.

    ****// get next spot in column (if none, ignore click)
    const y = this.findSpotForCol(x);
    if (y === null) {
      return;**
    }
    // place piece in board and add to HTML table
    this.board[y][x] = this.currPlayer;
    this.placeInTable(y, x);
    // check for tie
    if (this.board.every(row => row.every(cell => cell))) {
      return this.endGame('Tie!');
    }
    // check for win
    if (this.checkForWin()) {
      this.gameOver = true;
      return this.endGame(`The ${this.currPlayer.color} player won!`);
    }
    // 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.getElementById('start-game').addEventListener('click', () => {
  let p1 = new Player(document.getElementById('p1-color').value);
  let p2 = new Player(document.getElementById('p2-color').value);
  new Game(p1, p2);
});

Answer

A big part of programming is decomposing problems into smaller ones that you can understand. It’s likely the syntax and size of this problem is a little advanced for a beginner.

In general – here is an overview:

  1. Correct
  2. There is a ‘board’ in javascript and a ‘board’ in HTML. The javascript one is for logic, while the HTML one is for display purposes. That’s why you see two boards being created
  3. findSpotForCol is finding the highest unfilled spot in a given column. This would be a good problem for you to really dive into and try to write it yourself. When you drop a token in a connect 4, it goes to highest spot in that column, that isn’t currently filled. findSpotforCol is an algorithm to do that.
  4. Each player has their own color. This is putting the checker in the right spot with the correct players color. This is taking our JavaScript logic board, and making it display correctly on the page when a player makes a move
  5. It’s okay to feel overwhelmed! (“I have no idea how I could even think of this logic”). Think about everything you do when you play connect 4. First you drop in a checker to a column. It goes to the lowest spot available in that column. Then – if the whole board is full, it’s a tie. Then you might check if a player won. (Note – there is a bug in this code you pasted, if a player wins on the last checker, it will say ‘Tie’, since it checks for a tie first). Then, it’s the other players turn.

It took me a long time of doing lots of beginner exercises for me to understand a problem like this, which is getting more advanced, so don’t feel bad about having to review the beginner exercises or learn from other platforms/tools/books. If you feel 100% overwhelmed, that’s not a good spot to learn from, and you should maybe look for a simpler problem. Tic-Tac-Toe for example would be one step easier than connect four.