[SOLVED] Trying to convert Coding Challenge #10.2: Maze Generator with p5.js to processing code

Hi, I was watching one of Dan's cool videos and there's one in particular that I tried to follow, and convert it from p5.js to processing 3 but I can't get past the 2nd video called Coding Challenge #10.2: Maze Generator with p5.js - Part 2

the code below is what I have done, but the result is it draws a bunch of random blank squares, purple squares, and green squares, eventually all but 1 is purple and the last one is green, do you know what I'm doing wrong that would cause this? also none of the grid lines are disappearing as the maze progresses :( I've been at this for 4 days now haha

int w=20;
int cols=floor(400/w);
int rows=floor(400/w);
int[] x = new int[rows+1];
int[] y = new int[cols+1];
int[][] visited = new int[cols+1][rows+1];
boolean[][][] wallPos=new boolean[5][cols+1][rows+1];
int current=0;
void setup() {
  size(401, 401);
  frameRate(1);
  for (int i=0; i<4; i++) {
    for (int j=0; j<rows; j++) {
      for (int k=0; k<cols; k++) {
        wallPos[i][j][k]=true;
      }
    }
  }
  for (int i=0; i<rows; i++) {
    for (int j=0; j<cols; j++) {
      if (i==0 && j==0) {
        visited[0][0]=1;
      }
      if ((i!=0 && j==0) || j>0) {
        visited[i][j]=0;
      }
    }
  }
}

int index(int r, int s) {
  if (r<0 || s<0 || r>cols-1 || s>rows-1) {
    return -1;
  } 
  return r+s*cols;
}

