Minayotan/src/modules/maze/render-maze.ts

244 lines
8.4 KiB
TypeScript

import * as gen from 'random-seed';
import { createCanvas } from 'canvas';
import { CellType } from './maze';
import { themes } from './themes';
const imageSize = 4096; // px
const margin = 96 * 4;
const mazeAreaSize = imageSize - (margin * 2);
export function renderMaze(seed, maze: CellType[][]) {
const rand = gen.create(seed);
const mazeSize = maze.length;
const colors = themes[rand(themes.length)];
const canvas = createCanvas(imageSize, imageSize);
const ctx = canvas.getContext('2d');
ctx.antialias = 'none';
ctx.fillStyle = colors.bg1;
ctx.beginPath();
ctx.fillRect(0, 0, imageSize, imageSize);
ctx.fillStyle = colors.bg2;
ctx.beginPath();
ctx.fillRect(margin / 2, margin / 2, imageSize - ((margin / 2) * 2), imageSize - ((margin / 2) * 2));
// Draw
function drawCell(ctx, x, y, size, left, right, top, bottom, mark) {
const wallThickness = size / 6;
const margin = size / 6;
const markerMargin = size / 3;
ctx.fillStyle = colors.road;
if (left) {
ctx.beginPath();
ctx.fillRect(x, y + margin, size - margin, size - (margin * 2));
}
if (right) {
ctx.beginPath();
ctx.fillRect(x + margin, y + margin, size - margin, size - (margin * 2));
}
if (top) {
ctx.beginPath();
ctx.fillRect(x + margin, y, size - (margin * 2), size - margin);
}
if (bottom) {
ctx.beginPath();
ctx.fillRect(x + margin, y + margin, size - (margin * 2), size - margin);
}
if (mark) {
ctx.fillStyle = colors.marker;
ctx.beginPath();
ctx.fillRect(x + markerMargin, y + markerMargin, size - (markerMargin * 2), size - (markerMargin * 2));
}
ctx.strokeStyle = colors.wall;
ctx.lineWidth = wallThickness;
ctx.lineCap = 'square';
function line(ax, ay, bx, by) {
ctx.beginPath();
ctx.lineTo(x + ax, y + ay);
ctx.lineTo(x + bx, y + by);
ctx.stroke();
}
if (left && right && top && bottom) {
ctx.beginPath();
if (rand(2) === 0) {
line(0, margin, size, margin); // ─ 上
line(0, size - margin, size, size - margin); // ─ 下
line(margin, 0, margin, margin); // │ 左上
line(size - margin, 0, size - margin, margin); // │ 右上
line(margin, size - margin, margin, size); // │ 左下
line(size - margin, size - margin, size - margin, size); // │ 右下
} else {
line(margin, 0, margin, size); // │ 左
line(size - margin, 0, size - margin, size); // │ 右
line(0, margin, margin, margin); // ─ 左上
line(size - margin, margin, size, margin); // ─ 右上
line(0, size - margin, margin, size - margin); // ─ 左下
line(size - margin, size - margin, size, size - margin); // ─ 右下
}
return;
}
// ─
if (left && right && !top && !bottom) {
line(0, margin, size, margin); // ─ 上
line(0, size - margin, size, size - margin); // ─ 下
return;
}
// │
if (!left && !right && top && bottom) {
line(margin, 0, margin, size); // │ 左
line(size - margin, 0, size - margin, size); // │ 右
return;
}
// 左行き止まり
if (!left && right && !top && !bottom) {
line(margin, margin, size, margin); // ─ 上
line(margin, margin, margin, size - margin); // │ 左
line(margin, size - margin, size, size - margin); // ─ 下
return;
}
// 右行き止まり
if (left && !right && !top && !bottom) {
line(0, margin, size - margin, margin); // ─ 上
line(size - margin, margin, size - margin, size - margin); // │ 右
line(0, size - margin, size - margin, size - margin); // ─ 下
return;
}
// 上行き止まり
if (!left && !right && !top && bottom) {
line(margin, margin, size - margin, margin); // ─ 上
line(margin, margin, margin, size); // │ 左
line(size - margin, margin, size - margin, size); // │ 右
return;
}
// 下行き止まり
if (!left && !right && top && !bottom) {
line(margin, size - margin, size - margin, size - margin); // ─ 下
line(margin, 0, margin, size - margin); // │ 左
line(size - margin, 0, size - margin, size - margin); // │ 右
return;
}
// ┌
if (!left && !top && right && bottom) {
line(margin, margin, size, margin); // ─ 上
line(margin, margin, margin, size); // │ 左
line(size - margin, size - margin, size, size - margin); // ─ 下
line(size - margin, size - margin, size - margin, size); // │ 右
return;
}
// ┐
if (left && !right && !top && bottom) {
line(0, margin, size - margin, margin); // ─ 上
line(size - margin, margin, size - margin, size); // │ 右
line(0, size - margin, margin, size - margin); // ─ 下
line(margin, size - margin, margin, size); // │ 左
return;
}
// └
if (!left && right && top && !bottom) {
line(margin, 0, margin, size - margin); // │ 左
line(margin, size - margin, size, size - margin); // ─ 下
line(size - margin, 0, size - margin, margin); // │ 右
line(size - margin, margin, size, margin); // ─ 上
return;
}
// ┘
if (left && !right && top && !bottom) {
line(margin, 0, margin, margin); // │ 左
line(0, margin, margin, margin); // ─ 上
line(size - margin, 0, size - margin, size - margin); // │ 右
line(0, size - margin, size - margin, size - margin); // ─ 下
return;
}
// ├
if (!left && right && top && bottom) {
line(margin, 0, margin, size); // │ 左
line(size - margin, 0, size - margin, margin); // │ 右
line(size - margin, margin, size, margin); // ─ 上
line(size - margin, size - margin, size, size - margin); // ─ 下
line(size - margin, size - margin, size - margin, size); // │ 右
return;
}
// ┤
if (left && !right && top && bottom) {
line(size - margin, 0, size - margin, size); // │ 右
line(margin, 0, margin, margin); // │ 左
line(0, margin, margin, margin); // ─ 上
line(0, size - margin, margin, size - margin); // ─ 下
line(margin, size - margin, margin, size); // │ 左
return;
}
// ┬
if (left && right && !top && bottom) {
line(0, margin, size, margin); // ─ 上
line(0, size - margin, margin, size - margin); // ─ 下
line(margin, size - margin, margin, size); // │ 左
line(size - margin, size - margin, size, size - margin); // ─ 下
line(size - margin, size - margin, size - margin, size); // │ 右
return;
}
// ┴
if (left && right && top && !bottom) {
line(0, size - margin, size, size - margin); // ─ 下
line(margin, 0, margin, margin); // │ 左
line(0, margin, margin, margin); // ─ 上
line(size - margin, 0, size - margin, margin); // │ 右
line(size - margin, margin, size, margin); // ─ 上
return;
}
}
const cellSize = mazeAreaSize / mazeSize;
for (let x = 0; x < mazeSize; x++) {
for (let y = 0; y < mazeSize; y++) {
const actualX = margin + (cellSize * x);
const actualY = margin + (cellSize * y);
const cell = maze[x][y];
const mark = (x === 0 && y === 0) || (x === mazeSize - 1 && y === mazeSize - 1);
if (cell === 'left') drawCell(ctx, actualX, actualY, cellSize, true, false, false, false, mark);
if (cell === 'right') drawCell(ctx, actualX, actualY, cellSize, false, true, false, false, mark);
if (cell === 'top') drawCell(ctx, actualX, actualY, cellSize, false, false, true, false, mark);
if (cell === 'bottom') drawCell(ctx, actualX, actualY, cellSize, false, false, false, true, mark);
if (cell === 'leftTop') drawCell(ctx, actualX, actualY, cellSize, true, false, true, false, mark);
if (cell === 'leftBottom') drawCell(ctx, actualX, actualY, cellSize, true, false, false, true, mark);
if (cell === 'rightTop') drawCell(ctx, actualX, actualY, cellSize, false, true, true, false, mark);
if (cell === 'rightBottom') drawCell(ctx, actualX, actualY, cellSize, false, true, false, true, mark);
if (cell === 'leftRightTop') drawCell(ctx, actualX, actualY, cellSize, true, true, true, false, mark);
if (cell === 'leftRightBottom') drawCell(ctx, actualX, actualY, cellSize, true, true, false, true, mark);
if (cell === 'leftTopBottom') drawCell(ctx, actualX, actualY, cellSize, true, false, true, true, mark);
if (cell === 'rightTopBottom') drawCell(ctx, actualX, actualY, cellSize, false, true, true, true, mark);
if (cell === 'leftRight') drawCell(ctx, actualX, actualY, cellSize, true, true, false, false, mark);
if (cell === 'topBottom') drawCell(ctx, actualX, actualY, cellSize, false, false, true, true, mark);
if (cell === 'cross') drawCell(ctx, actualX, actualY, cellSize, true, true, true, true, mark);
}
}
return canvas.toBuffer();
}