日常の進捗

主に自分のための,行為とその習慣化の記録

Mod:Coding Challenge #10.2: Maze Generator with p5.js - Part 2

昨日の続きで、迷路ジェネレータをProcessingで書く。途中なのでそんなに面白くはないけど、書いてる側は結構面白い。

アルゴリズム再帰的バックトラック法ってやつを使うらしい。アクティブなセルを紫にしていて、セルごとに通過したかどうかを真偽値でチェックして移動させる。p5.jsだとJavaScriptなのでセルのインデックス番号を取得する時とか-1を返せばいいみたいだけど、JavaベースのProcessingだとそうもいかないので書き方を考えたりした。そんな感じでp5.jsは関数含めてあまり意識せずに書けるのが良さ何だと思う一方で、型をプログラマに厳密に意識させることでプログラムに融通の部分を用意しないJavaの書き方もフェイルセーフで良いのかもしれない。

コード

float cols, rows;
float grid = 40;

ArrayList<Cell> cells = new ArrayList<Cell>();
Cell current;
void setup() {
  size(800, 800);
  colorMode(HSB, 360, 100, 100);
  cols = floor(width/grid);
  rows = floor(height/grid);
  for (int j = 0; j < rows; j++) {
    for (int i = 0; i < cols; i++) {
      Cell cell = new Cell(i, j);
      cells.add(cell);
    }
  }
  current = cells.get(0);
}

void draw() {
  background(0, 0, 25);
  for (Cell cell : cells) {
    cell.draw();
  }
  current.isVisited = true;
  Cell next = current.checkNeighbors();
  if (next != null) {
    next.isVisited = true;
    current = next;
  }
}

class Cell {
  float i, j;
  Boolean[] walls = new Boolean[4];
  Boolean isVisited = false;
  Cell(float _i, float _j) {
    i = _i;
    j = _j;
    for (int k = 0; k < walls.length; k++) {
      if (random(1) < 0.3) {
        walls[k] = true;
      } else {
        walls[k] = false;
      }
    }
  }
  void draw() {
    float x = i * grid;
    float y = j * grid;
    stroke(0, 0, 100);
    if (walls[0]) {
      line(x, y, x+grid, y);
    }
    if (walls[1]) {
      line(x+grid, y, x+grid, y+grid);
    }
    if (walls[2]) {
      line(x+grid, y+grid, x, y+grid);
    }
    if (walls[3]) {
      line(x, y, x, y+grid);
    }
    if (isVisited) {
      fill(300, 80, 100, 50);
      rect(x, y, grid, grid);
    }
  }
  int index(float i, float j) {
    if (i < 0 || j < 0 || i > cols-1 || j > rows-1) {
      return -1;
    }
    return int(i + j * cols);
  }

  Cell checkNeighbors() {
    ArrayList<Cell> neighbors = new ArrayList<Cell>();
    if (index(i, j-1) != -1) {
      Cell top = cells.get(index(i, j-1));
      if (!top.isVisited) {
        neighbors.add(top);
      }
    }
    if (index(i, j+1) != -1) {
      Cell bottom = cells.get(index(i, j+1));
      if (!bottom.isVisited) {
        neighbors.add(bottom);
      }
    }
    if (index(i-1, j) != -1) {
      Cell left = cells.get(index(i-1, j));
      if (!left.isVisited) {
        neighbors.add(left);
      }
    }
    if (index(i+1, j) != -1) {
      Cell right = cells.get(index(i+1, j));
      if (!right.isVisited) {
        neighbors.add(right);
      }
    }

    if (neighbors.size() > 0) {
      int r = floor(random(0, neighbors.size()));
      return neighbors.get(r);
    } else {
      return null;
    }
  }
}

リファレンス