六角网格环不工作

时间:2015-03-23 19:03:01

标签: javascript recursion

我有以下脚本:

<html>
<!-- HexMaze, version 1.0, by Dan Rollins -->
<!-- Modified by posfan12 -->
<!-- Creates a maze of hexagonal cells, similar to a honeycomb -->
<!--http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/A_7849-Hex-Maze.html-->
<body>
<pre id='mazeDisplay'></pre>
</body>
<script type="text/javascript">
var gnX;
var gnY;
var gtMaze;       // the TMaze object -- variables and functions
var radius = 4
var gnWide = radius * 2 - 1;
var gnHigh = radius * 2 - 1;

var ignore_list =
[
    [0,0],  // 1
    [1,0],  // 2
    [2,0],  // 3
    [4,0],  // 4
    [5,0],  // 5
    [6,0],  // 6
    [0,1],  // 7
    [6,1],  // 8
    [0,6],  // 9
    [1,6],  // 10
    [5,6],  // 11
    [6,6]   // 12
]

//------------------------------ CONSTANTS
DIR_N = 0; DIR_NE = 1; DIR_SE = 2; DIR_S = 3; DIR_SW = 4; DIR_NW = 5;
DOOR_N = 1; DOOR_NE = 2; DOOR_SE = 4; DOOR_S = 8; DOOR_SW = 16; DOOR_NW = 32; DOOR_ALL = 63;

//----------------------------- delta arrays  00 offsets to add to 
//-----------------------------   X,Y when moving in any of 6 directions
var ganDeltaX = new Array(6);
var ganDeltaY = new Array(6);

ganDeltaX[DIR_N]  = 0;  ganDeltaY[DIR_N]   =-1;  
ganDeltaX[DIR_NE] = 1;  ganDeltaY[DIR_NE]  =-1;
ganDeltaX[DIR_SE] = 1;  ganDeltaY[DIR_SE]  = 1;
ganDeltaX[DIR_S]  = 0;  ganDeltaY[DIR_S]   = 1;  
ganDeltaX[DIR_SW] =-1;  ganDeltaY[DIR_SW]  = 1;
ganDeltaX[DIR_NW] =-1;  ganDeltaY[DIR_NW]  =-1;  

//=======================================================
// The 2-dimensional array that contains the cell information
//
function TMazeArray(nHigh, nWide) {
    var a = new Array(nHigh);
    for (var i = 0; i < nHigh; i++) {
        a[i] =  new Array(nWide);
        for (var j = 0; j < nWide; j++) {   
            a[i][j] = 0; 
        }
    }
    return a;
}


//=======================================================
//=======================================================
//=======================================================
// The TMaze object
//------------------------------------------------------------------------------ Ctor
function TMaze(nHigh, nWide) {
    this.high = nHigh;
    this.wide = nWide;
    this.ary = TMazeArray(nHigh, nWide);

    this.totRooms = nHigh * nWide - ignore_list.length;  // less (short) bottom line
    this.curRoomCnt = 0;  // rooms that have been visited/door opened

    this.GetCell = function(x,y) {return this.ary[y][x];}
    this.SetCell = function(x,y,value) {this.ary[y][x] = value;}

    this.HasCellBit = function(x,y,value) {return ((this.ary[y][x] & value) == value);}
    this.SetCellBit = function(x,y,value) {this.ary[y][x] |= value;}
    this.ClearCellBit = function(x,y,value) {this.ary[y][x] &= ~value;}
    this.ToggleCellBit = function(x,y,value) {this.ary[y][x] ^= value;}

    this.IsEmptyCellAt = IsEmptyCellAt;  // some member fns, defined below
    this.IsValidXY = IsValidXY;
    this.GetNewXY = GetNewXY;
}

//----------- TRUE if cell in that direction is empty and valid
//
function IsEmptyCellAt(x, y, dir) {
    var o = this.GetNewXY(x, y, dir);

    if (!this.IsValidXY(o.newX, o.newY))   return (false); 
    if (this.GetCell(o.newX, o.newY) != 0)  return (false);

    return true;  // yes, it's possible to move into that cell
}

//------------------------------------------------------------------------------
// return -1 if that would be an invalid move (off the board)
// true if X,Y is on the board
//
function IsValidXY(x, y) {
    if (y < 0) return (false);
    if (y > this.high-1) return (false);

    if (x < 0) return (false);
    if (x > this.wide-1) return (false);

//    if (y & 1) {  // on off Y, max X an maxY are 1 less
//        if (x > this.wide-2) return (false);
//        if (y > this.high-2) return (false);
//    }
    return true;  // possible to move into that direction
}

