Compare commits

...

12 Commits

Author SHA1 Message Date
platane
d7ef7da9fb . 2025-03-24 22:01:03 +01:00
platane
db283098a9 . 2025-03-24 21:23:51 +01:00
platane
621d78be60 . 2025-03-24 21:23:37 +01:00
platane
42f5b68655 . 2025-03-23 15:24:13 +01:00
platane
c135277bdf . 2025-03-23 14:33:58 +01:00
platane
34d5617f54 . 2025-03-23 13:45:30 +01:00
platane
be9fca7f10 . 2025-03-23 12:00:49 +01:00
platane
c0a042d6b4 . 2025-03-23 11:24:57 +01:00
platane
85e229a04d . 2025-03-23 10:32:07 +01:00
platane
da5e045399 add tests 2025-03-23 10:31:17 +01:00
platane
c22b80d02b . 2025-03-22 16:50:10 +01:00
platane
3db2b4069e wasm 2025-03-22 15:58:46 +01:00
18 changed files with 1103 additions and 4 deletions

View File

@@ -9,14 +9,22 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v1
- uses: dtolnay/rust-toolchain@stable
- run: bun install --frozen-lockfile
- run: bun run build
working-directory: packages/solver-r
- run: npm run type
- run: npm run lint
- run: bun test
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: cargo test
working-directory: packages/solver-r
- run: npm run lint
test-action:
runs-on: ubuntu-latest

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ build
.env
.wrangler
.dev.vars
target

View File

