hbengine 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -0
- package/engine-cli/connect.mjs +73 -0
- package/engine-cli/hbengine.mjs +565 -0
- package/engine-cli/package.json +1 -0
- package/engine-cli/templates.mjs +14 -0
- package/engine-conformance/analyse-worker.mjs +12 -0
- package/engine-conformance/analyse.mjs +4458 -0
- package/engine-conformance/bundle.mjs +208 -0
- package/engine-conformance/clock.mjs +294 -0
- package/engine-conformance/csp.go +56 -0
- package/engine-conformance/csp.json +6 -0
- package/engine-conformance/csp.mjs +20 -0
- package/engine-conformance/gzip-sizes.mjs +9 -0
- package/engine-conformance/package.json +1 -0
- package/engine-conformance/picture.mjs +55 -0
- package/engine-conformance/report.go +349 -0
- package/engine-conformance/run.mjs +1217 -0
- package/engine-conformance/scan.mjs +476 -0
- package/engine-conformance/testdata/clock-overlay/bundle/assets.json +1 -0
- package/engine-conformance/testdata/clock-overlay/bundle/game.css +17 -0
- package/engine-conformance/testdata/clock-overlay/bundle/game.js +83 -0
- package/engine-conformance/testdata/clock-overlay/bundle/hbtest.json +4 -0
- package/engine-conformance/testdata/clock-overlay/bundle/index.html +34 -0
- package/engine-conformance/testdata/clock-probe/bundle/assets.json +1 -0
- package/engine-conformance/testdata/clock-probe/bundle/game.css +17 -0
- package/engine-conformance/testdata/clock-probe/bundle/game.js +65 -0
- package/engine-conformance/testdata/clock-probe/bundle/hbtest.json +4 -0
- package/engine-conformance/testdata/clock-probe/bundle/index.html +35 -0
- package/engine-conformance/testdata/clock-probe/bundle/probe-worker.js +46 -0
- package/engine-conformance/testdata/clock-probe/bundle/probe.js +210 -0
- package/engine-conformance/testdata/clock-probe/math/dice.tsv +100 -0
- package/engine-conformance/testdata/clock-probe/math/manifest.json +2925 -0
- package/engine-conformance/testdata/clock-worker/bundle/assets.json +1 -0
- package/engine-conformance/testdata/clock-worker/bundle/clock-worker.js +14 -0
- package/engine-conformance/testdata/clock-worker/bundle/game.css +17 -0
- package/engine-conformance/testdata/clock-worker/bundle/game.js +61 -0
- package/engine-conformance/testdata/clock-worker/bundle/hbtest.json +4 -0
- package/engine-conformance/testdata/clock-worker/bundle/index.html +35 -0
- package/engine-conformance/testdata/clock-worker/math/dice.tsv +100 -0
- package/engine-conformance/testdata/clock-worker/math/manifest.json +2925 -0
- package/engine-conformance/travel.mjs +1209 -0
- package/engine-conformance/vendor/acorn/LICENSE +21 -0
- package/engine-conformance/vendor/acorn/acorn.mjs +6266 -0
- package/engine-conformance/wasm-releases.json +168 -0
- package/engine-examples/README.md +23 -0
- package/engine-examples/coin/AGENTS.md +3 -0
- package/engine-examples/coin/README.md +7 -0
- package/engine-examples/coin/bundle/assets.json +1 -0
- package/engine-examples/coin/bundle/game.css +5 -0
- package/engine-examples/coin/bundle/game.js +19 -0
- package/engine-examples/coin/bundle/hbtest.json +5 -0
- package/engine-examples/coin/bundle/index.html +16 -0
- package/engine-examples/coin/math/coin.tsv +2 -0
- package/engine-examples/coin/math/manifest.json +17 -0
- package/engine-examples/crash/AGENTS.md +3 -0
- package/engine-examples/crash/README.md +14 -0
- package/engine-examples/crash/bundle/assets.json +1 -0
- package/engine-examples/crash/bundle/game.css +8 -0
- package/engine-examples/crash/bundle/game.js +90 -0
- package/engine-examples/crash/bundle/hbtest.json +5 -0
- package/engine-examples/crash/bundle/index.html +20 -0
- package/engine-examples/crash/math/crash-01.tsv +2 -0
- package/engine-examples/crash/math/crash-02.tsv +2 -0
- package/engine-examples/crash/math/crash-03.tsv +2 -0
- package/engine-examples/crash/math/crash-04.tsv +2 -0
- package/engine-examples/crash/math/crash-05.tsv +2 -0
- package/engine-examples/crash/math/crash-06.tsv +2 -0
- package/engine-examples/crash/math/crash-07.tsv +2 -0
- package/engine-examples/crash/math/crash-08.tsv +2 -0
- package/engine-examples/crash/math/crash-09.tsv +2 -0
- package/engine-examples/crash/math/crash-10.tsv +2 -0
- package/engine-examples/crash/math/crash-11.tsv +2 -0
- package/engine-examples/crash/math/crash-12.tsv +2 -0
- package/engine-examples/crash/math/crash-13.tsv +2 -0
- package/engine-examples/crash/math/crash-14.tsv +2 -0
- package/engine-examples/crash/math/crash-15.tsv +2 -0
- package/engine-examples/crash/math/crash-16.tsv +2 -0
- package/engine-examples/crash/math/crash-17.tsv +2 -0
- package/engine-examples/crash/math/crash-18.tsv +2 -0
- package/engine-examples/crash/math/crash-19.tsv +2 -0
- package/engine-examples/crash/math/crash-20.tsv +2 -0
- package/engine-examples/crash/math/crash-21.tsv +2 -0
- package/engine-examples/crash/math/crash-22.tsv +2 -0
- package/engine-examples/crash/math/crash-23.tsv +2 -0
- package/engine-examples/crash/math/crash-24.tsv +2 -0
- package/engine-examples/crash/math/crash-25.tsv +2 -0
- package/engine-examples/crash/math/crash-26.tsv +2 -0
- package/engine-examples/crash/math/crash-27.tsv +2 -0
- package/engine-examples/crash/math/crash-28.tsv +2 -0
- package/engine-examples/crash/math/crash-29.tsv +2 -0
- package/engine-examples/crash/math/crash-30.tsv +2 -0
- package/engine-examples/crash/math/crash-31.tsv +2 -0
- package/engine-examples/crash/math/crash-32.tsv +2 -0
- package/engine-examples/crash/math/crash-33.tsv +2 -0
- package/engine-examples/crash/math/crash-34.tsv +2 -0
- package/engine-examples/crash/math/crash-35.tsv +2 -0
- package/engine-examples/crash/math/crash-36.tsv +2 -0
- package/engine-examples/crash/math/crash-37.tsv +2 -0
- package/engine-examples/crash/math/crash-38.tsv +2 -0
- package/engine-examples/crash/math/crash-39.tsv +2 -0
- package/engine-examples/crash/math/crash-40.tsv +2 -0
- package/engine-examples/crash/math/crash-41.tsv +2 -0
- package/engine-examples/crash/math/crash-42.tsv +2 -0
- package/engine-examples/crash/math/crash-43.tsv +2 -0
- package/engine-examples/crash/math/crash-44.tsv +2 -0
- package/engine-examples/crash/math/crash-45.tsv +2 -0
- package/engine-examples/crash/math/crash-46.tsv +2 -0
- package/engine-examples/crash/math/crash-47.tsv +2 -0
- package/engine-examples/crash/math/crash-48.tsv +2 -0
- package/engine-examples/crash/math/crash-49.tsv +2 -0
- package/engine-examples/crash/math/crash-50.tsv +2 -0
- package/engine-examples/crash/math/crash-51.tsv +2 -0
- package/engine-examples/crash/math/crash-52.tsv +2 -0
- package/engine-examples/crash/math/crash-53.tsv +2 -0
- package/engine-examples/crash/math/crash-54.tsv +2 -0
- package/engine-examples/crash/math/crash-55.tsv +2 -0
- package/engine-examples/crash/math/crash-56.tsv +2 -0
- package/engine-examples/crash/math/crash-57.tsv +2 -0
- package/engine-examples/crash/math/crash-58.tsv +2 -0
- package/engine-examples/crash/math/crash-59.tsv +2 -0
- package/engine-examples/crash/math/crash-60.tsv +2 -0
- package/engine-examples/crash/math/crash-61.tsv +2 -0
- package/engine-examples/crash/math/crash-62.tsv +2 -0
- package/engine-examples/crash/math/crash-63.tsv +2 -0
- package/engine-examples/crash/math/crash-64.tsv +2 -0
- package/engine-examples/crash/math/gen.mjs +31 -0
- package/engine-examples/crash/math/manifest.json +1 -0
- package/engine-examples/dice/AGENTS.md +3 -0
- package/engine-examples/dice/README.md +25 -0
- package/engine-examples/dice/bundle/assets.json +1 -0
- package/engine-examples/dice/bundle/game.css +17 -0
- package/engine-examples/dice/bundle/game.js +61 -0
- package/engine-examples/dice/bundle/hbtest.json +4 -0
- package/engine-examples/dice/bundle/index.html +34 -0
- package/engine-examples/dice/math/dice.tsv +100 -0
- package/engine-examples/dice/math/manifest.json +2925 -0
- package/engine-examples/keno/AGENTS.md +3 -0
- package/engine-examples/keno/README.md +11 -0
- package/engine-examples/keno/bundle/assets.json +1 -0
- package/engine-examples/keno/bundle/game.css +14 -0
- package/engine-examples/keno/bundle/game.js +86 -0
- package/engine-examples/keno/bundle/hbtest.json +4 -0
- package/engine-examples/keno/bundle/i18n.json +342 -0
- package/engine-examples/keno/bundle/index.html +20 -0
- package/engine-examples/keno/bundle/model.json +1 -0
- package/engine-examples/keno/math/gen.mjs +35 -0
- package/engine-examples/keno/math/keno-picks-1.tsv +2 -0
- package/engine-examples/keno/math/keno-picks-10.tsv +11 -0
- package/engine-examples/keno/math/keno-picks-2.tsv +3 -0
- package/engine-examples/keno/math/keno-picks-3.tsv +4 -0
- package/engine-examples/keno/math/keno-picks-4.tsv +5 -0
- package/engine-examples/keno/math/keno-picks-5.tsv +6 -0
- package/engine-examples/keno/math/keno-picks-6.tsv +7 -0
- package/engine-examples/keno/math/keno-picks-7.tsv +8 -0
- package/engine-examples/keno/math/keno-picks-8.tsv +9 -0
- package/engine-examples/keno/math/keno-picks-9.tsv +10 -0
- package/engine-examples/keno/math/manifest.json +1 -0
- package/engine-examples/keno/math-kit/pack.mjs +165 -0
- package/engine-examples/keno/math-kit/package.json +8 -0
- package/engine-examples/keno/math-kit/slot.mjs +94 -0
- package/engine-examples/keno/math-kit/tumble.mjs +94 -0
- package/engine-examples/lines/AGENTS.md +3 -0
- package/engine-examples/lines/README.md +20 -0
- package/engine-examples/lines/bundle/assets.json +1 -0
- package/engine-examples/lines/bundle/game.css +16 -0
- package/engine-examples/lines/bundle/game.js +125 -0
- package/engine-examples/lines/bundle/hbtest.json +4 -0
- package/engine-examples/lines/bundle/i18n.json +242 -0
- package/engine-examples/lines/bundle/index.html +23 -0
- package/engine-examples/lines/bundle/model.json +1 -0
- package/engine-examples/lines/math/gen.mjs +54 -0
- package/engine-examples/lines/math-kit/pack.mjs +165 -0
- package/engine-examples/lines/math-kit/package.json +8 -0
- package/engine-examples/lines/math-kit/slot.mjs +94 -0
- package/engine-examples/lines/math-kit/tumble.mjs +94 -0
- package/engine-examples/mines/AGENTS.md +3 -0
- package/engine-examples/mines/README.md +13 -0
- package/engine-examples/mines/bundle/assets.json +1 -0
- package/engine-examples/mines/bundle/game.css +12 -0
- package/engine-examples/mines/bundle/game.js +58 -0
- package/engine-examples/mines/bundle/hbtest.json +8 -0
- package/engine-examples/mines/bundle/index.html +16 -0
- package/engine-examples/mines/math/gen.mjs +40 -0
- package/engine-examples/mines/math/manifest.json +1 -0
- package/engine-examples/mines/math/mines-1-1.tsv +2 -0
- package/engine-examples/mines/math/mines-1-2.tsv +2 -0
- package/engine-examples/mines/math/mines-1-22.tsv +2 -0
- package/engine-examples/mines/math/mines-1-23.tsv +2 -0
- package/engine-examples/mines/math/mines-1-24.tsv +2 -0
- package/engine-examples/mines/math/mines-1-3.tsv +2 -0
- package/engine-examples/mines/math/mines-10-1.tsv +2 -0
- package/engine-examples/mines/math/mines-10-10.tsv +2 -0
- package/engine-examples/mines/math/mines-10-11.tsv +2 -0
- package/engine-examples/mines/math/mines-10-12.tsv +2 -0
- package/engine-examples/mines/math/mines-10-13.tsv +2 -0
- package/engine-examples/mines/math/mines-10-14.tsv +2 -0
- package/engine-examples/mines/math/mines-10-15.tsv +2 -0
- package/engine-examples/mines/math/mines-10-2.tsv +2 -0
- package/engine-examples/mines/math/mines-10-3.tsv +2 -0
- package/engine-examples/mines/math/mines-10-4.tsv +2 -0
- package/engine-examples/mines/math/mines-10-5.tsv +2 -0
- package/engine-examples/mines/math/mines-10-6.tsv +2 -0
- package/engine-examples/mines/math/mines-10-7.tsv +2 -0
- package/engine-examples/mines/math/mines-10-8.tsv +2 -0
- package/engine-examples/mines/math/mines-10-9.tsv +2 -0
- package/engine-examples/mines/math/mines-11-1.tsv +2 -0
- package/engine-examples/mines/math/mines-11-10.tsv +2 -0
- package/engine-examples/mines/math/mines-11-11.tsv +2 -0
- package/engine-examples/mines/math/mines-11-12.tsv +2 -0
- package/engine-examples/mines/math/mines-11-13.tsv +2 -0
- package/engine-examples/mines/math/mines-11-14.tsv +2 -0
- package/engine-examples/mines/math/mines-11-2.tsv +2 -0
- package/engine-examples/mines/math/mines-11-3.tsv +2 -0
- package/engine-examples/mines/math/mines-11-4.tsv +2 -0
- package/engine-examples/mines/math/mines-11-5.tsv +2 -0
- package/engine-examples/mines/math/mines-11-6.tsv +2 -0
- package/engine-examples/mines/math/mines-11-7.tsv +2 -0
- package/engine-examples/mines/math/mines-11-8.tsv +2 -0
- package/engine-examples/mines/math/mines-11-9.tsv +2 -0
- package/engine-examples/mines/math/mines-12-1.tsv +2 -0
- package/engine-examples/mines/math/mines-12-10.tsv +2 -0
- package/engine-examples/mines/math/mines-12-11.tsv +2 -0
- package/engine-examples/mines/math/mines-12-12.tsv +2 -0
- package/engine-examples/mines/math/mines-12-13.tsv +2 -0
- package/engine-examples/mines/math/mines-12-2.tsv +2 -0
- package/engine-examples/mines/math/mines-12-3.tsv +2 -0
- package/engine-examples/mines/math/mines-12-4.tsv +2 -0
- package/engine-examples/mines/math/mines-12-5.tsv +2 -0
- package/engine-examples/mines/math/mines-12-6.tsv +2 -0
- package/engine-examples/mines/math/mines-12-7.tsv +2 -0
- package/engine-examples/mines/math/mines-12-8.tsv +2 -0
- package/engine-examples/mines/math/mines-12-9.tsv +2 -0
- package/engine-examples/mines/math/mines-13-1.tsv +2 -0
- package/engine-examples/mines/math/mines-13-10.tsv +2 -0
- package/engine-examples/mines/math/mines-13-11.tsv +2 -0
- package/engine-examples/mines/math/mines-13-12.tsv +2 -0
- package/engine-examples/mines/math/mines-13-2.tsv +2 -0
- package/engine-examples/mines/math/mines-13-3.tsv +2 -0
- package/engine-examples/mines/math/mines-13-4.tsv +2 -0
- package/engine-examples/mines/math/mines-13-5.tsv +2 -0
- package/engine-examples/mines/math/mines-13-6.tsv +2 -0
- package/engine-examples/mines/math/mines-13-7.tsv +2 -0
- package/engine-examples/mines/math/mines-13-8.tsv +2 -0
- package/engine-examples/mines/math/mines-13-9.tsv +2 -0
- package/engine-examples/mines/math/mines-14-1.tsv +2 -0
- package/engine-examples/mines/math/mines-14-10.tsv +2 -0
- package/engine-examples/mines/math/mines-14-11.tsv +2 -0
- package/engine-examples/mines/math/mines-14-2.tsv +2 -0
- package/engine-examples/mines/math/mines-14-3.tsv +2 -0
- package/engine-examples/mines/math/mines-14-4.tsv +2 -0
- package/engine-examples/mines/math/mines-14-5.tsv +2 -0
- package/engine-examples/mines/math/mines-14-6.tsv +2 -0
- package/engine-examples/mines/math/mines-14-7.tsv +2 -0
- package/engine-examples/mines/math/mines-14-8.tsv +2 -0
- package/engine-examples/mines/math/mines-14-9.tsv +2 -0
- package/engine-examples/mines/math/mines-15-1.tsv +2 -0
- package/engine-examples/mines/math/mines-15-10.tsv +2 -0
- package/engine-examples/mines/math/mines-15-2.tsv +2 -0
- package/engine-examples/mines/math/mines-15-3.tsv +2 -0
- package/engine-examples/mines/math/mines-15-4.tsv +2 -0
- package/engine-examples/mines/math/mines-15-5.tsv +2 -0
- package/engine-examples/mines/math/mines-15-6.tsv +2 -0
- package/engine-examples/mines/math/mines-15-7.tsv +2 -0
- package/engine-examples/mines/math/mines-15-8.tsv +2 -0
- package/engine-examples/mines/math/mines-15-9.tsv +2 -0
- package/engine-examples/mines/math/mines-16-1.tsv +2 -0
- package/engine-examples/mines/math/mines-16-2.tsv +2 -0
- package/engine-examples/mines/math/mines-16-3.tsv +2 -0
- package/engine-examples/mines/math/mines-16-4.tsv +2 -0
- package/engine-examples/mines/math/mines-16-5.tsv +2 -0
- package/engine-examples/mines/math/mines-16-6.tsv +2 -0
- package/engine-examples/mines/math/mines-16-7.tsv +2 -0
- package/engine-examples/mines/math/mines-16-8.tsv +2 -0
- package/engine-examples/mines/math/mines-16-9.tsv +2 -0
- package/engine-examples/mines/math/mines-17-1.tsv +2 -0
- package/engine-examples/mines/math/mines-17-2.tsv +2 -0
- package/engine-examples/mines/math/mines-17-3.tsv +2 -0
- package/engine-examples/mines/math/mines-17-4.tsv +2 -0
- package/engine-examples/mines/math/mines-17-5.tsv +2 -0
- package/engine-examples/mines/math/mines-17-6.tsv +2 -0
- package/engine-examples/mines/math/mines-17-7.tsv +2 -0
- package/engine-examples/mines/math/mines-17-8.tsv +2 -0
- package/engine-examples/mines/math/mines-18-1.tsv +2 -0
- package/engine-examples/mines/math/mines-18-2.tsv +2 -0
- package/engine-examples/mines/math/mines-18-3.tsv +2 -0
- package/engine-examples/mines/math/mines-18-4.tsv +2 -0
- package/engine-examples/mines/math/mines-18-5.tsv +2 -0
- package/engine-examples/mines/math/mines-18-6.tsv +2 -0
- package/engine-examples/mines/math/mines-18-7.tsv +2 -0
- package/engine-examples/mines/math/mines-19-1.tsv +2 -0
- package/engine-examples/mines/math/mines-19-2.tsv +2 -0
- package/engine-examples/mines/math/mines-19-3.tsv +2 -0
- package/engine-examples/mines/math/mines-19-4.tsv +2 -0
- package/engine-examples/mines/math/mines-19-5.tsv +2 -0
- package/engine-examples/mines/math/mines-19-6.tsv +2 -0
- package/engine-examples/mines/math/mines-2-1.tsv +2 -0
- package/engine-examples/mines/math/mines-2-19.tsv +2 -0
- package/engine-examples/mines/math/mines-2-2.tsv +2 -0
- package/engine-examples/mines/math/mines-2-20.tsv +2 -0
- package/engine-examples/mines/math/mines-2-21.tsv +2 -0
- package/engine-examples/mines/math/mines-2-22.tsv +2 -0
- package/engine-examples/mines/math/mines-2-23.tsv +2 -0
- package/engine-examples/mines/math/mines-2-3.tsv +2 -0
- package/engine-examples/mines/math/mines-2-4.tsv +2 -0
- package/engine-examples/mines/math/mines-2-5.tsv +2 -0
- package/engine-examples/mines/math/mines-20-1.tsv +2 -0
- package/engine-examples/mines/math/mines-20-2.tsv +2 -0
- package/engine-examples/mines/math/mines-20-3.tsv +2 -0
- package/engine-examples/mines/math/mines-20-4.tsv +2 -0
- package/engine-examples/mines/math/mines-20-5.tsv +2 -0
- package/engine-examples/mines/math/mines-21-1.tsv +2 -0
- package/engine-examples/mines/math/mines-21-2.tsv +2 -0
- package/engine-examples/mines/math/mines-21-3.tsv +2 -0
- package/engine-examples/mines/math/mines-21-4.tsv +2 -0
- package/engine-examples/mines/math/mines-22-1.tsv +2 -0
- package/engine-examples/mines/math/mines-22-2.tsv +2 -0
- package/engine-examples/mines/math/mines-22-3.tsv +2 -0
- package/engine-examples/mines/math/mines-23-1.tsv +2 -0
- package/engine-examples/mines/math/mines-23-2.tsv +2 -0
- package/engine-examples/mines/math/mines-24-1.tsv +2 -0
- package/engine-examples/mines/math/mines-3-1.tsv +2 -0
- package/engine-examples/mines/math/mines-3-17.tsv +2 -0
- package/engine-examples/mines/math/mines-3-18.tsv +2 -0
- package/engine-examples/mines/math/mines-3-19.tsv +2 -0
- package/engine-examples/mines/math/mines-3-2.tsv +2 -0
- package/engine-examples/mines/math/mines-3-20.tsv +2 -0
- package/engine-examples/mines/math/mines-3-21.tsv +2 -0
- package/engine-examples/mines/math/mines-3-22.tsv +2 -0
- package/engine-examples/mines/math/mines-3-3.tsv +2 -0
- package/engine-examples/mines/math/mines-3-4.tsv +2 -0
- package/engine-examples/mines/math/mines-3-5.tsv +2 -0
- package/engine-examples/mines/math/mines-3-6.tsv +2 -0
- package/engine-examples/mines/math/mines-4-1.tsv +2 -0
- package/engine-examples/mines/math/mines-4-13.tsv +2 -0
- package/engine-examples/mines/math/mines-4-14.tsv +2 -0
- package/engine-examples/mines/math/mines-4-15.tsv +2 -0
- package/engine-examples/mines/math/mines-4-16.tsv +2 -0
- package/engine-examples/mines/math/mines-4-17.tsv +2 -0
- package/engine-examples/mines/math/mines-4-18.tsv +2 -0
- package/engine-examples/mines/math/mines-4-19.tsv +2 -0
- package/engine-examples/mines/math/mines-4-2.tsv +2 -0
- package/engine-examples/mines/math/mines-4-20.tsv +2 -0
- package/engine-examples/mines/math/mines-4-21.tsv +2 -0
- package/engine-examples/mines/math/mines-4-3.tsv +2 -0
- package/engine-examples/mines/math/mines-4-4.tsv +2 -0
- package/engine-examples/mines/math/mines-4-5.tsv +2 -0
- package/engine-examples/mines/math/mines-4-6.tsv +2 -0
- package/engine-examples/mines/math/mines-4-7.tsv +2 -0
- package/engine-examples/mines/math/mines-4-8.tsv +2 -0
- package/engine-examples/mines/math/mines-4-9.tsv +2 -0
- package/engine-examples/mines/math/mines-5-1.tsv +2 -0
- package/engine-examples/mines/math/mines-5-10.tsv +2 -0
- package/engine-examples/mines/math/mines-5-11.tsv +2 -0
- package/engine-examples/mines/math/mines-5-12.tsv +2 -0
- package/engine-examples/mines/math/mines-5-13.tsv +2 -0
- package/engine-examples/mines/math/mines-5-14.tsv +2 -0
- package/engine-examples/mines/math/mines-5-15.tsv +2 -0
- package/engine-examples/mines/math/mines-5-16.tsv +2 -0
- package/engine-examples/mines/math/mines-5-17.tsv +2 -0
- package/engine-examples/mines/math/mines-5-18.tsv +2 -0
- package/engine-examples/mines/math/mines-5-19.tsv +2 -0
- package/engine-examples/mines/math/mines-5-2.tsv +2 -0
- package/engine-examples/mines/math/mines-5-20.tsv +2 -0
- package/engine-examples/mines/math/mines-5-3.tsv +2 -0
- package/engine-examples/mines/math/mines-5-4.tsv +2 -0
- package/engine-examples/mines/math/mines-5-5.tsv +2 -0
- package/engine-examples/mines/math/mines-5-6.tsv +2 -0
- package/engine-examples/mines/math/mines-5-7.tsv +2 -0
- package/engine-examples/mines/math/mines-5-8.tsv +2 -0
- package/engine-examples/mines/math/mines-5-9.tsv +2 -0
- package/engine-examples/mines/math/mines-6-1.tsv +2 -0
- package/engine-examples/mines/math/mines-6-10.tsv +2 -0
- package/engine-examples/mines/math/mines-6-11.tsv +2 -0
- package/engine-examples/mines/math/mines-6-12.tsv +2 -0
- package/engine-examples/mines/math/mines-6-13.tsv +2 -0
- package/engine-examples/mines/math/mines-6-14.tsv +2 -0
- package/engine-examples/mines/math/mines-6-15.tsv +2 -0
- package/engine-examples/mines/math/mines-6-16.tsv +2 -0
- package/engine-examples/mines/math/mines-6-17.tsv +2 -0
- package/engine-examples/mines/math/mines-6-18.tsv +2 -0
- package/engine-examples/mines/math/mines-6-19.tsv +2 -0
- package/engine-examples/mines/math/mines-6-2.tsv +2 -0
- package/engine-examples/mines/math/mines-6-3.tsv +2 -0
- package/engine-examples/mines/math/mines-6-4.tsv +2 -0
- package/engine-examples/mines/math/mines-6-5.tsv +2 -0
- package/engine-examples/mines/math/mines-6-6.tsv +2 -0
- package/engine-examples/mines/math/mines-6-7.tsv +2 -0
- package/engine-examples/mines/math/mines-6-8.tsv +2 -0
- package/engine-examples/mines/math/mines-6-9.tsv +2 -0
- package/engine-examples/mines/math/mines-7-1.tsv +2 -0
- package/engine-examples/mines/math/mines-7-10.tsv +2 -0
- package/engine-examples/mines/math/mines-7-11.tsv +2 -0
- package/engine-examples/mines/math/mines-7-12.tsv +2 -0
- package/engine-examples/mines/math/mines-7-13.tsv +2 -0
- package/engine-examples/mines/math/mines-7-14.tsv +2 -0
- package/engine-examples/mines/math/mines-7-15.tsv +2 -0
- package/engine-examples/mines/math/mines-7-16.tsv +2 -0
- package/engine-examples/mines/math/mines-7-17.tsv +2 -0
- package/engine-examples/mines/math/mines-7-18.tsv +2 -0
- package/engine-examples/mines/math/mines-7-2.tsv +2 -0
- package/engine-examples/mines/math/mines-7-3.tsv +2 -0
- package/engine-examples/mines/math/mines-7-4.tsv +2 -0
- package/engine-examples/mines/math/mines-7-5.tsv +2 -0
- package/engine-examples/mines/math/mines-7-6.tsv +2 -0
- package/engine-examples/mines/math/mines-7-7.tsv +2 -0
- package/engine-examples/mines/math/mines-7-8.tsv +2 -0
- package/engine-examples/mines/math/mines-7-9.tsv +2 -0
- package/engine-examples/mines/math/mines-8-1.tsv +2 -0
- package/engine-examples/mines/math/mines-8-10.tsv +2 -0
- package/engine-examples/mines/math/mines-8-11.tsv +2 -0
- package/engine-examples/mines/math/mines-8-12.tsv +2 -0
- package/engine-examples/mines/math/mines-8-13.tsv +2 -0
- package/engine-examples/mines/math/mines-8-14.tsv +2 -0
- package/engine-examples/mines/math/mines-8-15.tsv +2 -0
- package/engine-examples/mines/math/mines-8-16.tsv +2 -0
- package/engine-examples/mines/math/mines-8-17.tsv +2 -0
- package/engine-examples/mines/math/mines-8-2.tsv +2 -0
- package/engine-examples/mines/math/mines-8-3.tsv +2 -0
- package/engine-examples/mines/math/mines-8-4.tsv +2 -0
- package/engine-examples/mines/math/mines-8-5.tsv +2 -0
- package/engine-examples/mines/math/mines-8-6.tsv +2 -0
- package/engine-examples/mines/math/mines-8-7.tsv +2 -0
- package/engine-examples/mines/math/mines-8-8.tsv +2 -0
- package/engine-examples/mines/math/mines-8-9.tsv +2 -0
- package/engine-examples/mines/math/mines-9-1.tsv +2 -0
- package/engine-examples/mines/math/mines-9-10.tsv +2 -0
- package/engine-examples/mines/math/mines-9-11.tsv +2 -0
- package/engine-examples/mines/math/mines-9-12.tsv +2 -0
- package/engine-examples/mines/math/mines-9-13.tsv +2 -0
- package/engine-examples/mines/math/mines-9-14.tsv +2 -0
- package/engine-examples/mines/math/mines-9-15.tsv +2 -0
- package/engine-examples/mines/math/mines-9-16.tsv +2 -0
- package/engine-examples/mines/math/mines-9-2.tsv +2 -0
- package/engine-examples/mines/math/mines-9-3.tsv +2 -0
- package/engine-examples/mines/math/mines-9-4.tsv +2 -0
- package/engine-examples/mines/math/mines-9-5.tsv +2 -0
- package/engine-examples/mines/math/mines-9-6.tsv +2 -0
- package/engine-examples/mines/math/mines-9-7.tsv +2 -0
- package/engine-examples/mines/math/mines-9-8.tsv +2 -0
- package/engine-examples/mines/math/mines-9-9.tsv +2 -0
- package/engine-examples/plinko/AGENTS.md +3 -0
- package/engine-examples/plinko/README.md +9 -0
- package/engine-examples/plinko/bundle/assets.json +1 -0
- package/engine-examples/plinko/bundle/game.css +5 -0
- package/engine-examples/plinko/bundle/game.js +92 -0
- package/engine-examples/plinko/bundle/hbtest.json +4 -0
- package/engine-examples/plinko/bundle/index.html +16 -0
- package/engine-examples/plinko/bundle/model.json +1 -0
- package/engine-examples/plinko/math/gen.mjs +40 -0
- package/engine-examples/plinko/math/manifest.json +1 -0
- package/engine-examples/plinko/math/plinko-12-high.tsv +13 -0
- package/engine-examples/plinko/math/plinko-12-low.tsv +13 -0
- package/engine-examples/plinko/math/plinko-12-medium.tsv +13 -0
- package/engine-examples/plinko/math/plinko-16-high.tsv +17 -0
- package/engine-examples/plinko/math/plinko-16-low.tsv +17 -0
- package/engine-examples/plinko/math/plinko-16-medium.tsv +17 -0
- package/engine-examples/plinko/math/plinko-8-high.tsv +9 -0
- package/engine-examples/plinko/math/plinko-8-low.tsv +9 -0
- package/engine-examples/plinko/math/plinko-8-medium.tsv +9 -0
- package/engine-examples/plinko/math-kit/pack.mjs +165 -0
- package/engine-examples/plinko/math-kit/package.json +8 -0
- package/engine-examples/plinko/math-kit/slot.mjs +94 -0
- package/engine-examples/plinko/math-kit/tumble.mjs +94 -0
- package/engine-examples/slot/AGENTS.md +3 -0
- package/engine-examples/slot/README.md +26 -0
- package/engine-examples/slot/bundle/assets.json +1 -0
- package/engine-examples/slot/bundle/game.css +19 -0
- package/engine-examples/slot/bundle/game.js +42 -0
- package/engine-examples/slot/bundle/hbtest.json +4 -0
- package/engine-examples/slot/bundle/index.html +23 -0
- package/engine-examples/slot/math/gen.mjs +79 -0
- package/engine-examples/slot/math/manifest.json +1 -0
- package/engine-examples/slot/math/slot.tsv +110592 -0
- package/engine-examples/tower/AGENTS.md +3 -0
- package/engine-examples/tower/README.md +21 -0
- package/engine-examples/tower/bundle/assets.json +1 -0
- package/engine-examples/tower/bundle/game.css +8 -0
- package/engine-examples/tower/bundle/game.js +37 -0
- package/engine-examples/tower/bundle/hbtest.json +5 -0
- package/engine-examples/tower/bundle/index.html +16 -0
- package/engine-examples/tower/math/floor.tsv +4 -0
- package/engine-examples/tower/math/manifest.json +61 -0
- package/engine-examples/tumble/AGENTS.md +3 -0
- package/engine-examples/tumble/README.md +18 -0
- package/engine-examples/tumble/bundle/assets.json +1 -0
- package/engine-examples/tumble/bundle/game.css +13 -0
- package/engine-examples/tumble/bundle/game.js +119 -0
- package/engine-examples/tumble/bundle/hbtest.json +4 -0
- package/engine-examples/tumble/bundle/i18n.json +122 -0
- package/engine-examples/tumble/bundle/index.html +20 -0
- package/engine-examples/tumble/bundle/model.json +1 -0
- package/engine-examples/tumble/math/gen.mjs +38 -0
- package/engine-examples/tumble/math-kit/pack.mjs +165 -0
- package/engine-examples/tumble/math-kit/package.json +8 -0
- package/engine-examples/tumble/math-kit/slot.mjs +94 -0
- package/engine-examples/tumble/math-kit/tumble.mjs +94 -0
- package/engine-examples/wheel/README.md +14 -0
- package/engine-examples/wheel/bundle/assets.json +1 -0
- package/engine-examples/wheel/bundle/game.css +7 -0
- package/engine-examples/wheel/bundle/game.js +51 -0
- package/engine-examples/wheel/bundle/hbtest.json +4 -0
- package/engine-examples/wheel/bundle/index.html +19 -0
- package/engine-examples/wheel/math/high.tsv +24 -0
- package/engine-examples/wheel/math/low.tsv +24 -0
- package/engine-examples/wheel/math/manifest.json +48 -0
- package/engine-examples/wheel/math/medium.tsv +24 -0
- package/engine-math/pack.mjs +165 -0
- package/engine-math/package.json +1 -0
- package/engine-math/slot.mjs +94 -0
- package/engine-math/tumble.mjs +94 -0
- package/engine-mcp/package.json +1 -0
- package/engine-mcp/server.mjs +151 -0
- package/engine-sdk/GUIDE.md +855 -0
- package/engine-sdk/assets.js +92 -0
- package/engine-sdk/autoplay.js +82 -0
- package/engine-sdk/bet-field.js +391 -0
- package/engine-sdk/kit/fiat-coins.js +51 -0
- package/engine-sdk/kit/numeric-input.js +116 -0
- package/engine-sdk/kit/wallet-format.js +423 -0
- package/engine-sdk/marks.js +22 -0
- package/engine-sdk/messages.js +289 -0
- package/engine-sdk/money.js +89 -0
- package/engine-sdk/package.json +1 -0
- package/engine-sdk/protocol.js +263 -0
- package/engine-sdk/sdk.d.ts +138 -0
- package/engine-sdk/sdk.js +330 -0
- package/engine-sdk/stake.js +68 -0
- package/engine-sdk/ui.d.ts +36 -0
- package/engine-sdk/ui.js +340 -0
- package/engine-shell/core/faults.js +127 -0
- package/engine-shell/core/rgs.js +193 -0
- package/engine-shell/core/router.js +917 -0
- package/engine-shell/host/boot.js +408 -0
- package/engine-shell/host/engine-v1.js +438 -0
- package/engine-shell/host/fair.js +285 -0
- package/engine-shell/host/fonts/SOURCE.json +11 -0
- package/engine-shell/host/fonts/figtree-400.woff2 +0 -0
- package/engine-shell/host/fonts/figtree-500.woff2 +0 -0
- package/engine-shell/host/fonts/figtree-600.woff2 +0 -0
- package/engine-shell/host/fonts/red-hat-display-700.woff2 +0 -0
- package/engine-shell/host/index.html +230 -0
- package/engine-shell/host/page.js +809 -0
- package/engine-shell/host/sandbox-panel.js +681 -0
- package/engine-shell/host/sandbox-scenarios.js +554 -0
- package/engine-shell/host/site-bridge.js +87 -0
- package/engine-shell/host/strings.js +916 -0
- package/engine-shell/package.json +1 -0
- package/engine-shell/verifiers/badcat/coin.tsv +2 -0
- package/engine-shell/verifiers/badcat/dice-2.tsv +11 -0
- package/engine-shell/verifiers/badcat/dice-5.tsv +26 -0
- package/engine-shell/verifiers/badcat/dice-9.tsv +46 -0
- package/engine-shell/verifiers/badcat/manifest.json +3344 -0
- package/engine-shell/verifiers/badcat/rps.tsv +3 -0
- package/engine-shell/verifiers/badcat/triple.tsv +66 -0
- package/engine-shell/verifiers/engine-verify.js +358 -0
- package/engine-shell/verifiers/package.json +5 -0
- package/engine-shell/verifiers/parity/manifest.json +27 -0
- package/engine-shell/verifiers/parity/wide.tsv +5 -0
- package/engine-shell/verifiers/parity-vectors.json +244 -0
- package/engine-shell/verifiers/vectors.json +100 -0
- package/package.json +10 -0
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
# For agents
|
|
2
|
+
|
|
3
|
+
This is a House Engine game (Housebets). Read the guide first: `engine_guide` (MCP) or `engine-sdk/GUIDE.md`. Then `hbengine verify`, `hbengine dev`, `hbengine upload` (or the `engine_*` tools). The math is `math/`, the frontend `bundle/`; never compute money or outcomes in the frontend.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Tower — a ladder with cash-out
|
|
2
|
+
|
|
3
|
+
Eight floors; four tiles each, one is a trap. Every floor survived multiplies
|
|
4
|
+
the pot by about 4/3; the player cashes out after any floor, or loses the
|
|
5
|
+
stake on a trap. Max 9.89×.
|
|
6
|
+
|
|
7
|
+
Cumulative payout after k survived floors, exactly (`ladderBp`):
|
|
8
|
+
|
|
9
|
+
13200 · 17600 · 23466 · 31288 · 41718 · 55624 · 74166 · 98888 bp
|
|
10
|
+
|
|
11
|
+
RTP of stopping after floor k = ladderBp[k-1] · (3/4)^k, every stop ≤ 99 %:
|
|
12
|
+
|
|
13
|
+
9900 · 9900 · 9899.72 · 9899.72 · 9899.88 · 9899.88 · 9899.97 · 9899.97 bp
|
|
14
|
+
|
|
15
|
+
The best stop bounds every strategy (the player learns only "survived so
|
|
16
|
+
far"), so the bet's RTP is 99.00 %. The panel (`/engine-sdk/ui.js`) draws Bet,
|
|
17
|
+
Next and Cash out; this bundle's `game.js` renders the tower and reveals each
|
|
18
|
+
floor the server drew.
|
|
19
|
+
|
|
20
|
+
npx hbengine verify . exact RTP per stop, the mathHash
|
|
21
|
+
npx hbengine init my-tower --template tower --slug my-tower # make it yours, then: verify, dev, upload
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "groups": { "boot": { "files": ["index.html", "game.js", "game.css"] } } }
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
body { margin: 0; background: #08141a; }
|
|
2
|
+
.tower { display: grid; grid-template-rows: repeat(8, 44px); gap: 6px; padding: 20px; width: min(360px, 100%); box-sizing: border-box; margin: 0 auto; }
|
|
3
|
+
.floor { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; opacity: .5; transition: opacity 160ms ease; }
|
|
4
|
+
.floor.revealed { opacity: 1; }
|
|
5
|
+
.tile { height: 44px; border-radius: 8px; background: #0d2a38; box-shadow: inset 0 0 0 1px rgba(40,243,243,.1); transition: background 180ms ease, box-shadow 180ms ease, transform 180ms ease; }
|
|
6
|
+
.floor.revealed .tile.safe { background: #0b3b2a; box-shadow: inset 0 0 0 1px #3ad67a; }
|
|
7
|
+
.floor.revealed .tile.trap { background: #3b0f14; box-shadow: inset 0 0 0 1px #ff5a6a; }
|
|
8
|
+
.floor.bust .tile.trap { background: #ff5a6a; transform: scale(1.04); }
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { mount } from '/engine-sdk/ui.js';
|
|
2
|
+
|
|
3
|
+
const FLOORS = 8;
|
|
4
|
+
const TILES = 4;
|
|
5
|
+
const zone = document.getElementById('tower');
|
|
6
|
+
|
|
7
|
+
for (let i = FLOORS; i >= 1; i--) {
|
|
8
|
+
const row = document.createElement('div');
|
|
9
|
+
row.className = 'floor';
|
|
10
|
+
row.dataset.floor = i;
|
|
11
|
+
for (let t = 0; t < TILES; t++) {
|
|
12
|
+
const tile = document.createElement('div');
|
|
13
|
+
tile.className = 'tile';
|
|
14
|
+
tile.dataset.tile = t;
|
|
15
|
+
row.append(tile);
|
|
16
|
+
}
|
|
17
|
+
zone.append(row);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function render(round) {
|
|
21
|
+
const bust = round.state === 'busted'; // round.busted is the drawn path's, also after a cash-out
|
|
22
|
+
for (let i = 1; i <= FLOORS; i++) {
|
|
23
|
+
const row = zone.querySelector(`[data-floor="${i}"]`);
|
|
24
|
+
const data = round.data[i - 1];
|
|
25
|
+
row.classList.toggle('revealed', !!data);
|
|
26
|
+
row.classList.toggle('bust', bust && i === round.step);
|
|
27
|
+
for (const tile of row.children) {
|
|
28
|
+
const t = Number(tile.dataset.tile);
|
|
29
|
+
tile.classList.toggle('trap', !!data && t === data.trap);
|
|
30
|
+
tile.classList.toggle('safe', !!data && t !== data.trap);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
await mount(document.getElementById('game'), {
|
|
36
|
+
step: (round) => render(round),
|
|
37
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
{
|
|
2
|
+
"stake": { "page": "index.html", "selector": "hb-game hb-bet-amount input", "value": "1.00" },
|
|
3
|
+
"bet": { "page": "index.html", "selector": "hb-game [data-main]" },
|
|
4
|
+
"then": [{ "page": "index.html", "selector": "hb-game [data-next]" }, { "page": "index.html", "selector": "hb-game [data-cashout]" }]
|
|
5
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
6
|
+
<title>Tower</title>
|
|
7
|
+
<link rel="stylesheet" href="./game.css">
|
|
8
|
+
<script type="module" src="/engine-sdk/bet-field.js"></script>
|
|
9
|
+
<script type="module" src="./game.js"></script>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<hb-game id="game">
|
|
13
|
+
<div slot="zone" class="tower" id="tower" aria-live="polite"></div>
|
|
14
|
+
</hb-game>
|
|
15
|
+
</body>
|
|
16
|
+
</html>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"format": "house-engine-math/1",
|
|
3
|
+
"game": "tower",
|
|
4
|
+
"rtpBp": 9900,
|
|
5
|
+
"modes": [
|
|
6
|
+
{
|
|
7
|
+
"id": "climb",
|
|
8
|
+
"label": "Climb",
|
|
9
|
+
"kind": "ladder",
|
|
10
|
+
"steps": [
|
|
11
|
+
{
|
|
12
|
+
"table": "floor.tsv"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"table": "floor.tsv"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"table": "floor.tsv"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"table": "floor.tsv"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"table": "floor.tsv"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"table": "floor.tsv"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"table": "floor.tsv"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"table": "floor.tsv"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"cashout": true,
|
|
37
|
+
"ladderBp": [
|
|
38
|
+
13200,
|
|
39
|
+
17600,
|
|
40
|
+
23466,
|
|
41
|
+
31288,
|
|
42
|
+
41718,
|
|
43
|
+
55624,
|
|
44
|
+
74166,
|
|
45
|
+
98888
|
|
46
|
+
],
|
|
47
|
+
"bets": [
|
|
48
|
+
{
|
|
49
|
+
"id": "climb",
|
|
50
|
+
"label": "Climb",
|
|
51
|
+
"survive": [
|
|
52
|
+
[
|
|
53
|
+
0,
|
|
54
|
+
2
|
|
55
|
+
]
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
# For agents
|
|
2
|
+
|
|
3
|
+
This is a House Engine game (Housebets). Read the guide first: `engine_guide` (MCP) or `engine-sdk/GUIDE.md`. Then `hbengine verify`, `hbengine dev`, `hbengine upload` (or the `engine_*` tools). The math is `math/`, the frontend `bundle/`; never compute money or outcomes in the frontend.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Tumble — a scatter-pays slot with tumbles, from the maths kit
|
|
2
|
+
|
|
3
|
+
A 6 × 5 grid: 8 or more of a symbol anywhere pays; the winners vanish and
|
|
4
|
+
new symbols drop in until nothing pays. Four scatters pay and start ten free
|
|
5
|
+
spins where multiplier symbols (2× to 100×) add up and multiply each winning
|
|
6
|
+
spin; three scatters in free spins add five (up to 30). 5,000× cap. RTP
|
|
7
|
+
exactly 96.00%, hit rate 22.7%.
|
|
8
|
+
|
|
9
|
+
| path | what |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `math/gen.mjs` | the model, 300,000 rounds played into rows, `fit` to exactly 96%; writes `bundle/model.json` |
|
|
12
|
+
| `math-kit/tumble.mjs` | the tumble model (grid, scatter pays, tumbles, free spins, multipliers) |
|
|
13
|
+
| `bundle/game.js` | drops the grid, plays each tumble and the free spins the row holds; a tap skips the free spins |
|
|
14
|
+
|
|
15
|
+
A row: `{"b":[grid, [[winners, winBp, fill per column…]…], multipliers?], "f":[spin…]}`;
|
|
16
|
+
the grid is column by column, top to bottom, one character per symbol.
|
|
17
|
+
|
|
18
|
+
node math/gen.mjs && npx hbengine verify .
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"groups": {"boot": {"files": ["index.html", "game.js", "game.css", "model.json", "i18n.json"]}}}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
body { margin: 0; background: #08141a; }
|
|
2
|
+
.tumble { container-type: inline-size; display: flex; flex-direction: column; align-items: center; gap: 12px; width: 100%; padding: 14px 12px; box-sizing: border-box; }
|
|
3
|
+
.banner, .win { height: 22px; font: 700 15px/22px 'Red Hat Display', 'Figtree', system-ui, sans-serif; font-variant-numeric: tabular-nums; }
|
|
4
|
+
.banner { color: #8F96A8; font-size: 13px; }
|
|
5
|
+
.win { color: #FDDC73; }
|
|
6
|
+
.grid { --c: min(84px, (100cqi - 40px) / 6); position: relative; display: grid; grid-template-columns: repeat(6, var(--c)); gap: 4px; padding: 8px; border-radius: 14px; background: #061218; box-shadow: inset 0 0 0 1px #0D2A38; }
|
|
7
|
+
.col { position: relative; height: calc(var(--c) * 5); overflow: hidden; border-radius: 8px; background: #0b1f28; }
|
|
8
|
+
.cell { position: absolute; left: 0; top: 0; width: var(--c); height: var(--c); display: grid; place-items: center; transition: transform 260ms cubic-bezier(.3, .7, .3, 1), opacity 200ms; }
|
|
9
|
+
.cell svg { width: 70%; height: 70%; }
|
|
10
|
+
.cell.won { background: rgba(253, 220, 115, .14); border-radius: 8px; }
|
|
11
|
+
.cell.gone { opacity: 0; }
|
|
12
|
+
.cell i { position: absolute; font: 800 calc(var(--c) * .26)/1 'Red Hat Display', system-ui, sans-serif; color: #041015; font-style: normal; }
|
|
13
|
+
@media (prefers-reduced-motion: reduce) { .cell { transition: none; } }
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Tumble: a 6 × 5 grid that pays 8 or more of a symbol anywhere. The panel
|
|
2
|
+
// is the engine's (engine-sdk/ui.js); this file plays back the row the
|
|
3
|
+
// server drew: the first grid, each tumble (what paid, what drops in), and
|
|
4
|
+
// the free spins with their multipliers. model.json comes from math/gen.mjs.
|
|
5
|
+
import { mount } from '/engine-sdk/ui.js';
|
|
6
|
+
|
|
7
|
+
const model = await (await fetch('./model.json')).json();
|
|
8
|
+
// The page's own words in the player's language (bundle/i18n.json, English otherwise).
|
|
9
|
+
const I18N = await (await fetch('./i18n.json')).json();
|
|
10
|
+
let W = I18N.en;
|
|
11
|
+
const t = (k, v = {}) => W[k].replace(/\{(\w+)\}/g, (_, x) => v[x]);
|
|
12
|
+
const ROWS = model.rows, COLS = model.cols;
|
|
13
|
+
const gridEl = document.getElementById('grid'), banner = document.getElementById('banner'), winEl = document.getElementById('win');
|
|
14
|
+
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
15
|
+
const shape = (d, fill, stroke) => `<svg viewBox="0 0 40 40"><path d="${d}" fill="${fill}" stroke="${stroke}" stroke-width="2.2" stroke-linejoin="round"/></svg>`;
|
|
16
|
+
// Deep fills, bright strokes: the big shapes stay muted.
|
|
17
|
+
const ART = {
|
|
18
|
+
R: shape('M20 34L7 21a7.5 7.5 0 0113-9 7.5 7.5 0 0113 9z', '#7e1f3a', '#ff6b81'),
|
|
19
|
+
P: shape('M20 5l13 10-5 17H12L7 15z', '#4a2a6b', '#c89bff'),
|
|
20
|
+
G: shape('M20 5l14 15-14 15L6 20z', '#1f5a3a', '#7cf2b0'),
|
|
21
|
+
B: shape('M8 14l6-8h12l6 8-12 20z', '#0d5f6e', '#5cf6f6'),
|
|
22
|
+
a: shape('M20 7a13 13 0 110 26 13 13 0 010-26z', '#7d5410', '#FDDC73'),
|
|
23
|
+
b: shape('M9 9h22v22H9z', '#2b2f6b', '#a6adff'),
|
|
24
|
+
c: shape('M20 6l15 26H5z', '#5a2a2a', '#ff9f80'),
|
|
25
|
+
d: shape('M12 7h16l7 13-7 13H12L5 20z', '#264a52', '#9fe0ea'),
|
|
26
|
+
e: shape('M20 6l4 10h10l-8 7 3 11-9-6-9 6 3-11-8-7h10z', '#3b4a1f', '#d4f27c'),
|
|
27
|
+
S: shape('M20 4l4.5 10.5L36 16l-8.5 7.5L30 35l-10-6-10 6 2.5-11.5L4 16l11.5-1.5z', '#7d5410', '#FDDC73'),
|
|
28
|
+
M: shape('M20 6a14 14 0 110 28 14 14 0 010-28z', '#F9F9FB', '#FDDC73'),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
let c = 80;
|
|
32
|
+
const cols = Array.from({ length: COLS }, () => { const e = document.createElement('div'); e.className = 'col'; gridEl.append(e); return { el: e, cells: [] }; });
|
|
33
|
+
const place = (cell, y) => { cell.el.style.transform = `translateY(${y * c}px)`; };
|
|
34
|
+
const make = (sym, y) => {
|
|
35
|
+
const el = document.createElement('div');
|
|
36
|
+
el.className = 'cell';
|
|
37
|
+
el.innerHTML = ART[sym] || sym;
|
|
38
|
+
el.style.transition = 'none';
|
|
39
|
+
el.style.transform = `translateY(${y * c}px)`;
|
|
40
|
+
return { sym, el };
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// A new grid falls in from above.
|
|
44
|
+
async function drop(grid, quick) {
|
|
45
|
+
c = cols[0].el.getBoundingClientRect().height / ROWS || c;
|
|
46
|
+
cols.forEach((col, x) => {
|
|
47
|
+
col.el.replaceChildren();
|
|
48
|
+
col.cells = [...grid.slice(x * ROWS, x * ROWS + ROWS)].map((s, y) => make(s, y - ROWS - 1));
|
|
49
|
+
col.cells.forEach((cell) => col.el.append(cell.el));
|
|
50
|
+
});
|
|
51
|
+
void gridEl.offsetWidth;
|
|
52
|
+
cols.forEach((col, x) => col.cells.forEach((cell, y) => { cell.el.style.transition = ''; cell.el.style.transitionDelay = quick ? '0ms' : `${x * 40}ms`; place(cell, y); }));
|
|
53
|
+
await wait(quick ? 200 : 520);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// One tumble: the winners light up and vanish, the rest fall, new ones drop in.
|
|
57
|
+
async function tumble([paid, , ...fills], quick) {
|
|
58
|
+
cols.forEach((col) => col.cells.forEach((cell) => cell.el.classList.toggle('won', paid.includes(cell.sym))));
|
|
59
|
+
await wait(quick ? 120 : 520);
|
|
60
|
+
cols.forEach((col) => col.cells.forEach((cell) => { if (paid.includes(cell.sym)) cell.el.classList.add('gone'); }));
|
|
61
|
+
await wait(quick ? 60 : 200);
|
|
62
|
+
cols.forEach((col, x) => {
|
|
63
|
+
const kept = col.cells.filter((cell) => !paid.includes(cell.sym));
|
|
64
|
+
col.cells.filter((cell) => paid.includes(cell.sym)).forEach((cell) => cell.el.remove());
|
|
65
|
+
const add = [...fills[x]].map((s, i) => make(s, i - fills[x].length - 1));
|
|
66
|
+
add.forEach((cell) => col.el.append(cell.el));
|
|
67
|
+
col.cells = [...add, ...kept];
|
|
68
|
+
void col.el.offsetWidth;
|
|
69
|
+
col.cells.forEach((cell, y) => { cell.el.style.transition = ''; cell.el.style.transitionDelay = '0ms'; place(cell, y); });
|
|
70
|
+
});
|
|
71
|
+
await wait(quick ? 160 : 360);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const times = (bp) => (bp / 10000).toFixed(2) + '×';
|
|
75
|
+
|
|
76
|
+
// One spin of the row: the grid, its tumbles, its multipliers. Returns its win.
|
|
77
|
+
async function play([grid, tumbles, bombs], quick, already) {
|
|
78
|
+
await drop(grid, quick);
|
|
79
|
+
let win = 0;
|
|
80
|
+
for (const t of tumbles) {
|
|
81
|
+
await tumble(t, quick);
|
|
82
|
+
win += t[1];
|
|
83
|
+
winEl.textContent = times(already + win);
|
|
84
|
+
}
|
|
85
|
+
if (bombs) {
|
|
86
|
+
let i = 0;
|
|
87
|
+
cols.forEach((col) => col.cells.forEach((cell) => { if (cell.sym === 'M') cell.el.insertAdjacentHTML('beforeend', `<i>${bombs[i++]}×</i>`); }));
|
|
88
|
+
if (win) { win *= bombs.reduce((a, b) => a + b, 0); winEl.textContent = times(already + win); await wait(quick ? 150 : 600); }
|
|
89
|
+
}
|
|
90
|
+
return win;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
drop(Array.from({ length: COLS * ROWS }, (_, i) => 'edcbaBGPR'[i % 9]), true);
|
|
94
|
+
|
|
95
|
+
const game = await mount(document.getElementById('game'), {
|
|
96
|
+
async reveal(round) {
|
|
97
|
+
const d = round.data[0];
|
|
98
|
+
winEl.textContent = ''; banner.textContent = '';
|
|
99
|
+
let total = await play(d.b, false, 0);
|
|
100
|
+
const scatters = cols.flatMap((col) => col.cells).filter((cell) => cell.sym === 'S').length; // on the last grid, as the maths counts them
|
|
101
|
+
if (model.scatter.pays[Math.min(scatters, 6)]) total += model.scatter.pays[Math.min(scatters, 6)];
|
|
102
|
+
if (total) winEl.textContent = times(total);
|
|
103
|
+
if (d.f) {
|
|
104
|
+
let skip = false;
|
|
105
|
+
const tap = () => { skip = true; };
|
|
106
|
+
gridEl.addEventListener('pointerdown', tap);
|
|
107
|
+
await wait(600);
|
|
108
|
+
for (let i = 0; i < d.f.length; i++) {
|
|
109
|
+
banner.textContent = t('freeSpins', { i: i + 1, n: d.f.length }) + (skip ? '' : ` · ${t('tapToSkip')}`);
|
|
110
|
+
total += await play(d.f[i], skip, total);
|
|
111
|
+
}
|
|
112
|
+
gridEl.removeEventListener('pointerdown', tap);
|
|
113
|
+
banner.textContent = t('freeOver');
|
|
114
|
+
}
|
|
115
|
+
if (d.cap) winEl.textContent = `${times(model.maxWinBp)} · ${t('maxWin')}`;
|
|
116
|
+
else if (total) winEl.textContent = times(total);
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
W = I18N[(game.engine.config.locale || 'en').slice(0, 2)] || I18N.en;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
{
|
|
2
|
+
"en": {
|
|
3
|
+
"freeSpins": "Free spins {i} of {n}",
|
|
4
|
+
"tapToSkip": "tap to skip",
|
|
5
|
+
"freeOver": "Free spins over",
|
|
6
|
+
"maxWin": "max win"
|
|
7
|
+
},
|
|
8
|
+
"ar": {
|
|
9
|
+
"freeSpins": "دورات مجانية {i} من {n}",
|
|
10
|
+
"tapToSkip": "اضغط للتخطي",
|
|
11
|
+
"freeOver": "انتهت الدورات المجانية",
|
|
12
|
+
"maxWin": "أقصى ربح"
|
|
13
|
+
},
|
|
14
|
+
"da": {
|
|
15
|
+
"freeSpins": "Gratis spins {i} af {n}",
|
|
16
|
+
"tapToSkip": "tryk for at springe over",
|
|
17
|
+
"freeOver": "Gratis spins slut",
|
|
18
|
+
"maxWin": "maks. gevinst"
|
|
19
|
+
},
|
|
20
|
+
"de": {
|
|
21
|
+
"freeSpins": "Freispiele {i} von {n}",
|
|
22
|
+
"tapToSkip": "zum Überspringen tippen",
|
|
23
|
+
"freeOver": "Freispiele beendet",
|
|
24
|
+
"maxWin": "Maximalgewinn"
|
|
25
|
+
},
|
|
26
|
+
"es": {
|
|
27
|
+
"freeSpins": "Giros gratis {i} de {n}",
|
|
28
|
+
"tapToSkip": "toca para saltar",
|
|
29
|
+
"freeOver": "Giros gratis terminados",
|
|
30
|
+
"maxWin": "premio máximo"
|
|
31
|
+
},
|
|
32
|
+
"fi": {
|
|
33
|
+
"freeSpins": "Ilmaiskierrokset {i}/{n}",
|
|
34
|
+
"tapToSkip": "ohita napauttamalla",
|
|
35
|
+
"freeOver": "Ilmaiskierrokset päättyivät",
|
|
36
|
+
"maxWin": "maksimivoitto"
|
|
37
|
+
},
|
|
38
|
+
"fr": {
|
|
39
|
+
"freeSpins": "Tours gratuits {i} sur {n}",
|
|
40
|
+
"tapToSkip": "touchez pour passer",
|
|
41
|
+
"freeOver": "Tours gratuits terminés",
|
|
42
|
+
"maxWin": "gain maximal"
|
|
43
|
+
},
|
|
44
|
+
"hi": {
|
|
45
|
+
"freeSpins": "फ्री स्पिन {i} / {n}",
|
|
46
|
+
"tapToSkip": "छोड़ने के लिए टैप करें",
|
|
47
|
+
"freeOver": "फ्री स्पिन खत्म",
|
|
48
|
+
"maxWin": "अधिकतम जीत"
|
|
49
|
+
},
|
|
50
|
+
"hu": {
|
|
51
|
+
"freeSpins": "Ingyenes pörgetés {i}/{n}",
|
|
52
|
+
"tapToSkip": "koppints az átugráshoz",
|
|
53
|
+
"freeOver": "Vége az ingyenes pörgetéseknek",
|
|
54
|
+
"maxWin": "max. nyeremény"
|
|
55
|
+
},
|
|
56
|
+
"id": {
|
|
57
|
+
"freeSpins": "Putaran gratis {i} dari {n}",
|
|
58
|
+
"tapToSkip": "ketuk untuk lewati",
|
|
59
|
+
"freeOver": "Putaran gratis selesai",
|
|
60
|
+
"maxWin": "kemenangan maks"
|
|
61
|
+
},
|
|
62
|
+
"it": {
|
|
63
|
+
"freeSpins": "Giri gratis {i} di {n}",
|
|
64
|
+
"tapToSkip": "tocca per saltare",
|
|
65
|
+
"freeOver": "Giri gratis finiti",
|
|
66
|
+
"maxWin": "vincita massima"
|
|
67
|
+
},
|
|
68
|
+
"ja": {
|
|
69
|
+
"freeSpins": "フリースピン {i}/{n}",
|
|
70
|
+
"tapToSkip": "タップでスキップ",
|
|
71
|
+
"freeOver": "フリースピン終了",
|
|
72
|
+
"maxWin": "最大配当"
|
|
73
|
+
},
|
|
74
|
+
"ko": {
|
|
75
|
+
"freeSpins": "프리 스핀 {i}/{n}",
|
|
76
|
+
"tapToSkip": "탭하여 건너뛰기",
|
|
77
|
+
"freeOver": "프리 스핀 종료",
|
|
78
|
+
"maxWin": "최대 당첨"
|
|
79
|
+
},
|
|
80
|
+
"pl": {
|
|
81
|
+
"freeSpins": "Darmowe spiny {i} z {n}",
|
|
82
|
+
"tapToSkip": "dotknij, aby pominąć",
|
|
83
|
+
"freeOver": "Koniec darmowych spinów",
|
|
84
|
+
"maxWin": "maks. wygrana"
|
|
85
|
+
},
|
|
86
|
+
"pt": {
|
|
87
|
+
"freeSpins": "Giros grátis {i} de {n}",
|
|
88
|
+
"tapToSkip": "toque para pular",
|
|
89
|
+
"freeOver": "Giros grátis terminados",
|
|
90
|
+
"maxWin": "ganho máximo"
|
|
91
|
+
},
|
|
92
|
+
"ru": {
|
|
93
|
+
"freeSpins": "Бесплатные вращения {i} из {n}",
|
|
94
|
+
"tapToSkip": "нажмите, чтобы пропустить",
|
|
95
|
+
"freeOver": "Бесплатные вращения закончились",
|
|
96
|
+
"maxWin": "максимальный выигрыш"
|
|
97
|
+
},
|
|
98
|
+
"th": {
|
|
99
|
+
"freeSpins": "ฟรีสปิน {i} จาก {n}",
|
|
100
|
+
"tapToSkip": "แตะเพื่อข้าม",
|
|
101
|
+
"freeOver": "ฟรีสปินจบแล้ว",
|
|
102
|
+
"maxWin": "รางวัลสูงสุด"
|
|
103
|
+
},
|
|
104
|
+
"tr": {
|
|
105
|
+
"freeSpins": "Bedava dönüş {i}/{n}",
|
|
106
|
+
"tapToSkip": "geçmek için dokun",
|
|
107
|
+
"freeOver": "Bedava dönüşler bitti",
|
|
108
|
+
"maxWin": "maksimum kazanç"
|
|
109
|
+
},
|
|
110
|
+
"vi": {
|
|
111
|
+
"freeSpins": "Lượt quay miễn phí {i}/{n}",
|
|
112
|
+
"tapToSkip": "chạm để bỏ qua",
|
|
113
|
+
"freeOver": "Hết lượt quay miễn phí",
|
|
114
|
+
"maxWin": "thắng tối đa"
|
|
115
|
+
},
|
|
116
|
+
"zh": {
|
|
117
|
+
"freeSpins": "免费旋转 {i}/{n}",
|
|
118
|
+
"tapToSkip": "点击跳过",
|
|
119
|
+
"freeOver": "免费旋转结束",
|
|
120
|
+
"maxWin": "最高奖金"
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
|
6
|
+
<title>Tumble</title>
|
|
7
|
+
<link rel="stylesheet" href="./game.css">
|
|
8
|
+
<script type="module" src="/engine-sdk/bet-field.js"></script>
|
|
9
|
+
<script type="module" src="./game.js"></script>
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<hb-game id="game">
|
|
13
|
+
<div slot="zone" class="tumble">
|
|
14
|
+
<div class="banner" id="banner" aria-live="polite"></div>
|
|
15
|
+
<div class="grid" id="grid"></div>
|
|
16
|
+
<div class="win" id="win" aria-live="polite"></div>
|
|
17
|
+
</div>
|
|
18
|
+
</hb-game>
|
|
19
|
+
</body>
|
|
20
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"cols":6,"rows":5,"weights":{"e":16,"d":15,"c":14,"b":13,"a":12,"B":9,"G":8,"P":7,"R":6,"S":3},"freeWeights":{"e":16,"d":15,"c":14,"b":13,"a":12,"B":9,"G":8,"P":7,"R":6,"S":3,"M":3},"pays":{"R":[[8,250000],[10,600000],[12,1200000]],"P":[[8,60000],[10,250000],[12,600000]],"G":[[8,50000],[10,120000],[12,400000]],"B":[[8,40000],[10,50000],[12,300000]],"a":[[8,25000],[10,40000],[12,250000]],"b":[[8,20000],[10,30000],[12,200000]],"c":[[8,12000],[10,25000],[12,120000]],"d":[[8,10000],[10,22000],[12,100000]],"e":[[8,6000],[10,18000],[12,50000]]},"scatter":{"symbol":"S","pays":{"4":30000,"5":50000,"6":1000000},"spins":{"4":10,"5":10,"6":10},"retrigger":{"count":3,"spins":5},"cap":30},"bomb":{"symbol":"M","values":[[2,40],[3,25],[4,15],[5,10],[10,6],[25,3],[50,1],[100,0.5]]},"maxWinBp":50000000}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The tumble slot's maths: a 6 × 5 grid that pays 8 or more of a symbol
|
|
3
|
+
// anywhere; winners vanish and new symbols drop in until nothing pays. Four
|
|
4
|
+
// scatters start ten free spins where multiplier symbols (2× to 100×) add up
|
|
5
|
+
// and multiply each winning spin; three scatters in free spins add five.
|
|
6
|
+
// 5,000× cap. Played into whole-round rows and fitted to exactly 96.00%;
|
|
7
|
+
// the model goes to the bundle too.
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { fit, rng, writePack } from '../math-kit/pack.mjs';
|
|
12
|
+
import { books } from '../math-kit/slot.mjs';
|
|
13
|
+
import { tumble } from '../math-kit/tumble.mjs';
|
|
14
|
+
|
|
15
|
+
const DIR = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const project = join(DIR, '..', 'hbengine.json');
|
|
17
|
+
const GAME = process.argv[2] || (existsSync(project) ? JSON.parse(readFileSync(project, 'utf8')).slug : 'tumble');
|
|
18
|
+
const RTP = 9600, ROUNDS = Number(process.env.ROUNDS || 300_000), SEED = 20261015;
|
|
19
|
+
|
|
20
|
+
const weights = { e: 16, d: 15, c: 14, b: 13, a: 12, B: 9, G: 8, P: 7, R: 6, S: 3 };
|
|
21
|
+
const model = {
|
|
22
|
+
cols: 6, rows: 5, weights, freeWeights: { ...weights, M: 3 },
|
|
23
|
+
// × the stake for 8–9, 10–11, 12 or more anywhere (basis points below)
|
|
24
|
+
pays: Object.fromEntries(Object.entries({
|
|
25
|
+
R: [25, 60, 120], P: [6, 25, 60], G: [5, 12, 40], B: [4, 5, 30],
|
|
26
|
+
a: [2.5, 4, 25], b: [2, 3, 20], c: [1.2, 2.5, 12], d: [1, 2.2, 10], e: [0.6, 1.8, 5],
|
|
27
|
+
}).map(([s, [x, y, z]]) => [s, [[8, x * 10000], [10, y * 10000], [12, z * 10000]]])),
|
|
28
|
+
scatter: { symbol: 'S', pays: { 4: 30000, 5: 50000, 6: 1000000 }, spins: { 4: 10, 5: 10, 6: 10 }, retrigger: { count: 3, spins: 5 }, cap: 30 },
|
|
29
|
+
bomb: { symbol: 'M', values: [[2, 40], [3, 25], [4, 15], [5, 10], [10, 6], [25, 3], [50, 1], [100, 0.5]] },
|
|
30
|
+
maxWinBp: 50_000_000,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const rows = books(tumble(model), rng(SEED), ROUNDS);
|
|
34
|
+
const raw = rows.reduce((a, r) => [a[0] + r.weight * BigInt(r.pay.spin), a[1] + r.weight], [0n, 0n]);
|
|
35
|
+
const hits = rows.reduce((a, r) => a + (r.pay.spin > 0 ? r.weight : 0n), 0n);
|
|
36
|
+
console.log(`played ${ROUNDS}: before the fit RTP ${(Number(raw[0] * 1000000n / raw[1]) / 1e6 / 100).toFixed(2)}%, hit rate ${(Number(hits * 10000n / BigInt(ROUNDS)) / 100).toFixed(2)}%`);
|
|
37
|
+
writePack(DIR, { game: GAME, rtpBp: RTP, modes: [{ id: 'base', label: 'Spin', rows: fit(rows, RTP), bets: [{ id: 'spin', label: 'Spin' }] }] });
|
|
38
|
+
writeFileSync(join(DIR, '..', 'bundle', 'model.json'), JSON.stringify(model) + '\n');
|