//------------------------------------------
// If I move in a direction, what are the new X,Y values?
// Return an object with newX and newY properties
//
function GetNewXY(x, y, dir) {
    var oRet = {"newX":-1, "newY":-1, "isValid":false};
    var newX = x;
    var newY = y;

    newX += ganDeltaX[dir];  // add the deltas
    newY += ganDeltaY[dir];

    if (this.IsValidXY(newX, newY)) {
        oRet.newX = newX;
        oRet.newY = newY;
        oRet.isValid = true;
    }
    return oRet;
}
//=====================================================
//=====================================================
//===================================================== end of TMaze members

//------------------------------------------
// generate the inner HTML (all of the img objects)
//
function DrawMaze() {
    var s = "";
    for (var y = 0; y < gtMaze.high; y ++) {
        //----------------------- first line of images per cell row
        for (var x = 0; x < gtMaze.wide; x ++) {
            var v = gtMaze.GetCell(x, y);
            if (x%2 == 0) {
                if ((v < 10) && (v > 0))
                    s += "0" + v;
                else if (v == 0)
                    s += "--";
                else
                    s += v;
            }
            else
                s += "--";
        }
        s += "\n";
        //----------------------- second line of images per cell row
        for (var x = 0; x < gtMaze.wide; x ++) {
            var v = gtMaze.GetCell(x, y);
            if (x%2 == 1) {
                if ((v < 10) && (v > 0))
                    s += "0" + v;
                else if (v == 0)
                    s += "--";
                else
                    s += v;
            }
            else
                s += "--";
        }
        s += "\n";
    }
    document.getElementById('mazeDisplay').innerHTML = s;
}

//==========================================
function ClearTheMaze() {
    gtMaze = new TMaze(gnHigh, gnWide);
    for (var y = 0; y < gtMaze.high; y++) {
        for (var x = 0; x < gtMaze.wide; x++) {
            gtMaze.ary[y][x] = 0;
        }
    }
}

//=========================================================
// Create the maze, using the incremental technique to enable 
// watching the creation process
//=========================================================

function DoCreate() {
    ClearTheMaze();       // set all cells to 0

    gnX = Math.floor(gtMaze.wide/2);
    gnY = Math.floor(gtMaze.high/2);

    gtMaze.curRoomCnt = 1;  // account for the entry room

    while (gtMaze.curRoomCnt < gtMaze.totRooms) {
        DoOneStepCreate()

    }

//    gtMaze.SetCellBit(0, 0, DOOR_NW);  // put the entrance door in place
//    var nExitX = gnWide-1;
//    var nExitY = gnHigh-1;
//    gtMaze.SetCellBit(nExitX, nExitY, DOOR_SE);  // put the exit door in place, doesn't work
//    gtMaze.SetCellBit(gtMaze.wide/2, gtMaze.high/2, DOOR_ALL);  // test

    gfCreateDone = true;
    DrawMaze();    // already drawn as you watched!
}

//---------------------------------------------------------
// Perform one step of the creation process
// Add a door to a room and the adjacent room
// If stuck, scan for a place to branch
//
function DoOneStepCreate() {
    var anDirs = new Array(6);                 // N, WE, SE, S, SW, NW
    var nDirCnt = GetDirs(gnX, gnY, anDirs);   // Fill anDirs with valid directions to move from here

    while (nDirCnt == 0) {           // Trapped! Look for a room I've been in
        gnY++;                       //          that is next to a doorless one
        if (gnY > gtMaze.high-1) {
            gnY = 0;
            gnX++;
            if (gnX > gtMaze.wide-1) {
                gnX = 0;
            }
        }
        if (gtMaze.GetCell(gnX, gnY) != 0) {
            nDirCnt = GetDirs(gnX, gnY, anDirs);
        }
    }

    //-------- It is now possible to move to another room
    var nDirIdx = RndmInt(0, nDirCnt);       // 0 thru possible dirs -- pick one at random
    var nDir = anDirs[nDirIdx];              // 0, 1, 2, 3, 4,  or 5  (direction code)
    var nDoorVal = (1 << nDir);               // 1, 2, 4, 8, 16, or 32 (door value)
    gtMaze.SetCellBit(gnX, gnY, nDoorVal);  // put the door in place

    var o = GetNewXY(gnX, gnY, nDir);
    gnX = o.newX;                             // move into that room
    gnY = o.newY;
                                             //======= set door in this room, too
    nDir = (nDir+3) % 6;                      //=== clockwize opposite (1->4, 2->5, 3->0, etc
    nDoorVal = (1 << nDir);                   // 1, 2, 4, 8, 16, or 32 (door value)
    gtMaze.SetCellBit(gnX, gnY, nDoorVal);  // put the door in place
    gtMaze.curRoomCnt++;
}

