修改迷宮演算

``````class Maze {
constructor(rows, columns) {
this.rows = rows;
this.columns = columns;
// 最後總行數
this.outMostcolumns = columns * pow(2, floor(rows / 2));
// 第一列的 x 步進值
this.initialXStep = this.outMostcolumns / columns;

}

backtracker(x = 0, y = 0) {
this.cells = [];
this.cells.push(cell(x, y, Maze.TOP_RIGHT_WALL));
backtracker(this);
}
}
``````

``````function xStep(maze, y) {
return maze.initialXStep / pow(2, floor(y / 2));
}
``````

``````function isVisitable(maze, x, y) {
return y >= 0 && y < maze.rows &&
x >= 0 && x < maze.outMostcolumns &&  // 這邊改用 outMostcolumns
notVisited(maze, x, y);
}
``````

``````const R = 0;
const T = 1;
const L = 2;
const B = 3;
const BL = 4;  // 左下
const BR = 5;  // 右下

function nextX(cell, dir, step) {
const isYEven = cell.y % 2 == 0;
const isStepOdd = (cell.x / step) % 2 == 1;
return cell.x + [
step,
isYEven && isStepOdd ? -step : 0,
-step,
0,
0,
step / 2
][dir];
}

function nextY(y, dir) {
return y + [0, -1, 0, 1, 1, 1][dir];
}
``````

`visitRight``visitLeft` 等，現在不是單純地對 x 加或減 1，改呼叫 `nextX``nextY`

``````function visitRight(maze, currentCell, step) {
if(currentCell.wallType === Maze.TOP_RIGHT_WALL) {
currentCell.wallType = Maze.TOP_WALL;
}
else {
currentCell.wallType = Maze.NO_WALL;
}

maze.cells.push(cell(nextX(currentCell, R, step), nextY(currentCell.y, R), Maze.TOP_RIGHT_WALL));
}

function visitTop(maze, currentCell, step) {
if(currentCell.wallType === Maze.TOP_RIGHT_WALL) {
currentCell.wallType = Maze.RIGHT_WALL;
}
else {
currentCell.wallType = Maze.NO_WALL;
}

maze.cells.push(cell(nextX(currentCell, T, step), nextY(currentCell.y, T), Maze.TOP_RIGHT_WALL));
}

function visitLeft(maze, currentCell, step) {
maze.cells.push(cell(nextX(currentCell, L, step), nextY(currentCell.y, L), Maze.TOP_WALL));
}

function visitBottom(maze, currentCell, step) {
maze.cells.push(cell(nextX(currentCell, B, step), nextY(currentCell.y, B), Maze.RIGHT_WALL));
}
``````

``````function visitBottomLeft(maze, currentCell, step) {
maze.cells.push(cell(nextX(currentCell, BL, step), nextY(currentCell.y, BL), Maze.RIGHT_WALL));
}

function visitBottomRight(maze, currentCell, step) {
maze.cells.push(cell(nextX(currentCell, BR, step), nextY(currentCell.y, BR), Maze.RIGHT_WALL));
}
``````

`visit` 增加 `BL``BR` 兩個 `case`

``````function visit(maze, currentCell, dir, step) {
switch(dir) {
case R:
visitRight(maze, currentCell, step); break;
case T:
visitTop(maze, currentCell, step); break;
case L:
visitLeft(maze, currentCell, step); break;
case B:
visitBottom(maze, currentCell, step); break;
case BL:
visitBottomLeft(maze, currentCell, step); break;
case BR:
visitBottomRight(maze, currentCell, step); break;
}
}
``````

``````function backtracker(maze) {
const currentCell = maze.cells[maze.cells.length - 1];

// 計算 x 步進值
const step = xStep(maze, currentCell.y);
// 隨機選擇時要看 y 為偶數或奇數
const rdirs = shuffle(currentCell.y % 2 == 0 ? [R, T, L, B] : [R, T, L, BL, BR]);

const vdirs = rdirs.filter(dir => {
const nx = nextX(currentCell, dir, step);
const ny = nextY(currentCell.y, dir);
return isVisitable(maze, nx, ny);
});

if(vdirs.length === 0) {
return;
}

vdirs.forEach(dir => {
const nx = nextX(currentCell, dir, step);
const ny = nextY(currentCell.y, dir);

if(isVisitable(maze, nx, ny)) {
visit(maze, currentCell, dir, step);
backtracker(maze);
}
});
}
``````