void draw() {
  background(51); 
  stroke(255);
  for (int j=0; j<rows; j++) {
    for (int i=0; i<cols; i++) {
      String[] picker = new String[5];
      for (int k=0; k<4; k++) {
        picker[k]="nobody";
      }
      int checker=0;
      int p=0;
      p=round(random(3));
      while (picker[p]=="nobody") {
        if (index(i, j-1)!=-1 && p==0 && visited[i][j-1]==0)
        {
          picker[0]="top";
          visited[i][j-1]=1;
          wallPos[0][i][j]=false;
          wallPos[2][i][j-1]=false;
          current=index(i, j);
          checker=1;
        }
        if (index(i+1, j)!=-1 && p==1 && visited[i+1][j]==0)
        {
          picker[1]="right";
          visited[i+1][j]=1;
          wallPos[1][i][j]=false;
          wallPos[3][i+1][j]=false;
          current=index(i, j);
          checker=1;
        }
        if (index(i, j+1)!=-1 && p==2 && visited[i][j+1]==0)
        {
          picker[2]="bottom";
          visited[i][j+1]=1;
          wallPos[2][i][j]=false;
          wallPos[0][i][j+1]=false;
          current=index(i, j);
          checker=1;
        }
        if (picker[3]=="nobody" && index(i-1, j)!=-1 && p==3 && visited[i-1][j]==0)
        {
          picker[3]="left";
          visited[i-1][j]=1;
          wallPos[3][i][j]=false;
          wallPos[1][i-1][j]=false;
          current=index(i, j);
          checker=1;
        } 
        if (checker==1 || (picker[0]=="nobody" && picker[1]=="nobody" && picker[2]=="nobody" && picker[3]=="nobody")) break;
      }
      x[i]=i*w;
      y[j]=j*w;
      if (wallPos[0][i][j]==true) {
        line(x[i], y[j], x[i]+w, y[j]);
      }
      if (wallPos[1][i][j]==true) {
        line(x[i]+w, y[j], x[i]+w, y[j]+w);
      }
      if (wallPos[2][i][j]==true) {
        line(x[i]+w, y[j]+w, x[i], y[j]+w);
      }
      if (wallPos[3][i][j]==true) {
        line(x[i], y[j]+w, x[i], y[j]);
      }
      if (visited[i][j]==1) {
        fill(255, 0, 255);
        rect(x[i], y[j], w, w);
      }
      if (current==index(i, j)) {
        fill(0, 255, 0);
        rect(x[i], y[j], w, w);
      }
    }
  }
}`

Answers

  • Comparing​ strings using == ?

    Define integer constants instead and use those. Extra points if you use a bit mask...

    Ctrl-t in the editor will indent your code nicely.

  • edited July 2017

    Comparing​ strings using ==?

    In that particular case, equality operator == should suffice, b/c only String literals are assigned to String picker[] in that sketch! :ar!

    But I'd change variable picker[] from String[] to byte[] datatype for efficiency. $-)

    And I would make byte constants outta those "" String literals. >-)

  • @wraithious, you'd make things much easier if you posted the original p5.js too.
    As already mentioned, hit CTRL+T within the PDE for auto code indentation for your Java sketch. *-:)
    For JS source code, you can use instead: http://JSBeautifier.org O:-)

  • @GoToLoop Here is a link to Dan's code project in p5.js but note that I did not download or look at that code, I followed the Utube videos he had and got to video #2 out of 4 and converted what he was saying on the fly. Also I just edited my post with proper code indentation as you guys suggested. I'm new to processing so I'm going to have to read up on the whole string = string format thing as used for processing as it's different in some languages, for example gml is simply if (string1 == string2) { do something } and java is if(string1.equals(string2)) { do something } @koogs thanks I will try that method of just using integers instead of trying to compare strings and see how it goes

  • Since the sketch I posted is only half way complete I'd like to summarize what the sketch is supposed to do, and to point out what it isn't doing. Firstly this maze generator is based off the information on wickpedia for Recursive backtracker on a hexagonal grid: The depth-first search algorithm of maze generation is frequently implemented using backtracking:

    1. Make the initial cell the current cell and mark it as visited
    2. While there are unvisited cells If the current cell has any neighbours which have not been visited Choose randomly one of the unvisited neighbours
    3. Push the current cell to the stack
    4. Remove the wall between the current cell and the chosen cell
    5. Make the chosen cell the current cell and mark it as visited
    6. Else if stack is not empty Pop a cell from the stack Make it the current cell

    I have completed steps 1,2,4 and 5. The expected result at this point is to see 1 green square representing the current square, then it should move to the next available space randomly either up,right, down or left only if it has not been visited. When a square in the grid has been visited it should turn purple. any walls representing the grid should disappear between the visited square and the current square between the direction the current square has moved. The result I'm getting is a bunch of green squares randomly moving about the grid until they are all visited with the end result being all purple squares and 1 green square.

  • if dan's project in p5 works, why don't you look there?

    what he says in the video will probably be more simple than what goes on in the code, so please look at the code

    I would also suggest to use recursion since backtracking is meant for that. also try to put your draw() content in sub functions

    best, Chrisir

  • @Chrisir the p5 code is too different, i was unable to use things like this.that and function, it's all handled differently. Im trying to learn processing so thats why im converting the code over to it. As for recursion that comes later, i skipped step 3 a d 6 for that exact reason, I need to get the sketch working to that point and then ill add my recursion code after, which is what was done in the video series, 1st he got a grid going, then got the path finding that ends if there is no free spaces around the current square and thats where im at, the last 2 videos handle recursion to backtrack untill finding another empty space to fill.

  • edited July 2017

    Just a remark here:

    Are you aware that draw() doesn't update the screen throughout but just at the very end of draw()?

    That means you can't see anything until all for-loops are done and draw() is finished.

    To tackle this you could use the fact that draw() in itself loops automatically. So you would get rid e.g. of the outer for loop (or the two outer for-loops) and instead implement something like

    // simulate two nested for-loops with for j...for i....
    j++;
    if(j>=rows) {
        j=0; // start next column  
        i++;
        if(i>=cols) return; // leave draw()
    }
    

    at the very end of draw. i and j need to be global variables here (declared before setup()).

    For further discussion of draw():

    https://forum.processing.org/two/discussion/8085/i-display-images-in-sequence-but-i-see-only-the-last-one-why

    Best, Chrisir ;-)

  • @Chrisir Ok that explains allot as to why the visual output seems to be a jumble of blocks changing in huge groups instead of them changing one at a time, I'll have a look at your link and it seems correct that i'd want to draw after each iteration of the forloop instead of running through everything a d then draw the end result, thanks!

  • Hi, ok so I pretty much redid the entire sketch, removing some unnecessary things, and adding a few things. 2 nagging things remain, 1. the draw method refuses to draw untill the for loops complete, what I tried: a. used 2 seperate but identical draw code blocks, one after the double for loop, and one after all statements in the second for loop. b. used 5 seperate but identical draw code blocks, one after the double for loop, and 1 inside each randomly chosen direction code block. nothing worked, it still only draws upon the completion of the double for loop. 2. The removal of walls upon the squares that have been visited refuse to work, most strangely of all is if in the setup() method if I change the 3d walls array to read all walls as being false (0 actually, also tried it the boolean way as true or false with the same results) the result is there are walls shown where the cells HAVE been visited and NO walls everywhere else. When walls are set to true (or 1) in the setup() method ALL WALLS are allways visible. how is that even possible??? here's my current sketch you can throw in processing to see what I'm talking about:

    int m = 1;
    int p = 0;
    int w = 20;
    int checker = 0;
    int current = 0;
    int cols = floor(400/w);
    int rows = floor(400/w);
    int picker[] = new int[4];
    int x = 0;
    int y = 0;
    int[][] visited = new int[cols+1][rows+1];
    int[][][] wallPos = new int[5][cols+1][rows+1];
    
    void setup() {
      size(401, 401);
      frameRate(1);
      for (int i=0; i<rows; i++) {
        for (int j=0; j<cols; j++) {
          visited[i][j]=0;
          for (int k=0; k<4; k++) {
            wallPos[k][i][j]=1;
            if (picker[k] != 0) picker[k] = 0;
          }
        }
      }
      visited[0][0]=1;
      //run();
    }
    
    int index(int r, int s) {
      if (r<0 || s<0 || r>cols-1 || s>rows-1) {
        return -1;
      } 
      return r+s*cols;
    }
    
    void draw() {
    
      for (int j=0; j<rows; j++) {
        for (int i=0; i<cols; i++) {
          while (m==1) {
            if (index(i, j-1)!=-1) {
              if (visited[i][j-1]==0)
              {
                picker[0]=1;
                checker=1;
              }
            }
            if (index(i+1, j)!=-1) {
              if (visited[i+1][j]==0)
              {
                picker[1]=1;
                checker=1;
              }
            }
            if (index(i, j+1)!=-1) {
              if (visited[i][j+1]==0)
              {
                picker[2]=1;            
                checker=1;
              }
            }
            if (index(i-1, j)!=-1) {
              if (visited[i-1][j]==0)
              {
                picker[3]=1;            
                checker=1;
              }
            }
            if (checker==1) {
              p=round(random(3));
              while (picker[p]!=1) {
                p=round(random(3));
              }
              if (p==0) {
                visited[i][j-1]=1;
                wallPos[0][i][j]=0;
                wallPos[2][i][j-1]=0;
                current=index(i, j-1);
                j=j-1;
              }
              if (p==1) {
                visited[i+1][j]=1;
                wallPos[1][i][j]=0;
                wallPos[3][i+1][j]=0;
                current=index(i+1, j);
                i=i+1;
              }
              if (p==2) {
                visited[i][j+1]=1;
                wallPos[2][i][j]=0;
                wallPos[0][i][j+1]=0;
                current=index(i, j+1);
                j=j+1;
              }
              if (p==3) {        
                visited[i-1][j]=1;
                wallPos[3][i][j]=0;
                wallPos[1][i-1][j]=0;
                current=index(i-1, j);
                i=i-1;
              }
            }
            for (int k=0; k<4; k++) {
              picker[k]=0;
            }
            if (checker==0) {
              m=0;
            }
            checker=0;
          }
        }
      }
      background(65, 81, 69); 
      stroke(255);
      for (int r=0; r<rows; r++) {
        for (int q=0; q<cols; q++) {
          x=q*w;
          y=r*w;
            if (wallPos[0][q][r]==1) {
              line(x, y, x+w, y);
            }
            if (wallPos[1][q][r]==1) {
              line(x+w, y, x+w, y+w);
            }
            if (wallPos[2][q][r]==1) {
              line(x+w, y+w, x, y+w);
          }
            if (wallPos[3][q][r]==1) {
              line(x, y+w, x, y);
            }
          if (visited[q][r]==1 && current!=index(q, r)) {
            fill(255, 0, 255);
            rect(x, y, w, w);
            fill(0, 0, 0);
            text(index(q, r), x+1, y+w-5);
          }
          if (current==index(q, r)) {
            fill(0, 255, 0);
            rect(x, y, w, w);
            fill(0, 0, 0);
            text(current, x+1, y+w-5);
          }
        }
      }
    }
    
  • I tried but I failed.


    This failed:

    As we discussed, get rid of the

      for (int j=0; j<rows; j++) {
        for (int i=0; i<cols; i++) {
    

    and replace with

    // simulate two nested for-loops with for j...for i....
    j++;
    if(j>=rows) {
        j=0; // start next column  
        i++;
        if(i>=cols) return; // leave draw()
    }
    

    It didn't work for me but I saw you change i and j which is not recommended. Can you find another way without changing i and j ?

  • edited July 2017

    @Chrisir Not sure what you mean sorry, I used separate variables for the draw loop- q and r, so the draw code runs off the saved global variables from the code loops running, not i and j. when you say failed do you mean the sketch doesn't run for you? Also where are you suggesting I remove the for loops and replace them with only i and j variables? in the actual draw code? EDIT: as far as the wall results not working as expected, this is the output I get with line 21 set to wallPos[k][i][j]=1;

    and when line 21 is set to wallPos[k][i][j]=0; I get this result:

    This is the result I'm expecting but not getting:

  • ??

    On 25th July I wrote to get rid of the two outer for loops and replace them with manual handling of i and j as shown.

    The outer for loops lead to the fact that you can see results only at the very end.

    But you still have the outer for loops...

    Now I tried to get of the two for loops and replace them with the lines j++; etc. but this failed. That's what I meant.

    But to see anything throughout you have to: distinguish between working loops that actually change the grid and loops that only display the grid (is that r q loops?). The former should not be a nested for loop (j,i) but use draw()s looping itself, the latter can be a for loop.

    Your code is too complicate for me, please look at shifmans code too

  • @Chrisir ok thank you very much! your imput solved my problem with the draw code! I ended up taking out all the code in the draw method that finds empty squares and randomly visits the next empty square and put it separate from the draw code and made it it's own method and removed the for loop as I noticed it is not needed since it isn't executed in numerical order anyway, then called it last in the setup method. Then in the draw loop I simply used a timer to call the square code once per second. Now if I can figure out why the walls aren't working properly I can move on to recursion, again thanks!

  • You're welcome!

  • edited July 2017

    Solved! I'm new with processing, but I couldn't figure out why the draw code wasn't removing walls between visited cells, apparently it all had to do with the stroke function, I ended up using the variables indicating if a wall should or should not exist by using an if statement with BOTH conditions. Here is the working code:

        int i=0;
        int j=0;
        int m = 1;
        int p = 0;
        int w = 40;
        int checker = 0;
        int current = 0;
        int timer=1000;
        int cols = floor(800/w);
        int rows = floor(800/w);
        int picker[] = new int[4];
        int x = 0;
        int y = 0;
        int[][] visited = new int[cols+1][rows+1];
        int[][] wallPos1 = new int[cols+1][rows+1];
        int[][] wallPos2 = new int[cols+1][rows+1];
        int[][] wallPos3 = new int[cols+1][rows+1];
        int[][] wallPos4 = new int[cols+1][rows+1];
        void setup() {
          size(801, 801);
          frameRate(30);
          for (int i=0; i<rows; i++) {
            for (int j=0; j<cols; j++) {
              visited[i][j]=0;
              wallPos1[i][j]=1;
              wallPos2[i][j]=1;
              wallPos3[i][j]=1;
              wallPos4[i][j]=1;
            }
            for (int k=0; k<4; k++) {
              picker[k] = 0;
            }
          }
          visited[0][0]=1;
          nest();
        }
    
        int index(int s, int t) {
          if (s<0 || t<0 || s>cols-1 || t>rows-1) {
            return -1;
          } 
          return s+t*cols;
        }
    
        void nest() {
          if (index(i, j-1)!=-1) {
            if (visited[i][j-1]==0)
            {
              picker[0]=1;
              checker=1;
            }
          }
          if (index(i+1, j)!=-1) {
            if (visited[i+1][j]==0)
            {
              picker[1]=1;
              checker=1;
            }
          }
          if (index(i, j+1)!=-1) {
            if (visited[i][j+1]==0)
            {
              picker[2]=1;            
              checker=1;
            }
          }
          if (index(i-1, j)!=-1) {
            if (visited[i-1][j]==0)
            {
              picker[3]=1;            
              checker=1;
            }
          }
          if (checker==1) {
            p=round(random(3));
            while (picker[p]!=1) {
              p=round(random(3));
            }
            if (p==0) {
              visited[i][j-1]=1;
              wallPos1[i][j]=0;
              wallPos3[i][j-1]=0;
              current=index(i, j-1);
              j=j-1;
            }
            if (p==1) {
              visited[i+1][j]=1;
              wallPos2[i][j]=0;
              wallPos4[i+1][j]=0;
              current=index(i+1, j);
              i=i+1;
            }
            if (p==2) {
              visited[i][j+1]=1;
              wallPos3[i][j]=0;
              wallPos1[i][j+1]=0;
              current=index(i, j+1);
              j=j+1;
            }
            if (p==3) {        
              visited[i-1][j]=1;
              wallPos4[i][j]=0;
              wallPos2[i-1][j]=0;
              current=index(i-1, j);
              i=i-1;
            }
          }
          for (int k=0; k<4; k++) {
            picker[k]=0;
          }
          if (checker==0) {
            m=0;
          }
          checker=0;
        }
    
        void draw() {
          int r=0;
          int q=0;
          background(65, 81, 69);
          for (r=0; r<rows; r++) {
            for (q=0; q<cols; q++) {
              x=q*w;
              y=r*w;
              if (visited[q][r]==1 && current!=index(q, r)) {
                fill(255, 0, 255);
                rect(x, y, w, w);
                fill(0, 0, 0);
                text(index(q, r), x+1, y+w-5);
              }
              if (current==index(q, r)) {
                fill(0, 255, 0);
                rect(x, y, w, w);
                fill(0, 0, 0);
                text(current, x+1, y+w-5);
              }
              if (wallPos1[q][r] ==1) stroke(255);
              if (wallPos1[q][r] ==0) stroke(255, 0, 255);
              line(x, y, x+w, y);
    
              if (wallPos2[q][r] ==1) stroke(255); 
              if (wallPos2[q][r] ==0) stroke(255, 0, 255);
              line(x+w, y, x+w, y+w);
    
              if (wallPos3[q][r] ==1) stroke(255); 
              if (wallPos3[q][r] ==0) stroke(255, 0, 255);
              line(x+w, y+w, x, y+w);
    
              if (wallPos4[q][r] ==1) stroke(255); 
              if (wallPos4[q][r] ==0) stroke(255, 0, 255);
              line(x, y+w, x, y);
              if (timer>0 && m==1) {
                timer-=1;
                if (timer<=0) {
                  timer=1000;
                  nest();
                }
              }
            }
          }
        }
    
  • Answer ✓

    Well done!

  • Given that visited is only ever 0 or 1 then a boolean seems a better choice. Checker also.

    Wallpos1-4 are also only ever 0 or 1 but in that case i'd have a single array holding a bit mask for the walls.

  • Thanks @koogs those are good ways to polish my sketch, I'll have a look at bit masking, I've never used that method so it will be something good to learn how to do. I ended up finishing the sketch by implementing recursion via the IntList stack system which works well, so now I have a nice random cave generator without recursion, and a nice full map generator with recursion. I'm really starting to like processing a lot!

Sign In or Register to comment.