🚀 imrpove algorithm

This commit is contained in:
platane
2020-10-31 17:23:19 +01:00
parent d81ecec836
commit b595e7de53
22 changed files with 707 additions and 451 deletions

View File

@@ -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,
};
};

View File

@@ -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();

View File

@@ -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();
});

View File

@@ -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();

View File

@@ -1 +1 @@
["interactive", "getBestTunnel", "getBestRoute", "getPathTo"]
["interactive", "getBestTunnel", "getBestRoute", "outside", "getPathTo"]

View 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
View 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);

View File

@@ -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 = () => {

View File

@@ -25,7 +25,7 @@ const config: Configuration = {
transpileOnly: true,
compilerOptions: {
lib: ["dom", "es2020"],
target: "es5",
target: "es2019",
},
},
},