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

Dani Ivanov
Dani Ivanov
10,732 Points

I am getting undefined error and I cant figure out the reason

I am recreating the code (Maze Game) in the course Object-Oriented JavaScript: Part 1 but I am getting this error "Uncaught TypeError: Cannot read property 'south' of undefined --- robotmazeinterface.js:42" and I cant figure out why. If somebody could have a look at the files and tell me whats wrong or at least suggest what could be the reason, that would be great. I've tried but I can't find the reason myself.

Index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Maze</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div id="page">
        Loading...
    </div>
    <script src="js/robot.js"></script>
    <script src="js/maze.js"></script>
    <script src="js/mazeSpaces.js"></script>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="js/robotmazeinterface.js"></script>      
    <link rel="stylesheet" href="css/robotmazeinterface.css">
    <link rel="stylesheet" href="css/font-awesome.css">

    <script>
        var m = new Maze(7, 5);
        m.setStart(1,1,"north");
        m.setEnd(7,1);
        m.setWall(1,1,"east");

        var i = new RobotMazeInterface(null,m,"#page");       
        $(document).ready(function() {
            i.render();
        });         

    </script>
</body> 
</html>

maze.js

"use strict";

function Maze(width, height) {
    this.width = width;
    this.height = height;

    this.startX = null;
    this.startY = null;
    this.startOrientation = null;
    this.endX = null;
    this.endY = null;

    this.spaces = [];

    var x, y;
    for(x = 1; x < width; x++) {
        this.spaces[x] = [];   
        for(y = 1; y < height; y++) {
            this.spaces[x][y] = new MazeSpace();   
        }
    }
}

Maze.prototype.setStart = function(x, y, orientation) {
    this.startX = x;
    this.startY = y;
    this.startOrientation = orientation;    
}

Maze.prototype.setEnd = function(x, y) {
    this.endX = x;
    this.endY = y;
}

Maze.prototype.setWall = function(x, y, direction) {
    if(x > 0 && x <= this.width &&
       y > 0 && y <= this.height &&
       ["north", "south", "east", "west"].indexOf(direction) !== -1) {
            this.spaces[x][y].setWall(direction);
            return true;
    }
    return false;
}

mazeSpaces.js

"use strict";

function MazeSpace() {
    this.north = false;
    this.east = false;
    this.south = false;
    this.west = false;
}

MazeSpace.prototype.setWall = function(direction) {
    this[direction] = true;
}

robotmazeinterface.js

function RobotMazeInterface(robot,maze,selector
  ) {
  this.robot = robot;
  this.maze  = maze;
  this.selector = selector;
}

RobotMazeInterface.prototype.canMove = function (x, y, direction) {
  var forwardX, forwardY, forwardDirection;

  if (["north","east","south","west"].indexOf(direction) === -1) {
    return false;
  }

  switch (direction) {
    case "north":
      forwardX = x;
      forwardY = y+1;
      forwardDirection = "south";
      break;
    case "east":
      forwardX = x+1;
      forwardY = y;
      forwardDirection = "west";
      break;
    case "south":
      forwardX = x;
      forwardY = y-1;
      forwardDirection = "north";
      break;
    case "west":
      forwardX = x-1;
      forwardY = y;
      forwardDirection = "east";
      break;
  }

  if (forwardX <= 0 || forwardX > this.maze.width || forwardY <= 0 || forwardY > this.maze.height) {
    return false
  }

  if (this.maze.spaces[x][y][direction]) {
    return false
  }

  if (this.maze.spaces[forwardX][forwardY][forwardDirection]) {
    return false
  }

  return true
}

RobotMazeInterface.prototype.render = function () {
  $(this.selector).empty().append(this.renderMaze(), this.renderControls());
};