@@ -92,6 +92,13 @@
"park-miller": "1.1.0",
},
},
"packages/solver-r": {
"name": "@snk/solver-r",
"version": "1.0.0",
"devDependencies": {
"wasm-pack": "0.13.1",
},
},
"packages/svg-creator": {
"name": "@snk/svg-creator",
"version": "1.0.0",
@@ -107,6 +114,9 @@
},
},
},
"trustedDependencies": [
"wasm-pack",
],
"packages": {
"@actions/core": ["@actions/core@1.11.1", "", { "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" } }, "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A=="],
@@ -260,6 +270,8 @@
"@snk/solver": ["@snk/solver@workspace:packages/solver"],
"@snk/solver-r": ["@snk/solver-r@workspace:packages/solver-r"],
"@snk/svg-creator": ["@snk/svg-creator@workspace:packages/svg-creator"],
"@snk/types": ["@snk/types@workspace:packages/types"],
@@ -400,6 +412,10 @@
"as-table": ["as-table@1.0.55", "", { "dependencies": { "printable-characters": "^1.0.42" } }, "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ=="],
"axios": ["axios@0.26.1", "", { "dependencies": { "follow-redirects": "^1.14.8" } }, "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA=="],
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="],
"batch": ["batch@0.6.1", "", {}, "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw=="],
@@ -416,6 +432,8 @@
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
"binary-install": ["binary-install@1.1.0", "", { "dependencies": { "axios": "^0.26.1", "rimraf": "^3.0.2", "tar": "^6.1.11" } }, "sha512-rkwNGW+3aQVSZoD0/o3mfPN6Yxh3Id0R/xzTVBVVpGNlVz8EGwusksxRlbk/A5iKTZt9zkMn3qIqmAt3vpfbzg=="],
"bl": ["bl@4.1.0", "", { "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", "readable-stream": "^3.4.0" } }, "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w=="],
"blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="],
@@ -426,6 +444,8 @@
"boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="],
"brace-expansion": ["brace-expansion@1.1.11", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="],
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
"browserslist": ["browserslist@4.24.4", "", { "dependencies": { "caniuse-lite": "^1.0.30001688", "electron-to-chromium": "^1.5.73", "node-releases": "^2.0.19", "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" } }, "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A=="],
@@ -492,6 +512,8 @@
"compression": ["compression@1.8.0", "", { "dependencies": { "bytes": "3.1.2", "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", "on-headers": "~1.0.2", "safe-buffer": "5.2.1", "vary": "~1.1.2" } }, "sha512-k6WLKfunuqCYD3t6AsuPGvQWaKwuLLh2/xHNcX4qE+vIfDNXpSqnrhwA7O53R7WVQUnt8dVAIW+YHr7xTgOgGA=="],
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
"confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="],
"config-chain": ["config-chain@1.1.13", "", { "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" } }, "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ=="],
@@ -672,6 +694,10 @@
"fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="],
"fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
"fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="],
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
@@ -692,6 +718,8 @@
"github-from-package": ["github-from-package@0.0.0", "", {}, "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="],
"glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="],
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="],
@@ -748,6 +776,8 @@
"import-local": ["import-local@3.2.0", "", { "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" }, "bin": { "import-local-fixture": "fixtures/cli.js" } }, "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA=="],
"inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="],
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
"ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="],
@@ -858,8 +888,16 @@
"minimalistic-assert": ["minimalistic-assert@1.0.1", "", {}, "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="],
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
"minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
"minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
"mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
"mkdirp-classic": ["mkdirp-classic@0.5.3", "", {}, "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="],
"mlly": ["mlly@1.7.4", "", { "dependencies": { "acorn": "^8.14.0", "pathe": "^2.0.1", "pkg-types": "^1.3.0", "ufo": "^1.5.4" } }, "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw=="],
@@ -950,6 +988,8 @@
"path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="],
"path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="],
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
@@ -1030,6 +1070,8 @@
"retry": ["retry@0.13.1", "", {}, "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="],
"rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="],
"rollup-plugin-inject": ["rollup-plugin-inject@3.0.2", "", { "dependencies": { "estree-walker": "^0.6.1", "magic-string": "^0.25.3", "rollup-pluginutils": "^2.8.1" } }, "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w=="],
"rollup-plugin-node-polyfills": ["rollup-plugin-node-polyfills@0.2.1", "", { "dependencies": { "rollup-plugin-inject": "^3.0.0" } }, "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA=="],
@@ -1136,6 +1178,8 @@
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
"tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
"tar-fs": ["tar-fs@2.1.2", "", { "dependencies": { "chownr": "^1.1.1", "mkdirp-classic": "^0.5.2", "pump": "^3.0.0", "tar-stream": "^2.1.4" } }, "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA=="],
"tar-stream": ["tar-stream@2.2.0", "", { "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", "fs-constants": "^1.0.0", "inherits": "^2.0.3", "readable-stream": "^3.1.1" } }, "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ=="],
@@ -1212,6 +1256,8 @@
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
"wasm-pack": ["wasm-pack@0.13.1", "", { "dependencies": { "binary-install": "^1.0.1" }, "bin": { "wasm-pack": "run.js" } }, "sha512-P9exD4YkjpDbw68xUhF3MDm/CC/3eTmmthyG5bHJ56kalxOTewOunxTke4SyF8MTXV6jUtNjXggPgrGmMtczGg=="],
"watchpack": ["watchpack@2.4.2", "", { "dependencies": { "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.1.2" } }, "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw=="],
"wbuf": ["wbuf@1.7.3", "", { "dependencies": { "minimalistic-assert": "^1.0.0" } }, "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA=="],
@@ -1246,7 +1292,7 @@
"xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
"yallist": ["yallist@2.1.2", "", {}, "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="],
"yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
"yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="],
@@ -1312,6 +1358,8 @@
"from2/readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="],
"fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
"get-source/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"got/decompress-response": ["decompress-response@3.3.0", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA=="],
@@ -1328,12 +1376,16 @@
"jest-worker/supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "^4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="],
"lru-cache/yallist": ["yallist@2.1.2", "", {}, "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A=="],
"make-dir/pify": ["pify@3.0.0", "", {}, "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg=="],
"miniflare/acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="],
"miniflare/undici": ["undici@5.28.5", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA=="],
"minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
"mlly/pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
"normalize-url/prepend-http": ["prepend-http@2.0.0", "", {}, "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA=="],
@@ -1368,6 +1420,8 @@
"strip-outer/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="],
"tar/chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
"tempfile/uuid": ["uuid@3.4.0", "", { "bin": { "uuid": "./bin/uuid" } }, "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="],
"terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="],

View File

