www.webdeveloper.com
Results 1 to 5 of 5

Thread: [RESOLVED] Help: How come this for-loop won't finish sometimes?

Hybrid View

  1. #1
    Join Date
    Mar 2013
    Posts
    2

    resolved [RESOLVED] Help: How come this for-loop won't finish sometimes?

    Hello Community

    I'm currently trying my skill at javascripting for the first time in coding a Civilization Revolution clone. Perhaps not the easiest choice of task, I know. I've only gotten started and I'm already running into problems with the map generation. Thus, I would much appreciate your knowledgeable advice.

    Below is the code I came up with. The problem that keeps occurring when running the code is this: Sometimes, the map generation will just stop short. (Infrequently, the map will generate completely.) As you will see upon inspecting my code, I'm using a div (with id = 'map') for displaying the map, appending other divs (with className = 'col') to it to make the map's columns and appending these with yet more divs (with className = 'tile') to make the actual tiles of the map.

    When tweaking the code I found I could increase the chance of the map generating completely by decreasing the number of rows (stored in variable 'Rows'). In fact, it seems that once the first column has generated with all its tiles, so will the rest of the columns and the map will generate fully. That is to say: The abortion of the map generation only seems to occur whenever there's something wrong with the FIRST column.

    I'm relying on a randomised variable (called 't') for the allocation of different terrains to the tiles. Perhaps that's what causes the bug?

    Again: I would much appreciate your help in this matter. As of now, the map generation isn't all that fancy. I would really love to improve on it to come up with some nifty maps once this bug is squashed.

    Here's my code:

    <!doctype html>

    <html>

    <head>

    <title>
    A Map in Javascript
    </title>

    <style>

    #map {
    width: 2560px; // 80 tiles * 32px
    height: 1440px; // 45 tiles * 32px
    }

    .col {
    float: left;
    width: 32px;
    }

    .tile {
    width: 32px;
    height: 32px;
    }

    </style>

    <script>
    // Draw Map
    // ********

    function drawMap () {
    for (var x = 0; x < Cols; x++) {

    // Create New Column-Div
    // *********************
    var newCol = document.createElement('div');
    newCol.className = 'col';
    document.getElementById('map').appendChild(newCol);

    for (var y = 0; y < Rows; y++) {

    // Create New Tile-Div
    // *******************
    var newTile = document.createElement('div');
    newTile.className = 'tile';
    document.getElementsByClassName('col')[x].appendChild(newTile);

    if (map[x][y].terrain == "deep sea") newTile.style.background = "navy";
    if (map[x][y].terrain == "shallow sea") newTile.style.background = "aqua";
    if (map[x][y].terrain == "plain") newTile.style.background = "lawngreen";
    if (map[x][y].terrain == "grassland") newTile.style.background = "limegreen";
    if (map[x][y].terrain == "forest") newTile.style.background = "darkgreen";
    if (map[x][y].terrain == "hill") newTile.style.background = "saddlebrown";
    if (map[x][y].terrain == "mountain") newTile.style.background = "dimgrey";
    if (map[x][y].terrain == "desert") newTile.style.background = "khaki";
    if (map[x][y].terrain == "ice") newTile.style.background = "white";
    }
    }
    }

    // Tile-Constructor
    // ****************

    function tile (x, y, terrain) {
    this.x = x;
    this.y = y;
    this.terrain = terrain;
    }

    // CheckAdjacentTilesForLand
    // *************************

    function checkAdjacentTilesForLand (x, y) {
    if (map[x-1][y-1].terrain !== "sea") return true;
    if (map[x] [y-1].terrain !== "sea") return true;
    if (map[x+1][y-1].terrain !== "sea") return true;
    if (map[x-1][y] .terrain !== "sea") return true;
    if (map[x+1][y] .terrain !== "sea") return true;
    if (map[x-1][y+1].terrain !== "sea") return true;
    if (map[x] [y+1].terrain !== "sea") return true;
    if (map[x+1][y+1].terrain !== "sea") return true;
    return false;
    }

    // Set Map Dimensions
    // ******************
    var Cols = 80; // Set map width
    var Rows = 45; // Set map height

    // Set Partioning of Terrains
    // **************************
    var Sea = 40; // Set % of sea-tiles
    var Plains = 10; // Set % of plain-tiles
    var Grasslands = 10; // Set % of grassland-tiles
    var Forests = 15; // Set % of forest-tiles
    var Hills = 10; // Set % of hill-tiles
    var Mountains = 10; // Set % of mountain-tiles
    var Deserts = 5; // Set % of desert-tiles

    if (Sea + Plains + Grasslands + Forests + Hills + Mountains + Deserts < 100) alert ('Too few!');
    if (Sea + Plains + Grasslands + Forests + Hills + Mountains + Deserts > 100) alert ('Too much!');

    // Initialize Map
    // **************
    var map = new Array (Cols);

    for (var x = 0; x < Cols; x++) {

    map[x] = new Array (Rows);

    for (var y = 0; y < Rows; y++) {

    // Set Terrain
    // ***********
    var t = Math.floor(Math.random()*100)+1;
    var terrain;
    if (t < Sea) terrain = "sea";
    else if (t < Sea + Plains) terrain = "plain";
    else if (t < Sea + Plains + Grasslands) terrain = "grassland";
    else if (t < Sea + Plains + Grasslands + Forests) terrain = "forest";
    else if (t < Sea + Plains + Grasslands + Forests + Hills) terrain = "hill";
    else if (t < Sea + Plains + Grasslands + Forests + Hills + Mountains) terrain = "mountain";
    else if (t < Sea + Plains + Grasslands + Forests + Hills + Mountains + Deserts) terrain = "desert";

    // Add Ice-Caps
    // ************
    if (y == 0 || y == Rows-1) terrain = "ice";

    // Shallow or Deep Sea
    // *******************
    if (terrain == "sea") {
    if (checkAdjacentTilesForLand (x, y)) terrain = "shallow sea";
    if (!checkAdjacentTilesForLand (x, y)) terrain = "deep sea";
    }

    // Create New Tile
    // ***************
    map[x][y] = new tile (x, y, terrain);
    }
    }
    </script>

    </head>

    <body onload="drawMap()">

    <div id="map"></div>

    </body>

    </html>

  2. #2
    Join Date
    Dec 2005
    Location
    FL
    Posts
    7,380
    Posted in error so see next post.
    Last edited by JMRKER; 03-13-2013 at 01:54 PM.

  3. #3
    Join Date
    Dec 2005
    Location
    FL
    Posts
    7,380

    Lightbulb

    My suspicion is an error in the following logic although I have not investigated all of your code at this time.

    Note the addition of the following range checks for the passed x and y parameters.
    I'm not sure what you expect to happen if x=0 and then you look at element x[-1]
    but I'm pretty sure you will not get what you expect unless it has been initialized.
    Same thing for the y parameter.

    I don't know if the return should be true or false so you might want to re-evaluate you logic about this function
    Code:
    function checkAdjacentTilesForLand (x, y) {
      if ((x-1) <0) { return true; } // ???
      if ((y-1) <0) { return true; } // ???
      if ((x+1) >= map.length) { return true; } // ???
      if ((y+1) >= map[x].length) { return true; } // ???
    
    if (map[x-1][y-1].terrain !== "sea") return true;
    if (map[x] [y-1].terrain !== "sea") return true;
    if (map[x+1][y-1].terrain !== "sea") return true;
    if (map[x-1][y] .terrain !== "sea") return true;
    if (map[x+1][y] .terrain !== "sea") return true;
    if (map[x-1][y+1].terrain !== "sea") return true;
    if (map[x] [y+1].terrain !== "sea") return true;
    if (map[x+1][y+1].terrain !== "sea") return true;
    return false;
    }
    Also note that your following code, the "if ... else" statements are not correct syntax
    The ';' character indicates the end of a statement, so the else portion of your first "if" will not get executed.
    Code:
    / Set Terrain
    // ***********
    var t = Math.floor(Math.random()*100)+1;
    var terrain;
    if (t < Sea) terrain = "sea";
    else if (t < Sea + Plains) terrain = "plain";
    else if (t < Sea + Plains + Grasslands) terrain = "grassland";
    else if (t < Sea + Plains + Grasslands + Forests) terrain = "forest";
    else if (t < Sea + Plains + Grasslands + Forests + Hills) terrain = "hill";
    else if (t < Sea + Plains + Grasslands + Forests + Hills + Mountains) terrain = "mountain";
    else if (t < Sea + Plains + Grasslands + Forests + Hills + Mountains + Deserts) terrain = "desert";
    And if the value of 'Sea' is 'sea' and the value of "Plains" is 'plain'
    then the test of Sea+Plains will become 'seaplain' which is probably not what you expect.

    BTW: You should enclose your code between [ code] and [ /code] tags (without the spaces)
    to make it easier to read, copy, test and evaluate your problem.

  4. #4
    Join Date
    Mar 2013
    Posts
    2
    Thanks so much JMRKER! You are indeed a SUPER Moderator!!!

    Turns out the bug did lie within the checkAdjacentTilesForLand-function.
    I commented it out and - tadaa! - the map will generate completely every time.

    Strange though: My incorrect syntax within the if-else-statements with the surplus semicolons doesn't seem to do any harm. Thanks for pointing it out, anyway. I deleted them. And thanks for letting me know about enclosing code in the appropriate tags. I'm sure I'll make use of that aplenty in the future.

    Gotta get to coding a new function. Thanks again!

  5. #5
    Join Date
    Dec 2005
    Location
    FL
    Posts
    7,380

    Lightbulb

    You're most welcome.
    Happy to help.

    If leaving in the ';' or removing them made no difference, then I suspect they are not need, nor are the 'else' portions
    Code:
    // Set Terrain
    // ***********
    var t = Math.floor(Math.random()*100)+1;
    var terrain;
    if (t < Sea) terrain = "sea";
    if (t < Sea + Plains) terrain = "plain";
    if (t < Sea + Plains + Grasslands) terrain = "grassland";
    if (t < Sea + Plains + Grasslands + Forests) terrain = "forest";
    if (t < Sea + Plains + Grasslands + Forests + Hills) terrain = "hill";
    if (t < Sea + Plains + Grasslands + Forests + Hills + Mountains) terrain = "mountain";
    if (t < Sea + Plains + Grasslands + Forests + Hills + Mountains + Deserts) terrain = "desert";
    // ...
    Because 't' is randomly assigned values from 1-100,
    I will make the assumption that Sea = (a number), Plaines = (a number), etc.
    Since I don't know what your (number) assignments are, this is only a recommendation.

    Consider numbering as this...
    Code:
    <script>
    var Terrain = ['sea','plain','grassland','forest','hill','mountain','desert'];
    
    // Set Terrain
    // ***********
    var t = Math.floor(Math.random()*Terrain.length);
    var terrain = Terrain[t];
    
    alert('Current terrain is: '+terrain);
    </script>
    Good Luck!

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center



Recent Articles