🚀 benchmark ?
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
"type": "tsc --noEmit",
|
||||
"lint": "yarn prettier -c '**/*.{ts,js,json,md,yml,yaml}' '!packages/action/dist/**' '!packages/demo/dist/**' '!packages/demo/webpack.config.js'",
|
||||
"test": "jest --verbose --passWithNoTests --no-cache",
|
||||
"dev:demo": "( cd packages/demo ; yarn dev )",
|
||||
"build:demo": "( cd packages/demo ; yarn build )",
|
||||
"build:action": "( cd packages/action ; yarn build )"
|
||||
}
|
||||
|
||||
@@ -19,6 +19,16 @@ setColor(corner, 4, 0, 1 as Color);
|
||||
setColor(corner, 4, 4, 1 as Color);
|
||||
setColor(corner, 0, 0, 1 as Color);
|
||||
|
||||
// enclaved color
|
||||
export const enclave = createEmptyGrid(7, 7);
|
||||
setColor(enclave, 3, 4, 2 as Color);
|
||||
setColor(enclave, 2, 3, 2 as Color);
|
||||
setColor(enclave, 2, 4, 2 as Color);
|
||||
setColor(enclave, 4, 4, 2 as Color);
|
||||
setColor(enclave, 4, 3, 2 as Color);
|
||||
setColor(enclave, 3, 3, 1 as Color);
|
||||
setColor(enclave, 5, 5, 1 as Color);
|
||||
|
||||
const create = (width: number, height: number, emptyP: number) => {
|
||||
const grid = createEmptyGrid(width, height);
|
||||
const random = new ParkMiller(10);
|
||||
@@ -31,3 +41,7 @@ const create = (width: number, height: number, emptyP: number) => {
|
||||
export const small = create(10, 7, 3);
|
||||
export const smallPacked = create(10, 7, 1);
|
||||
export const smallFull = create(10, 7, 0);
|
||||
|
||||
// small realistic
|
||||
export const realistic = create(52, 7, 3);
|
||||
export const realisticFull = create(52, 7, 0);
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { getAvailableInterestingRoutes } from "../getAvailableRoutes";
|
||||
import { small as grid } from "../__fixtures__/grid";
|
||||
import { snake3 } from "../__fixtures__/snake";
|
||||
import { performance } from "perf_hooks";
|
||||
import { getAvailableRoutes } from "../getAvailableRoutes2";
|
||||
|
||||
const m = 1000;
|
||||
{
|
||||
const s = performance.now();
|
||||
for (let k = m; k--; ) {
|
||||
const solutions = [];
|
||||
|
||||
getAvailableInterestingRoutes(
|
||||
grid,
|
||||
snake3,
|
||||
(snakes) => {
|
||||
solutions.push(snakes);
|
||||
return false;
|
||||
},
|
||||
2
|
||||
);
|
||||
}
|
||||
console.log((performance.now() - s) / m, "ms");
|
||||
}
|
||||
|
||||
{
|
||||
const s = performance.now();
|
||||
for (let k = m; k--; ) {
|
||||
getAvailableRoutes(grid, snake3, 2);
|
||||
}
|
||||
|
||||
console.log((performance.now() - s) / m, "ms");
|
||||
}
|
||||
|
||||
65
packages/compute/getAvailableRoutes2.ts
Normal file
65
packages/compute/getAvailableRoutes2.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
import { Grid, isInsideLarge, getColor, isInside, isEmpty } from "./grid";
|
||||
import { around4 } from "./point";
|
||||
import {
|
||||
getHeadX,
|
||||
getHeadY,
|
||||
nextSnake,
|
||||
Snake,
|
||||
snakeEquals,
|
||||
snakeWillSelfCollide,
|
||||
} from "./snake";
|
||||
|
||||
const snakeEqualsN = (a: Snake, b: Snake, n = a.length / 2) => {
|
||||
for (let i = 0; i < n * 2; i++) if (a[i] !== b[i]) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
export const getAvailableRoutes = (grid: Grid, snake0: Snake, n?: number) => {
|
||||
const openList: Snake[][] = [[snake0]];
|
||||
const closeList: Snake[] = [];
|
||||
|
||||
const solutions: Snake[][] = [];
|
||||
|
||||
while (openList.length) {
|
||||
const c = openList.shift()!;
|
||||
const [snake] = c;
|
||||
|
||||
closeList.push(snake);
|
||||
|
||||
const cx = getHeadX(snake);
|
||||
const cy = getHeadY(snake);
|
||||
|
||||
for (let i = 0; i < around4.length; i++) {
|
||||
const { x: dx, y: dy } = around4[i];
|
||||
|
||||
const nx = cx + dx;
|
||||
const ny = cy + dy;
|
||||
|
||||
if (
|
||||
isInsideLarge(grid, 1, nx, ny) &&
|
||||
!snakeWillSelfCollide(snake, dx, dy)
|
||||
) {
|
||||
const nsnake = nextSnake(snake, dx, dy);
|
||||
|
||||
if (!closeList.some((s) => snakeEquals(nsnake, s))) {
|
||||
const color = isInside(grid, nx, ny) && getColor(grid, nx, ny);
|
||||
|
||||
if (color && !isEmpty(color)) {
|
||||
if (solutions.every(([s]) => !snakeEqualsN(s, nsnake, n))) {
|
||||
const solution = [nsnake, ...c.slice(0, -1)];
|
||||
solutions.push(solution);
|
||||
}
|
||||
} else {
|
||||
if (!openList.some(([s]) => snakeEquals(nsnake, s))) {
|
||||
const chain = [nsnake, ...c];
|
||||
openList.push(chain);
|
||||
openList.sort((a, b) => a.length - b.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return solutions;
|
||||
};
|
||||
@@ -20,6 +20,8 @@ const createHeuristic = (grid0: Grid) => {
|
||||
colorCount[color] = (0 | colorCount[color]) + 1;
|
||||
}
|
||||
|
||||
// const colors = Object.keys(colorCount).map((x) => +x);
|
||||
|
||||
const target = Object.entries(colorCount)
|
||||
.sort(([a], [b]) => +a - +b)
|
||||
.map(([color, length]: any) => Array.from({ length }, () => +color))
|
||||
@@ -33,9 +35,22 @@ const createHeuristic = (grid0: Grid) => {
|
||||
_snake: Snake,
|
||||
stack: Color[]
|
||||
) => {
|
||||
const x = target[stack.length];
|
||||
const colorTarget = target[stack.length];
|
||||
|
||||
return (c: Color) => (x === c ? 1 : 0);
|
||||
// const cc = { ...colorCount };
|
||||
// for (const color of stack) cc[color]--;
|
||||
|
||||
// let colorTarget;
|
||||
// for (let i = colors.length; i--; )
|
||||
// if (cc[colors[i]] > 0) colorTarget = colors[i];
|
||||
|
||||
return (c: Color) => {
|
||||
if (colorTarget === c) return 1;
|
||||
|
||||
return 0;
|
||||
|
||||
// return 1 - Math.abs(colorTarget - c) / 10;
|
||||
};
|
||||
};
|
||||
|
||||
const isEnd = (_grid: Grid, _snake: Snake, stack: Color[]) =>
|
||||
|
||||
@@ -15,8 +15,6 @@ const { canvas, draw } = createCanvas(grid);
|
||||
document.body.appendChild(canvas);
|
||||
|
||||
const onChange = () => {
|
||||
debugger;
|
||||
|
||||
const grid0 = copyGrid(grid);
|
||||
const stack0: Color[] = [];
|
||||
let snake0 = snake;
|
||||
|
||||
21
packages/demo/demo.index.ts
Normal file
21
packages/demo/demo.index.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import * as grid from "@snk/compute/__fixtures__/grid";
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.style.fontFamily = "helvetica";
|
||||
document.body.appendChild(container);
|
||||
|
||||
for (const demo of ["getAvailableRoutes", "getBestRoute"]) {
|
||||
const title = document.createElement("h1");
|
||||
title.innerText = demo;
|
||||
|
||||
container.appendChild(title);
|
||||
|
||||
for (const g of Object.keys(grid)) {
|
||||
const a = document.createElement("a");
|
||||
a.style.display = "block";
|
||||
a.innerText = `${demo} - ${g}`;
|
||||
a.href = `/demo-${demo}.html?grid=${g}`;
|
||||
|
||||
container.appendChild(a);
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ const config: Configuration = {
|
||||
entry: {
|
||||
"demo.getAvailableRoutes": "./demo.getAvailableRoutes",
|
||||
"demo.getBestRoute": "./demo.getBestRoute",
|
||||
"demo.index": "./demo.index",
|
||||
},
|
||||
resolve: { extensions: [".ts", ".js"] },
|
||||
output: {
|
||||
@@ -36,6 +37,10 @@ const config: Configuration = {
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "index.html",
|
||||
chunks: ["demo.index"],
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "demo-getAvailableRoutes.html",
|
||||
chunks: ["demo.getAvailableRoutes"],
|
||||
|
||||
@@ -13,6 +13,25 @@ type Options = {
|
||||
sizeBorderRadius: number;
|
||||
};
|
||||
|
||||
export const drawStack = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
stack: Color[],
|
||||
max: number,
|
||||
width: number,
|
||||
o: { colorDots: Record<Color, string> }
|
||||
) => {
|
||||
ctx.save();
|
||||
|
||||
const m = width / max;
|
||||
|
||||
for (let i = 0; i < stack.length; i++) {
|
||||
// @ts-ignore
|
||||
ctx.fillStyle = o.colorDots[stack[i]];
|
||||
ctx.fillRect(i * m, 0, m + width * 0.005, 10);
|
||||
}
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
export const drawWorld = (
|
||||
ctx: CanvasRenderingContext2D,
|
||||
grid: Grid,
|
||||
@@ -28,15 +47,13 @@ export const drawWorld = (
|
||||
|
||||
ctx.restore();
|
||||
|
||||
const m = 5;
|
||||
|
||||
ctx.save();
|
||||
|
||||
ctx.translate(o.sizeCell, (grid.height + 4) * o.sizeCell);
|
||||
for (let i = 0; i < stack.length; i++) {
|
||||
// @ts-ignore
|
||||
ctx.fillStyle = o.colorDots[stack[i]];
|
||||
ctx.fillRect(i * m, 0, m, 10);
|
||||
}
|
||||
|
||||
const max = grid.data.reduce((sum, x) => sum + +!!x, stack.length);
|
||||
drawStack(ctx, stack, max, grid.width * o.sizeCell, o);
|
||||
|
||||
ctx.restore();
|
||||
|
||||
// ctx.save();
|
||||
|
||||
@@ -29,6 +29,7 @@ for (const key of [
|
||||
"corner",
|
||||
"small",
|
||||
"smallPacked",
|
||||
"enclave",
|
||||
] as const)
|
||||
it(`should generate ${key} gif`, async () => {
|
||||
const grid = grids[key];
|
||||
|
||||
Reference in New Issue
Block a user