Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript Object-Oriented JavaScript: Challenge Rendering the Game startGame() Method Solution

Uncaught TypeError: Cannot read property 'drawHTMLToken' of undefined

Help. I cannot for the life of me figure out where I am going wrong, I have stared at my code so long that my eyes hurt, I've gone through all the similar problems in the treehouse community and even compared my code to the final solutions and still can't understand :'(

class Game {
    constructor() {
        this.board = new Board();
        this.players = this.createPlayers();
        this.ready = false;
    }


    /**
     * Returns active player.
     * @return  {Object}    player - The active player.
     */
    get activePlayer() {
        return this.players.find(player => player.active);
    }


    /**
     * Creates two player objects
     * @return  {array}    An array of two player objects.
     */
    createPlayers() {
        const players = [new Player('Player 1', 1, '#e15258', true),
                         new Player('Player 2', 2, '#e59a13')];
        return players;
    }


    /**
     * Initializes game.
     */
    startGame(){
        this.board.drawHTMLBoard();
        this.activePlayer.activeToken.drawHTMLToken();
        this.ready = true;
    }
}
class Token {
    constructor(index, owner){
        this.owner = owner;
        this.id = `token-${index}-${owner.id}`;
        this.dropped = false;
    }

     get htmlToken() {
        return document.getElementById(this.id);
    }

     drawHTMLToken(){
        const token = document.createElement('div');
        document.getElementById('game-board-underlay').appendChild(token);
        token.setAttribute('id', this.id);
        token.setAttribute('class', 'token');
        token.style.backgroundColor = this.owner.color;
    }

}
class Space {
  constructor(x, y, id, token, diameter, radius)
  {
    this.x = x;
    this.y = y;
    this.id = `space-${x}-${y}`;
    this.token = null;
    this.diameter = 76;
    this.radius = this.diameter/2;
  }
  drawSVGSpace() {
    const svgSpace = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    svgSpace.setAttributeNS(null, "id", this.id);
svgSpace.setAttributeNS(null, "cx", (this.x * this.diameter) + this.radius);
svgSpace.setAttributeNS(null, "cy", (this.y * this.diameter) + this.radius);
svgSpace.setAttributeNS(null, "r", this.radius - 8);
svgSpace.setAttributeNS(null, "fill", "black");
svgSpace.setAttributeNS(null, "stroke", "none");
    document.getElementById("mask").appendChild(svgSpace); 
  }

}
class Board {
  constructor(rows, columns, spaces)
  {
    this.rows = 6;
    this.columns = 7;
    this.spaces = this.createSpaces();

  }
   createSpaces() {
     const spaces = [];
     for (let i = 0; i < this.columns.length; i++  )
     { const col = [];
       for (let j = 0; j < this.rows.length; j++)
      {
        let space = new Space(i, j);
    col.push(space);
    }
    spaces.push(col);
       }

    return spaces;
     }

     drawHTMLBoard(){
     for (let column of this.spaces)
     {for (let space of column) {

  space.drawSVGSpace();
         }
       }

     }
   }
class Player {
  constructor(name, id, colour, active = false){
    this.name = name;
    this.id = id;
    this.colour = colour;
    this.active = active;
    this.tokens = this.createTokens(21);
  }

   createTokens(num) {
      const tokens = [];
      for (let i; i < num; i++){
        let token = new Token(i, this);
    tokens.push(token);
    }
    return tokens;
}


 get unusedTokens(){
        return this.tokens.filter(token => !token.dropped);
    }


get activeToken(){
  return this.unusedTokens[0];
}
}

Feeling dumb as hell right now.

1 Answer

First issue I've noticed:

   createSpaces() {
     const spaces = [];
     for (let i = 0; i < this.columns.length; i++  )
     { const col = [];
       for (let j = 0; j < this.rows.length; j++)
      {
        let space = new Space(i, j);
    col.push(space);
    }
    spaces.push(col);
       }

    return spaces;
     }

You don't need "columns.length" and "rows.length". 'rows' and 'columns' refer to int variables, not arrays. So the counter needs to be set to the actual value, not a length method.