//------------------------------------------------------------------------------
// See which directions are possible; populate array anDirs
//
function GetDirs(x, y, anDirs) {
    var nCnt = 0;

    var f = gtMaze.IsEmptyCellAt(x, y, DIR_N);
    if (f) anDirs[nCnt++] = DIR_N;          // can go N

    f = gtMaze.IsEmptyCellAt(x, y, DIR_NE);
    if (f) anDirs[nCnt++] = DIR_NE;      // can go NE

    f = gtMaze.IsEmptyCellAt(x, y, DIR_SE);
    if (f) anDirs[nCnt++] = DIR_SE;      // can go SE

    f = gtMaze.IsEmptyCellAt(x, y, DIR_S);
    if (f) anDirs[nCnt++] = DIR_S;       // can go S

    f = gtMaze.IsEmptyCellAt(x, y, DIR_SW);
    if (f) anDirs[nCnt++] = DIR_SW;      // can go SW

    f = gtMaze.IsEmptyCellAt(x, y, DIR_NW );
    if (f) anDirs[nCnt++] = DIR_NW;      // can go NW

    return nCnt;
}

//------------------------------------------------------------------------------
// utility fn:  get a random integer in the specified range, inclusive
//
function RndmInt(min, max) {
    var tmp = Math.random() * (max-min);
    return Math.floor(tmp) + min;
}


//===================================================
//===================================================
//===================================================

DoCreate()

</script>
</html>

我正在尝试编辑 DoOneStepCreate()函数,以便检查 ignore_list 数组中是否应跳过但未填充的值。例如,使用这样的代码块:

for (var i = 0, n = ignore_list.length; i < n; i++) {
    var coo = ignore_list[i]
    if ((coo[0] == gnX) && (coo[1] == gnY)) {
        // remove this cell from the map
        break
    }
}

浏览器屏幕中的结果形状应为六边形。但是,无论我尝试什么,我都会弄乱循环。它要么被无休止地循环,要么它不能计算全部数值。任何人都可以帮助这样的循环吗?

到目前为止,这是我的尝试:

<html>
<!-- HexMaze, version 1.0, by Dan Rollins -->
<!-- Modified by posfan12 -->
<!-- Creates a maze of hexagonal cells, similar to a honeycomb -->
<!--http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/A_7849-Hex-Maze.html-->
<body>
<pre id='mazeDisplay'></pre>
</body>
<script type="text/javascript">
var gnX;
var gnY;
var gtMaze;       // the TMaze object -- variables and functions
var radius = 4
var gnWide = radius * 2 - 1;
var gnHigh = radius * 2 - 1;

var ignore_list =
[
    [0,0],  // 1
    [1,0],  // 2
    [2,0],  // 3
    [4,0],  // 4
    [5,0],  // 5
    [6,0],  // 6
    [0,1],  // 7
    [6,1],  // 8
    [0,6],  // 9
    [1,6],  // 10
    [5,6],  // 11
    [6,6]   // 12
]

//------------------------------ CONSTANTS
DIR_N = 0; DIR_NE = 1; DIR_SE = 2; DIR_S = 3; DIR_SW = 4; DIR_NW = 5;
DOOR_N = 1; DOOR_NE = 2; DOOR_SE = 4; DOOR_S = 8; DOOR_SW = 16; DOOR_NW = 32; DOOR_ALL = 63;

//----------------------------- delta arrays  00 offsets to add to 
//-----------------------------   X,Y when moving in any of 6 directions
var ganDeltaX = new Array(6);
var ganDeltaY = new Array(6);

ganDeltaX[DIR_N]  = 0;  ganDeltaY[DIR_N]   =-1;  
ganDeltaX[DIR_NE] = 1;  ganDeltaY[DIR_NE]  =-1;
ganDeltaX[DIR_SE] = 1;  ganDeltaY[DIR_SE]  = 1;
ganDeltaX[DIR_S]  = 0;  ganDeltaY[DIR_S]   = 1;  
ganDeltaX[DIR_SW] =-1;  ganDeltaY[DIR_SW]  = 1;
ganDeltaX[DIR_NW] =-1;  ganDeltaY[DIR_NW]  =-1;  