``````function drawCell(wallType, cellWidth, step) {
if(wallType === Maze.TOP_WALL || wallType === Maze.TOP_RIGHT_WALL) {
line(0, 0, cellWidth * step, 0);
}

if(wallType === Maze.RIGHT_WALL || wallType === Maze.TOP_RIGHT_WALL) {
line(cellWidth * step, 0, cellWidth * step, cellWidth);
}
}

function drawMaze(maze, cellWidth) {
maze.cells.forEach(cell => {
push();
// 依 x 步進決定細胞大小
const step = xStep(maze, cell.y);

translate(cell.x * cellWidth, cell.y * cellWidth);
drawCell(cell.wallType, cellWidth, step);

pop();
});

const totalWidth = cellWidth * maze.outMostcolumns;
const totalHeight = cellWidth * maze.rows;

line(0, 0, 0, totalHeight);
line(0, totalHeight, totalWidth, totalHeight);
}
``````

``````function setup() {
createCanvas(300, 300);
noLoop();
}

function draw() {
background(220);

const rows = 5;
const columns = 4;

const cellWidth = (width - 60) / (rows * 3);
const maze = new Maze(rows, columns);
maze.backtracker();

strokeWeight(5);
translate(cellWidth, height / 2 - cellWidth * rows / 2);
drawMaze(maze, cellWidth);
}

function cell(x, y, wallType) {
return {x, y, wallType};
}

class Maze {
constructor(rows, columns) {
this.rows = rows;
this.columns = columns;
this.outMostcolumns = columns * pow(2, floor(rows / 2));
this.initialXStep = this.outMostcolumns / columns;

}

backtracker(x = 0, y = 0) {
this.cells = [];
this.cells.push(cell(x, y, Maze.TOP_RIGHT_WALL));
backtracker(this);
}
}

function xStep(maze, y) {
return maze.initialXStep / pow(2, floor(y / 2));
}

Maze.NO_WALL = 'no_wall';
Maze.TOP_WALL = 'top_wall';
Maze.RIGHT_WALL = 'right_wall';
Maze.TOP_RIGHT_WALL = 'top_right_wall';

function notVisited(maze, x, y) {
return maze.cells.find(cell => cell.x === x && cell.y === y) === undefined;
}

function isVisitable(maze, x, y) {
return y >= 0 && y < maze.rows &&
x >= 0 && x < maze.outMostcolumns &&
notVisited(maze, x, y);
}

const R = 0;
const T = 1;
const L = 2;
const B = 3;
const BL = 4;
const BR = 5;

function nextX(cell, dir, step) {
const isYEven = cell.y % 2 == 0;
const isStepOdd = (cell.x / step) % 2 == 1;
return cell.x + [
step,
isYEven && isStepOdd ? -step : 0,
-step,
0,
0,
step / 2
][dir];
}

function nextY(y, dir) {
return y + [0, -1, 0, 1, 1, 1][dir];
}

function visitRight(maze, currentCell, step) {
if(currentCell.wallType === Maze.TOP_RIGHT_WALL) {
currentCell.wallType = Maze.TOP_WALL;
}
else {
currentCell.wallType = Maze.NO_WALL;
}

maze.cells.push(cell(nextX(currentCell, R, step), nextY(currentCell.y, R), Maze.TOP_RIGHT_WALL));
}

function visitTop(maze, currentCell, step) {
if(currentCell.wallType === Maze.TOP_RIGHT_WALL) {
currentCell.wallType = Maze.RIGHT_WALL;
}
else {
currentCell.wallType = Maze.NO_WALL;
}

maze.cells.push(cell(nextX(currentCell, T, step), nextY(currentCell.y, T), Maze.TOP_RIGHT_WALL));
}

function visitLeft(maze, currentCell, step) {
maze.cells.push(cell(nextX(currentCell, L, step), nextY(currentCell.y, L), Maze.TOP_WALL));
}

function visitBottom(maze, currentCell, step) {
maze.cells.push(cell(nextX(currentCell, B, step), nextY(currentCell.y, B), Maze.RIGHT_WALL));
}

function visitBottomLeft(maze, currentCell, step) {
maze.cells.push(cell(nextX(currentCell, BL, step), nextY(currentCell.y, BL), Maze.RIGHT_WALL));
}

