🚿 refactor + clean up
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { getGithubUserContribution } from "@snk/github-user-contribution";
|
||||
import { createGif } from "@snk/gif-creator";
|
||||
import { createSnake } from "@snk/compute/snake";
|
||||
import { getBestRoute } from "@snk/compute/getBestRoute";
|
||||
import { createSnakeFromCells } from "@snk/types/snake";
|
||||
import { userContributionToGrid } from "./userContributionToGrid";
|
||||
|
||||
export const generateContributionSnake = async (userName: string) => {
|
||||
@@ -10,7 +10,7 @@ export const generateContributionSnake = async (userName: string) => {
|
||||
|
||||
const grid0 = userContributionToGrid(cells);
|
||||
|
||||
const snake0 = createSnake([
|
||||
const snake0 = createSnakeFromCells([
|
||||
{ x: 4, y: -1 },
|
||||
{ x: 3, y: -1 },
|
||||
{ x: 2, y: -1 },
|
||||
@@ -25,7 +25,7 @@ export const generateContributionSnake = async (userName: string) => {
|
||||
sizeCell: 16 * upscale,
|
||||
sizeDot: 12 * upscale,
|
||||
colorBorder: "#1b1f230a",
|
||||
colorDots: colorScheme,
|
||||
colorDots: colorScheme as any,
|
||||
colorEmpty: colorScheme[0],
|
||||
colorSnake: "purple",
|
||||
cells,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { setColor, createEmptyGrid } from "@snk/compute/grid";
|
||||
import { setColor, createEmptyGrid } from "@snk/types/grid";
|
||||
import type { Cell } from "@snk/github-user-contribution";
|
||||
import type { Color } from "@snk/compute/grid";
|
||||
import type { Color } from "@snk/types/grid";
|
||||
|
||||
export const userContributionToGrid = (cells: Cell[]) => {
|
||||
const width = Math.max(0, ...cells.map((c) => c.x)) + 1;
|
||||
|
||||
27
packages/compute/README.md
Normal file
27
packages/compute/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# implementation
|
||||
|
||||
## target
|
||||
|
||||
The goal is have the stack of eaten color as sorted as possible.
|
||||
|
||||
The number of step is not very optimized as for now.
|
||||
|
||||
## algorithm
|
||||
|
||||
- for each type of color in the grid
|
||||
|
||||
- determine all the "free" cell of that color.
|
||||
|
||||
> a free cell can be reached by going through only empty cell ( or cell of the same color )
|
||||
>
|
||||
> basically, grabbing those cells have no penalty since we don't touch other color to get to the cell and to leave the cell
|
||||
|
||||
- eat all the free cells (without optimizing the path for the sake of performance)
|
||||
|
||||
- repeat for the next color, consider the current color as the same color
|
||||
|
||||
## future
|
||||
|
||||
- have an intermediate phase where we eat the remaining cell that are not free, to get rid of them before the next "eat free cells" phase
|
||||
|
||||
- use a better heuristic to allows to optimize the number of steps in the "eat free cells" phase
|
||||
@@ -1,5 +1,5 @@
|
||||
import { realistic as grid } from "../__fixtures__/grid";
|
||||
import { snake3 } from "../__fixtures__/snake";
|
||||
import { realistic as grid } from "@snk/types/__fixtures__/grid";
|
||||
import { snake3 } from "@snk/types/__fixtures__/snake";
|
||||
import { performance } from "perf_hooks";
|
||||
import { getAvailableRoutes } from "../getAvailableRoutes";
|
||||
import { getBestRoute } from "../getBestRoute";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { getBestRoute } from "../getBestRoute";
|
||||
import { Color, createEmptyGrid, setColor } from "../grid";
|
||||
import { createSnake, snakeToCells } from "../snake";
|
||||
import { Color, createEmptyGrid, setColor } from "@snk/types/grid";
|
||||
import { createSnakeFromCells, snakeToCells } from "@snk/types/snake";
|
||||
|
||||
it("should find best route", () => {
|
||||
const snk0 = [
|
||||
@@ -11,7 +11,7 @@ it("should find best route", () => {
|
||||
const grid = createEmptyGrid(5, 5);
|
||||
setColor(grid, 3, 3, 1 as Color);
|
||||
|
||||
const chain = getBestRoute(grid, createSnake(snk0))!;
|
||||
const chain = getBestRoute(grid, createSnakeFromCells(snk0))!;
|
||||
|
||||
expect(snakeToCells(chain[0])[1]).toEqual({ x: 0, y: 0 });
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { copyGrid, isEmpty, setColorEmpty } from "./grid";
|
||||
import { getHeadX, getHeadY, snakeEquals } from "./snake";
|
||||
import { copyGrid, isEmpty, setColorEmpty } from "@snk/types/grid";
|
||||
import { getHeadX, getHeadY, snakeEquals } from "@snk/types/snake";
|
||||
import { sortPush } from "./utils/sortPush";
|
||||
import { arrayEquals } from "./utils/array";
|
||||
import { getAvailableRoutes } from "./getAvailableRoutes";
|
||||
import type { Snake } from "./snake";
|
||||
import type { Grid } from "./grid";
|
||||
import type { Point } from "./point";
|
||||
import type { Snake } from "@snk/types/snake";
|
||||
import type { Grid } from "@snk/types/grid";
|
||||
import type { Point } from "@snk/types/point";
|
||||
|
||||
type M = {
|
||||
snake: Snake;
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { isInsideLarge, getColor, isInside, isEmpty } from "./grid";
|
||||
import { around4 } from "./point";
|
||||
import { isInsideLarge, getColor, isInside, isEmpty } from "@snk/types/grid";
|
||||
import { around4 } from "@snk/types/point";
|
||||
import {
|
||||
getHeadX,
|
||||
getHeadY,
|
||||
nextSnake,
|
||||
snakeEquals,
|
||||
snakeWillSelfCollide,
|
||||
} from "./snake";
|
||||
} from "@snk/types/snake";
|
||||
import { sortPush } from "./utils/sortPush";
|
||||
import type { Snake } from "./snake";
|
||||
import type { Grid, Color } from "./grid";
|
||||
import type { Snake } from "@snk/types/snake";
|
||||
import type { Grid, Color } from "@snk/types/grid";
|
||||
|
||||
/**
|
||||
* get routes leading to non-empty cells until onSolution returns true
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { copyGrid, extractColors } from "./grid";
|
||||
import type { Snake } from "./snake";
|
||||
import type { Grid } from "./grid";
|
||||
import { copyGrid, isEmpty } from "@snk/types/grid";
|
||||
import { pruneLayer } from "./pruneLayer";
|
||||
import { cleanLayer } from "./cleanLayer";
|
||||
import type { Snake } from "@snk/types/snake";
|
||||
import type { Color, Grid } from "@snk/types/grid";
|
||||
|
||||
export const getBestRoute = (grid0: Grid, snake0: Snake) => {
|
||||
const grid = copyGrid(grid0);
|
||||
@@ -20,3 +20,11 @@ export const getBestRoute = (grid0: Grid, snake0: Snake) => {
|
||||
|
||||
return chain.reverse().slice(1);
|
||||
};
|
||||
|
||||
const extractColors = (grid: Grid): Color[] => {
|
||||
const colors = new Set<Color>();
|
||||
grid.data.forEach((c: any) => {
|
||||
if (!isEmpty(c)) colors.add(c);
|
||||
});
|
||||
return Array.from(colors.keys()).sort();
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { getColor, isEmpty, isInside, setColorEmpty } from "./grid";
|
||||
import { around4 } from "./point";
|
||||
import { getColor, isEmpty, isInside, setColorEmpty } from "@snk/types/grid";
|
||||
import { around4 } from "@snk/types/point";
|
||||
import { sortPush } from "./utils/sortPush";
|
||||
import type { Color, Grid } from "./grid";
|
||||
import type { Point } from "./point";
|
||||
import type { Color, Grid } from "@snk/types/grid";
|
||||
import type { Point } from "@snk/types/point";
|
||||
|
||||
type M = Point & { parent: M | null; h: number };
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@ import {
|
||||
isEmpty,
|
||||
isInside,
|
||||
setColorEmpty,
|
||||
} from "./grid";
|
||||
import { getHeadX, getHeadY, Snake } from "./snake";
|
||||
} from "@snk/types/grid";
|
||||
import { getHeadX, getHeadY, Snake } from "@snk/types/snake";
|
||||
|
||||
export const step = (grid: Grid, stack: Color[], snake: Snake) => {
|
||||
const x = getHeadX(snake);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Color, Grid } from "@snk/compute/grid";
|
||||
import { Color, Grid } from "@snk/types/grid";
|
||||
import { drawLerpWorld, drawWorld } from "@snk/draw/drawWorld";
|
||||
import { Snake } from "@snk/compute/snake";
|
||||
import { Snake } from "@snk/types/snake";
|
||||
|
||||
export const drawOptions = {
|
||||
sizeBorderRadius: 2,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { createCanvas } from "./canvas";
|
||||
import { snakeToCells } from "@snk/compute/snake";
|
||||
import { snakeToCells } from "@snk/types/snake";
|
||||
import { GUI } from "dat.gui";
|
||||
import { grid, snake } from "./sample";
|
||||
import { getAvailableRoutes } from "@snk/compute/getAvailableRoutes";
|
||||
import type { Point } from "@snk/compute/point";
|
||||
import type { Snake } from "@snk/compute/snake";
|
||||
import type { Point } from "@snk/types/point";
|
||||
import type { Snake } from "@snk/types/snake";
|
||||
|
||||
//
|
||||
// compute
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createCanvas } from "./canvas";
|
||||
import { getBestRoute } from "@snk/compute/getBestRoute";
|
||||
import { Color, copyGrid } from "../compute/grid";
|
||||
import { Color, copyGrid } from "@snk/types/grid";
|
||||
import { grid, snake } from "./sample";
|
||||
import { step } from "@snk/compute/step";
|
||||
import { isStableAndBound, stepSpring } from "./springUtils";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as grid from "@snk/compute/__fixtures__/grid";
|
||||
import * as grid from "@snk/types/__fixtures__/grid";
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.style.fontFamily = "helvetica";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createCanvas } from "./canvas";
|
||||
import { Color, copyGrid } from "../compute/grid";
|
||||
import { Color, copyGrid } from "@snk/types/grid";
|
||||
import { grid, snake } from "./sample";
|
||||
import { pruneLayer } from "@snk/compute/pruneLayer";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Grid } from "@snk/compute/grid";
|
||||
import { Snake } from "@snk/compute/snake";
|
||||
import * as grids from "@snk/compute/__fixtures__/grid";
|
||||
import * as snakes from "@snk/compute/__fixtures__/snake";
|
||||
import * as grids from "@snk/types/__fixtures__/grid";
|
||||
import * as snakes from "@snk/types/__fixtures__/snake";
|
||||
import type { Snake } from "@snk/types/snake";
|
||||
import type { Grid } from "@snk/types/grid";
|
||||
|
||||
const sp = new URLSearchParams(window.location.search);
|
||||
|
||||
|
||||
@@ -28,11 +28,10 @@ const config: Configuration = {
|
||||
test: /\.ts$/,
|
||||
loader: "ts-loader",
|
||||
options: {
|
||||
transpileOnly: true,
|
||||
compilerOptions: {
|
||||
lib: ["dom", "es2020"],
|
||||
target: "es2020",
|
||||
module: "es2020",
|
||||
moduleResolution: "node",
|
||||
target: "es5",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Color } from "@snk/compute/grid";
|
||||
import { pathRoundedRect } from "./pathRoundedRect";
|
||||
import { Point } from "@snk/compute/point";
|
||||
import type { Color } from "@snk/types/grid";
|
||||
import type { Point } from "@snk/types/point";
|
||||
|
||||
type Options = {
|
||||
colorDots: Record<Color, string>;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { getColor } from "@snk/compute/grid";
|
||||
import { getColor } from "@snk/types/grid";
|
||||
import { pathRoundedRect } from "./pathRoundedRect";
|
||||
import type { Grid, Color } from "@snk/compute/grid";
|
||||
import type { Point } from "@snk/compute/point";
|
||||
import type { Grid, Color } from "@snk/types/grid";
|
||||
import type { Point } from "@snk/types/point";
|
||||
|
||||
type Options = {
|
||||
colorDots: Record<Color, string>;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { pathRoundedRect } from "./pathRoundedRect";
|
||||
import { Snake, snakeToCells } from "@snk/compute/snake";
|
||||
import { snakeToCells } from "@snk/types/snake";
|
||||
import type { Snake } from "@snk/types/snake";
|
||||
|
||||
type Options = {
|
||||
colorSnake: string;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { drawGrid } from "./drawGrid";
|
||||
import { drawSnake, drawSnakeLerp } from "./drawSnake";
|
||||
import type { Grid, Color } from "@snk/compute/grid";
|
||||
import type { Point } from "@snk/compute/point";
|
||||
import type { Snake } from "@snk/compute/snake";
|
||||
import type { Grid, Color } from "@snk/types/grid";
|
||||
import type { Point } from "@snk/types/point";
|
||||
import type { Snake } from "@snk/types/snake";
|
||||
|
||||
export type Options = {
|
||||
colorDots: Record<Color, string>;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { performance } from "perf_hooks";
|
||||
import { createSnake, nextSnake } from "@snk/compute/snake";
|
||||
import { realistic as grid } from "@snk/compute/__fixtures__/grid";
|
||||
import { createSnakeFromCells, nextSnake } from "@snk/types/snake";
|
||||
import { realistic as grid } from "@snk/types/__fixtures__/grid";
|
||||
import { createGif } from "..";
|
||||
|
||||
let snake = createSnake(Array.from({ length: 6 }, (_, i) => ({ x: i, y: -1 })));
|
||||
let snake = createSnakeFromCells(
|
||||
Array.from({ length: 6 }, (_, i) => ({ x: i, y: -1 }))
|
||||
);
|
||||
|
||||
const chain = [snake];
|
||||
for (let y = -1; y < grid.height; y++) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { createGif } from "..";
|
||||
import * as grids from "@snk/compute/__fixtures__/grid";
|
||||
import { snake3 as snake } from "@snk/compute/__fixtures__/snake";
|
||||
import { createSnake, nextSnake } from "@snk/compute/snake";
|
||||
import * as grids from "@snk/types/__fixtures__/grid";
|
||||
import { snake3 as snake } from "@snk/types/__fixtures__/snake";
|
||||
import { createSnakeFromCells, nextSnake } from "@snk/types/snake";
|
||||
import { getBestRoute } from "@snk/compute/getBestRoute";
|
||||
|
||||
jest.setTimeout(20 * 1000);
|
||||
@@ -49,7 +49,9 @@ for (const key of [
|
||||
|
||||
it(`should generate swipper`, async () => {
|
||||
const grid = grids.smallFull;
|
||||
let snk = createSnake(Array.from({ length: 6 }, (_, i) => ({ x: i, y: -1 })));
|
||||
let snk = createSnakeFromCells(
|
||||
Array.from({ length: 6 }, (_, i) => ({ x: i, y: -1 }))
|
||||
);
|
||||
|
||||
const chain = [snk];
|
||||
for (let y = -1; y < grid.height; y++) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import { createCanvas } from "canvas";
|
||||
import { Grid, copyGrid, Color } from "@snk/compute/grid";
|
||||
import { Snake } from "@snk/compute/snake";
|
||||
import { Grid, copyGrid, Color } from "@snk/types/grid";
|
||||
import { Snake } from "@snk/types/snake";
|
||||
import {
|
||||
Options,
|
||||
drawLerpWorld,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// @ts-ignore
|
||||
import * as ParkMiller from "park-miller";
|
||||
import { Color, createEmptyGrid, setColor } from "@snk/compute/grid";
|
||||
import { fillRandomGrid } from "../generateGrid";
|
||||
import { Color, createEmptyGrid, setColor } from "../grid";
|
||||
import { randomlyFillGrid } from "../randomlyFillGrid";
|
||||
|
||||
const colors = [1, 2, 3] as Color[];
|
||||
|
||||
@@ -39,8 +39,11 @@ setColor(enclaveBorder, 2, 0, 1 as Color);
|
||||
const create = (width: number, height: number, emptyP: number) => {
|
||||
const grid = createEmptyGrid(width, height);
|
||||
const random = new ParkMiller(10);
|
||||
const rand = (a: number, b: number) => random.integerInRange(a, b - 1);
|
||||
fillRandomGrid(grid, { colors, emptyP }, rand);
|
||||
randomlyFillGrid(
|
||||
grid,
|
||||
{ colors, emptyP },
|
||||
random.integerInRange.bind(random)
|
||||
);
|
||||
return grid;
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// @ts-ignore
|
||||
import { createSnake } from "../snake";
|
||||
import { createSnakeFromCells } from "../snake";
|
||||
|
||||
const create = (length: number) =>
|
||||
createSnake(Array.from({ length }, (_, i) => ({ x: i, y: -1 })));
|
||||
createSnakeFromCells(Array.from({ length }, (_, i) => ({ x: i, y: -1 })));
|
||||
|
||||
export const snake1 = create(1);
|
||||
export const snake3 = create(3);
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
createSnake,
|
||||
createSnakeFromCells,
|
||||
nextSnake,
|
||||
snakeToCells,
|
||||
snakeWillSelfCollide,
|
||||
@@ -12,7 +12,7 @@ it("should convert to point", () => {
|
||||
{ x: 0, y: 0 },
|
||||
];
|
||||
|
||||
expect(snakeToCells(createSnake(snk0))).toEqual(snk0);
|
||||
expect(snakeToCells(createSnakeFromCells(snk0))).toEqual(snk0);
|
||||
});
|
||||
|
||||
it("should return next snake", () => {
|
||||
@@ -28,7 +28,9 @@ it("should return next snake", () => {
|
||||
{ x: 1, y: 0 },
|
||||
];
|
||||
|
||||
expect(snakeToCells(nextSnake(createSnake(snk0), 1, 0))).toEqual(snk1);
|
||||
expect(snakeToCells(nextSnake(createSnakeFromCells(snk0), 1, 0))).toEqual(
|
||||
snk1
|
||||
);
|
||||
});
|
||||
|
||||
it("should test snake collision", () => {
|
||||
@@ -38,6 +40,6 @@ it("should test snake collision", () => {
|
||||
{ x: 0, y: 0 },
|
||||
];
|
||||
|
||||
expect(snakeWillSelfCollide(createSnake(snk0), 1, 0)).toBe(false);
|
||||
expect(snakeWillSelfCollide(createSnake(snk0), 0, -1)).toBe(true);
|
||||
expect(snakeWillSelfCollide(createSnakeFromCells(snk0), 1, 0)).toBe(false);
|
||||
expect(snakeWillSelfCollide(createSnakeFromCells(snk0), 0, -1)).toBe(true);
|
||||
});
|
||||
@@ -7,9 +7,6 @@ export type Grid = {
|
||||
data: Uint8Array;
|
||||
};
|
||||
|
||||
export const getIndex = (grid: Grid, x: number, y: number) =>
|
||||
x * grid.height + y;
|
||||
|
||||
export const isInside = (grid: Grid, x: number, y: number) =>
|
||||
x >= 0 && y >= 0 && x < grid.width && y < grid.height;
|
||||
|
||||
@@ -22,6 +19,8 @@ export const copyGrid = ({ width, height, data }: Grid) => ({
|
||||
data: Uint8Array.from(data),
|
||||
});
|
||||
|
||||
const getIndex = (grid: Grid, x: number, y: number) => x * grid.height + y;
|
||||
|
||||
export const getColor = (grid: Grid, x: number, y: number) =>
|
||||
grid.data[getIndex(grid, x, y)] as Color | Empty;
|
||||
|
||||
@@ -45,55 +44,9 @@ export const setColorEmpty = (grid: Grid, x: number, y: number) => {
|
||||
*/
|
||||
export const isGridEmpty = (grid: Grid) => grid.data.every((x) => x === 0);
|
||||
|
||||
/**
|
||||
* extract colors
|
||||
* return a list of the colors found in the grid
|
||||
*/
|
||||
export const extractColors = (grid: Grid): Color[] => {
|
||||
const colors = new Set<Color>();
|
||||
grid.data.forEach((c: any) => {
|
||||
if (!isEmpty(c)) colors.add(c);
|
||||
});
|
||||
return Array.from(colors.keys()).sort();
|
||||
};
|
||||
|
||||
/**
|
||||
* extract colors count
|
||||
* return a list of the colors and their occurrences found in the grid
|
||||
*/
|
||||
export const extractColorCount = (grid: Grid) => {
|
||||
const colors = new Map<Color, number>();
|
||||
grid.data.forEach((c: any) => {
|
||||
if (!isEmpty(c)) colors.set(c, 1 + (colors.get(c) || 0));
|
||||
});
|
||||
return Array.from(colors.entries()).map(([color, count]) => ({
|
||||
color,
|
||||
count,
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* return true if the both are equals
|
||||
*/
|
||||
export const gridEquals = (a: Grid, b: Grid) =>
|
||||
a.data.every((_, i) => a.data[i] === b.data[i]);
|
||||
|
||||
/**
|
||||
* return a unique string for the grid
|
||||
*/
|
||||
export const getGridKey = ({ data }: Grid) => {
|
||||
let key = "";
|
||||
const n = 5;
|
||||
const radius = 1 << n;
|
||||
for (let k = 0; k < data.length; k += n) {
|
||||
let u = 0;
|
||||
for (let i = n; i--; ) u += (1 << i) * +!!data[k + i];
|
||||
|
||||
key += u.toString(radius);
|
||||
}
|
||||
return key;
|
||||
};
|
||||
|
||||
export const createEmptyGrid = (width: number, height: number) => ({
|
||||
width,
|
||||
height,
|
||||
7
packages/types/package.json
Normal file
7
packages/types/package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"name": "@snk/types",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"park-miller": "1.1.0"
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Grid, Color, setColor, setColorEmpty } from "./grid";
|
||||
|
||||
const defaultRand = (a: number, b: number) =>
|
||||
Math.floor(Math.random() * (b - a)) + a;
|
||||
Math.floor(Math.random() * (b - a + 1)) + a;
|
||||
|
||||
export const fillRandomGrid = (
|
||||
export const randomlyFillGrid = (
|
||||
grid: Grid,
|
||||
{
|
||||
colors = [1, 2, 3] as Color[],
|
||||
@@ -13,7 +13,7 @@ export const fillRandomGrid = (
|
||||
) => {
|
||||
for (let x = grid.width; x--; )
|
||||
for (let y = grid.height; y--; ) {
|
||||
const k = rand(-emptyP, colors.length);
|
||||
const k = rand(-emptyP, colors.length - 1);
|
||||
|
||||
if (k >= 0) setColor(grid, x, y, colors[k]);
|
||||
else setColorEmpty(grid, x, y);
|
||||
@@ -1,15 +1,20 @@
|
||||
import { Point } from "./point";
|
||||
import type { Point } from "./point";
|
||||
|
||||
export type Snake = Uint8Array & { _tag: "__Snake__" };
|
||||
|
||||
export const getHeadX = (snake: Snake) => snake[0] - 2;
|
||||
export const getHeadY = (snake: Snake) => snake[1] - 2;
|
||||
|
||||
export const copySnake = (snake: Snake) => snake.slice() as Snake;
|
||||
|
||||
export const snakeEquals = (a: Snake, b: Snake) => {
|
||||
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* return a copy of the next snake, considering that dx, dy is the direction
|
||||
*/
|
||||
export const nextSnake = (snake: Snake, dx: number, dy: number) => {
|
||||
const copy = new Uint8Array(snake.length);
|
||||
for (let i = 2; i < snake.length; i++) copy[i] = snake[i - 2];
|
||||
@@ -18,6 +23,9 @@ export const nextSnake = (snake: Snake, dx: number, dy: number) => {
|
||||
return copy as Snake;
|
||||
};
|
||||
|
||||
/**
|
||||
* return true if the next snake will collide with itself
|
||||
*/
|
||||
export const snakeWillSelfCollide = (snake: Snake, dx: number, dy: number) => {
|
||||
const nx = snake[0] + dx;
|
||||
const ny = snake[1] + dy;
|
||||
@@ -28,13 +36,13 @@ export const snakeWillSelfCollide = (snake: Snake, dx: number, dy: number) => {
|
||||
return false;
|
||||
};
|
||||
|
||||
export const snakeToCells = (snake: Snake) =>
|
||||
export const snakeToCells = (snake: Snake): Point[] =>
|
||||
Array.from({ length: snake.length / 2 }, (_, i) => ({
|
||||
x: snake[i * 2 + 0] - 2,
|
||||
y: snake[i * 2 + 1] - 2,
|
||||
}));
|
||||
|
||||
export const createSnake = (points: Point[]) => {
|
||||
export const createSnakeFromCells = (points: Point[]) => {
|
||||
const snake = new Uint8Array(points.length * 2);
|
||||
for (let i = points.length; i--; ) {
|
||||
snake[i * 2 + 0] = points[i].x + 2;
|
||||
@@ -42,5 +50,3 @@ export const createSnake = (points: Point[]) => {
|
||||
}
|
||||
return snake as Snake;
|
||||
};
|
||||
|
||||
export const copySnake = (snake: Snake) => snake.slice() as Snake;
|
||||
Reference in New Issue
Block a user