🚀 refactor algorithm
This commit is contained in:
@@ -34,6 +34,7 @@ export const createCanvas = ({
|
||||
canvas.style.width = w + "px";
|
||||
canvas.style.height = h + "px";
|
||||
canvas.style.display = "block";
|
||||
canvas.style.pointerEvents = "none";
|
||||
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
import "./menu";
|
||||
import { createCanvas } from "./canvas";
|
||||
import { getHeadX, getHeadY, snakeToCells } from "@snk/types/snake";
|
||||
import { grid, snake } from "./sample";
|
||||
import { getColor } from "@snk/types/grid";
|
||||
import { getAvailableRoutes } from "@snk/compute/getAvailableRoutes";
|
||||
import type { Snake } from "@snk/types/snake";
|
||||
import type { Color, Empty } from "@snk/types/grid";
|
||||
|
||||
//
|
||||
// compute
|
||||
|
||||
const solutions: {
|
||||
x: number;
|
||||
y: number;
|
||||
chain: Snake[];
|
||||
color: Color | Empty;
|
||||
}[] = [];
|
||||
getAvailableRoutes(grid, snake, (chain) => {
|
||||
const x = getHeadX(chain[0]);
|
||||
const y = getHeadY(chain[0]);
|
||||
|
||||
if (!solutions.some((s) => x === s.x && y === s.y))
|
||||
solutions.push({
|
||||
x,
|
||||
y,
|
||||
chain: [snake, ...chain.slice().reverse()],
|
||||
color: getColor(grid, x, y),
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
solutions.sort((a, b) => a.color - b.color);
|
||||
|
||||
const { canvas, ctx, draw, highlightCell } = createCanvas(grid);
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
let k = 0;
|
||||
let i = solutions[k].chain.length - 1;
|
||||
|
||||
const onChange = () => {
|
||||
const { chain } = solutions[k];
|
||||
|
||||
ctx.clearRect(0, 0, 9999, 9999);
|
||||
|
||||
draw(grid, chain[i], []);
|
||||
|
||||
chain
|
||||
.map(snakeToCells)
|
||||
.flat()
|
||||
.forEach(({ x, y }) => highlightCell(x, y));
|
||||
};
|
||||
|
||||
onChange();
|
||||
|
||||
const inputK = document.createElement("input") as any;
|
||||
inputK.type = "range";
|
||||
inputK.value = 0;
|
||||
inputK.step = 1;
|
||||
inputK.min = 0;
|
||||
inputK.max = solutions.length - 1;
|
||||
inputK.style.width = "90%";
|
||||
inputK.style.padding = "20px 0";
|
||||
inputK.addEventListener("input", () => {
|
||||
k = +inputK.value;
|
||||
i = inputI.value = inputI.max = solutions[k].chain.length - 1;
|
||||
onChange();
|
||||
});
|
||||
document.body.append(inputK);
|
||||
|
||||
const inputI = document.createElement("input") as any;
|
||||
inputI.type = "range";
|
||||
inputI.value = inputI.max = solutions[k].chain.length - 1;
|
||||
inputI.step = 1;
|
||||
inputI.min = 0;
|
||||
inputI.style.width = "90%";
|
||||
inputI.style.padding = "20px 0";
|
||||
inputI.addEventListener("input", () => {
|
||||
i = +inputI.value;
|
||||
onChange();
|
||||
});
|
||||
document.body.append(inputI);
|
||||
|
||||
window.addEventListener("click", (e) => {
|
||||
if (e.target === document.body || e.target === document.body.parentElement)
|
||||
inputK.focus();
|
||||
});
|
||||
@@ -4,55 +4,35 @@ import { getBestRoute } from "@snk/compute/getBestRoute";
|
||||
import { Color, copyGrid } from "@snk/types/grid";
|
||||
import { grid, snake } from "./sample";
|
||||
import { step } from "@snk/compute/step";
|
||||
import { isStableAndBound, stepSpring } from "./springUtils";
|
||||
|
||||
const chain = [snake, ...getBestRoute(grid, snake)!];
|
||||
const chain = getBestRoute(grid, snake)!;
|
||||
|
||||
//
|
||||
// draw
|
||||
let k = 0;
|
||||
|
||||
const spring = { x: 0, v: 0, target: 0 };
|
||||
const springParams = { tension: 120, friction: 20, maxVelocity: 50 };
|
||||
let animationFrame: number;
|
||||
|
||||
const { canvas, drawLerp } = createCanvas(grid);
|
||||
const { canvas, draw } = createCanvas(grid);
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
const clamp = (x: number, a: number, b: number) => Math.max(a, Math.min(b, x));
|
||||
const onChange = () => {
|
||||
const gridN = copyGrid(grid);
|
||||
const stack: Color[] = [];
|
||||
for (let i = 0; i <= k; i++) step(gridN, stack, chain[i]);
|
||||
|
||||
const loop = () => {
|
||||
cancelAnimationFrame(animationFrame);
|
||||
|
||||
stepSpring(spring, springParams, spring.target);
|
||||
const stable = isStableAndBound(spring, spring.target);
|
||||
|
||||
const grid0 = copyGrid(grid);
|
||||
const stack0: Color[] = [];
|
||||
for (let i = 0; i < Math.min(chain.length, spring.x); i++)
|
||||
step(grid0, stack0, chain[i]);
|
||||
|
||||
const snake0 = chain[clamp(Math.floor(spring.x), 0, chain.length - 1)];
|
||||
const snake1 = chain[clamp(Math.ceil(spring.x), 0, chain.length - 1)];
|
||||
const k = spring.x % 1;
|
||||
|
||||
drawLerp(grid0, snake0, snake1, stack0, k);
|
||||
|
||||
if (!stable) animationFrame = requestAnimationFrame(loop);
|
||||
draw(gridN, chain[k], stack);
|
||||
};
|
||||
|
||||
loop();
|
||||
onChange();
|
||||
|
||||
const input = document.createElement("input") as any;
|
||||
input.type = "range";
|
||||
input.value = 0;
|
||||
input.step = 1;
|
||||
input.min = 0;
|
||||
input.max = chain.length;
|
||||
input.max = chain.length - 1;
|
||||
input.style.width = "90%";
|
||||
input.addEventListener("input", () => {
|
||||
spring.target = +input.value;
|
||||
cancelAnimationFrame(animationFrame);
|
||||
animationFrame = requestAnimationFrame(loop);
|
||||
k = +input.value;
|
||||
onChange();
|
||||
});
|
||||
document.body.append(input);
|
||||
window.addEventListener("click", (e) => {
|
||||
|
||||
@@ -122,6 +122,7 @@ const createViewer = ({
|
||||
const h = (height / width) * w;
|
||||
canvas.style.width = w + "px";
|
||||
canvas.style.height = h + "px";
|
||||
canvas.style.pointerEvents = "none";
|
||||
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
@@ -205,7 +206,7 @@ const onSubmit = async (userName: string) => {
|
||||
|
||||
const snake = snake3;
|
||||
const grid = userContributionToGrid(cells);
|
||||
const chain = [snake, ...getBestRoute(grid, snake)!];
|
||||
const chain = getBestRoute(grid, snake)!;
|
||||
dispose();
|
||||
|
||||
createViewer({ grid0: grid, chain, drawOptions });
|
||||
|
||||
@@ -1,8 +1 @@
|
||||
[
|
||||
"getAvailableRoutes",
|
||||
"pruneLayer",
|
||||
"getBestRoute",
|
||||
"getBestRoundTrip",
|
||||
"getPathTo",
|
||||
"interactive"
|
||||
]
|
||||
["interactive", "getBestTunnel", "getBestRoute", "getPathTo"]
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import "./menu";
|
||||
import { createCanvas } from "./canvas";
|
||||
import { Color, copyGrid } from "@snk/types/grid";
|
||||
import { grid, snake } from "./sample";
|
||||
import { pruneLayer } from "@snk/compute/pruneLayer";
|
||||
import { getSnakeLength } from "@snk/types/snake";
|
||||
|
||||
const colors = [1, 2, 3] as Color[];
|
||||
|
||||
const snakeN = getSnakeLength(snake);
|
||||
|
||||
const layers = [{ grid, chunk: [] as { x: number; y: number }[] }];
|
||||
let grid0 = copyGrid(grid);
|
||||
for (const color of colors) {
|
||||
const chunk = pruneLayer(grid0, color, snakeN);
|
||||
layers.push({ chunk, grid: copyGrid(grid0) });
|
||||
}
|
||||
|
||||
const { canvas, ctx, highlightCell, draw } = createCanvas(grid);
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
let k = 0;
|
||||
|
||||
const loop = () => {
|
||||
const { grid, chunk } = layers[k];
|
||||
|
||||
draw(grid, snake, []);
|
||||
|
||||
ctx.fillStyle = "orange";
|
||||
chunk.forEach(({ x, y }) => highlightCell(x, y));
|
||||
};
|
||||
|
||||
loop();
|
||||
|
||||
const input = document.createElement("input") as any;
|
||||
input.type = "range";
|
||||
input.value = 0;
|
||||
input.step = 1;
|
||||
input.min = 0;
|
||||
input.max = layers.length - 1;
|
||||
input.style.width = "90%";
|
||||
input.addEventListener("input", () => {
|
||||
k = +input.value;
|
||||
loop();
|
||||
});
|
||||
document.body.append(input);
|
||||
|
||||
window.addEventListener("click", (e) => {
|
||||
if (e.target === document.body || e.target === document.body.parentElement)
|
||||
input.focus();
|
||||
});
|
||||
@@ -40,6 +40,11 @@ const config: Configuration = {
|
||||
chunks: [demo],
|
||||
})
|
||||
),
|
||||
new HtmlWebpackPlugin({
|
||||
title: "snk - " + demos[0],
|
||||
filename: `index.html`,
|
||||
chunks: [demos[0]],
|
||||
}),
|
||||
],
|
||||
|
||||
devtool: false,
|
||||
|
||||
Reference in New Issue
Block a user