function visitBottomRight(maze, currentCell, step) {
maze.cells.push(cell(nextX(currentCell, BR, step), nextY(currentCell.y, BR), Maze.RIGHT_WALL));
}

function visit(maze, currentCell, dir, step) {
switch(dir) {
case R:
visitRight(maze, currentCell, step); break;
case T:
visitTop(maze, currentCell, step); break;
case L:
visitLeft(maze, currentCell, step); break;
case B:
visitBottom(maze, currentCell, step); break;
case BL:
visitBottomLeft(maze, currentCell, step); break;
case BR:
visitBottomRight(maze, currentCell, step); break;
}
}

function backtracker(maze) {
const currentCell = maze.cells[maze.cells.length - 1];
const step = xStep(maze, currentCell.y);
const rdirs = shuffle(currentCell.y % 2 == 0 ? [R, T, L, B] : [R, T, L, BL, BR]);

const vdirs = rdirs.filter(dir => {
const nx = nextX(currentCell, dir, step);
const ny = nextY(currentCell.y, dir);
return isVisitable(maze, nx, ny);
});

if(vdirs.length === 0) {
return;
}

vdirs.forEach(dir => {
const nx = nextX(currentCell, dir, step);
const ny = nextY(currentCell.y, dir);

if(isVisitable(maze, nx, ny)) {
visit(maze, currentCell, dir, step);
backtracker(maze);
}
});
}

function drawCell(wallType, cellWidth, step) {
if(wallType === Maze.TOP_WALL || wallType === Maze.TOP_RIGHT_WALL) {
line(0, 0, cellWidth * step, 0);
}

if(wallType === Maze.RIGHT_WALL || wallType === Maze.TOP_RIGHT_WALL) {
line(cellWidth * step, 0, cellWidth * step, cellWidth);
}
}

function drawMaze(maze, cellWidth) {
maze.cells.forEach(cell => {
push();

const step = xStep(maze, cell.y);

translate(cell.x * cellWidth, cell.y * cellWidth);
drawCell(cell.wallType, cellWidth, step);

pop();
});

const totalWidth = cellWidth * maze.outMostcolumns;
const totalHeight = cellWidth * maze.rows;

line(0, 0, 0, totalHeight);
line(0, totalHeight, totalWidth, totalHeight);
}
``````

繪製為 Theta 迷宮

``````function drawMaze(maze, cellWidth) {
const thetaStep = TWO_PI / maze.outMostcolumns;

maze.cells.forEach(cell => {
if(cell.x === 0 && cell.y === 0) {
return;
}

// 最內環的半徑是 1
const innerR = (cell.y + 1) * cellWidth;
const outerR = (cell.y + 2) * cellWidth;
const theta1 = -thetaStep * cell.x;
// 根據 y 計算步進值
const theta2 = -thetaStep * (cell.x + xStep(maze, cell.y));

const innerVt1 = p5.Vector.fromAngle(theta1, innerR);
const innerVt2 = p5.Vector.fromAngle(theta2, innerR);
const outerVt2 = p5.Vector.fromAngle(theta2, outerR);

if(cell.wallType === Maze.TOP_WALL || cell.wallType === Maze.TOP_RIGHT_WALL) {
line(innerVt1.x, innerVt1.y, innerVt2.x, innerVt2.y);
}

if(cell.wallType === Maze.RIGHT_WALL || cell.wallType === Maze.TOP_RIGHT_WALL) {
line(innerVt2.x, innerVt2.y, outerVt2.x, outerVt2.y);
}
});

const r = cellWidth * (maze.rows + 1);
for(let theta = 0; theta < TWO_PI; theta = theta + thetaStep) {
const vt1 = p5.Vector.fromAngle(theta, r);
const vt2 = p5.Vector.fromAngle(theta + thetaStep, r);
line(vt1.x, vt1.y, vt2.x, vt2.y);
}
}
``````

``````function nextX(maze, cell, dir, step) {
const isYEven = cell.y % 2 == 0;
const isStepOdd = (cell.x / step) % 2 == 1;
const nx = (cell.x + [
step,
isYEven && isStepOdd ? -step : 0,
-step,
0,
0,
step / 2
][dir]);

//  順時針、逆時針都要能打通迷宮
return nx >= 0 ? (nx % maze.outMostcolumns) : (nx + maze.outMostcolumns);
}
``````

``````function setup() {
createCanvas(300, 300);
noLoop();
}

