🚀 imrpove algorithm
This commit is contained in:
@@ -18,6 +18,18 @@ export const drawOptions = {
|
||||
colorSnake: "purple",
|
||||
};
|
||||
|
||||
const getPointedCell = (canvas: HTMLCanvasElement) => ({
|
||||
pageX,
|
||||
pageY,
|
||||
}: MouseEvent) => {
|
||||
const { left, top } = canvas.getBoundingClientRect();
|
||||
|
||||
const x = Math.floor((pageX - left) / drawOptions.sizeCell) - 1;
|
||||
const y = Math.floor((pageY - top) / drawOptions.sizeCell) - 2;
|
||||
|
||||
return { x, y };
|
||||
};
|
||||
|
||||
export const createCanvas = ({
|
||||
width,
|
||||
height,
|
||||
@@ -34,9 +46,19 @@ export const createCanvas = ({
|
||||
canvas.style.width = w + "px";
|
||||
canvas.style.height = h + "px";
|
||||
canvas.style.display = "block";
|
||||
canvas.style.pointerEvents = "none";
|
||||
// canvas.style.pointerEvents = "none";
|
||||
|
||||
const cellInfo = document.createElement("div");
|
||||
cellInfo.style.height = "20px";
|
||||
|
||||
document.body.appendChild(cellInfo);
|
||||
document.body.appendChild(canvas);
|
||||
canvas.addEventListener("mousemove", (e) => {
|
||||
const { x, y } = getPointedCell(canvas)(e);
|
||||
cellInfo.innerText = [x, y]
|
||||
.map((u) => u.toString().padStart(2, " "))
|
||||
.join(" / ");
|
||||
});
|
||||
|
||||
const ctx = canvas.getContext("2d")!;
|
||||
ctx.scale(upscale, upscale);
|
||||
@@ -63,5 +85,12 @@ export const createCanvas = ({
|
||||
ctx.fillRect((1 + x + 0.5) * 16 - 2, (2 + y + 0.5) * 16 - 2, 4, 4);
|
||||
};
|
||||
|
||||
return { draw, drawLerp, highlightCell, canvas, ctx };
|
||||
return {
|
||||
draw,
|
||||
drawLerp,
|
||||
highlightCell,
|
||||
canvas,
|
||||
getPointedCell: getPointedCell(canvas),
|
||||
ctx,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ import { getSnakeLength } from "@snk/types/snake";
|
||||
import { grid, snake } from "./sample";
|
||||
import { getColor } from "@snk/types/grid";
|
||||
import { getBestTunnel } from "@snk/compute/getBestTunnel";
|
||||
import { createOutside } from "@snk/compute/outside";
|
||||
import type { Color } from "@snk/types/grid";
|
||||
import type { Point } from "@snk/types/point";
|
||||
|
||||
@@ -16,39 +17,64 @@ for (let x = 0; x < grid.width; x++)
|
||||
for (let y = 0; y < grid.height; y++)
|
||||
if (getColor(grid, x, y) === 1) ones.push({ x, y });
|
||||
|
||||
const points = getBestTunnel(
|
||||
grid,
|
||||
ones[0].x,
|
||||
ones[0].y,
|
||||
3 as Color,
|
||||
getSnakeLength(snake)
|
||||
);
|
||||
|
||||
let k = 0;
|
||||
const tunnels = ones.map(({ x, y }) => ({
|
||||
x,
|
||||
y,
|
||||
tunnel: getBestTunnel(
|
||||
grid,
|
||||
createOutside(grid),
|
||||
x,
|
||||
y,
|
||||
3 as Color,
|
||||
getSnakeLength(snake)
|
||||
),
|
||||
}));
|
||||
|
||||
const onChange = () => {
|
||||
const k = +inputK.value;
|
||||
const i = +inputI.value;
|
||||
|
||||
ctx.clearRect(0, 0, 9999, 9999);
|
||||
|
||||
draw(grid, [] as any, []);
|
||||
if (!tunnels[k]) return;
|
||||
|
||||
if (points) {
|
||||
points.forEach(({ x, y }) => highlightCell(x, y));
|
||||
highlightCell(points[k].x, points[k].y, "blue");
|
||||
const { x, y, tunnel } = tunnels[k]!;
|
||||
|
||||
draw(grid, snake, []);
|
||||
|
||||
highlightCell(x, y, "red");
|
||||
|
||||
if (tunnel) {
|
||||
tunnel.forEach(({ x, y }) => highlightCell(x, y));
|
||||
highlightCell(x, y, "red");
|
||||
highlightCell(tunnel[i].x, tunnel[i].y, "blue");
|
||||
}
|
||||
};
|
||||
|
||||
onChange();
|
||||
|
||||
const inputK = document.createElement("input") as any;
|
||||
inputK.type = "range";
|
||||
inputK.value = 0;
|
||||
inputK.step = 1;
|
||||
inputK.min = 0;
|
||||
inputK.max = points ? points.length - 1 : 0;
|
||||
inputK.max = tunnels ? tunnels.length - 1 : 0;
|
||||
inputK.style.width = "90%";
|
||||
inputK.style.padding = "20px 0";
|
||||
inputK.addEventListener("input", () => {
|
||||
k = +inputK.value;
|
||||
inputI.value = 0;
|
||||
inputI.max = (tunnels[+inputK.value]?.tunnel?.length || 1) - 1;
|
||||
onChange();
|
||||
});
|
||||
document.body.append(inputK);
|
||||
|
||||
const inputI = document.createElement("input") as any;
|
||||
inputI.type = "range";
|
||||
inputI.value = 0;
|
||||
inputI.step = 1;
|
||||
inputI.min = 0;
|
||||
inputI.max = (tunnels[+inputK.value]?.tunnel?.length || 1) - 1;
|
||||
inputI.style.width = "90%";
|
||||
inputI.style.padding = "20px 0";
|
||||
inputI.addEventListener("input", onChange);
|
||||
document.body.append(inputI);
|
||||
|
||||
onChange();
|
||||
|
||||
@@ -1,64 +1,53 @@
|
||||
import "./menu";
|
||||
import { createCanvas } from "./canvas";
|
||||
import { snakeToCells } from "@snk/types/snake";
|
||||
import { grid, snake } from "./sample";
|
||||
import { getColor } from "@snk/types/grid";
|
||||
import { copySnake, snakeToCells } from "@snk/types/snake";
|
||||
import { grid, snake as snake0 } from "./sample";
|
||||
import { getPathTo } from "@snk/compute/getPathTo";
|
||||
import type { Point } from "@snk/types/point";
|
||||
|
||||
const { canvas, ctx, draw, highlightCell } = createCanvas(grid);
|
||||
document.body.appendChild(canvas);
|
||||
const { canvas, ctx, draw, getPointedCell, highlightCell } = createCanvas(grid);
|
||||
canvas.style.pointerEvents = "auto";
|
||||
|
||||
const ones: Point[] = [];
|
||||
let snake = copySnake(snake0);
|
||||
let chain = [snake];
|
||||
|
||||
for (let x = 0; x < grid.width; x++)
|
||||
for (let y = 0; y < grid.height; y++)
|
||||
if (getColor(grid, x, y) === 1) ones.push({ x, y });
|
||||
canvas.addEventListener("mousemove", (e) => {
|
||||
const { x, y } = getPointedCell(e);
|
||||
|
||||
const chains = ones.map((p) => {
|
||||
const chain = getPathTo(grid, snake, p.x, p.y);
|
||||
return chain && [...chain, snake];
|
||||
chain = [...(getPathTo(grid, snake, x, y) || []), snake].reverse();
|
||||
|
||||
inputI.max = chain.length - 1;
|
||||
i = inputI.value = chain.length - 1;
|
||||
|
||||
onChange();
|
||||
});
|
||||
|
||||
let k = 0;
|
||||
let i = 0;
|
||||
canvas.addEventListener("click", () => {
|
||||
snake = chain.slice(-1)[0];
|
||||
|
||||
chain = [snake];
|
||||
inputI.max = chain.length - 1;
|
||||
i = inputI.value = chain.length - 1;
|
||||
|
||||
onChange();
|
||||
});
|
||||
|
||||
let i = 0;
|
||||
const onChange = () => {
|
||||
ctx.clearRect(0, 0, 9999, 9999);
|
||||
|
||||
const chain = chains[k];
|
||||
|
||||
if (chain) {
|
||||
draw(grid, chain[i], []);
|
||||
chain
|
||||
.map(snakeToCells)
|
||||
.flat()
|
||||
.forEach(({ x, y }) => highlightCell(x, y));
|
||||
} else draw(grid, snake, []);
|
||||
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 = k;
|
||||
inputK.step = 1;
|
||||
inputK.min = 0;
|
||||
inputK.max = chains.length - 1;
|
||||
inputK.style.width = "90%";
|
||||
inputK.style.padding = "20px 0";
|
||||
inputK.addEventListener("input", () => {
|
||||
k = +inputK.value;
|
||||
i = inputI.value = 0;
|
||||
inputI.max = chains[k] ? chains[k]!.length - 1 : 0;
|
||||
onChange();
|
||||
});
|
||||
document.body.append(inputK);
|
||||
|
||||
const inputI = document.createElement("input") as any;
|
||||
inputI.type = "range";
|
||||
inputI.value = 0;
|
||||
inputI.max = chains[k] ? chains[k]!.length - 1 : 0;
|
||||
inputI.max = chain ? chain.length - 1 : 0;
|
||||
inputI.step = 1;
|
||||
inputI.min = 0;
|
||||
inputI.style.width = "90%";
|
||||
@@ -68,8 +57,3 @@ inputI.addEventListener("input", () => {
|
||||
onChange();
|
||||
});
|
||||
document.body.append(inputI);
|
||||
|
||||
window.addEventListener("click", (e) => {
|
||||
if (e.target === document.body || e.target === document.body.parentElement)
|
||||
inputK.focus();
|
||||
});
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
Options,
|
||||
} from "@snk/draw/drawWorld";
|
||||
import { userContributionToGrid } from "../action/userContributionToGrid";
|
||||
import { snake3 } from "@snk/types/__fixtures__/snake";
|
||||
import { snake4 as snake } from "@snk/types/__fixtures__/snake";
|
||||
|
||||
const createForm = ({
|
||||
onSubmit,
|
||||
@@ -204,7 +204,6 @@ const onSubmit = async (userName: string) => {
|
||||
cells,
|
||||
};
|
||||
|
||||
const snake = snake3;
|
||||
const grid = userContributionToGrid(cells);
|
||||
const chain = getBestRoute(grid, snake)!;
|
||||
dispose();
|
||||
|
||||
@@ -1 +1 @@
|
||||
["interactive", "getBestTunnel", "getBestRoute", "getPathTo"]
|
||||
["interactive", "getBestTunnel", "getBestRoute", "outside", "getPathTo"]
|
||||
|
||||
42
packages/demo/demo.outside.ts
Normal file
42
packages/demo/demo.outside.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import "./menu";
|
||||
import { createCanvas } from "./canvas";
|
||||
import { grid } from "./sample";
|
||||
import type { Color } from "@snk/types/grid";
|
||||
import { createOutside, isOutside } from "@snk/compute/outside";
|
||||
|
||||
const { canvas, ctx, draw, highlightCell } = createCanvas(grid);
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
let k = 0;
|
||||
|
||||
const onChange = () => {
|
||||
ctx.clearRect(0, 0, 9999, 9999);
|
||||
|
||||
draw(grid, [] as any, []);
|
||||
|
||||
const outside = createOutside(grid, k as Color);
|
||||
|
||||
for (let x = outside.width; x--; )
|
||||
for (let y = outside.height; y--; )
|
||||
if (isOutside(outside, 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 = 4;
|
||||
inputK.style.width = "90%";
|
||||
inputK.style.padding = "20px 0";
|
||||
inputK.addEventListener("input", () => {
|
||||
k = +inputK.value;
|
||||
onChange();
|
||||
});
|
||||
document.body.append(inputK);
|
||||
window.addEventListener("click", (e) => {
|
||||
if (e.target === document.body || e.target === document.body.parentElement)
|
||||
inputK.focus();
|
||||
});
|
||||
12
packages/demo/demo.svg.ts
Normal file
12
packages/demo/demo.svg.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import "./menu";
|
||||
import { getBestRoute } from "@snk/compute/getBestRoute";
|
||||
import { createSvg } from "../svg-creator";
|
||||
import { grid, snake } from "./sample";
|
||||
import { drawOptions } from "./canvas";
|
||||
|
||||
const chain = getBestRoute(grid, snake);
|
||||
const svg = createSvg(grid, chain, drawOptions, { frameDuration: 200 });
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.innerHTML = svg;
|
||||
document.body.appendChild(container);
|
||||
@@ -15,8 +15,8 @@ const config = {
|
||||
demo: demos[0],
|
||||
};
|
||||
{
|
||||
const d = window.location.pathname.match(/(\w+)\.html/)?.[1];
|
||||
if (d && demos.includes(d)) config.demo = d;
|
||||
const d = window.location.pathname.match(/(\w+)\.html/);
|
||||
if (d && demos.includes(d[1])) config.demo = d[1];
|
||||
}
|
||||
|
||||
const onChange = () => {
|
||||
|
||||
@@ -25,7 +25,7 @@ const config: Configuration = {
|
||||
transpileOnly: true,
|
||||
compilerOptions: {
|
||||
lib: ["dom", "es2020"],
|
||||
target: "es5",
|
||||
target: "es2019",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user