//=======================================================
// The 2-dimensional array that contains the cell information
//
function TMazeArray(nHigh, nWide) {
    var a = new Array(nHigh);
    for (var i = 0; i < nHigh; i++) {
        a[i] =  new Array(nWide);
        for (var j = 0; j < nWide; j++) {   
            a[i][j] = 0; 
        }
    }
    return a;
}


//=======================================================
//=======================================================
//=======================================================
// The TMaze object
//------------------------------------------------------------------------------ Ctor
function TMaze(nHigh, nWide) {
    this.high = nHigh;
    this.wide = nWide;
    this.ary = TMazeArray(nHigh, nWide);

    this.totRooms = nHigh * nWide - ignore_list.length;  // less (short) bottom line
    this.curRoomCnt = 0;  // rooms that have been visited/door opened

    this.GetCell = function(x,y) {return this.ary[y][x];}
    this.SetCell = function(x,y,value) {this.ary[y][x] = value;}

    this.HasCellBit = function(x,y,value) {return ((this.ary[y][x] & value) == value);}
    this.SetCellBit = function(x,y,value) {this.ary[y][x] |= value;}
    this.ClearCellBit = function(x,y,value) {this.ary[y][x] &= ~value;}
    this.ToggleCellBit = function(x,y,value) {this.ary[y][x] ^= value;}

    this.IsEmptyCellAt = IsEmptyCellAt;  // some member fns, defined below
    this.IsValidXY = IsValidXY;
    this.GetNewXY = GetNewXY;
}

//----------- TRUE if cell in that direction is empty and valid
//
function IsEmptyCellAt(x, y, dir) {
    var o = this.GetNewXY(x, y, dir);

    if (!this.IsValidXY(o.newX, o.newY))   return (false); 
    if (this.GetCell(o.newX, o.newY) != 0)  return (false);

    return true;  // yes, it's possible to move into that cell
}

//------------------------------------------------------------------------------
// return -1 if that would be an invalid move (off the board)
// true if X,Y is on the board
//
function IsValidXY(x, y) {
    if (y < 0) return (false);
    if (y > this.high-1) return (false);

    if (x < 0) return (false);
    if (x > this.wide-1) return (false);

//    if (y & 1) {  // on off Y, max X an maxY are 1 less
//        if (x > this.wide-2) return (false);
//        if (y > this.high-2) return (false);
//    }
    return true;  // possible to move into that direction
}

//------------------------------------------
// If I move in a direction, what are the new X,Y values?
// Return an object with newX and newY properties
//
function GetNewXY(x, y, dir) {
    var oRet = {"newX":-1, "newY":-1, "isValid":false};
    var newX = x;
    var newY = y;

    newX += ganDeltaX[dir];  // add the deltas
    newY += ganDeltaY[dir];

    if (this.IsValidXY(newX, newY)) {
        oRet.newX = newX;
        oRet.newY = newY;
        oRet.isValid = true;
    }
    return oRet;
}
//=====================================================
//=====================================================
//===================================================== end of TMaze members

//------------------------------------------
// generate the inner HTML (all of the img objects)
//
function DrawMaze() {
    var s = "";
    for (var y = 0; y < gtMaze.high; y ++) {
        //----------------------- first line of images per cell row
        for (var x = 0; x < gtMaze.wide; x ++) {
            var v = gtMaze.GetCell(x, y);
            if (x%2 == 0) {
                if ((v < 10) && (v > 0))
                    s += "0" + v;
                else if (v == 0)
                    s += "--";
                else
                    s += v;
            }
            else
                s += "--";
        }
        s += "\n";
        //----------------------- second line of images per cell row
        for (var x = 0; x < gtMaze.wide; x ++) {
            var v = gtMaze.GetCell(x, y);
            if (x%2 == 1) {
                if ((v < 10) && (v > 0))
                    s += "0" + v;
                else if (v == 0)
                    s += "--";
                else
                    s += v;
            }
            else
                s += "--";
        }
        s += "\n";
    }
    document.getElementById('mazeDisplay').innerHTML = s;
}

//==========================================
function ClearTheMaze() {
    gtMaze = new TMaze(gnHigh, gnWide);
    for (var y = 0; y < gtMaze.high; y++) {
        for (var x = 0; x < gtMaze.wide; x++) {
            gtMaze.ary[y][x] = 0;
        }
    }
}

//=========================================================
// Create the maze, using the incremental technique to enable 
// watching the creation process
//=========================================================