function draw() {
background(220);

const rows = 8;
const columns = 8;

const cellWidth = (width - 60) / (rows * 2);
const maze = new Maze(rows, columns);
maze.backtracker();

strokeWeight(2);
translate(width / 2 , height / 2);
drawMaze(maze, cellWidth);

}

function cell(x, y, wallType) {
return {x, y, wallType};
}

class Maze {
constructor(rows, columns) {
this.rows = rows;
this.columns = columns;
this.outMostcolumns = columns * pow(2, floor(rows / 2));
this.initialXStep = this.outMostcolumns / columns;

}

backtracker(x = 0, y = 0) {
this.cells = [];
this.cells.push(cell(x, y, Maze.TOP_RIGHT_WALL));
backtracker(this);
}
}

function xStep(maze, y) {
return maze.initialXStep / pow(2, floor(y / 2));
}

Maze.NO_WALL = 'no_wall';
Maze.TOP_WALL = 'top_wall';
Maze.RIGHT_WALL = 'right_wall';
Maze.TOP_RIGHT_WALL = 'top_right_wall';

function notVisited(maze, x, y) {
return maze.cells.find(cell => cell.x === x && cell.y === y) === undefined;
}

function isVisitable(maze, x, y) {
return y >= 0 && y < maze.rows &&
x >= 0 && x < maze.outMostcolumns &&
notVisited(maze, x, y);
}

const R = 0;
const T = 1;
const L = 2;
const B = 3;
const BL = 4;
const BR = 5;

function nextX(maze, cell, dir, step) {
const isYEven = cell.y % 2 == 0;
const isStepOdd = (cell.x / step) % 2 == 1;
const nx = (cell.x + [
step,
isYEven && isStepOdd ? -step : 0,
-step,
0,
0,
step / 2
][dir]);

return nx >= 0 ? (nx % maze.outMostcolumns) : (nx + maze.outMostcolumns);
}

function nextY(y, dir) {
return y + [0, -1, 0, 1, 1, 1][dir];
}

function visitRight(maze, currentCell, step) {
if(currentCell.wallType === Maze.TOP_RIGHT_WALL) {
currentCell.wallType = Maze.TOP_WALL;
}
else {
currentCell.wallType = Maze.NO_WALL;
}

maze.cells.push(cell(nextX(maze, currentCell, R, step), nextY(currentCell.y, R), Maze.TOP_RIGHT_WALL));
}

function visitTop(maze, currentCell, step) {
if(currentCell.wallType === Maze.TOP_RIGHT_WALL) {
currentCell.wallType = Maze.RIGHT_WALL;
}
else {
currentCell.wallType = Maze.NO_WALL;
}

maze.cells.push(cell(nextX(maze, currentCell, T, step), nextY(currentCell.y, T), Maze.TOP_RIGHT_WALL));
}

function visitLeft(maze, currentCell, step) {
maze.cells.push(cell(nextX(maze, currentCell, L, step), nextY(currentCell.y, L), Maze.TOP_WALL));
}

function visitBottom(maze, currentCell, step) {
maze.cells.push(cell(nextX(maze, currentCell, B, step), nextY(currentCell.y, B), Maze.RIGHT_WALL));
}

function visitBottomLeft(maze, currentCell, step) {
maze.cells.push(cell(nextX(maze, currentCell, BL, step), nextY(currentCell.y, BL), Maze.RIGHT_WALL));
}

function visitBottomRight(maze, currentCell, step) {
maze.cells.push(cell(nextX(maze, currentCell, BR, step), nextY(currentCell.y, BR), Maze.RIGHT_WALL));
}

function visit(maze, currentCell, dir, step) {
switch(dir) {
case R:
visitRight(maze, currentCell, step); break;
case T:
visitTop(maze, currentCell, step); break;
case L:
visitLeft(maze, currentCell, step); break;
case B:
visitBottom(maze, currentCell, step); break;
case BL:
visitBottomLeft(maze, currentCell, step); break;
case BR:
visitBottomRight(maze, currentCell, step); break;
}
}

