🚀 benchmark ?
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
"type": "tsc --noEmit",
|
"type": "tsc --noEmit",
|
||||||
"lint": "yarn prettier -c '**/*.{ts,js,json,md,yml,yaml}' '!packages/action/dist/**' '!packages/demo/dist/**' '!packages/demo/webpack.config.js'",
|
"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",
|
"test": "jest --verbose --passWithNoTests --no-cache",
|
||||||
|
"dev:demo": "( cd packages/demo ; yarn dev )",
|
||||||
"build:demo": "( cd packages/demo ; yarn build )",
|
"build:demo": "( cd packages/demo ; yarn build )",
|
||||||
"build:action": "( cd packages/action ; 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, 4, 4, 1 as Color);
|
||||||
setColor(corner, 0, 0, 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 create = (width: number, height: number, emptyP: number) => {
|
||||||
const grid = createEmptyGrid(width, height);
|
const grid = createEmptyGrid(width, height);
|
||||||
const random = new ParkMiller(10);
|
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 small = create(10, 7, 3);
|
||||||
export const smallPacked = create(10, 7, 1);
|
export const smallPacked = create(10, 7, 1);
|
||||||
export const smallFull = create(10, 7, 0);
|
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;
|
colorCount[color] = (0 | colorCount[color]) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// const colors = Object.keys(colorCount).map((x) => +x);
|
||||||
|
|
||||||
const target = Object.entries(colorCount)
|
const target = Object.entries(colorCount)
|
||||||
.sort(([a], [b]) => +a - +b)
|
.sort(([a], [b]) => +a - +b)
|
||||||
.map(([color, length]: any) => Array.from({ length }, () => +color))
|
.map(([color, length]: any) => Array.from({ length }, () => +color))
|
||||||
@@ -33,9 +35,22 @@ const createHeuristic = (grid0: Grid) => {
|
|||||||
_snake: Snake,
|
_snake: Snake,
|
||||||
stack: Color[]
|
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[]) =>
|
const isEnd = (_grid: Grid, _snake: Snake, stack: Color[]) =>
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ const { canvas, draw } = createCanvas(grid);
|
|||||||
document.body.appendChild(canvas);
|
document.body.appendChild(canvas);
|
||||||
|
|
||||||
const onChange = () => {
|
const onChange = () => {
|
||||||
debugger;
|
|
||||||
|
|
||||||
const grid0 = copyGrid(grid);
|
const grid0 = copyGrid(grid);
|
||||||
const stack0: Color[] = [];
|
const stack0: Color[] = [];
|
||||||
let snake0 = snake;
|
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: {
|
entry: {
|
||||||
"demo.getAvailableRoutes": "./demo.getAvailableRoutes",
|
"demo.getAvailableRoutes": "./demo.getAvailableRoutes",
|
||||||
"demo.getBestRoute": "./demo.getBestRoute",
|
"demo.getBestRoute": "./demo.getBestRoute",
|
||||||
|
"demo.index": "./demo.index",
|
||||||
},
|
},
|
||||||
resolve: { extensions: [".ts", ".js"] },
|
resolve: { extensions: [".ts", ".js"] },
|
||||||
output: {
|
output: {
|
||||||
@@ -36,6 +37,10 @@ const config: Configuration = {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: "index.html",
|
||||||
|
chunks: ["demo.index"],
|
||||||
|
}),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
filename: "demo-getAvailableRoutes.html",
|
filename: "demo-getAvailableRoutes.html",
|
||||||
chunks: ["demo.getAvailableRoutes"],
|
chunks: ["demo.getAvailableRoutes"],
|
||||||
|
|||||||
@@ -13,6 +13,25 @@ type Options = {
|
|||||||
sizeBorderRadius: number;
|
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 = (
|
export const drawWorld = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
@@ -28,15 +47,13 @@ export const drawWorld = (
|
|||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
|
|
||||||
const m = 5;
|
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
ctx.translate(o.sizeCell, (grid.height + 4) * o.sizeCell);
|
ctx.translate(o.sizeCell, (grid.height + 4) * o.sizeCell);
|
||||||
for (let i = 0; i < stack.length; i++) {
|
|
||||||
// @ts-ignore
|
const max = grid.data.reduce((sum, x) => sum + +!!x, stack.length);
|
||||||
ctx.fillStyle = o.colorDots[stack[i]];
|
drawStack(ctx, stack, max, grid.width * o.sizeCell, o);
|
||||||
ctx.fillRect(i * m, 0, m, 10);
|
|
||||||
}
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
|
|
||||||
// ctx.save();
|
// ctx.save();
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ for (const key of [
|
|||||||
"corner",
|
"corner",
|
||||||
"small",
|
"small",
|
||||||
"smallPacked",
|
"smallPacked",
|
||||||
|
"enclave",
|
||||||
] as const)
|
] as const)
|
||||||
it(`should generate ${key} gif`, async () => {
|
it(`should generate ${key} gif`, async () => {
|
||||||
const grid = grids[key];
|
const grid = grids[key];
|
||||||
|
|||||||
Reference in New Issue
Block a user