RobotMazeInterface.prototype.renderMaze = function () {
  var $maze = $("<div class='maze'>");
  var $mazeRow, $mazeSpace;
  for (var y=this.maze.height; y >= 1; y -=1 ){
    $mazeRow = $('<div class="mazeRow">').appendTo($maze);
    for (var x=1; x <= this.maze.width; x +=1 ){
      $mazeSpace = $('<div class="mazeSpace">').appendTo($mazeRow);
      $mazeSpace.append(this.renderSpace(x,y));
      $mazeSpace.append("&nbsp;")
        .toggleClass('north', !this.canMove(x, y, 'north'))
        .toggleClass('south', !this.canMove(x, y, 'south'))
        .toggleClass('east', !this.canMove(x, y, 'east'))
        .toggleClass('west', !this.canMove(x, y, 'west'));
    }
  }
  return $maze;
}

RobotMazeInterface.prototype.renderSpace = function (x,y) {
  var isRobot = false;
  var isStart = false;
  var isEnd = false;

  if (this.robot !== null && this.robot.x == x && this.robot.y == y) {
      isRobot = true;
  }
  if (this.maze.endX == x && this.maze.endY == y) {
      isEnd = true;
  }
  if (this.maze.startX == x && this.maze.startY == y)  {
      isStart = true;
  }

  if (!isRobot && !isStart && !isEnd) {
    return "";
  }

  var icons = {
    start: "icon-screenshot",
    end: "icon-remove-circle",
    northRobot: "icon-arrow-up",
    eastRobot: "icon-arrow-right",
    southRobot: "icon-arrow-down",
    westRobot: "icon-arrow-left",
    northRobotStart: "icon-circle-arrow-up",
    eastRobotStart: "icon-circle-arrow-right",
    southRobotStart: "icon-circle-arrow-down",
    westRobotStart: "icon-circle-arrow-left",
    robotEnd: "icon-ok-sign "
  }  
  var $space = $('<i>');

  if (isRobot) {
    $space.addClass("robot");
  }
  if (isStart) {
    $space.addClass("start");
  }
  if (isEnd) {
    $space.addClass("end");
  }

  if (isRobot && isEnd) {
    $space.addClass(icons["robotEnd"]);    
  } else if (isRobot && isStart) {
    $space.addClass(icons[this.robot.orientation + "RobotStart"]);
  } else if (isRobot) {
    $space.addClass(icons[this.robot.orientation + "Robot"]);
  } else if (isEnd) {
    $space.addClass(icons["end"]);        
  } else if (isStart)  {
    $space.addClass(icons["start"]);        
  }  

  return $space;

}

RobotMazeInterface.prototype.renderControls = function () {
  var interface = this;
  if (interface.robot === null) return false;
  var $actions = $("<div class='actions'>");


  var buttons = {};
  if(typeof interface.robot.turnLeft == 'function') { 
    buttons["Turn Left"] = function () {
        interface.robot.turnLeft();
        interface.render();
      };
  }
  if(typeof interface.robot.turnRight == 'function') { 
    buttons["Turn Right"] = function () {
        interface.robot.turnRight();
        interface.render();
      };
  }
  if(typeof interface.robot.moveForward == 'function') {   
  buttons["Move Forward"] = function () {
      interface.robot.moveForward();
      interface.render();
    };
  }
  if(typeof interface.robot.canMoveForward == 'function') {   
    buttons["Can Move Forward?"] = function () {
        if (interface.robot.canMoveForward()) {
            alert("Yes!");
        } else {
            alert ("No.");
        }
      };
  }
  if(typeof interface.robot.setMaze == 'function') {   
    buttons["Place in Maze"] = function () {
        interface.robot.setMaze(interface.maze);
        interface.render();
      };
  }
  if(typeof interface.robot.exitMaze == 'function') {   
    buttons["Exit Maze"] = function () {    
        if (interface.robot.maze == interface.maze) {
          (function callExitMaze(){
              setTimeout(function() {
                  result = interface.robot.exitMaze(1);
                  interface.render();
                  if (result === false) {
                      callExitMaze();
                  }
                 return result;
              }, 300);
          })();
        }
      };
  }

  for (var label in buttons) {
    if (buttons.hasOwnProperty(label)){
      var $btn = $('<a class="btn">')
        .text(label)
        .appendTo($actions)
        .click(buttons[label]);
    }
  }

  if (this.robot.maze != this.maze) {
    $robot = $('<i class="robot icon-user"></i>').appendTo($actions);
  }  

  return $actions;
}