@@ -18,5 +18,8 @@
"dev:demo": "( cd packages/demo ; npm run dev )",
"build:demo": "( cd packages/demo ; npm run build )",
"build:action": "( cd packages/action ; npm run build )"
}
},
"trustedDependencies": [
"wasm-pack"
]
}

View File

@@ -5,5 +5,6 @@
"outside",
"getPathToPose",
"getPathTo",
"svg"
"svg",
"rust"
]

View File

@@ -0,0 +1,24 @@
import { createCanvas } from "./canvas";
import "./menu";
import { grid } from "./sample";
(async () => {
const api = await import("@snk/solver-r");
const g = api.IGrid.create(grid.width, grid.height, grid.data);
const freeCells = api.iget_free_cell(g);
{
const { canvas, draw, highlightCell } = createCanvas(g);
document.body.appendChild(canvas);
draw({ width: g.width, height: g.height, data: g.data }, [] as any, []);
for (let i = freeCells.length / 2; i--; ) {
const x = freeCells[i * 2 + 0];
const y = freeCells[i * 2 + 1];
highlightCell(x, y);
}
}
})();

View File

@@ -42,6 +42,9 @@ const webpackConfiguration: WebpackConfiguration = {
path: path.join(__dirname, "dist"),
filename: "[contenthash].js",
},
experiments: {
asyncWebAssembly: true,
},
module: {
rules: [
{

2
packages/solver-r/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
target
pkg

341
packages/solver-r/Cargo.lock generated Normal file
View File

@@ -0,0 +1,341 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "bumpalo"
version = "3.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
[[package]]
name = "cc"
version = "1.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a"
dependencies = [
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
"cfg-if",
"wasm-bindgen",
]
[[package]]
name = "console_log"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be8aed40e4edbf4d3b4431ab260b63fdc40f5780a4766824329ea0f1eefe3c0f"
dependencies = [
"log",
"web-sys",
]
[[package]]
name = "js-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
dependencies = [
"once_cell",
"wasm-bindgen",
]
[[package]]
name = "log"
version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
[[package]]
name = "minicov"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f27fe9f1cc3c22e1687f9446c2083c4c5fc7f0bcf1c7a86bdbded14985895b4b"
dependencies = [
"cc",
"walkdir",
]
[[package]]
name = "once_cell"
version = "1.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc"
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rustversion"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "snk-solver-rust"
version = "1.0.0"
dependencies = [
"console_error_panic_hook",
"console_log",
"js-sys",
"log",
"wasm-bindgen",
"wasm-bindgen-test",
]
[[package]]
name = "syn"
version = "2.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
dependencies = [
"cfg-if",
"once_cell",
"rustversion",
"wasm-bindgen-macro",
]
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
dependencies = [
"bumpalo",
"log",
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61"
dependencies = [
"cfg-if",
"js-sys",
"once_cell",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
]
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
dependencies = [
"proc-macro2",
"quote",
"syn",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-bindgen-test"
version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66c8d5e33ca3b6d9fa3b4676d774c5778031d27a578c2b007f905acf816152c3"
dependencies = [
"js-sys",
"minicov",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test-macro",
]
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17d5042cc5fa009658f9a7333ef24291b1291a25b6382dd68862a7f3b969f69b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "web-sys"
version = "0.3.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "winapi-util"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [
"windows-sys",
]
[[package]]
name = "windows-sys"
version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-targets"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_gnullvm",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
[[package]]
name = "windows_i686_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"

View File

@@ -0,0 +1,26 @@
[package]
name = "snk-solver-rust"
version = "1.0.0"
authors = ["platane"]
edition = "2018"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.100"
js-sys = "0.3.77"
console_log = "1.0.0"
log = "0.4"
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.7", optional = true }
[dev-dependencies]
wasm-bindgen-test = "0.3.34"

View File

@@ -0,0 +1,11 @@
{
"name": "@snk/solver-r",
"version": "1.0.0",
"devDependencies": {
"wasm-pack": "0.13.1"
},
"main": "./pkg/snk_solver_rust.js",
"scripts": {
"build": "wasm-pack build"
}
}

View File

@@ -0,0 +1,84 @@
#[derive(Copy, Clone, Hash, Eq, PartialEq, Debug)]
pub struct Point {
pub x: i8,
pub y: i8,
}
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum Cell {
Empty = 0,
Color1 = 1,
Color2 = 2,
Color3 = 3,
Color4 = 4,
}
#[derive(Clone)]
pub struct Grid {
pub width: u8,
pub height: u8,
pub cells: Vec<Cell>,
}
impl Grid {
pub fn create_empty(width: u8, height: u8) -> Grid {
let n = (width as usize) * (height as usize);
let cells = (0..n).map(|_| Cell::Empty).collect();
Grid {
width,
height,
cells,
}
}
pub fn get_index(&self, x: i8, y: i8) -> usize {
return (x as usize) * (self.height as usize) + (y as usize);
}
pub fn get_cell(&self, p: &Point) -> Cell {
let i = self.get_index(p.x, p.y);
return self.cells[i];
}
pub fn set_cell(&mut self, p: &Point, value: Cell) -> () {
let i = self.get_index(p.x, p.y);
self.cells[i] = value;
}
pub fn is_inside(&self, p: &Point) -> bool {
p.x >= 0 && p.x < (self.width as i8) && p.y >= 0 && p.y < (self.height as i8)
}
}
pub const DIRECTION_RIGHT: Point = Point { x: 1, y: 0 };
pub const DIRECTION_LEFT: Point = Point { x: -1, y: 0 };
pub const DIRECTION_UP: Point = Point { x: 0, y: 1 };
pub const DIRECTION_DOWN: Point = Point { x: 0, y: -1 };
pub const DIRECTIONS: [Point; 4] = [
DIRECTION_RIGHT,
DIRECTION_LEFT,
DIRECTION_UP,
DIRECTION_DOWN,
];
#[test]
fn it_should_sort_cell() {
assert_eq!(Cell::Empty < Cell::Color1, true);
assert_eq!(Cell::Color1 < Cell::Color2, true);
assert_eq!(Cell::Color2 < Cell::Color3, true);
assert_eq!(Cell::Color3 < Cell::Color4, true);
}
#[test]
fn it_should_grid_create() {
let grid = Grid::create_empty(30, 10);
assert_eq!(grid.width, 30);
assert_eq!(grid.height, 10);
assert_eq!(grid.get_cell(&Point { x: 2, y: 3 }), Cell::Empty);
}
#[test]
fn it_should_grid_setter() {
let mut grid = Grid::create_empty(20, 10);
grid.set_cell(&Point { x: 12, y: 3 }, Cell::Color1);
assert_eq!(grid.get_cell(&Point { x: 12, y: 3 }), Cell::Color1);
}

View File

@@ -0,0 +1,79 @@
mod grid;
mod snake;
mod snake_compact;
mod snake_walk;
mod solver;
use grid::{Cell, Grid};
use js_sys;
use solver::get_free_cell;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
extern "C" {
fn alert(s: &str);
}
#[wasm_bindgen]
pub fn greet() {
alert("Hello, wasm-game-of-life!");
}
#[wasm_bindgen]
#[derive(Clone)]
pub struct IGrid {
pub width: u8,
pub height: u8,
cells: Vec<Cell>,
}
#[wasm_bindgen]
impl IGrid {
pub fn create(width: u8, height: u8, data: js_sys::Uint8Array) -> IGrid {
let cells = data
.to_vec()
.iter()
.map(|u| match u {
0 => Cell::Empty,
1 => Cell::Color1,
2 => Cell::Color2,
3 => Cell::Color3,
4 => Cell::Color4,
_ => panic!("unknown cell"),
})
.collect();
IGrid {
width,
height,
cells,
}
}
#[wasm_bindgen(getter)]
pub fn data(&self) -> js_sys::Uint8Array {
let o: Vec<u8> = self.cells.iter().map(|u| *u as u8).collect();
js_sys::Uint8Array::from(&o[..])
}
}
impl From<IGrid> for Grid {
fn from(value: IGrid) -> Self {
Self {
width: value.width,
height: value.height,
cells: value.cells,
}
}
}
#[wasm_bindgen]
pub fn iget_free_cell(grid: &IGrid) -> js_sys::Uint8Array {
let g = Grid::from(grid.clone());
let (_, out) = get_free_cell(&g, Cell::Color1);
let o: Vec<u8> = out.iter().flat_map(|p| [p.x as u8, p.y as u8]).collect();
js_sys::Uint8Array::from(&o[..])
}

View File

@@ -0,0 +1,95 @@
use crate::grid::{Point, DIRECTIONS, DIRECTION_DOWN, DIRECTION_LEFT, DIRECTION_UP};
/**
* head is at 0
*/
pub type Snake = Vec<Point>;
pub fn move_snake(s: &mut Snake, dir: &Point) -> () {
let mut e = s.pop().unwrap();
e.x = s[0].x + dir.x;
e.y = s[0].y + dir.y;
s.insert(0, e);
}
pub fn snake_will_self_collide(s: &Snake, dir: &Point) -> bool {
let next_head = Point {
x: s[0].x + dir.x,
y: s[0].y + dir.y,
};
(&s[0..(s.len() - 1)]).contains(&next_head)
}
pub fn get_snake_head(s: &Snake) -> Point {
s[0]
}
pub fn get_next_snake_head(s: &Snake, dir: &Point) -> Point {
Point {
x: s[0].x + dir.x,
y: s[0].y + dir.y,
}
}
#[test]
fn it_should_return_head() {
let s = vec![
//
Point { x: 3, y: 0 },
Point { x: 2, y: 0 },
Point { x: 1, y: 0 },
];
assert_eq!(get_snake_head(&s), Point { x: 3, y: 0 });
}
#[test]
fn it_should_detect_self_collide() {
let mut s = vec![
//
Point { x: 6, y: 0 },
Point { x: 5, y: 0 },
Point { x: 4, y: 0 },
Point { x: 3, y: 0 },
Point { x: 2, y: 0 },
Point { x: 1, y: 0 },
];
move_snake(&mut s, &DIRECTION_UP);
move_snake(&mut s, &DIRECTION_LEFT);
assert_eq!(snake_will_self_collide(&s, &DIRECTION_DOWN), true);
move_snake(&mut s, &DIRECTION_LEFT);
assert_eq!(snake_will_self_collide(&s, &DIRECTION_DOWN), false);
}
#[test]
fn it_should_detect_self_collide_2() {
let s = vec![
//
Point { x: 3, y: 0 },
Point { x: 2, y: 0 },
Point { x: 1, y: 0 },
];
assert_eq!(snake_will_self_collide(&s, &DIRECTION_LEFT), true);
}
#[test]
fn it_should_move_snake() {
let mut s = vec![
//
Point { x: 3, y: 0 },
Point { x: 2, y: 0 },
Point { x: 1, y: 0 },
];
move_snake(&mut s, &DIRECTION_UP);
assert_eq!(
s,
vec![
//
Point { x: 3, y: 1 },
Point { x: 3, y: 0 },
Point { x: 2, y: 0 },
]
);
}

View File

@@ -0,0 +1,176 @@
use crate::grid::Point;
#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
pub enum Direction {
Left = 0,
Right = 1,
Up = 2,
Down = 3,
}
fn get_direction_vector(dir: Direction) -> Point {
match dir {
Direction::Down => Point { x: 0, y: -1 },
Direction::Up => Point { x: 0, y: 1 },
Direction::Left => Point { x: -1, y: 0 },
Direction::Right => Point { x: 1, y: 0 },
}
}
fn get_direction_from_vector(v: &Point) -> Direction {
match v {
Point { x: 0, y: -1 } => Direction::Down,
Point { x: 0, y: 1 } => Direction::Up,
Point { x: -1, y: 0 } => Direction::Left,
Point { x: 1, y: 0 } => Direction::Right,
_ => panic!(),
}
}
#[derive(Clone)]
pub struct SnakeC {
pub head: Point,
pub body: Vec<Direction>,
}
impl SnakeC {
pub fn get_cells(&self) -> Vec<Point> {
let mut e = self.head.clone();
let mut out = Vec::new();
out.push(e.clone());
for dir in self.body.iter() {
let v = get_direction_vector(*dir);
e.x -= v.x;
e.y -= v.y;
out.push(e.clone());
}
out
}
pub fn is_head_self_colliding(&self) -> bool {
self.get_cells()[1..].contains(&self.head)
}
pub fn advance(&mut self, dir: Direction) -> () {
let v = get_direction_vector(dir);
self.head.x += v.x;
self.head.y += v.y;
self.body.pop();
self.body.insert(0, dir);
}
}
impl From<Vec<Point>> for SnakeC {
fn from(value: Vec<Point>) -> Self {
let head = value.get(0).unwrap().clone();
let body = value
.windows(2)
.map(|w| {
let v = Point {
x: w[0].x - w[1].x,
y: w[0].y - w[1].y,
};
get_direction_from_vector(&v)
})
.collect();
Self { head, body }
}
}
#[test]
fn it_should_get_the_snake_cell() {
let s = SnakeC {
head: Point { x: 10, y: 5 },
body: vec![Direction::Up, Direction::Up, Direction::Left],
};
assert_eq!(
s.get_cells(),
vec![
//
Point { x: 10, y: 5 },
Point { x: 10, y: 4 },
Point { x: 10, y: 3 },
Point { x: 11, y: 3 },
]
);
}
#[test]
fn it_should_get_snake_from_point_list() {
let s = SnakeC::from(vec![
//
Point { x: 10, y: 5 },
Point { x: 10, y: 4 },
Point { x: 10, y: 3 },
Point { x: 11, y: 3 },
Point { x: 12, y: 3 },
Point { x: 12, y: 2 },
]);
assert_eq!(
s.get_cells(),
vec![
//
Point { x: 10, y: 5 },
Point { x: 10, y: 4 },
Point { x: 10, y: 3 },
Point { x: 11, y: 3 },
Point { x: 12, y: 3 },
Point { x: 12, y: 2 },
]
);
}
#[test]
fn it_should_advance_snake() {
let mut s = SnakeC::from(vec![
//
Point { x: 10, y: 3 },
Point { x: 11, y: 3 },
Point { x: 12, y: 3 },
Point { x: 12, y: 2 },
]);
s.advance(Direction::Up);
assert_eq!(
s.get_cells(),
vec![
//
Point { x: 10, y: 4 },
Point { x: 10, y: 3 },
Point { x: 11, y: 3 },
Point { x: 12, y: 3 },
]
);
}
#[test]
fn it_should_detect_self_collision() {
let mut s = SnakeC::from(vec![
//
Point { x: 0, y: 0 },
Point { x: 0, y: 1 },
Point { x: 0, y: 2 },
Point { x: 0, y: 3 },
Point { x: 0, y: 4 },
Point { x: 0, y: 5 },
Point { x: 0, y: 6 },
]);
assert_eq!(s.is_head_self_colliding(), false);
s.advance(Direction::Right);
s.advance(Direction::Up);
s.advance(Direction::Up);
assert_eq!(s.is_head_self_colliding(), false);
s.advance(Direction::Left);
assert_eq!(s.is_head_self_colliding(), true);
}

View File

@@ -0,0 +1,58 @@
use std::collections::HashSet;
use crate::grid::{Cell, Grid, Point, DIRECTIONS};
use crate::snake::{
get_next_snake_head, get_snake_head, move_snake, snake_will_self_collide, Snake,
};
pub fn get_route_to_eat_all(
grid: &Grid,
walkable: Cell,
initial_snake: &Snake,
cells_to_eat: HashSet<Point>,
) -> Vec<Point> {
// let mut targets: Vec<Point> = cells_to_eat.iter().map(|p| p.clone()).collect();
let mut targets: Vec<&Point> = cells_to_eat.iter().collect();
let mut path: Vec<Point> = Vec::new();
let mut initial_snake = initial_snake.clone();
while let Some(target) = targets.pop() {
// prepare
let mut open_list: HashSet<(Snake, Vec<Point>)> = HashSet::new();
open_list.insert((initial_snake.clone(), Vec::new()));
while let Some(x) = open_list.iter().next().cloned() {
open_list.remove(&x);
let snake = x.0;
let mut sub_path = x.1;
if get_snake_head(&snake) == *target {
path.append(&mut sub_path);
initial_snake = snake;
break;
}
for dir in DIRECTIONS {
if {
let h = get_next_snake_head(&snake, &dir);
grid.get_cell(&h) <= walkable
} && !snake_will_self_collide(&snake, &dir)
{
let mut next_snake = snake.clone();
move_snake(&mut next_snake, &dir);
let mut next_sub_path = sub_path.clone();
next_sub_path.push(dir.clone());
open_list.insert((next_snake, next_sub_path));
}
}
}
}
path
}

View File

@@ -0,0 +1,127 @@
use std::collections::HashSet;
use crate::grid::{Cell, Grid, Point};
pub fn get_free_cell(grid: &Grid, walkable: Cell) -> (HashSet<Point>, HashSet<Point>) {
let mut free_cells: HashSet<Point> = HashSet::new();
let mut one_way_cells: HashSet<Point> = HashSet::new();
let mut open_list: HashSet<Point> = HashSet::new();
for x in 0..(grid.width as i8) {
open_list.insert(Point { x, y: 0 });
open_list.insert(Point {
x,
y: (grid.height as i8) - 1,
});
}
for y in 0..(grid.height as i8) {
open_list.insert(Point { x: 0, y });
open_list.insert(Point {
x: (grid.width as i8) - 1,
y,
});
}
open_list.retain(|p| grid.get_cell(&p) <= walkable);
let directions = [
Point { x: 1, y: 0 },
Point { x: -1, y: 0 },
Point { x: 0, y: 1 },
Point { x: 0, y: -1 },
];
while let Some(p) = open_list.iter().next().cloned() {
open_list.remove(&p);
let has_enough_free_exits = {
let mut exit_count = 0;
let mut visited: HashSet<Point> = HashSet::new();
for dir in directions {
let neighbour = Point {
x: p.x + dir.x,
y: p.y + dir.y,
};
if !visited.contains(&neighbour)
&& (free_cells.contains(&neighbour) || !grid.is_inside(&neighbour))
{
visited.insert(neighbour);
exit_count += 1;
}
if grid.is_inside(&neighbour) && grid.get_cell(&neighbour) <= walkable {
for alt in [-1, 1] {
let corner = {
if neighbour.x != 0 {
Point {
x: neighbour.x,
y: neighbour.y + alt,
}
} else {
Point {
x: neighbour.x + alt,
y: neighbour.y,
}
}
};
if !visited.contains(&neighbour)
&& !visited.contains(&corner)
&& (free_cells.contains(&corner) || !grid.is_inside(&corner))
{
visited.insert(neighbour);
visited.insert(corner);
exit_count += 1;
}
}
}
}
exit_count >= 2
};
if has_enough_free_exits {
free_cells.insert(p);
for dir in directions {
let neighbour = Point {
x: p.x + dir.x,
y: p.y + dir.y,
};
if !free_cells.contains(&neighbour)
&& grid.is_inside(&neighbour)
&& grid.get_cell(&neighbour) <= walkable
{
open_list.insert(neighbour);
}
}
} else {
one_way_cells.insert(p);
}
}
one_way_cells.retain(|p| !free_cells.contains(&p));
(free_cells, one_way_cells)
}
#[test]
fn it_should_collect_free_cell() {
let mut grid = Grid::create_empty(2, 2);
grid.set_cell(&Point { x: 1, y: 1 }, Cell::Color2);
let (free_cells, _) = get_free_cell(&grid, Cell::Color1);
assert_eq!(
free_cells,
HashSet::from([
//
Point { x: 0, y: 0 },
Point { x: 0, y: 1 },
Point { x: 1, y: 0 },
])
);
}

View File

@@ -84,6 +84,12 @@ export const tunnels = createFromAscii(`
#.# #.# #.#
#.# ### # #
`);
export const line = createFromAscii(`
#######
.. #
##### #
`);
const createRandom = (width: number, height: number, emptyP: number) => {
const grid = createEmptyGrid(width, height);