function backtracker(maze) {

const currentCell = maze.cells[maze.cells.length - 1];
const step = xStep(maze, currentCell.y);
const rdirs = shuffle(currentCell.y % 2 == 0 ? [R, T, L, B] : [R, T, L, BL, BR]);

const vdirs = rdirs.filter(dir => {
const nx = nextX(maze, currentCell, dir, step);
const ny = nextY(currentCell.y, dir);
return isVisitable(maze, nx, ny);
});

if(vdirs.length === 0) {
return;
}

vdirs.forEach(dir => {
const nx = nextX(maze, currentCell, dir, step);
const ny = nextY(currentCell.y, dir);
if(isVisitable(maze, nx, ny)) {
visit(maze, currentCell, dir, step);
backtracker(maze);
}
});
}

function drawMaze(maze, cellWidth) {
const thetaStep = TWO_PI / maze.outMostcolumns;

maze.cells.forEach(cell => {
if(cell.x === 0 && cell.y === 0) {
return;
}
const innerR = (cell.y + 1) * cellWidth;
const outerR = (cell.y + 2) * cellWidth;
const theta1 = -thetaStep * cell.x;
const theta2 = -thetaStep * (cell.x + xStep(maze, cell.y));

const innerVt1 = p5.Vector.fromAngle(theta1, innerR);
const innerVt2 = p5.Vector.fromAngle(theta2, innerR);
const outerVt2 = p5.Vector.fromAngle(theta2, outerR);

if(cell.wallType === Maze.TOP_WALL || cell.wallType === Maze.TOP_RIGHT_WALL) {
line(innerVt1.x, innerVt1.y, innerVt2.x, innerVt2.y);
}

if(cell.wallType === Maze.RIGHT_WALL || cell.wallType === Maze.TOP_RIGHT_WALL) {
line(innerVt2.x, innerVt2.y, outerVt2.x, outerVt2.y);
}
});

const r = cellWidth * (maze.rows + 1);
for(let theta = 0; theta < TWO_PI; theta = theta + thetaStep) {
const vt1 = p5.Vector.fromAngle(theta, r);
const vt2 = p5.Vector.fromAngle(theta + thetaStep, r);
line(vt1.x, vt1.y, vt2.x, vt2.y);
}
}
``````

調整切分方式

``````function setup() {
createCanvas(300, 300);
noLoop();
}

function draw() {
background(220);

const rows = 15;
const columns = 10;

const cellWidth = (width - 60) / (rows * 2);
const maze = new Maze(rows, columns);
maze.backtracker();

strokeWeight(2);
translate(width / 2 , height / 2);
drawMaze(maze, cellWidth);
}

function cell(x, y, wallType) {
return {x, y, wallType};
}

class Maze {
constructor(rows, columns) {
this.rows = rows;
this.columns = columns;
this.outMostcolumns = outMostColumns(this);
this.initialXStep = this.outMostcolumns / columns;
}

backtracker(x = 0, y = 0) {
this.cells = [];
this.cells.push(cell(x, y, Maze.TOP_RIGHT_WALL));
backtracker(this);
}
}

function outMostColumns(maze) {
let rowCount = maze.rows;
let diff = 2;
while((rowCount = rowCount - diff) > 0) {
diff++;
}
return pow(2, diff - 2) * maze.columns;
}

function nthSection(y) {
let yi = 1, i = 0, diff = 3;
while(y > yi) {
yi += diff;
diff++;
i++;
}
return i;
}

function sectionLine(y) {
let yi = 0, diff = 2;
while(y > yi) {
yi += diff;
diff++;
}
return yi === y;
}

function xStep(maze, y) {
return maze.initialXStep / pow(2, nthSection(y));
}

Maze.NO_WALL = 'no_wall';
Maze.TOP_WALL = 'top_wall';
Maze.RIGHT_WALL = 'right_wall';
Maze.TOP_RIGHT_WALL = 'top_right_wall';

function notVisited(maze, x, y) {
return maze.cells.find(cell => cell.x === x && cell.y === y) === undefined;
}

function isVisitable(maze, x, y) {
return y >= 0 && y < maze.rows &&
x >= 0 && x < maze.outMostcolumns &&
notVisited(maze, x, y);
}

const R = 0;
const T = 1;
const L = 2;
const B = 3;
const BL = 4;
const BR = 5;

function nextX(maze, cell, dir, step) {
const isYOdd = cell.y % 2 == 1;
const isStepOdd = (cell.x / step) % 2 == 1;
const nx = cell.x + [
step,
sectionLine(cell.y) && isStepOdd ? -step : 0,
-step,
0,
0,
step / 2
][dir];
return nx >= 0 ? (nx % maze.outMostcolumns) : (nx + maze.outMostcolumns);
}

