Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83033510f0 | ||
|
|
a69d1dbca7 | ||
|
|
f2057e5efe | ||
|
|
7fbc58b61d | ||
|
|
1f7630d984 | ||
|
|
852f0ae376 | ||
|
|
10c4c3c7bd | ||
|
|
ace186c41f | ||
|
|
79c252356c | ||
|
|
3c171061b3 | ||
|
|
4783e68ce7 | ||
|
|
85da3901f5 | ||
|
|
74bc4f0651 | ||
|
|
e55fe1f13c | ||
|
|
876448a004 | ||
|
|
d35dc83cf2 | ||
|
|
bb7d69dde8 | ||
|
|
14a003db51 | ||
|
|
2479713155 | ||
|
|
debec31440 | ||
|
|
5332254423 | ||
|
|
a9052b7ca2 |
52
.github/workflows/main.yml
vendored
52
.github/workflows/main.yml
vendored
@@ -8,15 +8,13 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: oven-sh/setup-bun@v1
|
||||||
with:
|
|
||||||
cache: yarn
|
- run: bun install --frozen-lockfile
|
||||||
node-version: 20
|
|
||||||
- run: yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
- run: npm run type
|
- run: npm run type
|
||||||
- run: npm run lint
|
- run: npm run lint
|
||||||
- run: npm run test --ci
|
- run: bun test
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
@@ -46,7 +44,7 @@ jobs:
|
|||||||
test -f dist/github-contribution-grid-snake-dark.svg
|
test -f dist/github-contribution-grid-snake-dark.svg
|
||||||
test -f dist/github-contribution-grid-snake.gif
|
test -f dist/github-contribution-grid-snake.gif
|
||||||
|
|
||||||
- uses: crazy-max/ghaction-github-pages@v3.1.0
|
- uses: crazy-max/ghaction-github-pages@v4.1.0
|
||||||
with:
|
with:
|
||||||
target_branch: output
|
target_branch: output
|
||||||
build_dir: dist
|
build_dir: dist
|
||||||
@@ -57,11 +55,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: oven-sh/setup-bun@v1
|
||||||
with:
|
|
||||||
cache: yarn
|
- run: bun install --frozen-lockfile
|
||||||
node-version: 20
|
|
||||||
- run: yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: build svg-only action
|
- name: build svg-only action
|
||||||
run: |
|
run: |
|
||||||
@@ -77,14 +73,16 @@ jobs:
|
|||||||
outputs: |
|
outputs: |
|
||||||
dist/github-contribution-grid-snake.svg
|
dist/github-contribution-grid-snake.svg
|
||||||
dist/github-contribution-grid-snake-dark.svg?palette=github-dark
|
dist/github-contribution-grid-snake-dark.svg?palette=github-dark
|
||||||
|
dist/github-contribution-grid-snake-blue.svg?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9
|
||||||
|
|
||||||
- name: ensure the generated file exists
|
- name: ensure the generated file exists
|
||||||
run: |
|
run: |
|
||||||
ls dist
|
ls dist
|
||||||
test -f dist/github-contribution-grid-snake.svg
|
test -f dist/github-contribution-grid-snake.svg
|
||||||
test -f dist/github-contribution-grid-snake-dark.svg
|
test -f dist/github-contribution-grid-snake-dark.svg
|
||||||
|
test -f dist/github-contribution-grid-snake-blue.svg
|
||||||
|
|
||||||
- uses: crazy-max/ghaction-github-pages@v3.1.0
|
- uses: crazy-max/ghaction-github-pages@v4.1.0
|
||||||
with:
|
with:
|
||||||
target_branch: output-svg-only
|
target_branch: output-svg-only
|
||||||
build_dir: dist
|
build_dir: dist
|
||||||
@@ -93,22 +91,28 @@ jobs:
|
|||||||
|
|
||||||
deploy-ghpages:
|
deploy-ghpages:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- uses: actions/setup-node@v3
|
- uses: oven-sh/setup-bun@v1
|
||||||
with:
|
|
||||||
cache: yarn
|
- run: bun install --frozen-lockfile
|
||||||
node-version: 20
|
|
||||||
- run: yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
- run: npm run build:demo
|
- run: npm run build:demo
|
||||||
env:
|
env:
|
||||||
GITHUB_USER_CONTRIBUTION_API_ENDPOINT: https://snk-one.vercel.app/api/github-user-contribution/
|
GITHUB_USER_CONTRIBUTION_API_ENDPOINT: https://github-user-contribution.platane.workers.dev/github-user-contribution/
|
||||||
|
|
||||||
- uses: crazy-max/ghaction-github-pages@v3.1.0
|
- uses: actions/upload-pages-artifact@v3
|
||||||
if: success() && github.ref == 'refs/heads/main'
|
|
||||||
with:
|
with:
|
||||||
target_branch: gh-pages
|
path: packages/demo/dist
|
||||||
build_dir: packages/demo/dist
|
|
||||||
|
- uses: actions/deploy-pages@v4
|
||||||
|
if: success() && github.ref == 'refs/heads/main'
|
||||||
|
|
||||||
|
- run: bunx wrangler deploy
|
||||||
|
if: success() && github.ref == 'refs/heads/main'
|
||||||
|
working-directory: packages/github-user-contribution-service
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.MY_GITHUB_TOKEN_GH_PAGES }}
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
|||||||
47
.github/workflows/manual-run.yml
vendored
Normal file
47
.github/workflows/manual-run.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: manual run
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
generate:
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 5
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: Platane/snk/svg-only@v3
|
||||||
|
with:
|
||||||
|
github_user_name: ${{ github.repository_owner }}
|
||||||
|
outputs: |
|
||||||
|
dist/only-svg/github-contribution-grid-snake.svg
|
||||||
|
dist/only-svg/github-contribution-grid-snake-dark.svg?palette=github-dark
|
||||||
|
dist/only-svg/github-contribution-grid-snake-blue.svg?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9
|
||||||
|
|
||||||
|
- uses: Platane/snk@v3
|
||||||
|
with:
|
||||||
|
github_user_name: ${{ github.repository_owner }}
|
||||||
|
outputs: |
|
||||||
|
dist/docker/github-contribution-grid-snake.svg
|
||||||
|
dist/docker/github-contribution-grid-snake-dark.svg?palette=github-dark
|
||||||
|
dist/docker/github-contribution-grid-snake.gif?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9
|
||||||
|
|
||||||
|
- name: ensure the generated file exists
|
||||||
|
run: |
|
||||||
|
ls dist
|
||||||
|
test -f dist/only-svg/github-contribution-grid-snake.svg
|
||||||
|
test -f dist/only-svg/github-contribution-grid-snake-dark.svg
|
||||||
|
test -f dist/only-svg/github-contribution-grid-snake-blue.svg
|
||||||
|
|
||||||
|
test -f dist/docker/github-contribution-grid-snake.svg
|
||||||
|
test -f dist/docker/github-contribution-grid-snake-dark.svg
|
||||||
|
test -f dist/docker/github-contribution-grid-snake.gif
|
||||||
|
|
||||||
|
- name: push github-contribution-grid-snake.svg to the output branch
|
||||||
|
uses: crazy-max/ghaction-github-pages@v4.1.0
|
||||||
|
with:
|
||||||
|
target_branch: manual-run-output
|
||||||
|
build_dir: dist
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
@@ -45,20 +45,18 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sed -i "s/image: .*/image: docker:\/\/platane\/snk@${{ steps.docker-build.outputs.digest }}/" action.yml
|
sed -i "s/image: .*/image: docker:\/\/platane\/snk@${{ steps.docker-build.outputs.digest }}/" action.yml
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
- uses: oven-sh/setup-bun@v1
|
||||||
with:
|
|
||||||
cache: yarn
|
- run: bun install --frozen-lockfile
|
||||||
node-version: 20
|
|
||||||
|
|
||||||
- name: build svg-only action
|
- name: build svg-only action
|
||||||
run: |
|
run: |
|
||||||
yarn install --frozen-lockfile
|
|
||||||
npm run build:action
|
npm run build:action
|
||||||
rm -r svg-only/dist
|
rm -r svg-only/dist
|
||||||
mv packages/action/dist svg-only/dist
|
mv packages/action/dist svg-only/dist
|
||||||
|
|
||||||
- name: bump package version
|
- name: bump package version
|
||||||
run: yarn version --no-git-tag-version --new-version ${{ github.event.inputs.version }}
|
run: npm version --no-git-tag-version --new-version ${{ github.event.inputs.version }}
|
||||||
|
|
||||||
- name: push new build, tag version and push
|
- name: push new build, tag version and push
|
||||||
id: push-tags
|
id: push-tags
|
||||||
@@ -77,13 +75,11 @@ jobs:
|
|||||||
git tag v$( echo $VERSION | cut -d. -f 1-2 )
|
git tag v$( echo $VERSION | cut -d. -f 1-2 )
|
||||||
git push origin --tags --force
|
git push origin --tags --force
|
||||||
echo "prerelease=false" >> $GITHUB_OUTPUT
|
echo "prerelease=false" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "prerelease=true" >> $GITHUB_OUTPUT
|
echo "prerelease=true" >> $GITHUB_OUTPUT
|
||||||
fi
|
fi
|
||||||
|
|
||||||
- uses: ncipollo/release-action@v1.12.0
|
- uses: ncipollo/release-action@v1.15.0
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
with:
|
with:
|
||||||
tag: v${{ github.event.inputs.version }}
|
tag: v${{ github.event.inputs.version }}
|
||||||
body: ${{ github.event.inputs.description }}
|
body: ${{ github.event.inputs.description }}
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -1,7 +1,8 @@
|
|||||||
node_modules
|
node_modules
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-error.log*
|
|
||||||
dist
|
dist
|
||||||
!svg-only/dist
|
!svg-only/dist
|
||||||
build
|
build
|
||||||
.env
|
.env
|
||||||
|
.wrangler
|
||||||
|
.dev.vars
|
||||||
|
|||||||
19
Dockerfile
19
Dockerfile
@@ -1,32 +1,27 @@
|
|||||||
FROM node:20-slim as builder
|
FROM oven/bun:1.2.2-slim as builder
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY package.json yarn.lock ./
|
COPY package.json bun.lock ./
|
||||||
|
|
||||||
COPY tsconfig.json ./
|
COPY tsconfig.json ./
|
||||||
|
|
||||||
COPY packages packages
|
COPY packages packages
|
||||||
|
|
||||||
RUN export YARN_CACHE_FOLDER="$(mktemp -d)" \
|
RUN bun install --no-cache
|
||||||
&& yarn install --frozen-lockfile \
|
|
||||||
&& rm -r "$YARN_CACHE_FOLDER"
|
|
||||||
|
|
||||||
RUN yarn build:action
|
RUN bun run build:action
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FROM node:20-slim
|
FROM oven/bun:1.2.2-slim
|
||||||
|
|
||||||
WORKDIR /action-release
|
WORKDIR /action-release
|
||||||
|
|
||||||
RUN export YARN_CACHE_FOLDER="$(mktemp -d)" \
|
RUN bun add canvas@3.1.0 gifsicle@5.3.0 --no-lockfile --no-cache
|
||||||
&& yarn add canvas@2.11.2 gifsicle@5.3.0 --no-lockfile \
|
|
||||||
&& rm -r "$YARN_CACHE_FOLDER"
|
|
||||||
|
|
||||||
COPY --from=builder /app/packages/action/dist/ /action-release/
|
COPY --from=builder /app/packages/action/dist/ /action-release/
|
||||||
|
|
||||||
CMD ["node", "/action-release/index.js"]
|
CMD ["bun", "/action-release/index.js"]
|
||||||
|
|
||||||
|
|||||||
@@ -54,13 +54,9 @@ Available as github action. It can automatically generate a new image each day.
|
|||||||
dist/github-snake.svg
|
dist/github-snake.svg
|
||||||
dist/github-snake-dark.svg?palette=github-dark
|
dist/github-snake-dark.svg?palette=github-dark
|
||||||
dist/ocean.gif?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9
|
dist/ocean.gif?color_snake=orange&color_dots=#bfd6f6,#8dbdff,#64a1f4,#4b91f1,#3c7dd9
|
||||||
|
|
||||||
env:
|
|
||||||
# a github token is required to fetch the contribution calendar from github API
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
[example with cron job](https://github.com/Platane/Platane/blob/master/.github/workflows/main.yml#L26-L35)
|
[example with cron job](https://github.com/Platane/Platane/blob/master/.github/workflows/main.yml#L26-L33)
|
||||||
|
|
||||||
If you are only interested in generating a svg, consider using this faster action: `uses: Platane/snk/svg-only@v3`
|
If you are only interested in generating a svg, consider using this faster action: `uses: Platane/snk/svg-only@v3`
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ author: "platane"
|
|||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: docker
|
using: docker
|
||||||
image: docker://platane/snk@sha256:1c8a0b51a75ad8cf36b7defddd2187bdbb92bbbb5521a9e6cc5df795b00fc590
|
image: docker://platane/snk@sha256:96390294299275740e5963058c9784c60c5393b3b8b16082dcf41b240db791f9
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
github_user_name:
|
github_user_name:
|
||||||
@@ -16,7 +16,6 @@ inputs:
|
|||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
outputs:
|
outputs:
|
||||||
required: false
|
required: false
|
||||||
default: null
|
|
||||||
description: |
|
description: |
|
||||||
list of files to generate.
|
list of files to generate.
|
||||||
one file per line. Each output can be customized with options as query string.
|
one file per line. Each output can be customized with options as query string.
|
||||||
|
|||||||
24
package.json
24
package.json
@@ -1,34 +1,20 @@
|
|||||||
{
|
{
|
||||||
"name": "snk",
|
"name": "snk",
|
||||||
"description": "Generates a snake game from a github user contributions grid",
|
"description": "Generates a snake game from a github user contributions grid",
|
||||||
"version": "3.2.0",
|
"version": "3.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": "github:platane/snk",
|
"repository": "github:platane/snk",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sucrase/jest-plugin": "3.0.0",
|
"@types/bun": "1.2.2",
|
||||||
"@types/jest": "29.5.5",
|
"prettier": "3.5.1",
|
||||||
"@types/node": "20.6.3",
|
"typescript": "5.7.3"
|
||||||
"jest": "29.7.0",
|
|
||||||
"prettier": "2.8.8",
|
|
||||||
"sucrase": "3.34.0",
|
|
||||||
"typescript": "5.2.2"
|
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/**"
|
"packages/*"
|
||||||
],
|
],
|
||||||
"jest": {
|
|
||||||
"testEnvironment": "node",
|
|
||||||
"testMatch": [
|
|
||||||
"**/__tests__/**/?(*.)+(spec|test).ts"
|
|
||||||
],
|
|
||||||
"transform": {
|
|
||||||
"\\.(ts|tsx)$": "@sucrase/jest-plugin"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"type": "tsc --noEmit",
|
"type": "tsc --noEmit",
|
||||||
"lint": "prettier -c '**/*.{ts,js,json,md,yml,yaml}' '!packages/*/dist/**' '!svg-only/dist/**'",
|
"lint": "prettier -c '**/*.{ts,js,json,md,yml,yaml}' '!packages/*/dist/**' '!svg-only/dist/**'",
|
||||||
"test": "jest --verbose --no-cache",
|
|
||||||
"dev:demo": "( cd packages/demo ; npm run dev )",
|
"dev:demo": "( cd packages/demo ; npm run dev )",
|
||||||
"build:demo": "( cd packages/demo ; npm run build )",
|
"build:demo": "( cd packages/demo ; npm run build )",
|
||||||
"build:action": "( cd packages/action ; npm run build )"
|
"build:action": "( cd packages/action ; npm run build )"
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
import { it, expect } from "bun:test";
|
||||||
import { generateContributionSnake } from "../generateContributionSnake";
|
import { generateContributionSnake } from "../generateContributionSnake";
|
||||||
import { parseOutputsOption } from "../outputsOptions";
|
import { parseOutputsOption } from "../outputsOptions";
|
||||||
import { config } from "dotenv";
|
|
||||||
config({ path: __dirname + "/../../../.env" });
|
|
||||||
|
|
||||||
jest.setTimeout(2 * 60 * 1000);
|
|
||||||
|
|
||||||
const silent = (handler: () => void | Promise<void>) => async () => {
|
const silent = (handler: () => void | Promise<void>) => async () => {
|
||||||
const originalConsoleLog = console.log;
|
const originalConsoleLog = console.log;
|
||||||
@@ -43,5 +40,6 @@ it(
|
|||||||
fs.writeFileSync(outputs[0]!.filename, results[0]!);
|
fs.writeFileSync(outputs[0]!.filename, results[0]!);
|
||||||
fs.writeFileSync(outputs[1]!.filename, results[1]!);
|
fs.writeFileSync(outputs[1]!.filename, results[1]!);
|
||||||
fs.writeFileSync(outputs[2]!.filename, results[2]!);
|
fs.writeFileSync(outputs[2]!.filename, results[2]!);
|
||||||
})
|
}),
|
||||||
|
{ timeout: 2 * 60 * 1000 },
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,43 +1,44 @@
|
|||||||
import { parseEntry } from "../outputsOptions";
|
import { parseEntry } from "../outputsOptions";
|
||||||
|
import { it, expect } from "bun:test";
|
||||||
|
|
||||||
it("should parse options as json", () => {
|
it("should parse options as json", () => {
|
||||||
expect(
|
expect(
|
||||||
parseEntry(`/out.svg {"color_snake":"yellow"}`)?.drawOptions
|
parseEntry(`/out.svg {"color_snake":"yellow"}`)?.drawOptions,
|
||||||
).toHaveProperty("colorSnake", "yellow");
|
).toHaveProperty("colorSnake", "yellow");
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
parseEntry(`/out.svg?{"color_snake":"yellow"}`)?.drawOptions
|
parseEntry(`/out.svg?{"color_snake":"yellow"}`)?.drawOptions,
|
||||||
).toHaveProperty("colorSnake", "yellow");
|
).toHaveProperty("colorSnake", "yellow");
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
parseEntry(`/out.svg?{"color_dots":["#000","#111","#222","#333","#444"]}`)
|
parseEntry(`/out.svg?{"color_dots":["#000","#111","#222","#333","#444"]}`)
|
||||||
?.drawOptions.colorDots
|
?.drawOptions.colorDots,
|
||||||
).toEqual(["#000", "#111", "#222", "#333", "#444"]);
|
).toEqual(["#000", "#111", "#222", "#333", "#444"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should parse options as searchparams", () => {
|
it("should parse options as searchparams", () => {
|
||||||
expect(parseEntry(`/out.svg?color_snake=yellow`)?.drawOptions).toHaveProperty(
|
expect(parseEntry(`/out.svg?color_snake=yellow`)?.drawOptions).toHaveProperty(
|
||||||
"colorSnake",
|
"colorSnake",
|
||||||
"yellow"
|
"yellow",
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
parseEntry(`/out.svg?color_dots=#000,#111,#222,#333,#444`)?.drawOptions
|
parseEntry(`/out.svg?color_dots=#000,#111,#222,#333,#444`)?.drawOptions
|
||||||
.colorDots
|
.colorDots,
|
||||||
).toEqual(["#000", "#111", "#222", "#333", "#444"]);
|
).toEqual(["#000", "#111", "#222", "#333", "#444"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should parse filename", () => {
|
it("should parse filename", () => {
|
||||||
expect(parseEntry(`/a/b/c.svg?{"color_snake":"yellow"}`)).toHaveProperty(
|
expect(parseEntry(`/a/b/c.svg?{"color_snake":"yellow"}`)).toHaveProperty(
|
||||||
"filename",
|
"filename",
|
||||||
"/a/b/c.svg"
|
"/a/b/c.svg",
|
||||||
);
|
);
|
||||||
expect(
|
expect(
|
||||||
parseEntry(`/a/b/out.svg?.gif.svg?{"color_snake":"yellow"}`)
|
parseEntry(`/a/b/out.svg?.gif.svg?{"color_snake":"yellow"}`),
|
||||||
).toHaveProperty("filename", "/a/b/out.svg?.gif.svg");
|
).toHaveProperty("filename", "/a/b/out.svg?.gif.svg");
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
parseEntry(`/a/b/{[-1].svg?.gif.svg?{"color_snake":"yellow"}`)
|
parseEntry(`/a/b/{[-1].svg?.gif.svg?{"color_snake":"yellow"}`),
|
||||||
).toHaveProperty("filename", "/a/b/{[-1].svg?.gif.svg");
|
).toHaveProperty("filename", "/a/b/{[-1].svg?.gif.svg");
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -56,5 +57,5 @@ it("should parse filename", () => {
|
|||||||
].forEach((entry) =>
|
].forEach((entry) =>
|
||||||
it(`should parse ${entry}`, () => {
|
it(`should parse ${entry}`, () => {
|
||||||
expect(parseEntry(entry)).toMatchSnapshot();
|
expect(parseEntry(entry)).toMatchSnapshot();
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const generateContributionSnake = async (
|
|||||||
drawOptions: DrawOptions;
|
drawOptions: DrawOptions;
|
||||||
animationOptions: AnimationOptions;
|
animationOptions: AnimationOptions;
|
||||||
} | null)[],
|
} | null)[],
|
||||||
options: { githubToken: string }
|
options: { githubToken: string },
|
||||||
) => {
|
) => {
|
||||||
console.log("🎣 fetching github user contribution");
|
console.log("🎣 fetching github user contribution");
|
||||||
const cells = await getGithubUserContribution(userName, options);
|
const cells = await getGithubUserContribution(userName, options);
|
||||||
@@ -43,10 +43,10 @@ export const generateContributionSnake = async (
|
|||||||
cells,
|
cells,
|
||||||
chain,
|
chain,
|
||||||
drawOptions,
|
drawOptions,
|
||||||
animationOptions
|
animationOptions,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { parseOutputsOption } from "./outputsOptions";
|
|||||||
core.getMultilineInput("outputs") ?? [
|
core.getMultilineInput("outputs") ?? [
|
||||||
core.getInput("gif_out_path"),
|
core.getInput("gif_out_path"),
|
||||||
core.getInput("svg_out_path"),
|
core.getInput("svg_out_path"),
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
const githubToken =
|
const githubToken =
|
||||||
process.env.GITHUB_TOKEN ?? core.getInput("github_token");
|
process.env.GITHUB_TOKEN ?? core.getInput("github_token");
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "@snk/action",
|
"name": "@snk/action",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/core": "1.10.1",
|
"@actions/core": "1.11.1",
|
||||||
"@snk/gif-creator": "1.0.0",
|
"@snk/gif-creator": "1.0.0",
|
||||||
"@snk/github-user-contribution": "1.0.0",
|
"@snk/github-user-contribution": "1.0.0",
|
||||||
"@snk/solver": "1.0.0",
|
"@snk/solver": "1.0.0",
|
||||||
@@ -10,11 +10,9 @@
|
|||||||
"@snk/types": "1.0.0"
|
"@snk/types": "1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vercel/ncc": "0.38.0",
|
"@vercel/ncc": "0.38.3"
|
||||||
"dotenv": "16.3.1"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ncc build --external canvas --external gifsicle --out dist ./index.ts",
|
"build": "ncc build --external canvas --external gifsicle --out dist ./index.ts"
|
||||||
"run:build": "INPUT_GITHUB_USER_NAME=platane INPUT_OUTPUTS='dist/out.svg' node dist/index.js"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export const createCanvas = ({
|
|||||||
snake0: Snake,
|
snake0: Snake,
|
||||||
snake1: Snake,
|
snake1: Snake,
|
||||||
stack: Color[],
|
stack: Color[],
|
||||||
k: number
|
k: number,
|
||||||
) => {
|
) => {
|
||||||
ctx.clearRect(0, 0, 9999, 9999);
|
ctx.clearRect(0, 0, 9999, 9999);
|
||||||
drawLerpWorld(ctx, grid, null, snake0, snake1, stack, k, drawOptions);
|
drawLerpWorld(ctx, grid, null, snake0, snake1, stack, k, drawOptions);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const tunnels = ones.map(({ x, y }) => ({
|
|||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
3 as Color,
|
3 as Color,
|
||||||
getSnakeLength(snake)
|
getSnakeLength(snake),
|
||||||
),
|
),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const { canvas, ctx, draw, highlightCell } = createCanvas(grid);
|
|||||||
canvas.style.pointerEvents = "auto";
|
canvas.style.pointerEvents = "auto";
|
||||||
|
|
||||||
const target = createSnakeFromCells(
|
const target = createSnakeFromCells(
|
||||||
snakeToCells(snake).map((p) => ({ ...p, x: p.x - 1 }))
|
snakeToCells(snake).map((p) => ({ ...p, x: p.x - 1 })),
|
||||||
);
|
);
|
||||||
|
|
||||||
let chain = [snake, ...getPathToPose(snake, target)!];
|
let chain = [snake, ...getPathToPose(snake, target)!];
|
||||||
|
|||||||
@@ -253,7 +253,7 @@ const createViewer = ({
|
|||||||
: "") +
|
: "") +
|
||||||
`<a href="${svgLink.href}" download="github-user-contribution.svg">` +
|
`<a href="${svgLink.href}" download="github-user-contribution.svg">` +
|
||||||
svgString +
|
svgString +
|
||||||
"<a/>"
|
"<a/>",
|
||||||
);
|
);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
});
|
});
|
||||||
@@ -277,7 +277,7 @@ const createViewer = ({
|
|||||||
|
|
||||||
const onSubmit = async (userName: string) => {
|
const onSubmit = async (userName: string) => {
|
||||||
const res = await fetch(
|
const res = await fetch(
|
||||||
process.env.GITHUB_USER_CONTRIBUTION_API_ENDPOINT + userName
|
process.env.GITHUB_USER_CONTRIBUTION_API_ENDPOINT + userName,
|
||||||
);
|
);
|
||||||
const cells = (await res.json()) as Res;
|
const cells = (await res.json()) as Res;
|
||||||
|
|
||||||
@@ -294,8 +294,8 @@ const worker = new Worker(
|
|||||||
new URL(
|
new URL(
|
||||||
"./demo.interactive.worker.ts",
|
"./demo.interactive.worker.ts",
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import.meta.url
|
import.meta.url,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
const { getChain } = createRpcClient<WorkerAPI>(worker);
|
const { getChain } = createRpcClient<WorkerAPI>(worker);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ const onChange = () => {
|
|||||||
|
|
||||||
const url = new URL(
|
const url = new URL(
|
||||||
config.demo + ".html?" + search,
|
config.demo + ".html?" + search,
|
||||||
window.location.href
|
window.location.href,
|
||||||
).toString();
|
).toString();
|
||||||
|
|
||||||
window.location.href = url;
|
window.location.href = url;
|
||||||
|
|||||||
@@ -10,15 +10,15 @@
|
|||||||
"@snk/types": "1.0.0"
|
"@snk/types": "1.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"dotenv": "16.3.1",
|
"@types/dat.gui": "0.7.13",
|
||||||
"@types/dat.gui": "0.7.10",
|
|
||||||
"dat.gui": "0.7.9",
|
"dat.gui": "0.7.9",
|
||||||
"html-webpack-plugin": "5.5.3",
|
"dotenv": "16.4.7",
|
||||||
"ts-loader": "9.4.4",
|
"html-webpack-plugin": "5.6.3",
|
||||||
"ts-node": "10.9.1",
|
"ts-loader": "9.5.2",
|
||||||
"webpack": "5.88.2",
|
"ts-node": "10.9.2",
|
||||||
"webpack-cli": "5.1.4",
|
"webpack": "5.98.0",
|
||||||
"webpack-dev-server": "4.15.1"
|
"webpack-cli": "6.0.1",
|
||||||
|
"webpack-dev-server": "5.2.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack",
|
"build": "webpack",
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const stepSpringOne = (
|
|||||||
maxVelocity = Infinity,
|
maxVelocity = Infinity,
|
||||||
}: { tension: number; friction: number; maxVelocity?: number },
|
}: { tension: number; friction: number; maxVelocity?: number },
|
||||||
target: number,
|
target: number,
|
||||||
dt = 1 / 60
|
dt = 1 / 60,
|
||||||
) => {
|
) => {
|
||||||
const a = -tension * (s.x - target) - friction * s.v;
|
const a = -tension * (s.x - target) - friction * s.v;
|
||||||
|
|
||||||
@@ -31,13 +31,13 @@ const stepSpringOne = (
|
|||||||
export const isStable = (
|
export const isStable = (
|
||||||
s: { x: number; v: number },
|
s: { x: number; v: number },
|
||||||
target: number,
|
target: number,
|
||||||
dt = 1 / 60
|
dt = 1 / 60,
|
||||||
) => Math.abs(s.x - target) < epsilon && Math.abs(s.v * dt) < epsilon;
|
) => Math.abs(s.x - target) < epsilon && Math.abs(s.v * dt) < epsilon;
|
||||||
|
|
||||||
export const isStableAndBound = (
|
export const isStableAndBound = (
|
||||||
s: { x: number; v: number },
|
s: { x: number; v: number },
|
||||||
target: number,
|
target: number,
|
||||||
dt?: number
|
dt?: number,
|
||||||
) => {
|
) => {
|
||||||
const stable = isStable(s, target, dt);
|
const stable = isStable(s, target, dt);
|
||||||
if (stable) {
|
if (stable) {
|
||||||
@@ -51,7 +51,7 @@ export const stepSpring = (
|
|||||||
s: { x: number; v: number },
|
s: { x: number; v: number },
|
||||||
params: { tension: number; friction: number; maxVelocity?: number },
|
params: { tension: number; friction: number; maxVelocity?: number },
|
||||||
target: number,
|
target: number,
|
||||||
dt = 1 / 60
|
dt = 1 / 60,
|
||||||
) => {
|
) => {
|
||||||
const interval = 1 / 60;
|
const interval = 1 / 60;
|
||||||
|
|
||||||
|
|||||||
@@ -2,31 +2,39 @@ import path from "path";
|
|||||||
import HtmlWebpackPlugin from "html-webpack-plugin";
|
import HtmlWebpackPlugin from "html-webpack-plugin";
|
||||||
import webpack from "webpack";
|
import webpack from "webpack";
|
||||||
import { getGithubUserContribution } from "@snk/github-user-contribution";
|
import { getGithubUserContribution } from "@snk/github-user-contribution";
|
||||||
import { config } from "dotenv";
|
|
||||||
import type { Configuration as WebpackConfiguration } from "webpack";
|
import type { Configuration as WebpackConfiguration } from "webpack";
|
||||||
import type { Configuration as WebpackDevServerConfiguration } from "webpack-dev-server";
|
import {
|
||||||
|
ExpressRequestHandler,
|
||||||
|
type Configuration as WebpackDevServerConfiguration,
|
||||||
|
} from "webpack-dev-server";
|
||||||
|
import { config } from "dotenv";
|
||||||
config({ path: __dirname + "/../../.env" });
|
config({ path: __dirname + "/../../.env" });
|
||||||
|
|
||||||
const demos: string[] = require("./demo.json");
|
const demos: string[] = require("./demo.json");
|
||||||
|
|
||||||
const webpackDevServerConfiguration: WebpackDevServerConfiguration = {
|
const webpackDevServerConfiguration: WebpackDevServerConfiguration = {
|
||||||
open: { target: demos[1] + ".html" },
|
open: { target: demos[1] + ".html" },
|
||||||
onAfterSetupMiddleware: ({ app }) => {
|
setupMiddlewares: (ms) => [
|
||||||
app!.get("/api/github-user-contribution/:userName", async (req, res) => {
|
...ms,
|
||||||
const userName: string = req.params.userName;
|
(async (req, res, next) => {
|
||||||
res.send(
|
const userName = req.url.match(
|
||||||
await getGithubUserContribution(userName, {
|
/\/api\/github-user-contribution\/(\w+)/,
|
||||||
githubToken: process.env.GITHUB_TOKEN!,
|
)?.[1];
|
||||||
})
|
if (userName)
|
||||||
);
|
res.send(
|
||||||
});
|
await getGithubUserContribution(userName, {
|
||||||
},
|
githubToken: process.env.GITHUB_TOKEN!,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
else next();
|
||||||
|
}) as ExpressRequestHandler,
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const webpackConfiguration: WebpackConfiguration = {
|
const webpackConfiguration: WebpackConfiguration = {
|
||||||
mode: "development",
|
mode: "development",
|
||||||
entry: Object.fromEntries(
|
entry: Object.fromEntries(
|
||||||
demos.map((demo: string) => [demo, `./demo.${demo}`])
|
demos.map((demo: string) => [demo, `./demo.${demo}`]),
|
||||||
),
|
),
|
||||||
target: ["web", "es2019"],
|
target: ["web", "es2019"],
|
||||||
resolve: { extensions: [".ts", ".js"] },
|
resolve: { extensions: [".ts", ".js"] },
|
||||||
@@ -57,7 +65,7 @@ const webpackConfiguration: WebpackConfiguration = {
|
|||||||
title: "snk - " + demo,
|
title: "snk - " + demo,
|
||||||
filename: `${demo}.html`,
|
filename: `${demo}.html`,
|
||||||
chunks: [demo],
|
chunks: [demo],
|
||||||
})
|
}),
|
||||||
),
|
),
|
||||||
new HtmlWebpackPlugin({
|
new HtmlWebpackPlugin({
|
||||||
title: "snk - " + demos[0],
|
title: "snk - " + demos[0],
|
||||||
|
|||||||
@@ -54,6 +54,6 @@ export const createRpcClient = <API_ extends API>(worker: Worker) => {
|
|||||||
worker.addEventListener("terminate", onTerminate);
|
worker.addEventListener("terminate", onTerminate);
|
||||||
worker.postMessage({ symbol, key, methodName, args });
|
worker.postMessage({ symbol, key, methodName, args });
|
||||||
}),
|
}),
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export const getCircleSize = (n: number) => {
|
|||||||
export const drawCircleStack = (
|
export const drawCircleStack = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
stack: Color[],
|
stack: Color[],
|
||||||
o: Options
|
o: Options,
|
||||||
) => {
|
) => {
|
||||||
for (let i = stack.length; i--; ) {
|
for (let i = stack.length; i--; ) {
|
||||||
const { x, y } = cellPath[i];
|
const { x, y } = cellPath[i];
|
||||||
@@ -67,7 +67,7 @@ export const drawCircleStack = (
|
|||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(
|
ctx.translate(
|
||||||
x * o.sizeCell + (o.sizeCell - o.sizeDot) / 2,
|
x * o.sizeCell + (o.sizeCell - o.sizeDot) / 2,
|
||||||
y * o.sizeCell + (o.sizeCell - o.sizeDot) / 2
|
y * o.sizeCell + (o.sizeCell - o.sizeDot) / 2,
|
||||||
);
|
);
|
||||||
|
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export const drawGrid = (
|
|||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
cells: Point[] | null,
|
cells: Point[] | null,
|
||||||
o: Options
|
o: Options,
|
||||||
) => {
|
) => {
|
||||||
for (let x = grid.width; x--; )
|
for (let x = grid.width; x--; )
|
||||||
for (let y = grid.height; y--; ) {
|
for (let y = grid.height; y--; ) {
|
||||||
@@ -27,7 +27,7 @@ export const drawGrid = (
|
|||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(
|
ctx.translate(
|
||||||
x * o.sizeCell + (o.sizeCell - o.sizeDot) / 2,
|
x * o.sizeCell + (o.sizeCell - o.sizeDot) / 2,
|
||||||
y * o.sizeCell + (o.sizeCell - o.sizeDot) / 2
|
y * o.sizeCell + (o.sizeCell - o.sizeDot) / 2,
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.fillStyle = color;
|
ctx.fillStyle = color;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ type Options = {
|
|||||||
export const drawSnake = (
|
export const drawSnake = (
|
||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
snake: Snake,
|
snake: Snake,
|
||||||
o: Options
|
o: Options,
|
||||||
) => {
|
) => {
|
||||||
const cells = snakeToCells(snake);
|
const cells = snakeToCells(snake);
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ export const drawSnake = (
|
|||||||
ctx,
|
ctx,
|
||||||
o.sizeCell - u * 2,
|
o.sizeCell - u * 2,
|
||||||
o.sizeCell - u * 2,
|
o.sizeCell - u * 2,
|
||||||
(o.sizeCell - u * 2) * 0.25
|
(o.sizeCell - u * 2) * 0.25,
|
||||||
);
|
);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
@@ -40,7 +40,7 @@ export const drawSnakeLerp = (
|
|||||||
snake0: Snake,
|
snake0: Snake,
|
||||||
snake1: Snake,
|
snake1: Snake,
|
||||||
k: number,
|
k: number,
|
||||||
o: Options
|
o: Options,
|
||||||
) => {
|
) => {
|
||||||
const m = 0.8;
|
const m = 0.8;
|
||||||
const n = snake0.length / 2;
|
const n = snake0.length / 2;
|
||||||
@@ -61,7 +61,7 @@ export const drawSnakeLerp = (
|
|||||||
ctx,
|
ctx,
|
||||||
o.sizeCell - u * 2,
|
o.sizeCell - u * 2,
|
||||||
o.sizeCell - u * 2,
|
o.sizeCell - u * 2,
|
||||||
(o.sizeCell - u * 2) * 0.25
|
(o.sizeCell - u * 2) * 0.25,
|
||||||
);
|
);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export const drawStack = (
|
|||||||
stack: Color[],
|
stack: Color[],
|
||||||
max: number,
|
max: number,
|
||||||
width: number,
|
width: number,
|
||||||
o: { colorDots: Record<Color, string> }
|
o: { colorDots: Record<Color, string> },
|
||||||
) => {
|
) => {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ export const drawWorld = (
|
|||||||
cells: Point[] | null,
|
cells: Point[] | null,
|
||||||
snake: Snake,
|
snake: Snake,
|
||||||
stack: Color[],
|
stack: Color[],
|
||||||
o: Options
|
o: Options,
|
||||||
) => {
|
) => {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ export const drawLerpWorld = (
|
|||||||
snake1: Snake,
|
snake1: Snake,
|
||||||
stack: Color[],
|
stack: Color[],
|
||||||
k: number,
|
k: number,
|
||||||
o: Options
|
o: Options,
|
||||||
) => {
|
) => {
|
||||||
ctx.save();
|
ctx.save();
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export const pathRoundedRect = (
|
|||||||
ctx: CanvasRenderingContext2D,
|
ctx: CanvasRenderingContext2D,
|
||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
borderRadius: number
|
borderRadius: number,
|
||||||
) => {
|
) => {
|
||||||
ctx.moveTo(borderRadius, 0);
|
ctx.moveTo(borderRadius, 0);
|
||||||
ctx.arcTo(width, 0, width, height, borderRadius);
|
ctx.arcTo(width, 0, width, height, borderRadius);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { getPathToPose } from "@snk/solver/getPathToPose";
|
|||||||
import type { Options as DrawOptions } from "@snk/draw/drawWorld";
|
import type { Options as DrawOptions } from "@snk/draw/drawWorld";
|
||||||
|
|
||||||
let snake = createSnakeFromCells(
|
let snake = createSnakeFromCells(
|
||||||
Array.from({ length: 4 }, (_, i) => ({ x: i, y: -1 }))
|
Array.from({ length: 4 }, (_, i) => ({ x: i, y: -1 })),
|
||||||
);
|
);
|
||||||
|
|
||||||
// const chain = [snake];
|
// const chain = [snake];
|
||||||
@@ -45,7 +45,7 @@ const animationOptions: AnimationOptions = { frameDuration: 100, step: 1 };
|
|||||||
) {
|
) {
|
||||||
const stats: number[] = [];
|
const stats: number[] = [];
|
||||||
|
|
||||||
let buffer: Buffer;
|
let buffer: Uint8Array;
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
const chainL = chain.slice(0, length);
|
const chainL = chain.slice(0, length);
|
||||||
for (let k = 0; k < 10 && (Date.now() - start < 10 * 1000 || k < 2); k++) {
|
for (let k = 0; k < 10 && (Date.now() - start < 10 * 1000 || k < 2); k++) {
|
||||||
@@ -55,7 +55,7 @@ const animationOptions: AnimationOptions = { frameDuration: 100, step: 1 };
|
|||||||
null,
|
null,
|
||||||
chainL,
|
chainL,
|
||||||
drawOptions,
|
drawOptions,
|
||||||
animationOptions
|
animationOptions,
|
||||||
);
|
);
|
||||||
stats.push(performance.now() - s);
|
stats.push(performance.now() - s);
|
||||||
}
|
}
|
||||||
@@ -73,12 +73,12 @@ const animationOptions: AnimationOptions = { frameDuration: 100, step: 1 };
|
|||||||
})}ms`,
|
})}ms`,
|
||||||
"",
|
"",
|
||||||
].join("\n"),
|
].join("\n"),
|
||||||
stats
|
stats,
|
||||||
);
|
);
|
||||||
|
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
`__tests__/__snapshots__/benchmark-output-${length}.gif`,
|
`__tests__/__snapshots__/benchmark-output-${length}.gif`,
|
||||||
buffer!
|
buffer!,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
|
import { it, expect } from "bun:test";
|
||||||
import { AnimationOptions, createGif } from "..";
|
import { AnimationOptions, createGif } from "..";
|
||||||
import * as grids from "@snk/types/__fixtures__/grid";
|
import * as grids from "@snk/types/__fixtures__/grid";
|
||||||
import { snake3 as snake } from "@snk/types/__fixtures__/snake";
|
import { snake3 as snake } from "@snk/types/__fixtures__/snake";
|
||||||
@@ -7,8 +8,6 @@ import { createSnakeFromCells, nextSnake } from "@snk/types/snake";
|
|||||||
import { getBestRoute } from "@snk/solver/getBestRoute";
|
import { getBestRoute } from "@snk/solver/getBestRoute";
|
||||||
import type { Options as DrawOptions } from "@snk/draw/drawWorld";
|
import type { Options as DrawOptions } from "@snk/draw/drawWorld";
|
||||||
|
|
||||||
jest.setTimeout(20 * 1000);
|
|
||||||
|
|
||||||
const upscale = 1;
|
const upscale = 1;
|
||||||
const drawOptions: DrawOptions = {
|
const drawOptions: DrawOptions = {
|
||||||
sizeDotBorderRadius: 2 * upscale,
|
sizeDotBorderRadius: 2 * upscale,
|
||||||
@@ -35,44 +34,58 @@ for (const key of [
|
|||||||
"small",
|
"small",
|
||||||
"smallPacked",
|
"smallPacked",
|
||||||
] as const)
|
] as const)
|
||||||
it(`should generate ${key} gif`, async () => {
|
it(
|
||||||
const grid = grids[key];
|
`should generate ${key} gif`,
|
||||||
|
async () => {
|
||||||
|
const grid = grids[key];
|
||||||
|
|
||||||
const chain = [snake, ...getBestRoute(grid, snake)!];
|
const chain = [snake, ...getBestRoute(grid, snake)!];
|
||||||
|
|
||||||
|
const gif = await createGif(
|
||||||
|
grid,
|
||||||
|
null,
|
||||||
|
chain,
|
||||||
|
drawOptions,
|
||||||
|
animationOptions,
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(gif).toBeDefined();
|
||||||
|
|
||||||
|
fs.writeFileSync(path.resolve(dir, key + ".gif"), gif);
|
||||||
|
},
|
||||||
|
{ timeout: 20 * 1000 },
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
`should generate swipper`,
|
||||||
|
async () => {
|
||||||
|
const grid = grids.smallFull;
|
||||||
|
let snk = createSnakeFromCells(
|
||||||
|
Array.from({ length: 6 }, (_, i) => ({ x: i, y: -1 })),
|
||||||
|
);
|
||||||
|
|
||||||
|
const chain = [snk];
|
||||||
|
for (let y = -1; y < grid.height; y++) {
|
||||||
|
snk = nextSnake(snk, 0, 1);
|
||||||
|
chain.push(snk);
|
||||||
|
|
||||||
|
for (let x = grid.width - 1; x--; ) {
|
||||||
|
snk = nextSnake(snk, (y + 100) % 2 ? 1 : -1, 0);
|
||||||
|
chain.push(snk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const gif = await createGif(
|
const gif = await createGif(
|
||||||
grid,
|
grid,
|
||||||
null,
|
null,
|
||||||
chain,
|
chain,
|
||||||
drawOptions,
|
drawOptions,
|
||||||
animationOptions
|
animationOptions,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(gif).toBeDefined();
|
expect(gif).toBeDefined();
|
||||||
|
|
||||||
fs.writeFileSync(path.resolve(dir, key + ".gif"), gif);
|
fs.writeFileSync(path.resolve(dir, "swipper.gif"), gif);
|
||||||
});
|
},
|
||||||
|
{ timeout: 20 * 1000 },
|
||||||
it(`should generate swipper`, async () => {
|
);
|
||||||
const grid = grids.smallFull;
|
|
||||||
let snk = createSnakeFromCells(
|
|
||||||
Array.from({ length: 6 }, (_, i) => ({ x: i, y: -1 }))
|
|
||||||
);
|
|
||||||
|
|
||||||
const chain = [snk];
|
|
||||||
for (let y = -1; y < grid.height; y++) {
|
|
||||||
snk = nextSnake(snk, 0, 1);
|
|
||||||
chain.push(snk);
|
|
||||||
|
|
||||||
for (let x = grid.width - 1; x--; ) {
|
|
||||||
snk = nextSnake(snk, (y + 100) % 2 ? 1 : -1, 0);
|
|
||||||
chain.push(snk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const gif = await createGif(grid, null, chain, drawOptions, animationOptions);
|
|
||||||
|
|
||||||
expect(gif).toBeDefined();
|
|
||||||
|
|
||||||
fs.writeFileSync(path.resolve(dir, "swipper.gif"), gif);
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import gifsicle from "gifsicle";
|
|||||||
import GIFEncoder from "gif-encoder-2";
|
import GIFEncoder from "gif-encoder-2";
|
||||||
|
|
||||||
const withTmpDir = async <T>(
|
const withTmpDir = async <T>(
|
||||||
handler: (dir: string) => Promise<T>
|
handler: (dir: string) => Promise<T>,
|
||||||
): Promise<T> => {
|
): Promise<T> => {
|
||||||
const { name: dir, removeCallback: cleanUp } = tmp.dirSync({
|
const { name: dir, removeCallback: cleanUp } = tmp.dirSync({
|
||||||
unsafeCleanup: true,
|
unsafeCleanup: true,
|
||||||
@@ -37,7 +37,7 @@ export const createGif = async (
|
|||||||
cells: Point[] | null,
|
cells: Point[] | null,
|
||||||
chain: Snake[],
|
chain: Snake[],
|
||||||
drawOptions: DrawOptions,
|
drawOptions: DrawOptions,
|
||||||
animationOptions: AnimationOptions
|
animationOptions: AnimationOptions,
|
||||||
) =>
|
) =>
|
||||||
withTmpDir(async (dir) => {
|
withTmpDir(async (dir) => {
|
||||||
const { width, height } = getCanvasWorldSize(grid0, drawOptions);
|
const { width, height } = getCanvasWorldSize(grid0, drawOptions);
|
||||||
@@ -70,7 +70,7 @@ export const createGif = async (
|
|||||||
snake1,
|
snake1,
|
||||||
stack,
|
stack,
|
||||||
k / animationOptions.step,
|
k / animationOptions.step,
|
||||||
drawOptions
|
drawOptions,
|
||||||
);
|
);
|
||||||
|
|
||||||
encoder.addFrame(ctx);
|
encoder.addFrame(ctx);
|
||||||
@@ -92,8 +92,8 @@ export const createGif = async (
|
|||||||
"--colors=18",
|
"--colors=18",
|
||||||
outFileName,
|
outFileName,
|
||||||
["--output", optimizedFileName],
|
["--output", optimizedFileName],
|
||||||
].flat()
|
].flat(),
|
||||||
);
|
);
|
||||||
|
|
||||||
return fs.readFileSync(optimizedFileName);
|
return new Uint8Array(fs.readFileSync(optimizedFileName));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,17 +4,16 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@snk/draw": "1.0.0",
|
"@snk/draw": "1.0.0",
|
||||||
"@snk/solver": "1.0.0",
|
"@snk/solver": "1.0.0",
|
||||||
"canvas": "2.11.2",
|
"canvas": "3.1.0",
|
||||||
"gif-encoder-2": "1.0.5",
|
"gif-encoder-2": "1.0.5",
|
||||||
"gifsicle": "5.3.0",
|
"gifsicle": "5.3.0",
|
||||||
"tmp": "0.2.1"
|
"tmp": "0.2.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/gifsicle": "5.2.0",
|
"@types/gifsicle": "5.2.2",
|
||||||
"@types/tmp": "0.2.4",
|
"@types/tmp": "0.2.6"
|
||||||
"@vercel/ncc": "0.38.0"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"benchmark": "ncc run __tests__/benchmark.ts --quiet"
|
"benchmark": "bun __tests__/benchmark.ts"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
# @snk/github-user-contribution-service
|
# @snk/github-user-contribution-service
|
||||||
|
|
||||||
Expose github-user-contribution as an endpoint, using vercel.sh
|
Expose github-user-contribution as an endpoint. hosted on cloudflare
|
||||||
|
|
||||||
|
```sh
|
||||||
|
|
||||||
|
|
||||||
|
# deploy
|
||||||
|
bunx wrangler deploy --branch=production
|
||||||
|
|
||||||
|
# change secret
|
||||||
|
bunx wrangler secret put GITHUB_TOKEN
|
||||||
|
|
||||||
|
```
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
import { getGithubUserContribution } from "@snk/github-user-contribution";
|
|
||||||
import { VercelRequest, VercelResponse } from "@vercel/node";
|
|
||||||
import nodeFetch from "node-fetch";
|
|
||||||
|
|
||||||
(global as any).fetch = nodeFetch;
|
|
||||||
|
|
||||||
export default async (req: VercelRequest, res: VercelResponse) => {
|
|
||||||
const { userName } = req.query;
|
|
||||||
|
|
||||||
try {
|
|
||||||
res.setHeader("Access-Control-Allow-Origin", "https://platane.github.io");
|
|
||||||
res.statusCode = 200;
|
|
||||||
res.json(
|
|
||||||
await getGithubUserContribution(userName as string, {
|
|
||||||
githubToken: process.env.GITHUB_TOKEN!,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
res.statusCode = 500;
|
|
||||||
res.end();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
52
packages/github-user-contribution-service/index.ts
Normal file
52
packages/github-user-contribution-service/index.ts
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
import { getGithubUserContribution } from "@snk/github-user-contribution";
|
||||||
|
|
||||||
|
const cors =
|
||||||
|
<
|
||||||
|
Req extends { headers: Headers },
|
||||||
|
Res extends { headers: Headers },
|
||||||
|
A extends Array<any>,
|
||||||
|
>(
|
||||||
|
f: (req: Req, ...args: A) => Res | Promise<Res>,
|
||||||
|
) =>
|
||||||
|
async (req: Req, ...args: A) => {
|
||||||
|
const res = await f(req, ...args);
|
||||||
|
|
||||||
|
const origin = req.headers.get("origin");
|
||||||
|
|
||||||
|
if (origin) {
|
||||||
|
const { host, hostname } = new URL(origin);
|
||||||
|
|
||||||
|
if (hostname === "localhost" || host === "platane.github.io")
|
||||||
|
res.headers.set("Access-Control-Allow-Origin", origin);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.headers.set("Access-Control-Allow-Methods", "GET, OPTIONS");
|
||||||
|
res.headers.set("Access-Control-Allow-Headers", "Content-Type");
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default {
|
||||||
|
fetch: cors(async (req: Request, env: { GITHUB_TOKEN: string }) => {
|
||||||
|
const url = new URL(req.url);
|
||||||
|
|
||||||
|
const [, userName] =
|
||||||
|
url.pathname.match(/^\/github-user-contribution\/([^\/]*)\/?$/) ?? [];
|
||||||
|
|
||||||
|
if (req.method === "OPTIONS") return new Response();
|
||||||
|
|
||||||
|
if (!userName || req.method !== "GET")
|
||||||
|
return new Response("unknown route", { status: 404 });
|
||||||
|
|
||||||
|
const body = await getGithubUserContribution(userName, {
|
||||||
|
githubToken: env.GITHUB_TOKEN,
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Response(JSON.stringify(body), {
|
||||||
|
status: 200,
|
||||||
|
headers: {
|
||||||
|
"Cache-Control": "max-age=21600, s-maxage=21600",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
};
|
||||||
@@ -2,11 +2,13 @@
|
|||||||
"name": "@snk/github-user-contribution-service",
|
"name": "@snk/github-user-contribution-service",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-fetch": "2.7.0",
|
"@snk/github-user-contribution": "1.0.0"
|
||||||
"@snk/github-user-contribution": "1.0.0",
|
|
||||||
"@vercel/node": "3.0.6"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node-fetch": "2.6.6"
|
"wrangler": "3.109.2",
|
||||||
|
"@cloudflare/workers-types": "4.20250214.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"deploy": "wrangler deploy"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
{
|
|
||||||
"github": {
|
|
||||||
"silent": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
9
packages/github-user-contribution-service/wrangler.toml
Normal file
9
packages/github-user-contribution-service/wrangler.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
name = "github-user-contribution"
|
||||||
|
main = "index.ts"
|
||||||
|
compatibility_date = "2024-09-02"
|
||||||
|
|
||||||
|
account_id = "56268cde636c288343cb0767952ecf2e"
|
||||||
|
workers_dev = true
|
||||||
|
|
||||||
|
# [observability]
|
||||||
|
# enabled = true
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import { getGithubUserContribution } from "..";
|
import { getGithubUserContribution } from "..";
|
||||||
import { config } from "dotenv";
|
import { describe, it, expect } from "bun:test";
|
||||||
config({ path: __dirname + "/../../../.env" });
|
|
||||||
|
|
||||||
describe("getGithubUserContribution", () => {
|
describe("getGithubUserContribution", () => {
|
||||||
const promise = getGithubUserContribution("platane", {
|
const promise = getGithubUserContribution("platane", {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
export const getGithubUserContribution = async (
|
export const getGithubUserContribution = async (
|
||||||
userName: string,
|
userName: string,
|
||||||
o: { githubToken: string }
|
o: { githubToken: string },
|
||||||
) => {
|
) => {
|
||||||
const query = /* GraphQL */ `
|
const query = /* GraphQL */ `
|
||||||
query ($login: String!) {
|
query ($login: String!) {
|
||||||
@@ -42,12 +42,13 @@ export const getGithubUserContribution = async (
|
|||||||
headers: {
|
headers: {
|
||||||
Authorization: `bearer ${o.githubToken}`,
|
Authorization: `bearer ${o.githubToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": "me@platane.me",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ variables, query }),
|
body: JSON.stringify({ variables, query }),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!res.ok) throw new Error(res.statusText);
|
if (!res.ok) throw new Error(await res.text().catch(() => res.statusText));
|
||||||
|
|
||||||
const { data, errors } = (await res.json()) as {
|
const { data, errors } = (await res.json()) as {
|
||||||
data: GraphQLRes;
|
data: GraphQLRes;
|
||||||
@@ -69,7 +70,7 @@ export const getGithubUserContribution = async (
|
|||||||
(d.contributionLevel === "SECOND_QUARTILE" && 2) ||
|
(d.contributionLevel === "SECOND_QUARTILE" && 2) ||
|
||||||
(d.contributionLevel === "FIRST_QUARTILE" && 1) ||
|
(d.contributionLevel === "FIRST_QUARTILE" && 1) ||
|
||||||
0,
|
0,
|
||||||
}))
|
})),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
{
|
{
|
||||||
"name": "@snk/github-user-contribution",
|
"name": "@snk/github-user-contribution",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0"
|
||||||
"devDependencies": {
|
|
||||||
"dotenv": "16.3.1"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { it, expect } from "bun:test";
|
||||||
import { getBestRoute } from "../getBestRoute";
|
import { getBestRoute } from "../getBestRoute";
|
||||||
import { snake3, snake4 } from "@snk/types/__fixtures__/snake";
|
import { snake3, snake4 } from "@snk/types/__fixtures__/snake";
|
||||||
import {
|
import {
|
||||||
@@ -16,7 +17,7 @@ for (const { width, height, snake } of [
|
|||||||
{ width: 5, height: 5, snake: snake4 },
|
{ width: 5, height: 5, snake: snake4 },
|
||||||
])
|
])
|
||||||
it(`should find solution for ${n} ${width}x${height} generated grids for ${getSnakeLength(
|
it(`should find solution for ${n} ${width}x${height} generated grids for ${getSnakeLength(
|
||||||
snake
|
snake,
|
||||||
)} length snake`, () => {
|
)} length snake`, () => {
|
||||||
const results = Array.from({ length: n }, (_, seed) => {
|
const results = Array.from({ length: n }, (_, seed) => {
|
||||||
const grid = createFromSeed(seed, width, height);
|
const grid = createFromSeed(seed, width, height);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { it, expect } from "bun:test";
|
||||||
import { getBestRoute } from "../getBestRoute";
|
import { getBestRoute } from "../getBestRoute";
|
||||||
import { Color, createEmptyGrid, setColor } from "@snk/types/grid";
|
import { Color, createEmptyGrid, setColor } from "@snk/types/grid";
|
||||||
import { createSnakeFromCells, snakeToCells } from "@snk/types/snake";
|
import { createSnakeFromCells, snakeToCells } from "@snk/types/snake";
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { it, expect } from "bun:test";
|
||||||
import { createEmptyGrid } from "@snk/types/grid";
|
import { createEmptyGrid } from "@snk/types/grid";
|
||||||
import { getHeadX, getHeadY } from "@snk/types/snake";
|
import { getHeadX, getHeadY } from "@snk/types/snake";
|
||||||
import { snake3 } from "@snk/types/__fixtures__/snake";
|
import { snake3 } from "@snk/types/__fixtures__/snake";
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { it, expect } from "bun:test";
|
||||||
import { createSnakeFromCells } from "@snk/types/snake";
|
import { createSnakeFromCells } from "@snk/types/snake";
|
||||||
import { getPathToPose } from "../getPathToPose";
|
import { getPathToPose } from "../getPathToPose";
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { it, expect, describe } from "bun:test";
|
||||||
import { sortPush } from "../utils/sortPush";
|
import { sortPush } from "../utils/sortPush";
|
||||||
|
|
||||||
const sortFn = (a: number, b: number) => a - b;
|
const sortFn = (a: number, b: number) => a - b;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const clearCleanColoredLayer = (
|
|||||||
grid: Grid,
|
grid: Grid,
|
||||||
outside: Outside,
|
outside: Outside,
|
||||||
snake0: Snake,
|
snake0: Snake,
|
||||||
color: Color
|
color: Color,
|
||||||
) => {
|
) => {
|
||||||
const snakeN = getSnakeLength(snake0);
|
const snakeN = getSnakeLength(snake0);
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ const getPathToNextPoint = (
|
|||||||
grid: Grid,
|
grid: Grid,
|
||||||
snake0: Snake,
|
snake0: Snake,
|
||||||
color: Color,
|
color: Color,
|
||||||
points: Point[]
|
points: Point[],
|
||||||
) => {
|
) => {
|
||||||
const closeList: Snake[] = [];
|
const closeList: Snake[] = [];
|
||||||
const openList: M[] = [{ snake: snake0 } as any];
|
const openList: M[] = [{ snake: snake0 } as any];
|
||||||
@@ -96,7 +96,7 @@ export const getTunnellablePoints = (
|
|||||||
grid: Grid,
|
grid: Grid,
|
||||||
outside: Outside,
|
outside: Outside,
|
||||||
snakeN: number,
|
snakeN: number,
|
||||||
color: Color
|
color: Color,
|
||||||
) => {
|
) => {
|
||||||
const points: Point[] = [];
|
const points: Point[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const clearResidualColoredLayer = (
|
|||||||
grid: Grid,
|
grid: Grid,
|
||||||
outside: Outside,
|
outside: Outside,
|
||||||
snake0: Snake,
|
snake0: Snake,
|
||||||
color: Color
|
color: Color,
|
||||||
) => {
|
) => {
|
||||||
const snakeN = getSnakeLength(snake0);
|
const snakeN = getSnakeLength(snake0);
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ export const getTunnellablePoints = (
|
|||||||
grid: Grid,
|
grid: Grid,
|
||||||
outside: Outside,
|
outside: Outside,
|
||||||
snakeN: number,
|
snakeN: number,
|
||||||
color: Color
|
color: Color,
|
||||||
) => {
|
) => {
|
||||||
const points: T[] = [];
|
const points: T[] = [];
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export const getBestRoute = (grid0: Grid, snake0: Snake) => {
|
|||||||
for (const color of extractColors(grid)) {
|
for (const color of extractColors(grid)) {
|
||||||
if (color > 1)
|
if (color > 1)
|
||||||
chain.unshift(
|
chain.unshift(
|
||||||
...clearResidualColoredLayer(grid, outside, chain[0], color)
|
...clearResidualColoredLayer(grid, outside, chain[0], color),
|
||||||
);
|
);
|
||||||
chain.unshift(...clearCleanColoredLayer(grid, outside, chain[0], color));
|
chain.unshift(...clearCleanColoredLayer(grid, outside, chain[0], color));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ const getSnakeEscapePath = (
|
|||||||
grid: Grid,
|
grid: Grid,
|
||||||
outside: Outside,
|
outside: Outside,
|
||||||
snake0: Snake,
|
snake0: Snake,
|
||||||
color: Color
|
color: Color,
|
||||||
) => {
|
) => {
|
||||||
const openList: M[] = [{ snake: snake0, w: 0 } as any];
|
const openList: M[] = [{ snake: snake0, w: 0 } as any];
|
||||||
const closeList: Snake[] = [];
|
const closeList: Snake[] = [];
|
||||||
@@ -79,7 +79,7 @@ export const getBestTunnel = (
|
|||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
color: Color,
|
color: Color,
|
||||||
snakeN: number
|
snakeN: number,
|
||||||
) => {
|
) => {
|
||||||
const c = { x, y };
|
const c = { x, y };
|
||||||
const snake0 = createSnakeFromCells(Array.from({ length: snakeN }, () => c));
|
const snake0 = createSnakeFromCells(Array.from({ length: snakeN }, () => c));
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const createOutside = (grid: Grid, color: Color = 0 as Color) => {
|
|||||||
export const fillOutside = (
|
export const fillOutside = (
|
||||||
outside: Outside,
|
outside: Outside,
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
color: Color = 0 as Color
|
color: Color = 0 as Color,
|
||||||
) => {
|
) => {
|
||||||
let changed = true;
|
let changed = true;
|
||||||
while (changed) {
|
while (changed) {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export const getTunnelPath = (snake0: Snake, tunnel: Point[]) => {
|
|||||||
export const updateTunnel = (
|
export const updateTunnel = (
|
||||||
grid: Grid,
|
grid: Grid,
|
||||||
tunnel: Point[],
|
tunnel: Point[],
|
||||||
toDelete: Point[]
|
toDelete: Point[],
|
||||||
) => {
|
) => {
|
||||||
while (tunnel.length) {
|
while (tunnel.length) {
|
||||||
const { x, y } = tunnel[0];
|
const { x, y } = tunnel[0];
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { it, expect } from "bun:test";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import * as path from "path";
|
import * as path from "path";
|
||||||
import { createSvg, DrawOptions as DrawOptions } from "..";
|
import { createSvg, DrawOptions as DrawOptions } from "..";
|
||||||
@@ -37,7 +38,7 @@ for (const [key, grid] of Object.entries(grids))
|
|||||||
null,
|
null,
|
||||||
chain,
|
chain,
|
||||||
drawOptions,
|
drawOptions,
|
||||||
animationOptions
|
animationOptions,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(svg).toBeDefined();
|
expect(svg).toBeDefined();
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { it, expect } from "bun:test";
|
||||||
import { minifyCss } from "../css-utils";
|
import { minifyCss } from "../css-utils";
|
||||||
|
|
||||||
it("should minify css", () => {
|
it("should minify css", () => {
|
||||||
@@ -6,8 +7,8 @@ it("should minify css", () => {
|
|||||||
.c {
|
.c {
|
||||||
color : red ;
|
color : red ;
|
||||||
}
|
}
|
||||||
|
|
||||||
`)
|
`),
|
||||||
).toBe(".c{color:red}");
|
).toBe(".c{color:red}");
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
@@ -17,10 +18,10 @@ it("should minify css", () => {
|
|||||||
color : red ;
|
color : red ;
|
||||||
}
|
}
|
||||||
|
|
||||||
# {
|
# {
|
||||||
animation: linear 10;
|
animation: linear 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
`)
|
`),
|
||||||
).toBe(".c{top:0;color:red}#{animation:linear 10}");
|
).toBe(".c{top:0;color:red}#{animation:linear 10}");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const mergeKeyFrames = (keyframes: { t: number; style: string }[]) => {
|
|||||||
*/
|
*/
|
||||||
export const createAnimation = (
|
export const createAnimation = (
|
||||||
name: string,
|
name: string,
|
||||||
keyframes: { t: number; style: string }[]
|
keyframes: { t: number; style: string }[],
|
||||||
) =>
|
) =>
|
||||||
`@keyframes ${name}{` +
|
`@keyframes ${name}{` +
|
||||||
mergeKeyFrames(keyframes)
|
mergeKeyFrames(keyframes)
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export type Options = {
|
|||||||
export const createGrid = (
|
export const createGrid = (
|
||||||
cells: (Point & { t: number | null; color: Color | Empty })[],
|
cells: (Point & { t: number | null; color: Color | Empty })[],
|
||||||
{ sizeDotBorderRadius, sizeDot, sizeCell }: Options,
|
{ sizeDotBorderRadius, sizeDot, sizeCell }: Options,
|
||||||
duration: number
|
duration: number,
|
||||||
) => {
|
) => {
|
||||||
const svgElements: string[] = [];
|
const svgElements: string[] = [];
|
||||||
const styles = [
|
const styles = [
|
||||||
@@ -48,7 +48,7 @@ export const createGrid = (
|
|||||||
`.c.${id}{
|
`.c.${id}{
|
||||||
fill: var(--c${color});
|
fill: var(--c${color});
|
||||||
animation-name: ${animationName}
|
animation-name: ${animationName}
|
||||||
}`
|
}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ export const createGrid = (
|
|||||||
y: y * sizeCell + m,
|
y: y * sizeCell + m,
|
||||||
rx: sizeDotBorderRadius,
|
rx: sizeDotBorderRadius,
|
||||||
ry: sizeDotBorderRadius,
|
ry: sizeDotBorderRadius,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,13 +34,13 @@ export type DrawOptions = {
|
|||||||
|
|
||||||
const getCellsFromGrid = ({ width, height }: Grid) =>
|
const getCellsFromGrid = ({ width, height }: Grid) =>
|
||||||
Array.from({ length: width }, (_, x) =>
|
Array.from({ length: width }, (_, x) =>
|
||||||
Array.from({ length: height }, (_, y) => ({ x, y }))
|
Array.from({ length: height }, (_, y) => ({ x, y })),
|
||||||
).flat();
|
).flat();
|
||||||
|
|
||||||
const createLivingCells = (
|
const createLivingCells = (
|
||||||
grid0: Grid,
|
grid0: Grid,
|
||||||
chain: Snake[],
|
chain: Snake[],
|
||||||
cells: Point[] | null
|
cells: Point[] | null,
|
||||||
) => {
|
) => {
|
||||||
const livingCells: (Point & {
|
const livingCells: (Point & {
|
||||||
t: number | null;
|
t: number | null;
|
||||||
@@ -73,7 +73,7 @@ export const createSvg = (
|
|||||||
cells: Point[] | null,
|
cells: Point[] | null,
|
||||||
chain: Snake[],
|
chain: Snake[],
|
||||||
drawOptions: DrawOptions,
|
drawOptions: DrawOptions,
|
||||||
animationOptions: Pick<AnimationOptions, "frameDuration">
|
animationOptions: Pick<AnimationOptions, "frameDuration">,
|
||||||
) => {
|
) => {
|
||||||
const width = (grid.width + 2) * drawOptions.sizeCell;
|
const width = (grid.width + 2) * drawOptions.sizeCell;
|
||||||
const height = (grid.height + 5) * drawOptions.sizeCell;
|
const height = (grid.height + 5) * drawOptions.sizeCell;
|
||||||
@@ -89,7 +89,7 @@ export const createSvg = (
|
|||||||
drawOptions,
|
drawOptions,
|
||||||
grid.width * drawOptions.sizeCell,
|
grid.width * drawOptions.sizeCell,
|
||||||
(grid.height + 2) * drawOptions.sizeCell,
|
(grid.height + 2) * drawOptions.sizeCell,
|
||||||
duration
|
duration,
|
||||||
),
|
),
|
||||||
createSnake(chain, drawOptions, duration),
|
createSnake(chain, drawOptions, duration),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -3,6 +3,5 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@snk/solver": "1.0.0"
|
"@snk/solver": "1.0.0"
|
||||||
},
|
}
|
||||||
"devDependencies": {}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const lerp = (k: number, a: number, b: number) => (1 - k) * a + k * b;
|
|||||||
export const createSnake = (
|
export const createSnake = (
|
||||||
chain: Snake[],
|
chain: Snake[],
|
||||||
{ sizeCell, sizeDot }: Options,
|
{ sizeCell, sizeDot }: Options,
|
||||||
duration: number
|
duration: number,
|
||||||
) => {
|
) => {
|
||||||
const snakeN = chain[0] ? getSnakeLength(chain[0]) : 0;
|
const snakeN = chain[0] ? getSnakeLength(chain[0]) : 0;
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ export const createSnake = (
|
|||||||
const animationName = id;
|
const animationName = id;
|
||||||
|
|
||||||
const keyframes = removeInterpolatedPositions(
|
const keyframes = removeInterpolatedPositions(
|
||||||
positions.map((tr, i, { length }) => ({ ...tr, t: i / length }))
|
positions.map((tr, i, { length }) => ({ ...tr, t: i / length })),
|
||||||
).map(({ t, ...p }) => ({ t, style: transform(p) }));
|
).map(({ t, ...p }) => ({ t, style: transform(p) }));
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export const createStack = (
|
|||||||
{ sizeDot }: Options,
|
{ sizeDot }: Options,
|
||||||
width: number,
|
width: number,
|
||||||
y: number,
|
y: number,
|
||||||
duration: number
|
duration: number,
|
||||||
) => {
|
) => {
|
||||||
const svgElements: string[] = [];
|
const svgElements: string[] = [];
|
||||||
const styles = [
|
const styles = [
|
||||||
@@ -51,7 +51,7 @@ export const createStack = (
|
|||||||
width: (ts.length * m + 0.6).toFixed(1),
|
width: (ts.length * m + 0.6).toFixed(1),
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
styles.push(
|
styles.push(
|
||||||
@@ -68,7 +68,7 @@ export const createStack = (
|
|||||||
].map(({ scale, t }) => ({
|
].map(({ scale, t }) => ({
|
||||||
t,
|
t,
|
||||||
style: `transform:scale(${scale.toFixed(3)},1)`,
|
style: `transform:scale(${scale.toFixed(3)},1)`,
|
||||||
}))
|
})),
|
||||||
),
|
),
|
||||||
|
|
||||||
`.u.${id} {
|
`.u.${id} {
|
||||||
@@ -76,7 +76,7 @@ export const createStack = (
|
|||||||
animation-name: ${animationName};
|
animation-name: ${animationName};
|
||||||
transform-origin: ${x}px 0
|
transform-origin: ${x}px 0
|
||||||
}
|
}
|
||||||
`
|
`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
import { it, expect, test } from "bun:test";
|
||||||
import { createEmptyGrid, setColor, getColor, isInside, Color } from "../grid";
|
import { createEmptyGrid, setColor, getColor, isInside, Color } from "../grid";
|
||||||
|
|
||||||
it("should set / get cell", () => {
|
it("should set / get cell", () => {
|
||||||
const grid = createEmptyGrid(2, 3);
|
const grid = createEmptyGrid(2, 3);
|
||||||
|
|
||||||
expect(getColor(grid, 0, 1)).toBe(0);
|
expect(getColor(grid, 0, 1)).toBe(0 as any);
|
||||||
|
|
||||||
setColor(grid, 0, 1, 1 as Color);
|
setColor(grid, 0, 1, 1 as Color);
|
||||||
|
|
||||||
expect(getColor(grid, 0, 1)).toBe(1);
|
expect(getColor(grid, 0, 1)).toBe(1 as any);
|
||||||
});
|
});
|
||||||
|
|
||||||
test.each([
|
test.each([
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { it, expect } from "bun:test";
|
||||||
import {
|
import {
|
||||||
createSnakeFromCells,
|
createSnakeFromCells,
|
||||||
nextSnake,
|
nextSnake,
|
||||||
@@ -29,7 +30,7 @@ it("should return next snake", () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
expect(snakeToCells(nextSnake(createSnakeFromCells(snk0), 1, 0))).toEqual(
|
expect(snakeToCells(nextSnake(createSnakeFromCells(snk0), 1, 0))).toEqual(
|
||||||
snk1
|
snk1,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ export const setColor = (
|
|||||||
grid: Grid,
|
grid: Grid,
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
color: Color | Empty
|
color: Color | Empty,
|
||||||
) => {
|
) => {
|
||||||
grid.data[getIndex(grid, x, y)] = color || 0;
|
grid.data[getIndex(grid, x, y)] = color || 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const randomlyFillGrid = (
|
|||||||
colors = [1, 2, 3] as Color[],
|
colors = [1, 2, 3] as Color[],
|
||||||
emptyP = 2,
|
emptyP = 2,
|
||||||
}: { colors?: Color[]; emptyP?: number } = {},
|
}: { colors?: Color[]; emptyP?: number } = {},
|
||||||
rand = defaultRand
|
rand = defaultRand,
|
||||||
) => {
|
) => {
|
||||||
for (let x = grid.width; x--; )
|
for (let x = grid.width; x--; )
|
||||||
for (let y = grid.height; y--; ) {
|
for (let y = grid.height; y--; ) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ inputs:
|
|||||||
default: ${{ github.token }}
|
default: ${{ github.token }}
|
||||||
outputs:
|
outputs:
|
||||||
required: false
|
required: false
|
||||||
default: null
|
|
||||||
description: |
|
description: |
|
||||||
list of files to generate.
|
list of files to generate.
|
||||||
one file per line. Each output can be customized with options as query string.
|
one file per line. Each output can be customized with options as query string.
|
||||||
|
|||||||
2129
svg-only/dist/155.index.js
vendored
Normal file
2129
svg-only/dist/155.index.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,17 +1,15 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
exports.id = 407;
|
exports.id = 324;
|
||||||
exports.ids = [407];
|
exports.ids = [324];
|
||||||
exports.modules = {
|
exports.modules = {
|
||||||
|
|
||||||
/***/ 407:
|
/***/ 324:
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||||
|
|
||||||
// ESM COMPAT FLAG
|
|
||||||
__webpack_require__.r(__webpack_exports__);
|
|
||||||
|
|
||||||
// EXPORTS
|
// EXPORTS
|
||||||
__webpack_require__.d(__webpack_exports__, {
|
__webpack_require__.d(__webpack_exports__, {
|
||||||
"generateContributionSnake": () => (/* binding */ generateContributionSnake)
|
generateContributionSnake: () => (/* binding */ generateContributionSnake)
|
||||||
});
|
});
|
||||||
|
|
||||||
;// CONCATENATED MODULE: ../github-user-contribution/index.ts
|
;// CONCATENATED MODULE: ../github-user-contribution/index.ts
|
||||||
@@ -55,12 +53,13 @@ const getGithubUserContribution = async (userName, o) => {
|
|||||||
headers: {
|
headers: {
|
||||||
Authorization: `bearer ${o.githubToken}`,
|
Authorization: `bearer ${o.githubToken}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
|
"User-Agent": "me@platane.me",
|
||||||
},
|
},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify({ variables, query }),
|
body: JSON.stringify({ variables, query }),
|
||||||
});
|
});
|
||||||
if (!res.ok)
|
if (!res.ok)
|
||||||
throw new Error(res.statusText);
|
throw new Error(await res.text().catch(() => res.statusText));
|
||||||
const { data, errors } = (await res.json());
|
const { data, errors } = (await res.json());
|
||||||
if (errors?.[0])
|
if (errors?.[0])
|
||||||
throw errors[0];
|
throw errors[0];
|
||||||
@@ -78,18 +77,18 @@ const getGithubUserContribution = async (userName, o) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// EXTERNAL MODULE: ../types/grid.ts
|
// EXTERNAL MODULE: ../types/grid.ts
|
||||||
var types_grid = __webpack_require__(2881);
|
var types_grid = __webpack_require__(105);
|
||||||
;// CONCATENATED MODULE: ./userContributionToGrid.ts
|
;// CONCATENATED MODULE: ./userContributionToGrid.ts
|
||||||
|
|
||||||
const userContributionToGrid = (cells) => {
|
const userContributionToGrid = (cells) => {
|
||||||
const width = Math.max(0, ...cells.map((c) => c.x)) + 1;
|
const width = Math.max(0, ...cells.map((c) => c.x)) + 1;
|
||||||
const height = Math.max(0, ...cells.map((c) => c.y)) + 1;
|
const height = Math.max(0, ...cells.map((c) => c.y)) + 1;
|
||||||
const grid = (0,types_grid/* createEmptyGrid */.u1)(width, height);
|
const grid = (0,types_grid/* createEmptyGrid */.Kb)(width, height);
|
||||||
for (const c of cells) {
|
for (const c of cells) {
|
||||||
if (c.level > 0)
|
if (c.level > 0)
|
||||||
(0,types_grid/* setColor */.vk)(grid, c.x, c.y, c.level);
|
(0,types_grid/* setColor */.wW)(grid, c.x, c.y, c.level);
|
||||||
else
|
else
|
||||||
(0,types_grid/* setColorEmpty */.Dy)(grid, c.x, c.y);
|
(0,types_grid/* setColorEmpty */.l$)(grid, c.x, c.y);
|
||||||
}
|
}
|
||||||
return grid;
|
return grid;
|
||||||
};
|
};
|
||||||
@@ -107,10 +106,10 @@ const pointEquals = (a, b) => a.x === b.x && a.y === b.y;
|
|||||||
|
|
||||||
|
|
||||||
const createOutside = (grid, color = 0) => {
|
const createOutside = (grid, color = 0) => {
|
||||||
const outside = (0,types_grid/* createEmptyGrid */.u1)(grid.width, grid.height);
|
const outside = (0,types_grid/* createEmptyGrid */.Kb)(grid.width, grid.height);
|
||||||
for (let x = outside.width; x--;)
|
for (let x = outside.width; x--;)
|
||||||
for (let y = outside.height; y--;)
|
for (let y = outside.height; y--;)
|
||||||
(0,types_grid/* setColor */.vk)(outside, x, y, 1);
|
(0,types_grid/* setColor */.wW)(outside, x, y, 1);
|
||||||
fillOutside(outside, grid, color);
|
fillOutside(outside, grid, color);
|
||||||
return outside;
|
return outside;
|
||||||
};
|
};
|
||||||
@@ -120,19 +119,19 @@ const fillOutside = (outside, grid, color = 0) => {
|
|||||||
changed = false;
|
changed = false;
|
||||||
for (let x = outside.width; x--;)
|
for (let x = outside.width; x--;)
|
||||||
for (let y = outside.height; y--;)
|
for (let y = outside.height; y--;)
|
||||||
if ((0,types_grid/* getColor */.Lq)(grid, x, y) <= color &&
|
if ((0,types_grid/* getColor */.oU)(grid, x, y) <= color &&
|
||||||
!isOutside(outside, x, y) &&
|
!isOutside(outside, x, y) &&
|
||||||
around4.some((a) => isOutside(outside, x + a.x, y + a.y))) {
|
around4.some((a) => isOutside(outside, x + a.x, y + a.y))) {
|
||||||
changed = true;
|
changed = true;
|
||||||
(0,types_grid/* setColorEmpty */.Dy)(outside, x, y);
|
(0,types_grid/* setColorEmpty */.l$)(outside, x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return outside;
|
return outside;
|
||||||
};
|
};
|
||||||
const isOutside = (outside, x, y) => !(0,types_grid/* isInside */.V0)(outside, x, y) || (0,types_grid/* isEmpty */.xb)((0,types_grid/* getColor */.Lq)(outside, x, y));
|
const isOutside = (outside, x, y) => !(0,types_grid/* isInside */.FK)(outside, x, y) || (0,types_grid/* isEmpty */.Im)((0,types_grid/* getColor */.oU)(outside, x, y));
|
||||||
|
|
||||||
// EXTERNAL MODULE: ../types/snake.ts
|
// EXTERNAL MODULE: ../types/snake.ts
|
||||||
var types_snake = __webpack_require__(9347);
|
var types_snake = __webpack_require__(777);
|
||||||
;// CONCATENATED MODULE: ../solver/utils/sortPush.ts
|
;// CONCATENATED MODULE: ../solver/utils/sortPush.ts
|
||||||
const sortPush = (arr, x, sortFn) => {
|
const sortPush = (arr, x, sortFn) => {
|
||||||
let a = 0;
|
let a = 0;
|
||||||
@@ -165,9 +164,9 @@ const getTunnelPath = (snake0, tunnel) => {
|
|||||||
const chain = [];
|
const chain = [];
|
||||||
let snake = snake0;
|
let snake = snake0;
|
||||||
for (let i = 1; i < tunnel.length; i++) {
|
for (let i = 1; i < tunnel.length; i++) {
|
||||||
const dx = tunnel[i].x - (0,types_snake/* getHeadX */.If)(snake);
|
const dx = tunnel[i].x - (0,types_snake/* getHeadX */.tN)(snake);
|
||||||
const dy = tunnel[i].y - (0,types_snake/* getHeadY */.IP)(snake);
|
const dy = tunnel[i].y - (0,types_snake/* getHeadY */.Ap)(snake);
|
||||||
snake = (0,types_snake/* nextSnake */.kv)(snake, dx, dy);
|
snake = (0,types_snake/* nextSnake */.Sc)(snake, dx, dy);
|
||||||
chain.unshift(snake);
|
chain.unshift(snake);
|
||||||
}
|
}
|
||||||
return chain;
|
return chain;
|
||||||
@@ -195,7 +194,7 @@ const updateTunnel = (grid, tunnel, toDelete) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const isEmptySafe = (grid, x, y) => !(0,types_grid/* isInside */.V0)(grid, x, y) || (0,types_grid/* isEmpty */.xb)((0,types_grid/* getColor */.Lq)(grid, x, y));
|
const isEmptySafe = (grid, x, y) => !(0,types_grid/* isInside */.FK)(grid, x, y) || (0,types_grid/* isEmpty */.Im)((0,types_grid/* getColor */.oU)(grid, x, y));
|
||||||
/**
|
/**
|
||||||
* remove empty cell from start
|
* remove empty cell from start
|
||||||
*/
|
*/
|
||||||
@@ -230,14 +229,14 @@ const trimTunnelEnd = (grid, tunnel) => {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const getColorSafe = (grid, x, y) => (0,types_grid/* isInside */.V0)(grid, x, y) ? (0,types_grid/* getColor */.Lq)(grid, x, y) : 0;
|
const getColorSafe = (grid, x, y) => (0,types_grid/* isInside */.FK)(grid, x, y) ? (0,types_grid/* getColor */.oU)(grid, x, y) : 0;
|
||||||
const setEmptySafe = (grid, x, y) => {
|
const setEmptySafe = (grid, x, y) => {
|
||||||
if ((0,types_grid/* isInside */.V0)(grid, x, y))
|
if ((0,types_grid/* isInside */.FK)(grid, x, y))
|
||||||
(0,types_grid/* setColorEmpty */.Dy)(grid, x, y);
|
(0,types_grid/* setColorEmpty */.l$)(grid, x, y);
|
||||||
};
|
};
|
||||||
const unwrap = (m) => !m
|
const unwrap = (m) => !m
|
||||||
? []
|
? []
|
||||||
: [...unwrap(m.parent), { x: (0,types_snake/* getHeadX */.If)(m.snake), y: (0,types_snake/* getHeadY */.IP)(m.snake) }];
|
: [...unwrap(m.parent), { x: (0,types_snake/* getHeadX */.tN)(m.snake), y: (0,types_snake/* getHeadY */.Ap)(m.snake) }];
|
||||||
/**
|
/**
|
||||||
* returns the path to reach the outside which contains the least color cell
|
* returns the path to reach the outside which contains the least color cell
|
||||||
*/
|
*/
|
||||||
@@ -246,15 +245,15 @@ const getSnakeEscapePath = (grid, outside, snake0, color) => {
|
|||||||
const closeList = [];
|
const closeList = [];
|
||||||
while (openList[0]) {
|
while (openList[0]) {
|
||||||
const o = openList.shift();
|
const o = openList.shift();
|
||||||
const x = (0,types_snake/* getHeadX */.If)(o.snake);
|
const x = (0,types_snake/* getHeadX */.tN)(o.snake);
|
||||||
const y = (0,types_snake/* getHeadY */.IP)(o.snake);
|
const y = (0,types_snake/* getHeadY */.Ap)(o.snake);
|
||||||
if (isOutside(outside, x, y))
|
if (isOutside(outside, x, y))
|
||||||
return unwrap(o);
|
return unwrap(o);
|
||||||
for (const a of around4) {
|
for (const a of around4) {
|
||||||
const c = getColorSafe(grid, x + a.x, y + a.y);
|
const c = getColorSafe(grid, x + a.x, y + a.y);
|
||||||
if (c <= color && !(0,types_snake/* snakeWillSelfCollide */.nJ)(o.snake, a.x, a.y)) {
|
if (c <= color && !(0,types_snake/* snakeWillSelfCollide */.J)(o.snake, a.x, a.y)) {
|
||||||
const snake = (0,types_snake/* nextSnake */.kv)(o.snake, a.x, a.y);
|
const snake = (0,types_snake/* nextSnake */.Sc)(o.snake, a.x, a.y);
|
||||||
if (!closeList.some((s0) => (0,types_snake/* snakeEquals */.kE)(s0, snake))) {
|
if (!closeList.some((s0) => (0,types_snake/* snakeEquals */.sW)(s0, snake))) {
|
||||||
const w = o.w + 1 + +(c === color) * 1000;
|
const w = o.w + 1 + +(c === color) * 1000;
|
||||||
sortPush(openList, { snake, w, parent: o }, (a, b) => a.w - b.w);
|
sortPush(openList, { snake, w, parent: o }, (a, b) => a.w - b.w);
|
||||||
closeList.push(snake);
|
closeList.push(snake);
|
||||||
@@ -271,7 +270,7 @@ const getSnakeEscapePath = (grid, outside, snake0, color) => {
|
|||||||
*/
|
*/
|
||||||
const getBestTunnel = (grid, outside, x, y, color, snakeN) => {
|
const getBestTunnel = (grid, outside, x, y, color, snakeN) => {
|
||||||
const c = { x, y };
|
const c = { x, y };
|
||||||
const snake0 = (0,types_snake/* createSnakeFromCells */.xG)(Array.from({ length: snakeN }, () => c));
|
const snake0 = (0,types_snake/* createSnakeFromCells */.yS)(Array.from({ length: snakeN }, () => c));
|
||||||
const one = getSnakeEscapePath(grid, outside, snake0, color);
|
const one = getSnakeEscapePath(grid, outside, snake0, color);
|
||||||
if (!one)
|
if (!one)
|
||||||
return null;
|
return null;
|
||||||
@@ -279,9 +278,9 @@ const getBestTunnel = (grid, outside, x, y, color, snakeN) => {
|
|||||||
const snakeICells = one.slice(0, snakeN);
|
const snakeICells = one.slice(0, snakeN);
|
||||||
while (snakeICells.length < snakeN)
|
while (snakeICells.length < snakeN)
|
||||||
snakeICells.push(snakeICells[snakeICells.length - 1]);
|
snakeICells.push(snakeICells[snakeICells.length - 1]);
|
||||||
const snakeI = (0,types_snake/* createSnakeFromCells */.xG)(snakeICells);
|
const snakeI = (0,types_snake/* createSnakeFromCells */.yS)(snakeICells);
|
||||||
// remove from the grid the colors that one eat
|
// remove from the grid the colors that one eat
|
||||||
const gridI = (0,types_grid/* copyGrid */.VJ)(grid);
|
const gridI = (0,types_grid/* copyGrid */.mi)(grid);
|
||||||
for (const { x, y } of one)
|
for (const { x, y } of one)
|
||||||
setEmptySafe(gridI, x, y);
|
setEmptySafe(gridI, x, y);
|
||||||
const two = getSnakeEscapePath(gridI, outside, snakeI, color);
|
const two = getSnakeEscapePath(gridI, outside, snakeI, color);
|
||||||
@@ -309,15 +308,15 @@ const getPathTo = (grid, snake0, x, y) => {
|
|||||||
const closeList = [];
|
const closeList = [];
|
||||||
while (openList.length) {
|
while (openList.length) {
|
||||||
const c = openList.shift();
|
const c = openList.shift();
|
||||||
const cx = (0,types_snake/* getHeadX */.If)(c.snake);
|
const cx = (0,types_snake/* getHeadX */.tN)(c.snake);
|
||||||
const cy = (0,types_snake/* getHeadY */.IP)(c.snake);
|
const cy = (0,types_snake/* getHeadY */.Ap)(c.snake);
|
||||||
for (let i = 0; i < around4.length; i++) {
|
for (let i = 0; i < around4.length; i++) {
|
||||||
const { x: dx, y: dy } = around4[i];
|
const { x: dx, y: dy } = around4[i];
|
||||||
const nx = cx + dx;
|
const nx = cx + dx;
|
||||||
const ny = cy + dy;
|
const ny = cy + dy;
|
||||||
if (nx === x && ny === y) {
|
if (nx === x && ny === y) {
|
||||||
// unwrap
|
// unwrap
|
||||||
const path = [(0,types_snake/* nextSnake */.kv)(c.snake, dx, dy)];
|
const path = [(0,types_snake/* nextSnake */.Sc)(c.snake, dx, dy)];
|
||||||
let e = c;
|
let e = c;
|
||||||
while (e.parent) {
|
while (e.parent) {
|
||||||
path.push(e.snake);
|
path.push(e.snake);
|
||||||
@@ -325,11 +324,11 @@ const getPathTo = (grid, snake0, x, y) => {
|
|||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
if ((0,types_grid/* isInsideLarge */.HJ)(grid, 2, nx, ny) &&
|
if ((0,types_grid/* isInsideLarge */.Yd)(grid, 2, nx, ny) &&
|
||||||
!(0,types_snake/* snakeWillSelfCollide */.nJ)(c.snake, dx, dy) &&
|
!(0,types_snake/* snakeWillSelfCollide */.J)(c.snake, dx, dy) &&
|
||||||
(!(0,types_grid/* isInside */.V0)(grid, nx, ny) || (0,types_grid/* isEmpty */.xb)((0,types_grid/* getColor */.Lq)(grid, nx, ny)))) {
|
(!(0,types_grid/* isInside */.FK)(grid, nx, ny) || (0,types_grid/* isEmpty */.Im)((0,types_grid/* getColor */.oU)(grid, nx, ny)))) {
|
||||||
const nsnake = (0,types_snake/* nextSnake */.kv)(c.snake, dx, dy);
|
const nsnake = (0,types_snake/* nextSnake */.Sc)(c.snake, dx, dy);
|
||||||
if (!closeList.some((s) => (0,types_snake/* snakeEquals */.kE)(nsnake, s))) {
|
if (!closeList.some((s) => (0,types_snake/* snakeEquals */.sW)(nsnake, s))) {
|
||||||
const w = c.w + 1;
|
const w = c.w + 1;
|
||||||
const h = Math.abs(nx - x) + Math.abs(ny - y);
|
const h = Math.abs(nx - x) + Math.abs(ny - y);
|
||||||
const f = w + h;
|
const f = w + h;
|
||||||
@@ -350,7 +349,7 @@ const getPathTo = (grid, snake0, x, y) => {
|
|||||||
|
|
||||||
|
|
||||||
const clearResidualColoredLayer = (grid, outside, snake0, color) => {
|
const clearResidualColoredLayer = (grid, outside, snake0, color) => {
|
||||||
const snakeN = (0,types_snake/* getSnakeLength */.JJ)(snake0);
|
const snakeN = (0,types_snake/* getSnakeLength */.T$)(snake0);
|
||||||
const tunnels = getTunnellablePoints(grid, outside, snakeN, color);
|
const tunnels = getTunnellablePoints(grid, outside, snakeN, color);
|
||||||
// sort
|
// sort
|
||||||
tunnels.sort((a, b) => b.priority - a.priority);
|
tunnels.sort((a, b) => b.priority - a.priority);
|
||||||
@@ -369,7 +368,7 @@ const clearResidualColoredLayer = (grid, outside, snake0, color) => {
|
|||||||
fillOutside(outside, grid);
|
fillOutside(outside, grid);
|
||||||
// update tunnels
|
// update tunnels
|
||||||
for (let i = tunnels.length; i--;)
|
for (let i = tunnels.length; i--;)
|
||||||
if ((0,types_grid/* isEmpty */.xb)((0,types_grid/* getColor */.Lq)(grid, tunnels[i].x, tunnels[i].y)))
|
if ((0,types_grid/* isEmpty */.Im)((0,types_grid/* getColor */.oU)(grid, tunnels[i].x, tunnels[i].y)))
|
||||||
tunnels.splice(i, 1);
|
tunnels.splice(i, 1);
|
||||||
else {
|
else {
|
||||||
const t = tunnels[i];
|
const t = tunnels[i];
|
||||||
@@ -390,8 +389,8 @@ const clearResidualColoredLayer = (grid, outside, snake0, color) => {
|
|||||||
const getNextTunnel = (ts, snake) => {
|
const getNextTunnel = (ts, snake) => {
|
||||||
let minDistance = Infinity;
|
let minDistance = Infinity;
|
||||||
let closestTunnel = null;
|
let closestTunnel = null;
|
||||||
const x = (0,types_snake/* getHeadX */.If)(snake);
|
const x = (0,types_snake/* getHeadX */.tN)(snake);
|
||||||
const y = (0,types_snake/* getHeadY */.IP)(snake);
|
const y = (0,types_snake/* getHeadY */.Ap)(snake);
|
||||||
const priority = ts[0].priority;
|
const priority = ts[0].priority;
|
||||||
for (let i = 0; ts[i] && ts[i].priority === priority; i++) {
|
for (let i = 0; ts[i] && ts[i].priority === priority; i++) {
|
||||||
const t = ts[i].tunnel;
|
const t = ts[i].tunnel;
|
||||||
@@ -410,8 +409,8 @@ const getTunnellablePoints = (grid, outside, snakeN, color) => {
|
|||||||
const points = [];
|
const points = [];
|
||||||
for (let x = grid.width; x--;)
|
for (let x = grid.width; x--;)
|
||||||
for (let y = grid.height; y--;) {
|
for (let y = grid.height; y--;) {
|
||||||
const c = (0,types_grid/* getColor */.Lq)(grid, x, y);
|
const c = (0,types_grid/* getColor */.oU)(grid, x, y);
|
||||||
if (!(0,types_grid/* isEmpty */.xb)(c) && c < color) {
|
if (!(0,types_grid/* isEmpty */.Im)(c) && c < color) {
|
||||||
const tunnel = getBestTunnel(grid, outside, x, y, color, snakeN);
|
const tunnel = getBestTunnel(grid, outside, x, y, color, snakeN);
|
||||||
if (tunnel) {
|
if (tunnel) {
|
||||||
const priority = getPriority(grid, color, tunnel);
|
const priority = getPriority(grid, color, tunnel);
|
||||||
@@ -432,7 +431,7 @@ const getPriority = (grid, color, tunnel) => {
|
|||||||
for (let i = 0; i < tunnel.length; i++) {
|
for (let i = 0; i < tunnel.length; i++) {
|
||||||
const { x, y } = tunnel[i];
|
const { x, y } = tunnel[i];
|
||||||
const c = clearResidualColoredLayer_getColorSafe(grid, x, y);
|
const c = clearResidualColoredLayer_getColorSafe(grid, x, y);
|
||||||
if (!(0,types_grid/* isEmpty */.xb)(c) && i === tunnel.findIndex((p) => p.x === x && p.y === y)) {
|
if (!(0,types_grid/* isEmpty */.Im)(c) && i === tunnel.findIndex((p) => p.x === x && p.y === y)) {
|
||||||
if (c === color)
|
if (c === color)
|
||||||
nColor += 1;
|
nColor += 1;
|
||||||
else
|
else
|
||||||
@@ -444,10 +443,10 @@ const getPriority = (grid, color, tunnel) => {
|
|||||||
return nLess / nColor;
|
return nLess / nColor;
|
||||||
};
|
};
|
||||||
const distanceSq = (ax, ay, bx, by) => (ax - bx) ** 2 + (ay - by) ** 2;
|
const distanceSq = (ax, ay, bx, by) => (ax - bx) ** 2 + (ay - by) ** 2;
|
||||||
const clearResidualColoredLayer_getColorSafe = (grid, x, y) => (0,types_grid/* isInside */.V0)(grid, x, y) ? (0,types_grid/* getColor */.Lq)(grid, x, y) : 0;
|
const clearResidualColoredLayer_getColorSafe = (grid, x, y) => (0,types_grid/* isInside */.FK)(grid, x, y) ? (0,types_grid/* getColor */.oU)(grid, x, y) : 0;
|
||||||
const clearResidualColoredLayer_setEmptySafe = (grid, x, y) => {
|
const clearResidualColoredLayer_setEmptySafe = (grid, x, y) => {
|
||||||
if ((0,types_grid/* isInside */.V0)(grid, x, y))
|
if ((0,types_grid/* isInside */.FK)(grid, x, y))
|
||||||
(0,types_grid/* setColorEmpty */.Dy)(grid, x, y);
|
(0,types_grid/* setColorEmpty */.l$)(grid, x, y);
|
||||||
};
|
};
|
||||||
|
|
||||||
;// CONCATENATED MODULE: ../solver/clearCleanColoredLayer.ts
|
;// CONCATENATED MODULE: ../solver/clearCleanColoredLayer.ts
|
||||||
@@ -457,14 +456,14 @@ const clearResidualColoredLayer_setEmptySafe = (grid, x, y) => {
|
|||||||
|
|
||||||
|
|
||||||
const clearCleanColoredLayer = (grid, outside, snake0, color) => {
|
const clearCleanColoredLayer = (grid, outside, snake0, color) => {
|
||||||
const snakeN = (0,types_snake/* getSnakeLength */.JJ)(snake0);
|
const snakeN = (0,types_snake/* getSnakeLength */.T$)(snake0);
|
||||||
const points = clearCleanColoredLayer_getTunnellablePoints(grid, outside, snakeN, color);
|
const points = clearCleanColoredLayer_getTunnellablePoints(grid, outside, snakeN, color);
|
||||||
const chain = [snake0];
|
const chain = [snake0];
|
||||||
while (points.length) {
|
while (points.length) {
|
||||||
const path = getPathToNextPoint(grid, chain[0], color, points);
|
const path = getPathToNextPoint(grid, chain[0], color, points);
|
||||||
path.pop();
|
path.pop();
|
||||||
for (const snake of path)
|
for (const snake of path)
|
||||||
clearCleanColoredLayer_setEmptySafe(grid, (0,types_snake/* getHeadX */.If)(snake), (0,types_snake/* getHeadY */.IP)(snake));
|
clearCleanColoredLayer_setEmptySafe(grid, (0,types_snake/* getHeadX */.tN)(snake), (0,types_snake/* getHeadY */.Ap)(snake));
|
||||||
chain.unshift(...path);
|
chain.unshift(...path);
|
||||||
}
|
}
|
||||||
fillOutside(outside, grid);
|
fillOutside(outside, grid);
|
||||||
@@ -477,19 +476,19 @@ const getPathToNextPoint = (grid, snake0, color, points) => {
|
|||||||
const openList = [{ snake: snake0 }];
|
const openList = [{ snake: snake0 }];
|
||||||
while (openList.length) {
|
while (openList.length) {
|
||||||
const o = openList.shift();
|
const o = openList.shift();
|
||||||
const x = (0,types_snake/* getHeadX */.If)(o.snake);
|
const x = (0,types_snake/* getHeadX */.tN)(o.snake);
|
||||||
const y = (0,types_snake/* getHeadY */.IP)(o.snake);
|
const y = (0,types_snake/* getHeadY */.Ap)(o.snake);
|
||||||
const i = points.findIndex((p) => p.x === x && p.y === y);
|
const i = points.findIndex((p) => p.x === x && p.y === y);
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
points.splice(i, 1);
|
points.splice(i, 1);
|
||||||
return clearCleanColoredLayer_unwrap(o);
|
return clearCleanColoredLayer_unwrap(o);
|
||||||
}
|
}
|
||||||
for (const { x: dx, y: dy } of around4) {
|
for (const { x: dx, y: dy } of around4) {
|
||||||
if ((0,types_grid/* isInsideLarge */.HJ)(grid, 2, x + dx, y + dy) &&
|
if ((0,types_grid/* isInsideLarge */.Yd)(grid, 2, x + dx, y + dy) &&
|
||||||
!(0,types_snake/* snakeWillSelfCollide */.nJ)(o.snake, dx, dy) &&
|
!(0,types_snake/* snakeWillSelfCollide */.J)(o.snake, dx, dy) &&
|
||||||
clearCleanColoredLayer_getColorSafe(grid, x + dx, y + dy) <= color) {
|
clearCleanColoredLayer_getColorSafe(grid, x + dx, y + dy) <= color) {
|
||||||
const snake = (0,types_snake/* nextSnake */.kv)(o.snake, dx, dy);
|
const snake = (0,types_snake/* nextSnake */.Sc)(o.snake, dx, dy);
|
||||||
if (!closeList.some((s0) => (0,types_snake/* snakeEquals */.kE)(s0, snake))) {
|
if (!closeList.some((s0) => (0,types_snake/* snakeEquals */.sW)(s0, snake))) {
|
||||||
closeList.push(snake);
|
closeList.push(snake);
|
||||||
openList.push({ snake, parent: o });
|
openList.push({ snake, parent: o });
|
||||||
}
|
}
|
||||||
@@ -504,8 +503,8 @@ const clearCleanColoredLayer_getTunnellablePoints = (grid, outside, snakeN, colo
|
|||||||
const points = [];
|
const points = [];
|
||||||
for (let x = grid.width; x--;)
|
for (let x = grid.width; x--;)
|
||||||
for (let y = grid.height; y--;) {
|
for (let y = grid.height; y--;) {
|
||||||
const c = (0,types_grid/* getColor */.Lq)(grid, x, y);
|
const c = (0,types_grid/* getColor */.oU)(grid, x, y);
|
||||||
if (!(0,types_grid/* isEmpty */.xb)(c) &&
|
if (!(0,types_grid/* isEmpty */.Im)(c) &&
|
||||||
c <= color &&
|
c <= color &&
|
||||||
!points.some((p) => p.x === x && p.y === y)) {
|
!points.some((p) => p.x === x && p.y === y)) {
|
||||||
const tunnel = getBestTunnel(grid, outside, x, y, color, snakeN);
|
const tunnel = getBestTunnel(grid, outside, x, y, color, snakeN);
|
||||||
@@ -517,12 +516,12 @@ const clearCleanColoredLayer_getTunnellablePoints = (grid, outside, snakeN, colo
|
|||||||
}
|
}
|
||||||
return points;
|
return points;
|
||||||
};
|
};
|
||||||
const clearCleanColoredLayer_getColorSafe = (grid, x, y) => (0,types_grid/* isInside */.V0)(grid, x, y) ? (0,types_grid/* getColor */.Lq)(grid, x, y) : 0;
|
const clearCleanColoredLayer_getColorSafe = (grid, x, y) => (0,types_grid/* isInside */.FK)(grid, x, y) ? (0,types_grid/* getColor */.oU)(grid, x, y) : 0;
|
||||||
const clearCleanColoredLayer_setEmptySafe = (grid, x, y) => {
|
const clearCleanColoredLayer_setEmptySafe = (grid, x, y) => {
|
||||||
if ((0,types_grid/* isInside */.V0)(grid, x, y))
|
if ((0,types_grid/* isInside */.FK)(grid, x, y))
|
||||||
(0,types_grid/* setColorEmpty */.Dy)(grid, x, y);
|
(0,types_grid/* setColorEmpty */.l$)(grid, x, y);
|
||||||
};
|
};
|
||||||
const clearCleanColoredLayer_isEmptySafe = (grid, x, y) => !(0,types_grid/* isInside */.V0)(grid, x, y) && (0,types_grid/* isEmpty */.xb)((0,types_grid/* getColor */.Lq)(grid, x, y));
|
const clearCleanColoredLayer_isEmptySafe = (grid, x, y) => !(0,types_grid/* isInside */.FK)(grid, x, y) && (0,types_grid/* isEmpty */.Im)((0,types_grid/* getColor */.oU)(grid, x, y));
|
||||||
|
|
||||||
;// CONCATENATED MODULE: ../solver/getBestRoute.ts
|
;// CONCATENATED MODULE: ../solver/getBestRoute.ts
|
||||||
|
|
||||||
@@ -530,7 +529,7 @@ const clearCleanColoredLayer_isEmptySafe = (grid, x, y) => !(0,types_grid/* isIn
|
|||||||
|
|
||||||
|
|
||||||
const getBestRoute = (grid0, snake0) => {
|
const getBestRoute = (grid0, snake0) => {
|
||||||
const grid = (0,types_grid/* copyGrid */.VJ)(grid0);
|
const grid = (0,types_grid/* copyGrid */.mi)(grid0);
|
||||||
const outside = createOutside(grid);
|
const outside = createOutside(grid);
|
||||||
const chain = [snake0];
|
const chain = [snake0];
|
||||||
for (const color of extractColors(grid)) {
|
for (const color of extractColors(grid)) {
|
||||||
@@ -548,7 +547,7 @@ const extractColors = (grid) => {
|
|||||||
|
|
||||||
;// CONCATENATED MODULE: ../types/__fixtures__/snake.ts
|
;// CONCATENATED MODULE: ../types/__fixtures__/snake.ts
|
||||||
|
|
||||||
const create = (length) => (0,types_snake/* createSnakeFromCells */.xG)(Array.from({ length }, (_, i) => ({ x: i, y: -1 })));
|
const create = (length) => (0,types_snake/* createSnakeFromCells */.yS)(Array.from({ length }, (_, i) => ({ x: i, y: -1 })));
|
||||||
const snake1 = create(1);
|
const snake1 = create(1);
|
||||||
const snake3 = create(3);
|
const snake3 = create(3);
|
||||||
const snake4 = create(4);
|
const snake4 = create(4);
|
||||||
@@ -561,20 +560,20 @@ const snake9 = create(9);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
const getPathToPose_isEmptySafe = (grid, x, y) => !(0,types_grid/* isInside */.V0)(grid, x, y) || (0,types_grid/* isEmpty */.xb)((0,types_grid/* getColor */.Lq)(grid, x, y));
|
const getPathToPose_isEmptySafe = (grid, x, y) => !(0,types_grid/* isInside */.FK)(grid, x, y) || (0,types_grid/* isEmpty */.Im)((0,types_grid/* getColor */.oU)(grid, x, y));
|
||||||
const getPathToPose = (snake0, target, grid) => {
|
const getPathToPose = (snake0, target, grid) => {
|
||||||
if ((0,types_snake/* snakeEquals */.kE)(snake0, target))
|
if ((0,types_snake/* snakeEquals */.sW)(snake0, target))
|
||||||
return [];
|
return [];
|
||||||
const targetCells = (0,types_snake/* snakeToCells */.Ks)(target).reverse();
|
const targetCells = (0,types_snake/* snakeToCells */.HU)(target).reverse();
|
||||||
const snakeN = (0,types_snake/* getSnakeLength */.JJ)(snake0);
|
const snakeN = (0,types_snake/* getSnakeLength */.T$)(snake0);
|
||||||
const box = {
|
const box = {
|
||||||
min: {
|
min: {
|
||||||
x: Math.min((0,types_snake/* getHeadX */.If)(snake0), (0,types_snake/* getHeadX */.If)(target)) - snakeN - 1,
|
x: Math.min((0,types_snake/* getHeadX */.tN)(snake0), (0,types_snake/* getHeadX */.tN)(target)) - snakeN - 1,
|
||||||
y: Math.min((0,types_snake/* getHeadY */.IP)(snake0), (0,types_snake/* getHeadY */.IP)(target)) - snakeN - 1,
|
y: Math.min((0,types_snake/* getHeadY */.Ap)(snake0), (0,types_snake/* getHeadY */.Ap)(target)) - snakeN - 1,
|
||||||
},
|
},
|
||||||
max: {
|
max: {
|
||||||
x: Math.max((0,types_snake/* getHeadX */.If)(snake0), (0,types_snake/* getHeadX */.If)(target)) + snakeN + 1,
|
x: Math.max((0,types_snake/* getHeadX */.tN)(snake0), (0,types_snake/* getHeadX */.tN)(target)) + snakeN + 1,
|
||||||
y: Math.max((0,types_snake/* getHeadY */.IP)(snake0), (0,types_snake/* getHeadY */.IP)(target)) + snakeN + 1,
|
y: Math.max((0,types_snake/* getHeadY */.Ap)(snake0), (0,types_snake/* getHeadY */.Ap)(target)) + snakeN + 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const [t0, ...forbidden] = targetCells;
|
const [t0, ...forbidden] = targetCells;
|
||||||
@@ -583,8 +582,8 @@ const getPathToPose = (snake0, target, grid) => {
|
|||||||
const closeList = [];
|
const closeList = [];
|
||||||
while (openList.length) {
|
while (openList.length) {
|
||||||
const o = openList.shift();
|
const o = openList.shift();
|
||||||
const x = (0,types_snake/* getHeadX */.If)(o.snake);
|
const x = (0,types_snake/* getHeadX */.tN)(o.snake);
|
||||||
const y = (0,types_snake/* getHeadY */.IP)(o.snake);
|
const y = (0,types_snake/* getHeadY */.Ap)(o.snake);
|
||||||
if (x === t0.x && y === t0.y) {
|
if (x === t0.x && y === t0.y) {
|
||||||
const path = [];
|
const path = [];
|
||||||
let e = o;
|
let e = o;
|
||||||
@@ -601,17 +600,17 @@ const getPathToPose = (snake0, target, grid) => {
|
|||||||
const { x: dx, y: dy } = around4[i];
|
const { x: dx, y: dy } = around4[i];
|
||||||
const nx = x + dx;
|
const nx = x + dx;
|
||||||
const ny = y + dy;
|
const ny = y + dy;
|
||||||
if (!(0,types_snake/* snakeWillSelfCollide */.nJ)(o.snake, dx, dy) &&
|
if (!(0,types_snake/* snakeWillSelfCollide */.J)(o.snake, dx, dy) &&
|
||||||
(!grid || getPathToPose_isEmptySafe(grid, nx, ny)) &&
|
(!grid || getPathToPose_isEmptySafe(grid, nx, ny)) &&
|
||||||
(grid
|
(grid
|
||||||
? (0,types_grid/* isInsideLarge */.HJ)(grid, 2, nx, ny)
|
? (0,types_grid/* isInsideLarge */.Yd)(grid, 2, nx, ny)
|
||||||
: box.min.x <= nx &&
|
: box.min.x <= nx &&
|
||||||
nx <= box.max.x &&
|
nx <= box.max.x &&
|
||||||
box.min.y <= ny &&
|
box.min.y <= ny &&
|
||||||
ny <= box.max.y) &&
|
ny <= box.max.y) &&
|
||||||
!forbidden.some((p) => p.x === nx && p.y === ny)) {
|
!forbidden.some((p) => p.x === nx && p.y === ny)) {
|
||||||
const snake = (0,types_snake/* nextSnake */.kv)(o.snake, dx, dy);
|
const snake = (0,types_snake/* nextSnake */.Sc)(o.snake, dx, dy);
|
||||||
if (!closeList.some((s) => (0,types_snake/* snakeEquals */.kE)(snake, s))) {
|
if (!closeList.some((s) => (0,types_snake/* snakeEquals */.sW)(snake, s))) {
|
||||||
const w = o.w + 1;
|
const w = o.w + 1;
|
||||||
const h = Math.abs(nx - x) + Math.abs(ny - y);
|
const h = Math.abs(nx - x) + Math.abs(ny - y);
|
||||||
const f = w + h;
|
const f = w + h;
|
||||||
@@ -644,12 +643,12 @@ const generateContributionSnake = async (userName, outputs, options) => {
|
|||||||
switch (format) {
|
switch (format) {
|
||||||
case "svg": {
|
case "svg": {
|
||||||
console.log(`🖌 creating svg (outputs[${i}])`);
|
console.log(`🖌 creating svg (outputs[${i}])`);
|
||||||
const { createSvg } = await __webpack_require__.e(/* import() */ 340).then(__webpack_require__.bind(__webpack_require__, 8340));
|
const { createSvg } = await __webpack_require__.e(/* import() */ 578).then(__webpack_require__.bind(__webpack_require__, 4578));
|
||||||
return createSvg(grid, cells, chain, drawOptions, animationOptions);
|
return createSvg(grid, cells, chain, drawOptions, animationOptions);
|
||||||
}
|
}
|
||||||
case "gif": {
|
case "gif": {
|
||||||
console.log(`📹 creating gif (outputs[${i}])`);
|
console.log(`📹 creating gif (outputs[${i}])`);
|
||||||
const { createGif } = await Promise.all(/* import() */[__webpack_require__.e(371), __webpack_require__.e(142)]).then(__webpack_require__.bind(__webpack_require__, 7142));
|
const { createGif } = await Promise.all(/* import() */[__webpack_require__.e(155), __webpack_require__.e(642)]).then(__webpack_require__.bind(__webpack_require__, 3642));
|
||||||
return await createGif(grid, cells, chain, drawOptions, animationOptions);
|
return await createGif(grid, cells, chain, drawOptions, animationOptions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -659,18 +658,18 @@ const generateContributionSnake = async (userName, outputs, options) => {
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 2881:
|
/***/ 105:
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||||
|
|
||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||||
/* harmony export */ "Dy": () => (/* binding */ setColorEmpty),
|
/* harmony export */ FK: () => (/* binding */ isInside),
|
||||||
/* harmony export */ "HJ": () => (/* binding */ isInsideLarge),
|
/* harmony export */ Im: () => (/* binding */ isEmpty),
|
||||||
/* harmony export */ "Lq": () => (/* binding */ getColor),
|
/* harmony export */ Kb: () => (/* binding */ createEmptyGrid),
|
||||||
/* harmony export */ "V0": () => (/* binding */ isInside),
|
/* harmony export */ Yd: () => (/* binding */ isInsideLarge),
|
||||||
/* harmony export */ "VJ": () => (/* binding */ copyGrid),
|
/* harmony export */ l$: () => (/* binding */ setColorEmpty),
|
||||||
/* harmony export */ "u1": () => (/* binding */ createEmptyGrid),
|
/* harmony export */ mi: () => (/* binding */ copyGrid),
|
||||||
/* harmony export */ "vk": () => (/* binding */ setColor),
|
/* harmony export */ oU: () => (/* binding */ getColor),
|
||||||
/* harmony export */ "xb": () => (/* binding */ isEmpty)
|
/* harmony export */ wW: () => (/* binding */ setColor)
|
||||||
/* harmony export */ });
|
/* harmony export */ });
|
||||||
/* unused harmony exports isGridEmpty, gridEquals */
|
/* unused harmony exports isGridEmpty, gridEquals */
|
||||||
const isInside = (grid, x, y) => x >= 0 && y >= 0 && x < grid.width && y < grid.height;
|
const isInside = (grid, x, y) => x >= 0 && y >= 0 && x < grid.width && y < grid.height;
|
||||||
@@ -703,18 +702,18 @@ const createEmptyGrid = (width, height) => ({
|
|||||||
|
|
||||||
/***/ }),
|
/***/ }),
|
||||||
|
|
||||||
/***/ 9347:
|
/***/ 777:
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||||
|
|
||||||
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
||||||
/* harmony export */ "IP": () => (/* binding */ getHeadY),
|
/* harmony export */ Ap: () => (/* binding */ getHeadY),
|
||||||
/* harmony export */ "If": () => (/* binding */ getHeadX),
|
/* harmony export */ HU: () => (/* binding */ snakeToCells),
|
||||||
/* harmony export */ "JJ": () => (/* binding */ getSnakeLength),
|
/* harmony export */ J: () => (/* binding */ snakeWillSelfCollide),
|
||||||
/* harmony export */ "Ks": () => (/* binding */ snakeToCells),
|
/* harmony export */ Sc: () => (/* binding */ nextSnake),
|
||||||
/* harmony export */ "kE": () => (/* binding */ snakeEquals),
|
/* harmony export */ T$: () => (/* binding */ getSnakeLength),
|
||||||
/* harmony export */ "kv": () => (/* binding */ nextSnake),
|
/* harmony export */ sW: () => (/* binding */ snakeEquals),
|
||||||
/* harmony export */ "nJ": () => (/* binding */ snakeWillSelfCollide),
|
/* harmony export */ tN: () => (/* binding */ getHeadX),
|
||||||
/* harmony export */ "xG": () => (/* binding */ createSnakeFromCells)
|
/* harmony export */ yS: () => (/* binding */ createSnakeFromCells)
|
||||||
/* harmony export */ });
|
/* harmony export */ });
|
||||||
/* unused harmony export copySnake */
|
/* unused harmony export copySnake */
|
||||||
const getHeadX = (snake) => snake[0] - 2;
|
const getHeadX = (snake) => snake[0] - 2;
|
||||||
5865
svg-only/dist/371.index.js
vendored
5865
svg-only/dist/371.index.js
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,21 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
exports.id = 340;
|
exports.id = 578;
|
||||||
exports.ids = [340];
|
exports.ids = [578];
|
||||||
exports.modules = {
|
exports.modules = {
|
||||||
|
|
||||||
/***/ 8340:
|
/***/ 4578:
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||||
|
|
||||||
// ESM COMPAT FLAG
|
|
||||||
__webpack_require__.r(__webpack_exports__);
|
|
||||||
|
|
||||||
// EXPORTS
|
// EXPORTS
|
||||||
__webpack_require__.d(__webpack_exports__, {
|
__webpack_require__.d(__webpack_exports__, {
|
||||||
"createSvg": () => (/* binding */ createSvg)
|
createSvg: () => (/* binding */ createSvg)
|
||||||
});
|
});
|
||||||
|
|
||||||
// EXTERNAL MODULE: ../types/grid.ts
|
// EXTERNAL MODULE: ../types/grid.ts
|
||||||
var types_grid = __webpack_require__(2881);
|
var types_grid = __webpack_require__(105);
|
||||||
// EXTERNAL MODULE: ../types/snake.ts
|
// EXTERNAL MODULE: ../types/snake.ts
|
||||||
var types_snake = __webpack_require__(9347);
|
var types_snake = __webpack_require__(777);
|
||||||
;// CONCATENATED MODULE: ../svg-creator/xml-utils.ts
|
;// CONCATENATED MODULE: ../svg-creator/xml-utils.ts
|
||||||
const h = (element, attributes) => `<${element} ${toAttribute(attributes)}/>`;
|
const h = (element, attributes) => `<${element} ${toAttribute(attributes)}/>`;
|
||||||
const toAttribute = (o) => Object.entries(o)
|
const toAttribute = (o) => Object.entries(o)
|
||||||
@@ -62,10 +60,10 @@ const minifyCss = (css) => css
|
|||||||
|
|
||||||
const lerp = (k, a, b) => (1 - k) * a + k * b;
|
const lerp = (k, a, b) => (1 - k) * a + k * b;
|
||||||
const createSnake = (chain, { sizeCell, sizeDot }, duration) => {
|
const createSnake = (chain, { sizeCell, sizeDot }, duration) => {
|
||||||
const snakeN = chain[0] ? (0,types_snake/* getSnakeLength */.JJ)(chain[0]) : 0;
|
const snakeN = chain[0] ? (0,types_snake/* getSnakeLength */.T$)(chain[0]) : 0;
|
||||||
const snakeParts = Array.from({ length: snakeN }, () => []);
|
const snakeParts = Array.from({ length: snakeN }, () => []);
|
||||||
for (const snake of chain) {
|
for (const snake of chain) {
|
||||||
const cells = (0,types_snake/* snakeToCells */.Ks)(snake);
|
const cells = (0,types_snake/* snakeToCells */.HU)(snake);
|
||||||
for (let i = cells.length; i--;)
|
for (let i = cells.length; i--;)
|
||||||
snakeParts[i].push(cells[i]);
|
snakeParts[i].push(cells[i]);
|
||||||
}
|
}
|
||||||
@@ -237,15 +235,15 @@ const createLivingCells = (grid0, chain, cells) => {
|
|||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
t: null,
|
t: null,
|
||||||
color: (0,types_grid/* getColor */.Lq)(grid0, x, y),
|
color: (0,types_grid/* getColor */.oU)(grid0, x, y),
|
||||||
}));
|
}));
|
||||||
const grid = (0,types_grid/* copyGrid */.VJ)(grid0);
|
const grid = (0,types_grid/* copyGrid */.mi)(grid0);
|
||||||
for (let i = 0; i < chain.length; i++) {
|
for (let i = 0; i < chain.length; i++) {
|
||||||
const snake = chain[i];
|
const snake = chain[i];
|
||||||
const x = (0,types_snake/* getHeadX */.If)(snake);
|
const x = (0,types_snake/* getHeadX */.tN)(snake);
|
||||||
const y = (0,types_snake/* getHeadY */.IP)(snake);
|
const y = (0,types_snake/* getHeadY */.Ap)(snake);
|
||||||
if ((0,types_grid/* isInside */.V0)(grid, x, y) && !(0,types_grid/* isEmpty */.xb)((0,types_grid/* getColor */.Lq)(grid, x, y))) {
|
if ((0,types_grid/* isInside */.FK)(grid, x, y) && !(0,types_grid/* isEmpty */.Im)((0,types_grid/* getColor */.oU)(grid, x, y))) {
|
||||||
(0,types_grid/* setColorEmpty */.Dy)(grid, x, y);
|
(0,types_grid/* setColorEmpty */.l$)(grid, x, y);
|
||||||
const cell = livingCells.find((c) => c.x === x && c.y === y);
|
const cell = livingCells.find((c) => c.x === x && c.y === y);
|
||||||
cell.t = i / chain.length;
|
cell.t = i / chain.length;
|
||||||
}
|
}
|
||||||
@@ -1,31 +1,29 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
exports.id = 142;
|
exports.id = 642;
|
||||||
exports.ids = [142];
|
exports.ids = [642];
|
||||||
exports.modules = {
|
exports.modules = {
|
||||||
|
|
||||||
/***/ 7142:
|
/***/ 3642:
|
||||||
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
||||||
|
|
||||||
// ESM COMPAT FLAG
|
|
||||||
__webpack_require__.r(__webpack_exports__);
|
|
||||||
|
|
||||||
// EXPORTS
|
// EXPORTS
|
||||||
__webpack_require__.d(__webpack_exports__, {
|
__webpack_require__.d(__webpack_exports__, {
|
||||||
"createGif": () => (/* binding */ createGif)
|
createGif: () => (/* binding */ createGif)
|
||||||
});
|
});
|
||||||
|
|
||||||
// EXTERNAL MODULE: external "fs"
|
// EXTERNAL MODULE: external "fs"
|
||||||
var external_fs_ = __webpack_require__(7147);
|
var external_fs_ = __webpack_require__(9896);
|
||||||
var external_fs_default = /*#__PURE__*/__webpack_require__.n(external_fs_);
|
var external_fs_default = /*#__PURE__*/__webpack_require__.n(external_fs_);
|
||||||
// EXTERNAL MODULE: external "path"
|
// EXTERNAL MODULE: external "path"
|
||||||
var external_path_ = __webpack_require__(1017);
|
var external_path_ = __webpack_require__(6928);
|
||||||
var external_path_default = /*#__PURE__*/__webpack_require__.n(external_path_);
|
var external_path_default = /*#__PURE__*/__webpack_require__.n(external_path_);
|
||||||
// EXTERNAL MODULE: external "child_process"
|
// EXTERNAL MODULE: external "child_process"
|
||||||
var external_child_process_ = __webpack_require__(2081);
|
var external_child_process_ = __webpack_require__(5317);
|
||||||
// EXTERNAL MODULE: external "canvas"
|
// EXTERNAL MODULE: external "canvas"
|
||||||
var external_canvas_ = __webpack_require__(1576);
|
var external_canvas_ = __webpack_require__(9919);
|
||||||
// EXTERNAL MODULE: ../types/grid.ts
|
// EXTERNAL MODULE: ../types/grid.ts
|
||||||
var types_grid = __webpack_require__(2881);
|
var types_grid = __webpack_require__(105);
|
||||||
;// CONCATENATED MODULE: ../draw/pathRoundedRect.ts
|
;// CONCATENATED MODULE: ../draw/pathRoundedRect.ts
|
||||||
const pathRoundedRect_pathRoundedRect = (ctx, width, height, borderRadius) => {
|
const pathRoundedRect_pathRoundedRect = (ctx, width, height, borderRadius) => {
|
||||||
ctx.moveTo(borderRadius, 0);
|
ctx.moveTo(borderRadius, 0);
|
||||||
@@ -42,7 +40,7 @@ const drawGrid_drawGrid = (ctx, grid, cells, o) => {
|
|||||||
for (let x = grid.width; x--;)
|
for (let x = grid.width; x--;)
|
||||||
for (let y = grid.height; y--;) {
|
for (let y = grid.height; y--;) {
|
||||||
if (!cells || cells.some((c) => c.x === x && c.y === y)) {
|
if (!cells || cells.some((c) => c.x === x && c.y === y)) {
|
||||||
const c = (0,types_grid/* getColor */.Lq)(grid, x, y);
|
const c = (0,types_grid/* getColor */.oU)(grid, x, y);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const color = !c ? o.colorEmpty : o.colorDots[c];
|
const color = !c ? o.colorEmpty : o.colorDots[c];
|
||||||
ctx.save();
|
ctx.save();
|
||||||
@@ -144,27 +142,27 @@ const getCanvasWorldSize = (grid, o) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// EXTERNAL MODULE: ../types/snake.ts
|
// EXTERNAL MODULE: ../types/snake.ts
|
||||||
var types_snake = __webpack_require__(9347);
|
var types_snake = __webpack_require__(777);
|
||||||
;// CONCATENATED MODULE: ../solver/step.ts
|
;// CONCATENATED MODULE: ../solver/step.ts
|
||||||
|
|
||||||
|
|
||||||
const step = (grid, stack, snake) => {
|
const step = (grid, stack, snake) => {
|
||||||
const x = (0,types_snake/* getHeadX */.If)(snake);
|
const x = (0,types_snake/* getHeadX */.tN)(snake);
|
||||||
const y = (0,types_snake/* getHeadY */.IP)(snake);
|
const y = (0,types_snake/* getHeadY */.Ap)(snake);
|
||||||
const color = (0,types_grid/* getColor */.Lq)(grid, x, y);
|
const color = (0,types_grid/* getColor */.oU)(grid, x, y);
|
||||||
if ((0,types_grid/* isInside */.V0)(grid, x, y) && !(0,types_grid/* isEmpty */.xb)(color)) {
|
if ((0,types_grid/* isInside */.FK)(grid, x, y) && !(0,types_grid/* isEmpty */.Im)(color)) {
|
||||||
stack.push(color);
|
stack.push(color);
|
||||||
(0,types_grid/* setColorEmpty */.Dy)(grid, x, y);
|
(0,types_grid/* setColorEmpty */.l$)(grid, x, y);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// EXTERNAL MODULE: ../../node_modules/tmp/lib/tmp.js
|
// EXTERNAL MODULE: ../../node_modules/tmp/lib/tmp.js
|
||||||
var tmp = __webpack_require__(6382);
|
var tmp = __webpack_require__(2644);
|
||||||
// EXTERNAL MODULE: external "gifsicle"
|
// EXTERNAL MODULE: external "gifsicle"
|
||||||
var external_gifsicle_ = __webpack_require__(542);
|
var external_gifsicle_ = __webpack_require__(5667);
|
||||||
var external_gifsicle_default = /*#__PURE__*/__webpack_require__.n(external_gifsicle_);
|
var external_gifsicle_default = /*#__PURE__*/__webpack_require__.n(external_gifsicle_);
|
||||||
// EXTERNAL MODULE: ../../node_modules/gif-encoder-2/index.js
|
// EXTERNAL MODULE: ../../node_modules/gif-encoder-2/index.js
|
||||||
var gif_encoder_2 = __webpack_require__(3561);
|
var gif_encoder_2 = __webpack_require__(1680);
|
||||||
var gif_encoder_2_default = /*#__PURE__*/__webpack_require__.n(gif_encoder_2);
|
var gif_encoder_2_default = /*#__PURE__*/__webpack_require__.n(gif_encoder_2);
|
||||||
;// CONCATENATED MODULE: ../gif-creator/index.ts
|
;// CONCATENATED MODULE: ../gif-creator/index.ts
|
||||||
|
|
||||||
@@ -193,7 +191,7 @@ const createGif = async (grid0, cells, chain, drawOptions, animationOptions) =>
|
|||||||
const { width, height } = getCanvasWorldSize(grid0, drawOptions);
|
const { width, height } = getCanvasWorldSize(grid0, drawOptions);
|
||||||
const canvas = (0,external_canvas_.createCanvas)(width, height);
|
const canvas = (0,external_canvas_.createCanvas)(width, height);
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext("2d");
|
||||||
const grid = (0,types_grid/* copyGrid */.VJ)(grid0);
|
const grid = (0,types_grid/* copyGrid */.mi)(grid0);
|
||||||
const stack = [];
|
const stack = [];
|
||||||
const encoder = new (gif_encoder_2_default())(width, height, "neuquant", true);
|
const encoder = new (gif_encoder_2_default())(width, height, "neuquant", true);
|
||||||
encoder.setRepeat(0);
|
encoder.setRepeat(0);
|
||||||
@@ -223,7 +221,7 @@ const createGif = async (grid0, cells, chain, drawOptions, animationOptions) =>
|
|||||||
outFileName,
|
outFileName,
|
||||||
["--output", optimizedFileName],
|
["--output", optimizedFileName],
|
||||||
].flat());
|
].flat());
|
||||||
return external_fs_default().readFileSync(optimizedFileName);
|
return new Uint8Array(external_fs_default().readFileSync(optimizedFileName));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
26137
svg-only/dist/index.js
vendored
26137
svg-only/dist/index.js
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user