Javascript Recursion Неожиданно взломанный - длинный код предупреждения - PullRequest
0 голосов
/ 08 ноября 2011

У меня проблема со следующим кодом.Кажется, он ломается во время рекурсии в функции лабиринта в NewMaze .Я запустил его через firebug и получил следующую ошибку:

parent is undefined: line 97 newmaze_generator.js
    [Break On This Error] self.visited = function() {return parent.visited();}; 

И я понятия не имею, почему она будет неопределенной, если это даже реальная проблема.

Я знаю, что этоспрашивать много, поэтому, пожалуйста, не тратьте свое время, если вы действительно не хотите помочь начинающему программисту javascript.Чтобы упростить задачу, у меня есть весь код на моем веб-сайте, так что вы можете запустить программу, которая в настоящий момент ничего не сделает.

http://level2games.com/games/dungeons/dungeons.html

На заметке сторон этотолько мой второй опыт программирования на javascript, поэтому я мог легко совершить глупую ошибку.

Мой MazeGenerator

function NewMaze(_grid) {
    var self = this;
    var stack = new Array();
    var grid = _grid;

    /**
     * A recursive depth-first-search style maze generator
     */
    self.maze = function() {
        var randx = Math.floor(Math.random()*(grid.getWidth()));
        var randy = Math.floor(Math.random()*(grid.getHeight()));
        var startOfMaze = new MyCell(grid.getCell(randx, randy));
        stack.push(startOfMaze);
        mazeHelper(startOfMaze);
    };

    /**
     * Internal recursive method used by maze.
     * A depth-first-search style algorithm.
     * @param mycell current cell
     * @returns {Boolean} true once finished
     */
    function mazeHelper(myCell) {
        var neighbors = myCell.getOpenNeighbors();
        myCell.markVisited();
        if (neighbors.length > 0) {
            var next = Math.floor(Math.random()*(neighbors.length));
            var nextCell = neighbors[next];
            stack.push(nextCell);
            removeWall(myCell, nextCell);
//          alert(myCell.getParent().getArrayLocation().getX()+" , "+myCell.getParent().getArrayLocation().getY());
            mazeHelper(nextCell);
        } else {
            alert("else");
            if (stack.length == 0) return true;
            else mazeHelper(stack.pop());
        };
    };

    /**
     * Removes the wall between the given cells
     * @param fromCell
     * @param toCell
     */
    function removeWall(fromCell, toCell) {
        var xDif = toCell.getParent().getArrayLocation().getX() - fromCell.getParent().getArrayLocation().getX();
        var yDif = toCell.getParent().getArrayLocation().getY() - fromCell.getParent().getArrayLocation().getY();

        if (xDif == -1) toCell.seWall = false;  // if moving up x axis
        if (xDif == 1) fromCell.seWall = false; // if moving down x axis
        if (yDif == -1) toCell.swWall = false;  // if moving up y axis
        if (yDif == 1) fromCell.swWall = false; // if moving down y axis

    };

    /**
     * @returns an instance of 'this' named self.
     */
    self.getSelf = function() {return self;};

    /**
     * Inner class that is an extension of Cell class
     * @param cell the parent cell
     * @returns {MyCell} instance of 'this' child
     */
    function MyCell(cell) {
        var self = this;
        var parent = cell;

        /**
         * Marks the referenced cell as visited using the super class's visited method.
         */
        self.markVisited = function() {parent.markVisited();};

        self.visited = function() {return parent.visited();};

        /**
         * Creates and returns an array of neighbors that have not been visited.
         * @returns {<MyCell>Array} an array of adjacent cells that have not been visited. 
         */
        self.getOpenNeighbors = function() {
            var neighbors = new Array();

            var tc0, tc1, tc3, tc4;
            var parentX = parent.getArrayLocation().getX();
            var parentY = parent.getArrayLocation().getY();

            tc0 = new MyCell(grid.getCell(parentX-1, parentY));
            tc1 = new MyCell(grid.getCell(parentX+1, parentY));
            tc2 = new MyCell(grid.getCell(parentX, parentY-1));
            tc3 = new MyCell(grid.getCell(parentX, parentY+1));

            if (tc0 != undefined && !tc0.visited()) neighbors.push(tc0);
            if (tc1 != undefined && !tc1.visited()) neighbors.push(tc1);
            if (tc2 != undefined && !tc2.visited()) neighbors.push(tc2);
            if (tc3 != undefined && !tc3.visited()) neighbors.push(tc3);

            return neighbors;
        };

        /**
         * @returns an instance of 'this' named self.
         */
        self.getSelf = function() {return self;};

        /**
         * @returns an instance of the 'super' class named parent.
         */
        self.getParent = function() {return parent;};
    };
};