function nextY(y, dir) {
return y + [0, -1, 0, 1][dir];
}

function visitRight(maze, currentCell, step) {
if(currentCell.wallType === Maze.TOP_RIGHT_WALL) {
currentCell.wallType = Maze.TOP_WALL;
}
else {
currentCell.wallType = Maze.NO_WALL;
}

maze.cells.push(cell(nextX(maze, currentCell, R, step), nextY(currentCell.y, R), Maze.TOP_RIGHT_WALL));
}

function visitTop(maze, currentCell, step) {
if(currentCell.wallType === Maze.TOP_RIGHT_WALL) {
currentCell.wallType = Maze.RIGHT_WALL;
}
else {
currentCell.wallType = Maze.NO_WALL;
}

maze.cells.push(cell(nextX(maze, currentCell, T, step), nextY(currentCell.y, T), Maze.TOP_RIGHT_WALL));
}

function visitLeft(maze, currentCell, step) {
maze.cells.push(cell(nextX(maze, currentCell, L, step), nextY(currentCell.y, L), Maze.TOP_WALL));
}

function visitBottom(maze, currentCell, step) {
maze.cells.push(cell(nextX(maze, currentCell, B, step), nextY(currentCell.y, B), Maze.RIGHT_WALL));
}

function visitBottomLeft(maze, currentCell, step) {
maze.cells.push(cell(nextX(maze, currentCell, BL, step), nextY(currentCell.y, BL), Maze.RIGHT_WALL));
}

function visitBottomRight(maze, currentCell, step) {
maze.cells.push(cell(nextX(maze, currentCell, BR, step), nextY(currentCell.y, BR), Maze.RIGHT_WALL));
}

function visit(maze, currentCell, dir, step) {
switch(dir) {
case R:
visitRight(maze, currentCell, step); break;
case T:
visitTop(maze, currentCell, step); break;
case L:
visitLeft(maze, currentCell, step); break;
case B:
visitBottom(maze, currentCell, step); break;
case BL:
visitBottomLeft(maze, currentCell, step); break;
case BR:
visitBottomRight(maze, currentCell, step); break;
}
}

function backtracker(maze) {

const currentCell = maze.cells[maze.cells.length - 1];
const step = xStep(maze, currentCell.y);
const rdirs = shuffle(sectionLine(cell.y) ? [R, T, L, B, BL, BR] : [R, T, L, B]);

const vdirs = rdirs.filter(dir => {
const nx = nextX(maze, currentCell, dir, step);
const ny = nextY(currentCell.y, dir);
return isVisitable(maze, nx, ny);
});

if(vdirs.length === 0) {
return;
}

vdirs.forEach(dir => {
const nx = nextX(maze, currentCell, dir, step);
const ny = nextY(currentCell.y, dir);
if(isVisitable(maze, nx, ny)) {
visit(maze, currentCell, dir, step);
backtracker(maze);
}
});
}

function drawMaze(maze, cellWidth) {
const thetaStep = TWO_PI / maze.outMostcolumns;

maze.cells.forEach(cell => {
if(cell.x === 0 && cell.y === 0) {
return;
}
const innerR = (cell.y + 1) * cellWidth;
const outerR = (cell.y + 2) * cellWidth;
const theta1 = -thetaStep * cell.x;
const theta2 = -thetaStep * (cell.x + xStep(maze, cell.y));

const innerVt1 = p5.Vector.fromAngle(theta1, innerR);
const innerVt2 = p5.Vector.fromAngle(theta2, innerR);
const outerVt2 = p5.Vector.fromAngle(theta2, outerR);

if(cell.wallType === Maze.TOP_WALL || cell.wallType === Maze.TOP_RIGHT_WALL) {
line(innerVt1.x, innerVt1.y, innerVt2.x, innerVt2.y);
}

if(cell.wallType === Maze.RIGHT_WALL || cell.wallType === Maze.TOP_RIGHT_WALL) {
line(innerVt2.x, innerVt2.y, outerVt2.x, outerVt2.y);
}
});

const r = cellWidth * (maze.rows + 1);
for(let theta = 0; theta < TWO_PI; theta = theta + thetaStep) {
const vt1 = p5.Vector.fromAngle(theta, r);
const vt2 = p5.Vector.fromAngle(theta + thetaStep, r);
line(vt1.x, vt1.y, vt2.x, vt2.y);
}
}
``````