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 Making the Game Interactive playToken() Method Solution

My playToken() Solution

Ashley's solution to this problem is a bit less than efficient in my opinion. To find the target space, you have to look for the lowest space that does not have a token value of null. Ashley's solution iterates over the column starting from the beginning and checks each Space object to see if it is empty, and if it is, assigns it as the target. Obviously by the time the loop finishes iterating over the whole column, there will be a target space that represents the lowest position in the column.

But I think it's a lot more efficient to use a for loop to start iterating over the column starting from the last index value and move backwards, and as soon as an empty space is found, break out of the loop. Why iterate over every single space in the column when you only need the lowest one?

Here is my solution:

    /**
     * Determine if current column location of active player's active token is full
     * If not full, determines target space and calls active token's drop() method
     */
    playToken()
    {
        const activeToken = this.activePlayer.activeToken;
        const tokenColumnLocation = activeToken.columnLocation;
        const column = this.board.spaces[tokenColumnLocation];
        if (column[0].token !== null) {
            return;
        } else {
            for (let i = 5; i >= 0; i--) {
                if (column[i].token === null) {
                    this.ready = false;
                    activeToken.drop(column[i]);
                    break;
                }
            }
        }
    }

First the method determines if the topmost position is occupied, and if it is returns out of the function. If the topmost position is not occupied, the method loops backwards through the column and passes the first unoccupied Space object to the drop method then breaks control flow. I just wanted to share this for anyone else out there interested in considering different ways of doing things. IMO many of Ashley's solutions are meant to be clear and simple to understand, but not necessarily efficient or the way a professional developer would write the solution.

anmo20
anmo20
6,470 Points

I did mine a lot differently. It doesn't look quite as efficient as some other people's code, but seems to work just fine. I decided I didn't care to test if the entire column was full from the beginning or not because I didn't think it mattered if I ran the loop to check whether the space was occupied or not from the bottom since there will never be an empty space in between 2 occupied spaces.

playToken(){
  let board = this.board;
  let spaces = board.spaces;
  let activeToken = this.activePlayer.activeToken;

     for (let x = 0; x <= board.columns - 1; x++){      //start a loop across the columns

        if (activeToken.columnLocation === x){       //when token and loop column match

           for (let y = board.rows - 1; y >= 0; y--){     //start another loop of the rows in the collumn from bottom

                if (spaces[x][y].token === null) {           //if the token value is null, drop the token
                    console.log("The space is empty");
                    activeToken.drop(spaces[x][y]);
                    game.ready = false;
                    break;                           //break the loop
                } else {                             //if it's occupied, do nothing
                    console.log("The space is occupied");
                }
          }
       }
    }
}

3 Answers

Lewis Marshall
Lewis Marshall
22,673 Points

Heres my playToken() solution

  /**
   * Find Space object to drop Token into, drops Token
   */
  playToken() {
    const spaces = this.board.spaces;
    const activeToken = this.activePlayer.activeToken;
    const targetColumn = spaces[activeToken.columnLocation];

    const freeSpaces = targetColumn.filter(space => !space.token);

    if (freeSpaces.length) {
      game.ready = false;
      const targetSpace = freeSpaces[freeSpaces.length - 1];

      this.activePlayer.activeToken.drop(targetSpace);
    }
  }

I filter the targetColumn array to get all the spaces that don't have a token. Then check if there are any spaces available by checking the length of the freeSpaces array. If there is then get the last space in the array as this will have the highest y property value.

I had this in mind as a possible solution too

Kacper Kucinski
Kacper Kucinski
14,011 Points

I took the same approach. It seems more straightforward (well, to me!) than Ashley's solution.

Here is my solution (I made this before watching the video, even if they are very similar).

Note the else bracket and the break. I have done this because if it finds a non-empty space, obviously all the next spaces will be non-empty too. There's no point in continuing the loop after finding the first filled space.

    playToken() {
        const column = this.board.spaces[this.activePlayer.activeToken.columnLocation];
        let target = null;
        for (let space of column) {
            if (space.token === null){
                target = space
            } else {
                break;
            }
        }
        if ( target ){
            this.ready = false;
            this.activePlayer.activeToken.drop(target, this.reset);
        }
    }
Dzmitry Aliakseichyk
Dzmitry Aliakseichyk
12,290 Points

As short as I could possibly make it haha. Works as intended by looping from the back of the arrays, finds a spot, drops the token and breaks the loop. I cut out the line that assigns token's .id to the space it's being placed into for now.

playToken() {
    let spaces = this.board.spaces;
    let activeToken = this.activePlayer.activeToken;
    for (let r = this.board.rows - 1, c = activeToken.columnLocation; r >= 0; r--) {
      if (spaces[c][r].token === null) {
        this.ready = false;
        activeToken.drop(spaces[c][r]);
        break;
      }
    }
  }