Мой класс лабиринта

function NewGrid(context, gwidth, gheight) {
    var self = this;    // stores and instance of 'this'
    var ctx = context;  // local pointer to the context;
    var width = 12;     // 12 is the default number of cells wide
    var height = 12;    // 12 is the default number of cells high

    // Public Variables - needed by NewCell class, umm... please don't overwrite
    NewGrid.FLOOR_COLOR = "#CABCAF"; // default base color - brown
    NewGrid.WALL_COLOR = "#333333"; // default wall color - dark grey
    NewGrid.CELL_WIDTH = FINAL_CELL_WIDTH;      // 200px is the default width
    NewGrid.CELL_HEIGHT = FINAL_CELL_HEIGHT;    // 100px is the default height

    var cells = new Array();    // 2d array of cells, fully instantiated in constructHelper
    contructHelper(gwidth, gheight);

    /**
     * Internal helper method (pseudo-constructor)
     */
    function contructHelper(gwidth, gheight) {
        if (gwidth != undefined && gheight != undefined) {
            width = gwidth;
            height = gheight;
        };

        // Constructs the 2d array of cells i.e. cells[y] = x[]
        cells = new Array(height);
        for (var i = 0; i < cells.length; i++) {
            cells[i] = new Array(height);
        };

        gridBuilder();
    };

    function gridBuilder() {
        var offSet = width * NewGrid.CELL_WIDTH / 2;
        for (var i = 0; i < cells.length; i++) {
            for (var j = cells[i].length - 1; j >= 0; j--) {
                var x = (j * NewGrid.CELL_WIDTH / 2) - (i * NewGrid.CELL_WIDTH / 2) + offSet;
                var y = (i * NewGrid.CELL_HEIGHT / 2) + (j * NewGrid.CELL_HEIGHT / 2);
                cells[i][j] = new NewCell(ctx, new Point(x,y), new Point(i,j));
            };
        };
    };

    /**
     * @returns the width of the grid
     */
    self.getWidth = function() {return width;};

    /**
     * @returns the height of the grid
     */
    self.getHeight = function() {return height;};

    /**
     * draws the grid to the screen
     * @param useViewport true if drawing only a portion
     */
    self.drawMe = function(useViewport) {
        if (!useViewport) {
            // draws the full grid to the canvas
            for (var i = 0; i < cells.length; i++) {
                for (var j = cells[i].length - 1; j >= 0; j--) {
                    cells[i][j].drawMe();
                };
            };
            for (var i = 0; i < cells.length; i++) {
                for (var j = cells[i].length - 1; j >= 0; j--) {
                    cells[i][j].drawWalls();
                };
            };
        } else {
            // draws only the viewable portion of the grid to the canvas.
            // not implemented yet
        }
    };

    self.getCell = function(x,y) {
        if (x >= 0 && x < width) {
            if (y >= 0 && y < height) {
                return cells[x][y].getSelf();
            };
        };
        return undefined;
    };

    /**
     * @returns an instance of 'this' named self.
     */
    self.getSelf = function() {return self;};

    /**
     * Internal class for the viewable portion of the grid
     * @param vpwidth (optional) number of cells to be displayed horizontally
     * @param vpheight (optional) number of cells to be displayed vertically
     */
    function ViewPort(vpwidth, vpheight) {
        var self = this;
        var width = 4;  // 4 is the default number of cells wide
        var height = 3; // 3 is the default number of cells high
        constructHelper(vpwidth, vpheight);

        /**
         * Internal helper method (pseudo-constructor)
         */
        function contructHelper(vpwidth, vpheight) {
            if (vpwidth != undefined && vpheight != undefined) {
                width = vpwidth;
                height = vpheight;
            }; 
        };

        /**
         * @returns the width of the view port
         */
        self.getWidth = function() {return width;};
        /**
         * @returns the height of the view port
         */
        self.getHeight = function() {return height;};

        /**
         * @returns an instance of 'this' named self.
         */
        self.getSelf = function() {return self;};
    };
};

My Cell Class

/**
 * @param context the context on which to be drawn.
 * @param ccorners an array of points representing the 4 corners
 * @param cwidth (optional) the number of pixels wide the cell is.
 * @param cheight (optional) the number of pixels high the cell is.
 */