function DoCreate() {
    ClearTheMaze();       // set all cells to 0

    gnX = Math.floor(gtMaze.wide/2);
    gnY = Math.floor(gtMaze.high/2);

    gtMaze.curRoomCnt = 1;  // account for the entry room

    while (gtMaze.curRoomCnt < gtMaze.totRooms) {
        DoOneStepCreate()

    }

//    gtMaze.SetCellBit(0, 0, DOOR_NW);  // put the entrance door in place
//    var nExitX = gnWide-1;
//    var nExitY = gnHigh-1;
//    gtMaze.SetCellBit(nExitX, nExitY, DOOR_SE);  // put the exit door in place, doesn't work
//    gtMaze.SetCellBit(gtMaze.wide/2, gtMaze.high/2, DOOR_ALL);  // test

    gfCreateDone = true;
    DrawMaze();    // already drawn as you watched!
}

//---------------------------------------------------------
// Perform one step of the creation process
// Add a door to a room and the adjacent room
// If stuck, scan for a place to branch
//
function DoOneStepCreate() {
    var anDirs = new Array(6);                 // N, WE, SE, S, SW, NW
    var nDirCnt = GetDirs(gnX, gnY, anDirs);   // Fill anDirs with valid directions to move from here

    while (nDirCnt == 0) {           // Trapped! Look for a room I've been in
        gnY++;                       //          that is next to a doorless one
        if (gnY > gtMaze.high-1) {
            gnY = 0;
            gnX++;
            if (gnX > gtMaze.wide-1) {
                gnX = 0;
            }
        }
        if (gtMaze.GetCell(gnX, gnY) != 0) {
            nDirCnt = GetDirs(gnX, gnY, anDirs);
        }
    }

    //-------- It is now possible to move to another room
    var nDirIdx = RndmInt(0, nDirCnt);       // 0 thru possible dirs -- pick one at random
    var nDir = anDirs[nDirIdx];              // 0, 1, 2, 3, 4,  or 5  (direction code)
    var nDoorVal = (1 << nDir);               // 1, 2, 4, 8, 16, or 32 (door value)
    for (var i = 0, n = ignore_list.length; i < n; i++) {
        var coo = ignore_list[i]
        if ((coo[0] == gnX) && (coo[1] == gnY)) {
            nDoorVal = 0
            break
        }
    }
    gtMaze.SetCellBit(gnX, gnY, nDoorVal);  // put the door in place

    var o = GetNewXY(gnX, gnY, nDir);
    gnX = o.newX;                             // move into that room
    gnY = o.newY;
                                             //======= set door in this room, too
    nDir = (nDir+3) % 6;                      //=== clockwize opposite (1->4, 2->5, 3->0, etc
    nDoorVal = (1 << nDir);                   // 1, 2, 4, 8, 16, or 32 (door value)
    for (var i = 0, n = ignore_list.length; i < n; i++) {
        var coo = ignore_list[i]
        if ((coo[0] == gnX) && (coo[1] == gnY)) {
            nDoorVal = 0
            break
        }
    }
    gtMaze.SetCellBit(gnX, gnY, nDoorVal);  // put the door in place
    gtMaze.curRoomCnt++;
}

//------------------------------------------------------------------------------
// See which directions are possible; populate array anDirs
//
function GetDirs(x, y, anDirs) {
    var nCnt = 0;

    var f = gtMaze.IsEmptyCellAt(x, y, DIR_N);
    if (f) anDirs[nCnt++] = DIR_N;          // can go N

    f = gtMaze.IsEmptyCellAt(x, y, DIR_NE);
    if (f) anDirs[nCnt++] = DIR_NE;      // can go NE

    f = gtMaze.IsEmptyCellAt(x, y, DIR_SE);
    if (f) anDirs[nCnt++] = DIR_SE;      // can go SE

    f = gtMaze.IsEmptyCellAt(x, y, DIR_S);
    if (f) anDirs[nCnt++] = DIR_S;       // can go S

    f = gtMaze.IsEmptyCellAt(x, y, DIR_SW);
    if (f) anDirs[nCnt++] = DIR_SW;      // can go SW

    f = gtMaze.IsEmptyCellAt(x, y, DIR_NW );
    if (f) anDirs[nCnt++] = DIR_NW;      // can go NW

    return nCnt;
}

//------------------------------------------------------------------------------
// utility fn:  get a random integer in the specified range, inclusive
//
function RndmInt(min, max) {
    var tmp = Math.random() * (max-min);
    return Math.floor(tmp) + min;
}


//===================================================
//===================================================
//===================================================

DoCreate()

</script>
</html>

六边形的边界受到尊重,但六边形并未完全填满。

0 个答案:

没有答案