function NewCell(context, origin, arrLoc) {
    var self = this;            // stores and instance of 'this'
    var ctx = context;          // local pointer to the context;
    var corners = new Array();  // an array of points representing the corners in n-e-s-w order
    var arrayLoc = arrLoc;  // position in the cells array
    var wallHeight = 5; // pixels used to draw the wall

    self.swWall = true; //determines is a wall is present to the south-west
    self.seWall = true; //determines is a wall is present to the south-east

    var visited = false;    // used by maze generator

    contructHelper(origin);

    /**
     * Internal helper method (pseudo-constructor)
     * @param origin is a Point representing the x,y value of the top corner
     */
    function contructHelper(origin) {
        corners[0] = new Point(origin.getX(), origin.getY());                                                       // 0,0
        corners[1] = new Point(origin.getX() + NewGrid.CELL_WIDTH / 2, origin.getY() + NewGrid.CELL_HEIGHT / 2);    // 0+100,0+50
        corners[2] = new Point(origin.getX(), origin.getY() + NewGrid.CELL_HEIGHT);                                 // 0, 0+100
        corners[3] = new Point(origin.getX() - NewGrid.CELL_WIDTH / 2, origin.getY() + NewGrid.CELL_HEIGHT / 2);    // 0-100, 0+50
    };

    /**
     * @returns the x,y value of the top corner as a Point
     */
    self.getOrigin = function() {return corners[0];};

    self.getArrayLocation = function() {return arrayLoc;};

    /**
     * @returns the x,y value of the center of the cell as a Point
     */
    self.getCenter = function() {return new Point(corners[0].getX(), corners[0].getY() + NewGrid.CELL_HEIGHT / 2);};

    /**
     * draws the cell to the canvas using an array of points
     * to from the corners and using (for temporary purposes)
     * a floor color and wall color and wall height.
     */
    self.drawMe = function() {
        ctx.lineWidth = wallHeight;
        ctx.fillStyle = NewGrid.FLOOR_COLOR;
        ctx.beginPath();
        ctx.moveTo(corners[0].getX(),corners[0].getY());
        ctx.lineTo(corners[1].getX(),corners[1].getY());
        ctx.lineTo(corners[2].getX(),corners[2].getY());
        ctx.lineTo(corners[3].getX(),corners[3].getY());
        ctx.closePath();
        ctx.fill();
    };

    self.drawWalls = function() {
        ctx.strokeStyle = NewGrid.WALL_COLOR;
        if (seWall) {
            ctx.beginPath();
            ctx.moveTo(corners[2].getX(),corners[2].getY());
            ctx.lineTo(corners[3].getX(),corners[3].getY());
            ctx.closePath();
            ctx.stroke();
        };

        if (swWall) {
            ctx.beginPath();
            ctx.moveTo(corners[3].getX(),corners[3].getY());
            ctx.lineTo(corners[0].getX(),corners[0].getY());
            ctx.closePath();
            ctx.stroke();
        };
    };

    self.visited = function() {return visited;};

    self.markVisited = function() {visited = true;};

    /**
     * @returns gets the array of the 4 neighboring cells
     */
    self.getNeighbors = function() {
        return neighbors;
    };

    /**
     * @returns an instance of 'this' named self.
     */
    self.getSelf = function() {return self;};
};

1 Ответ

0 голосов
/ 09 ноября 2011

Хорошо, я понял это! Я был глупой ошибкой, хорошо это или нет, но я не уверен.

Здесь была проблема:

В функции getOpenNeighbors я проверял, была ли ячейка неопределенной, и если это так, не добавляйте ее в массив возможных соседей, к которым нужно перейти. Ну, неопределенная проверка была написана неправильно. Я определил клетки так:

tc0 = new MyCell(grid.getCell(parentX-1, parentY));

Метод grid.getCell (x, y) вернул бы неопределенное значение, если бы в заданном месте не было ячейки, что я и хотел.

Однако в проверке я сделал, чтобы убедиться, что он не был добавлен в массив, который я написал так:

if (tc0 != undefined && !tc0.visited()) neighbors.push(tc0);

Ну ясно tc0 или любой из созданных таким образом объектов tc0-x не будет неопределенным. мне нужно было проверить, не определен ли объект, который я передал в качестве параметра. Ну, я относился к этому объекту как к родительскому или суперклассу, поэтому все, что мне нужно было сделать, - это использовать мой метод getParent () , и все было бы просто как фанат.

if (tc0.getParent() != undefined && !tc0.visited()) neighbors.push(tc0);

Теперь все работает! К сожалению, лабиринт не выглядит так, как должен, поэтому у меня есть некоторые проблемы со стрельбой, но, по крайней мере, я могу двигаться вперед.

...