From dc45ad45c9f23a948ba9156d8c861d4beb763db1 Mon Sep 17 00:00:00 2001 From: mike Date: Fri, 23 Jan 2026 01:55:12 +0100 Subject: [PATCH] redo --- package-lock.json | 428 ------------------ package.json | 13 - src/main/java/puzzle/Export.java | 36 +- src/main/java/puzzle/Main.java | 11 +- src/main/java/puzzle/Mask.java | 12 + src/main/java/puzzle/Masker.java | 17 +- src/main/java/puzzle/SwedishGenerator.java | 193 +++----- .../java/puzzle/DictJavaGeneratorMulti.java | 10 +- src/test/java/puzzle/MainTest.java | 10 +- src/test/java/puzzle/MarkerTest.java | 9 +- src/test/java/puzzle/PerformanceTest.java | 13 +- .../java/puzzle/SwedishGeneratorTest.java | 181 +++----- tools.iml | 8 - 13 files changed, 210 insertions(+), 731 deletions(-) delete mode 100644 package-lock.json delete mode 100644 package.json create mode 100644 src/main/java/puzzle/Mask.java delete mode 100644 tools.iml diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index e3ee4bf..0000000 --- a/package-lock.json +++ /dev/null @@ -1,428 +0,0 @@ -{ - "name": "puzzle-generator", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "puzzle-generator", - "version": "1.0.0", - "dependencies": { - "better-sqlite3": "^12.5.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/better-sqlite3": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.5.0.tgz", - "integrity": "sha512-WwCZ/5Diz7rsF29o27o0Gcc1Du+l7Zsv7SYtVPG0X3G/uUI1LqdxrQI7c9Hs2FWpqXXERjW9hp6g3/tH7DlVKg==", - "hasInstallScript": true, - "dependencies": { - "bindings": "^1.5.0", - "prebuild-install": "^7.1.1" - }, - "engines": { - "node": "20.x || 22.x || 23.x || 24.x || 25.x" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" - }, - "node_modules/napi-build-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==" - }, - "node_modules/node-abi": { - "version": "3.85.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.85.0.tgz", - "integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "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" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - } - } -} diff --git a/package.json b/package.json deleted file mode 100644 index edf2f03..0000000 --- a/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "puzzle-generator", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "private": true, - "dependencies": { - "better-sqlite3": "^12.5.0" - } -} diff --git a/src/main/java/puzzle/Export.java b/src/main/java/puzzle/Export.java index 1757f6c..15bbc22 100644 --- a/src/main/java/puzzle/Export.java +++ b/src/main/java/puzzle/Export.java @@ -12,6 +12,8 @@ import puzzle.SwedishGenerator.Dict; import puzzle.SwedishGenerator.FillResult; import puzzle.SwedishGenerator.Grid; import puzzle.SwedishGenerator.Slotinfo; +import static precomp.Const9x8.CLUE_DOWN0; +import static precomp.Const9x8.CLUE_RIGHT1; import static precomp.Const9x8.INIT_GRID_OUTPUT; import static precomp.Const9x8.INIT_GRID_OUTPUT_ARR; import static puzzle.Export.Clue.DOWN0; @@ -34,8 +36,6 @@ import static puzzle.SwedishGenerator.X; public record Export() { public static final ThreadLocal BYTES = ThreadLocal.withInitial(() -> new byte[8]); - static final byte CLUE_DOWN = 0; - static final byte CLUE_RIGHT = 1; static final byte CLUE_UP = 2; static final byte CLUE_LEFT = 3; static final byte CLUE_LEFT_TOP = 4; @@ -48,8 +48,8 @@ public record Export() { static int INDEX(int r, int cols, int c) { return r * cols + c; } @AllArgsConstructor enum Clue { - DOWN0(CLUE_DOWN, 'B', 'b'), - RIGHT1(CLUE_RIGHT, 'A', 'a'), + DOWN0(CLUE_DOWN0, 'B', 'b'), + RIGHT1(CLUE_RIGHT1, 'A', 'a'), UP2(CLUE_UP, 'C', 'c'), LEFT3(CLUE_LEFT, 'D', 'd'), LEFT_TOP4(CLUE_LEFT_TOP, 'E', 'e'), @@ -89,8 +89,8 @@ public record Export() { for (var l = c.lo & c.xlo & ~c.rlo & ~c.vlo; l != X; l &= l - 1) stream.accept(new Vestigium(Long.numberOfTrailingZeros(l), CLUE_LEFT_TOP)); for (var l = c.lo & c.xlo & ~c.rlo & c.vlo; l != X; l &= l - 1) stream.accept(new Vestigium(Long.numberOfTrailingZeros(l), CLUE_RIGHT_TOP)); - for (var h = c.hi & ~c.xhi & ~c.rhi & c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(HI(Long.numberOfTrailingZeros(h)), CLUE_RIGHT)); - for (var h = c.hi & ~c.xhi & ~c.rhi & ~c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(HI(Long.numberOfTrailingZeros(h)), CLUE_DOWN)); + for (var h = c.hi & ~c.xhi & ~c.rhi & c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(HI(Long.numberOfTrailingZeros(h)), CLUE_RIGHT1)); + for (var h = c.hi & ~c.xhi & ~c.rhi & ~c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(HI(Long.numberOfTrailingZeros(h)), CLUE_DOWN0)); for (var h = c.hi & ~c.xhi & c.rhi & ~c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(HI(Long.numberOfTrailingZeros(h)), CLUE_UP)); for (var h = c.hi & ~c.xhi & c.rhi & c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(HI(Long.numberOfTrailingZeros(h)), CLUE_LEFT)); for (var h = c.hi & c.xhi & ~c.rhi & ~c.vhi; h != X; h &= h - 1) stream.accept(new Vestigium(HI(Long.numberOfTrailingZeros(h)), CLUE_LEFT_TOP)); @@ -99,7 +99,7 @@ public record Export() { return stream.build(); } public Slotinfo[] slots(Dict D) { - return Masker.slots(c, D.index()); + return Masker.slots(c, D.index(), D.reversed()); } } @@ -214,20 +214,32 @@ public record Export() { public record WordOut(String word, int[] cell, int startRow, int startCol, char direction, int arrowRow, int arrowCol, boolean isReversed, int complex, String[] clue) { - private static ShardLem lookup(long w, byte[] bytes) { + record ShaLemma(String word, @Delegate ShardLem rec) { } + private static ShaLemma lookup(long w, byte[] bytes) { try { val rec = Meta.lookupSilent(w); System.out.println("\nQuery: w=" + w + " -> i=" + rec.mmap()); - System.out.println(" word=" + Lemma.asWord(w, bytes) + "\n" + " simpel=" + rec.simpel() + "\n" + " clues=" + Arrays.toString(rec.clues())); - return rec; + var word1 = Lemma.asWord(w, bytes); + System.out.println(" word=" + word1 + "\n" + " simpel=" + rec.simpel() + "\n" + " clues=" + Arrays.toString(rec.clues())); + return new ShaLemma(word1, rec); } catch (Exception e) { throw new RuntimeException(e); } } + static long reverse(long w) { + int L = Lemma.unpackSize(w) + 1; + long letters = w & Lemma.LETTER_MASK; + long rev = 0; + for (int i = 0; i < L; i++) { + long letter = (letters >>> (5 * i)) & 31; + rev |= (letter << (5 * (L - 1 - i))); + } + return (w & ~Lemma.LETTER_MASK) | rev; + } public WordOut(long l, int startRow, int startCol, char d, int arrowRow, int arrowCol, boolean isReversed, byte[] bytes) { - val meta = lookup(l, bytes); - this(Lemma.asWord(l, bytes), new int[]{ arrowRow, arrowCol, startRow, startCol }, startRow, startCol, d, arrowRow, arrowCol, isReversed, + val meta = lookup(isReversed ? reverse(l) : l, bytes); + this(meta.word, new int[]{ arrowRow, arrowCol, startRow, startCol }, startRow, startCol, d, arrowRow, arrowCol, isReversed, meta.simpel(), meta.clues()); } } diff --git a/src/main/java/puzzle/Main.java b/src/main/java/puzzle/Main.java index 69e209b..a86708e 100644 --- a/src/main/java/puzzle/Main.java +++ b/src/main/java/puzzle/Main.java @@ -59,7 +59,6 @@ public class Main { void main(String[] args) { _main(args); } - @SneakyThrows public void _main(String[] args) { var opts = parseArgs(args); @@ -254,9 +253,9 @@ public class Main { // Package-private method for testing PuzzleResult generatePuzzle(Opts opts) { - var tLoad0 = System.nanoTime(); + var tLoad0 = System.nanoTime(); Dict dict = puzzle.dict800.DictData800.DICT800;//loadDict(opts.wordsPath); - var tLoad1 = System.nanoTime(); + var tLoad1 = System.nanoTime(); section("Load"); info(String.format(Locale.ROOT, "words : %,d", dict.length())); @@ -370,9 +369,9 @@ public class Main { //val mask = generateClues(); if (mask == null) return null; - val slotInfo = Masker.slots(mask, dict.index()); + val slotInfo = Masker.slots(mask, dict.index(), dict.reversed()); var grid = Slotinfo.grid(slotInfo);// mask.toGrid(); - var filled = fillMask(rng, slotInfo, grid); + var filled = fillMask(rng, slotInfo, grid.lo, grid.hi, grid.g); if (!multiThreaded) { System.out.print("\r" + " ".repeat(120 - "".length()) + "\r"); @@ -405,6 +404,8 @@ public class Main { //System.out.println(Arrays.stream(new Clued(mask).gridToString().split("\n")).map(s -> "\"" + s + "\\n\" +").collect(Collectors.joining("\n"))); } if (filled.ok()) { + grid.lo = ~mask.lo; + grid.hi = 0xFFL & ~mask.hi; return new PuzzleResult(new Signa(mask), new Puzzle(grid, mask), slotInfo, filled); } diff --git a/src/main/java/puzzle/Mask.java b/src/main/java/puzzle/Mask.java new file mode 100644 index 0000000..332b721 --- /dev/null +++ b/src/main/java/puzzle/Mask.java @@ -0,0 +1,12 @@ +package puzzle; + +public interface Mask { + + record Masker(long lo, long hi) + implements Mask { } + default Mask or(Mask o) { return new Masker(o.lo() | lo(), o.hi() | hi()); } + default Mask and(Mask o) { return new Masker(o.lo() & lo(), o.hi() & hi()); } + + long hi(); + long lo(); +} \ No newline at end of file diff --git a/src/main/java/puzzle/Masker.java b/src/main/java/puzzle/Masker.java index 875e84c..e771946 100644 --- a/src/main/java/puzzle/Masker.java +++ b/src/main/java/puzzle/Masker.java @@ -1,8 +1,6 @@ package puzzle; import module java.base; -import anno.GenerateNeighbor; -import anno.GenerateNeighbors; import anno.Shaped; import lombok.AllArgsConstructor; import lombok.Getter; @@ -24,6 +22,7 @@ public final class Masker { @Shaped public static final int MIN_LEN = Neighbors9x8.MIN_LEN;//Config.MIN_LEN; @Shaped public static final int C = Neighbors9x8.C; @Shaped public static final int R = Neighbors9x8.R; + @Shaped public static final int SIZE = Neighbors9x8.SIZE; @Shaped public static final double SIZED = Neighbors9x8.SIZED;// ~18 @Shaped private static final long[] NBR_LO = Neighbors9x8.NBR_LO; @Shaped private static final long[] NBR_HI = Neighbors9x8.NBR_HI; @@ -43,6 +42,7 @@ public final class Masker { this.stack = stack; this.cache = cache; } + public static boolean isLo(int n) { return (n & 64) == 0; } public boolean isValid(Clues c) { return findOffendingClue(c) == -1; @@ -172,17 +172,18 @@ public final class Masker { if (Long.bitCount(rayLo) + Long.bitCount(rayHi) >= MIN_LEN) visitor.visit(key, rayLo, rayHi); } - public static Slot[] extractSlots(Clues c, DictEntry[] index) { + public static Slot[] extractSlots(Clues c, DictEntry[] index, DictEntry[] rev) { var slots = new ArrayList(c.clueCount()); - c.forEachSlot((key, lo, hi) -> slots.add(Slot.from(key, lo, hi, index[Slot.length(lo, hi)]))); + c.forEachSlot((key, lo, hi) -> slots.add(Slot.from(key, lo, hi, Slotinfo.increasing(key) ? index[Slot.length(lo, hi)] : rev[Slot.length(lo, hi)]))); return slots.toArray(Slot[]::new); } - public static Slotinfo[] slots(Clues mask, DictEntry[] index) { - var slots = Masker.extractSlots(mask, index); + public static Slotinfo[] slots(Clues mask, Dict d) { return slots(mask, d.index(), d.reversed()); } + public static Slotinfo[] slots(Clues mask, DictEntry[] index, DictEntry[] rev) { + var slots = Masker.extractSlots(mask, index, rev); return Masker.scoreSlots(slots); } public static Slotinfo[] scoreSlots(Slot[] slots) { - val count = new byte[SwedishGenerator.SIZE]; + val count = new byte[SIZE]; var slotInfo = new Slotinfo[slots.length]; for (var s : slots) { for (var b = s.lo; b != X; b &= b - 1) count[numberOfTrailingZeros(b)]++; @@ -714,7 +715,7 @@ public final class Masker { return (bitCount(matchLo & MASK_LO) + bitCount(matchHi & MASK_HI)) / SIZED; } - public Grid toGrid() { return new Grid(new byte[SwedishGenerator.SIZE], lo, hi); } + public Grid toGrid() { return new Grid(new byte[SIZE], lo, hi); } public void forEachSlot(SlotVisitor visitor) { for (var l = lo & ~xlo & ~rlo & vlo; l != X; l &= l - 1) processSlot(this, visitor, Slot.packSlotKey(numberOfTrailingZeros(l), 1)); diff --git a/src/main/java/puzzle/SwedishGenerator.java b/src/main/java/puzzle/SwedishGenerator.java index ec763dd..1a628fa 100644 --- a/src/main/java/puzzle/SwedishGenerator.java +++ b/src/main/java/puzzle/SwedishGenerator.java @@ -3,6 +3,8 @@ package puzzle; import anno.ConstGen; import anno.GenerateNeighbor; import anno.GenerateNeighbors; +import anno.GenerateShapedCopies; +import anno.Shaped; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.val; @@ -33,21 +35,21 @@ import static java.nio.charset.StandardCharsets.US_ASCII; @GenerateNeighbor(C = 9, R = 8, packageName = "precomp", className = "Neighbors9x8", MIN_LEN = 2), @GenerateNeighbor(C = 4, R = 3, packageName = "precomp", className = "Neighbors4x3", MIN_LEN = 2) }) + /*@GenerateShapedCopies( + className = "SwedishGeneratorX", shapes = { "precomp.Neighbors9x8", "precomp.Neighbors4x3" } )*/ public record SwedishGenerator() { - public static final long X = 0L; - public static final int SIZE = Neighbors9x8.SIZE; - public static final int MAX_TRIES_PER_SLOT = 500;// MAX_TRIES_PER_SLOT; - public static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE; - public static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624; + public static final int MAX_TRIES_PER_SLOT = 500;// MAX_TRIES_PER_SLOT; + public static final long X = 0L; + @Shaped private static final int SIZE = Neighbors9x8.SIZE; + @Shaped private static final long RANGE_0_SIZE = Neighbors9x8.RANGE_0_SIZE; + @Shaped private static final long RANGE_0_624 = Neighbors9x8.RANGE_0_624; - public static boolean isLo(int n) { return (n & 64) == 0; } interface Bit1029 { - static long[] bit1029() { return new long[2048]; } private static int wordIndex(int bitIndex) { return bitIndex >> 6; } static boolean get(long[] bits, int bitIndex) { return (bits[wordIndex(bitIndex)] & 1L << bitIndex) != X; } static void set(long[] bits, int bitIndex) { bits[wordIndex(bitIndex)] |= 1L << bitIndex; } @@ -55,12 +57,11 @@ public record SwedishGenerator() { } //@formatter:off - public record Dict(DictEntry[] index, int length) { } + public record Dict(DictEntry[] index,DictEntry[] reversed, int length) { public Dict(DictEntry[] index,int length){this(index,index,length);} } public record DictEntry(long[] words, long[][] posBitsets, int length, int numlong) { } @AllArgsConstructor @NoArgsConstructor static final class Assign { long w; } - public static final class FillStats { public double simplicity; } @AllArgsConstructor public static final class Grid { public final byte[] g; public long lo, hi; } - public record FillResult(boolean ok, long nodes, long backtracks, int lastMRV, long elapsed, FillStats stats) { } + public record FillResult(boolean ok, long nodes, long backtracks, int lastMRV, long elapsed ) { } //@formatter:on public static final class Rng { @@ -98,15 +99,15 @@ public record SwedishGenerator() { static long pack(long w, int shardIndex) { return w | (((long) shardIndex) << 43) | ((long) length0(w)) << 40; } static long packShiftIn(byte[] b) { long w = 0; - for (int i = b.length - 1; i >= 0; i--) w = (w << 5) | ((long) b[i] & 31); + for (var i = b.length - 1; i >= 0; i--) w = (w << 5) | ((long) b[i] & 31); return w; } static long from(String word) { return packShiftIn(word.getBytes(US_ASCII)) | ((long) (word.length() - 1) << 40); } static byte byteAt(long word, int idx) { return (byte) ((word >>> (idx * 5)) & 0b11111L); } static int length0(long word) { return ((63 - numberOfLeadingZeros(word & LETTER_MASK)) / 5); } static String asWord(long word, byte[] bytes) { - int bi = 0; - for (long w = word & LETTER_MASK; w != 0; w >>>= 5) bytes[bi++] = (byte) ((w & 31) | 64); + var bi = 0; + for (var w = word & LETTER_MASK; w != 0; w >>>= 5) bytes[bi++] = (byte) ((w & 31) | 64); return new String(bytes, 0, bi, US_ASCII); } static int unpackIndex(long w) { return (int) (w >>> 40); } @@ -132,70 +133,45 @@ public record SwedishGenerator() { } } - public static long patternForSlot(final long glo, final long ghi, final byte[] g, final int key, final long lo, final long hi) { - if (((lo & glo) | (hi & ghi)) == X) return X; + public static long patternForSlot(final long glo, final long ghi, final byte[] g, final long lo, final long hi) { + if (((lo & glo) == X) && (hi & ghi) == X) return X; long p = 0; int n = 0, offset, idx; - if (Slotinfo.increasing(key)) { - for (long b = lo & glo; b != X; b &= b - 1) { - idx = numberOfTrailingZeros(b); - p |= ((long) (bitCount(lo & ((1L << idx) - 1)) * 26 + g[idx])) << (n++ << 3); - } - offset = bitCount(lo); - for (long b = hi & ghi; b != X; b &= b - 1) { - idx = numberOfTrailingZeros(b); - p |= ((long) ((offset + bitCount(hi & ((1L << idx) - 1))) * 26 + g[64 | idx])) << (n++ << 3); - } - } else { - offset = bitCount(hi); - for (long b = hi & ghi; b != X; b &= b - 1) { - idx = numberOfTrailingZeros(b); - p |= ((long) (bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))) * 26 + g[64 | idx])) << (n++ << 3); - } - for (long b = lo & glo; b != X; b &= b - 1) { - idx = numberOfTrailingZeros(b); - p |= ((long) ((offset + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)))) * 26 + g[idx])) << (n++ << 3); - } + for (var b = lo & glo; b != X; b &= b - 1) { + idx = numberOfTrailingZeros(b); + p |= ((long) (bitCount(lo & ((1L << idx) - 1)) * 26 + g[idx])) << (n++ << 3); + } + offset = bitCount(lo); + for (var b = hi & ghi; b != X; b &= b - 1) { + idx = numberOfTrailingZeros(b); + p |= ((long) ((offset + bitCount(hi & ((1L << idx) - 1))) * 26 + g[64 | idx])) << (n++ << 3); } return p; } /// pattern cannot be X public static int[] candidateInfoForPattern(long[] res, long pattern, long[][] posBitsets, int numLongs) { - System.arraycopy(posBitsets[(int) (pattern & 0xFF) - 1], 0, res, 0, numLongs); - for (long p = pattern >>> 8; p != X; p >>>= 8) { - long[] bs = posBitsets[(int) (p & 0xFF) - 1]; - for (int k = 0; k < numLongs; k++) res[k] &= bs[k]; - } - - int count = 0; - for (int k = 0; k < numLongs; k++) count += bitCount(res[k]); - - int[] indices = new int[count]; - for (int k = 0, ki = 0; k < numLongs; k++) { - for (long w = res[k]; w != X; w &= w - 1) indices[ki++] = (k << 6) | numberOfTrailingZeros(w); - } - + var indices = new int[candidateCountForPattern(res, pattern, posBitsets, numLongs)]; + for (int k = 0, ki = 0; k < numLongs; k++) for (var w = res[k]; w != X; w &= w - 1) indices[ki++] = (k << 6) | numberOfTrailingZeros(w); return indices; } /// pattern cannot be X - public static int candidateCountForPattern(final long[] res, final long pattern, final long[][] posBitsets, final int numLongs) { - System.arraycopy(posBitsets[(int) (pattern & 0xFF) - 1], 0, res, 0, numLongs); - for (long p = pattern >>> 8; p != X; p >>>= 8) { - long[] bs = posBitsets[(int) (p & 0xFF) - 1]; - for (int k = 0; k < numLongs; k++) res[k] &= bs[k]; + public static int candidateCountForPattern(final long[] res, final long pattern, final long[][] pos, final int num) { + System.arraycopy(pos[(int) (pattern & 0xFF) - 1], 0, res, 0, num); + for (var p = pattern >>> 8; p != X; p >>>= 8) { + var bs = pos[(int) (p & 0xFF) - 1]; + for (var k = 0; k < num; k++) res[k] &= bs[k]; } - int count = 0; - for (int k = 0; k < numLongs; k++) count += bitCount(res[k]); + var count = 0; + for (var k = 0; k < num; k++) count += bitCount(res[k]); return count; } public static FillResult fillMask(final Rng rng, final Slotinfo[] slots, - final Grid grid) { + final long lo, final long hi, final byte[] g) { val used = new long[2048]; val bitset = new long[2500]; - val g = grid.g; val TOTAL = slots.length; val t0 = System.currentTimeMillis(); class Solver { @@ -203,82 +179,64 @@ public record SwedishGenerator() { static final int PICK_NOT_DONE = -1; static final int PICK_DONE = 0; long nodes; - long backtracks; - long glo = grid.lo, ghi = grid.hi; - Slotinfo currentSlot; - int[] currentIndices; - boolean placeWordDec(final long lo, final long hi, final long w) { + long tracks; + long glo = lo, ghi = hi; + Slotinfo slot; + int[] indices; + boolean place(final long lo, final long hi, final long w) { int idx; - int bcHi = bitCount(hi); - for (long b = hi & ghi; b != X; b &= b - 1) - if (g[64 | (idx = numberOfTrailingZeros(b))] != Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1))))) return false; - for (long b = lo & glo; b != X; b &= b - 1) - if (g[idx = numberOfTrailingZeros(b)] != Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1))))) return false; + for (var b = lo & glo; b != X; b &= b - 1) if (g[idx = numberOfTrailingZeros(b)] != Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)))) return true; + var bcLo = bitCount(lo); + for (var b = hi & ghi; b != X; b &= b - 1) if (g[64 | (idx = numberOfTrailingZeros(b))] != Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)))) return true; long maskLo = lo & ~glo, maskHi = hi & ~ghi; if ((maskLo | maskHi) != X) { - for (long b = maskHi; b != X; b &= b - 1) g[64 | (idx = numberOfTrailingZeros(b))] = Lemma.byteAt(w, bitCount(hi & ~((1L << idx) | ((1L << idx) - 1)))); - for (long b = maskLo; b != X; b &= b - 1) g[idx = numberOfTrailingZeros(b)] = Lemma.byteAt(w, bcHi + bitCount(lo & ~((1L << idx) | ((1L << idx) - 1)))); + for (var b = maskLo; b != X; b &= b - 1) g[idx = numberOfTrailingZeros(b)] = Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1))); + for (var b = maskHi; b != X; b &= b - 1) g[64 | (idx = numberOfTrailingZeros(b))] = Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1))); glo |= maskLo; ghi |= maskHi; } - return true; - } - boolean placeWordInc(final long lo, final long hi, final long w) { - int idx; - for (long b = lo & glo; b != X; b &= b - 1) if (g[idx = numberOfTrailingZeros(b)] != Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1)))) return false; - int bcLo = bitCount(lo); - for (long b = hi & ghi; b != X; b &= b - 1) if (g[64 | (idx = numberOfTrailingZeros(b))] != Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1)))) return false; - - long maskLo = lo & ~glo, maskHi = hi & ~ghi; - if ((maskLo | maskHi) != X) { - for (long b = maskLo; b != X; b &= b - 1) g[idx = idx = numberOfTrailingZeros(b)] = Lemma.byteAt(w, bitCount(lo & ((1L << idx) - 1))); - for (long b = maskHi; b != X; b &= b - 1) g[64 | (idx = numberOfTrailingZeros(b))] = Lemma.byteAt(w, bcLo + bitCount(hi & ((1L << idx) - 1))); - glo |= maskLo; - ghi |= maskHi; - } - return true; + return false; } int chooseMRV() { - Slotinfo best = null; - int count2 = -1, bestScore = -1; + Slotinfo best = null; + int max = -1, bestScore = -1; for (int i = 0, n = TOTAL; i < n; i++) { var s = slots[i]; if (s.assign.w != X) continue; - var pattern = patternForSlot(glo, ghi, g, s.key, s.lo, s.hi); + var pattern = patternForSlot(glo, ghi, g, s.lo, s.hi); var index = s.entry; - int count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong); + var count = pattern == X ? index.length : candidateCountForPattern(bitset, pattern, index.posBitsets, index.numlong); if (count == 0) return PICK_NOT_DONE; if (best == null - || count < count2 - || (count == count2 && s.score > bestScore)) { + || count < max + || (count == max && s.score > bestScore)) { best = s; bestScore = s.score; - count2 = count; + max = count; if (count <= 1) break; } } if (best == null) return PICK_DONE; - var pattern = patternForSlot(glo, ghi, g, best.key, best.lo, best.hi); - currentSlot = best; + var pattern = patternForSlot(glo, ghi, g, best.lo, best.hi); + slot = best; var index = best.entry; - currentIndices = pattern == X ? null : candidateInfoForPattern(bitset, pattern, index.posBitsets, index.numlong); + indices = pattern == X ? null : candidateInfoForPattern(bitset, pattern, index.posBitsets, index.numlong); return 1; } boolean backtrack(int depth) { if (Thread.currentThread().isInterrupted() || (System.currentTimeMillis() - t0) > 20_000) return false; nodes++; - int status = chooseMRV(); + var status = chooseMRV(); if (status == PICK_DONE) return true; if (status == PICK_NOT_DONE) { - backtracks++; + tracks++; return false; } - val info = currentIndices; - val s = currentSlot; - val inc = Slotinfo.increasing(s.key); + val info = indices; + val s = slot; val slo = s.lo; val shi = s.hi; val assign = s.assign; @@ -294,11 +252,7 @@ public record SwedishGenerator() { if (Bit1029.get(used, lemIdx)) continue; low = glo; top = ghi; - if (inc) { - if (!placeWordInc(slo, shi, w)) continue; - } else { - if (!placeWordDec(slo, shi, w)) continue; - } + if (place(slo, shi, w)) continue; Bit1029.set(used, lemIdx); assign.w = w; @@ -308,45 +262,36 @@ public record SwedishGenerator() { glo = low; ghi = top; } - backtracks++; + tracks++; return false; } var N = words.length; for (var t = 0; t < s.minL; t++) { - var w = words[rng.biasedIndexPow3(N - 1)]; - var lemIdx = Lemma.unpackIndex(w); - if (Bit1029.get(used, lemIdx)) continue; + var w = words[rng.biasedIndexPow3(N - 1)]; + var lem = Lemma.unpackIndex(w); + if (Bit1029.get(used, lem)) continue; low = glo; top = ghi; - if (inc) { - if (!placeWordInc(slo, shi, w)) continue; - } else { - if (!placeWordDec(slo, shi, w)) continue; - } + if (place(slo, shi, w)) continue; - Bit1029.set(used, lemIdx); + Bit1029.set(used, lem); assign.w = w; if (backtrack(depth + 1)) return true; assign.w = X; - Bit1029.clear(used, lemIdx); + Bit1029.clear(used, lem); glo = low; ghi = top; } - backtracks++; + tracks++; return false; } } - var solver = new Solver(); var ok = solver.backtrack(0); - grid.lo = solver.glo; - grid.hi = solver.ghi; - - return new FillResult(ok, solver.nodes, solver.backtracks, solver.currentSlot == null ? 0 : solver.currentSlot.entry.length, System.currentTimeMillis() - t0, - new FillStats()); + return new FillResult(ok, solver.nodes, solver.tracks, solver.slot == null ? 0 : solver.slot.entry.length, System.currentTimeMillis() - t0); } } diff --git a/src/test/java/puzzle/DictJavaGeneratorMulti.java b/src/test/java/puzzle/DictJavaGeneratorMulti.java index 6e12a70..8e54dce 100644 --- a/src/test/java/puzzle/DictJavaGeneratorMulti.java +++ b/src/test/java/puzzle/DictJavaGeneratorMulti.java @@ -5,15 +5,22 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import lombok.val; +import org.junit.jupiter.api.Test; import precomp.Neighbors9x8; import puzzle.SwedishGenerator.Dict; import puzzle.SwedishGenerator.DictEntry; import puzzle.SwedishGenerator.Lemma; +import puzzle.dict950.DictData950; import static java.nio.charset.StandardCharsets.US_ASCII; public final class DictJavaGeneratorMulti { - + @Test + void testReversed() { + val wOrig = DictData950.DICT950.index()[4].words()[4]; + val wRev = DictData950.DICT950.reversed()[4].words()[4]; + System.out.println(Lemma.asWord(wOrig, new byte[8]) + " " + Lemma.asWord(wRev, new byte[8])); + } interface Dicts { static Dict makeDict(long[] wordz) { @@ -52,7 +59,6 @@ public final class DictJavaGeneratorMulti { } } - record DictEntryDTO(LongArrayList words, IntListDTO[][] pos) { public DictEntryDTO(int L) { diff --git a/src/test/java/puzzle/MainTest.java b/src/test/java/puzzle/MainTest.java index 725297a..52cec3c 100644 --- a/src/test/java/puzzle/MainTest.java +++ b/src/test/java/puzzle/MainTest.java @@ -27,8 +27,6 @@ import static puzzle.LemmaData.AZ; import static puzzle.SwedishGenerator.Lemma; import static puzzle.SwedishGenerator.Slotinfo; import static puzzle.SwedishGenerator.fillMask; -import static puzzle.SwedishGeneratorTest.LETTER_A; -import static puzzle.SwedishGeneratorTest.LETTER_Z; @DictGen( packageName = "puzzle.dict950", className = "DictData950", @@ -101,7 +99,7 @@ public class MainTest { public void testGridBasics() { var clues = Signa.of(r2c1d2); var grid = new Puzzle(clues); - + r1c1.or(r0c1).lo(); // Test set/get GridBuilder.placeWord(grid.grid(), grid.grid().g, r2c1d2.slotKey, (1L << OFF_1_1) | (1L << OFF_0_1), 0, AZ); val map = grid.collect(Collectors.toMap(Lettrix::index, Lettrix::letter)); @@ -183,12 +181,12 @@ public class MainTest { ); var slotInfo = mask.slots(DictData950.DICT950); var grid = Slotinfo.grid(slotInfo); - var filled = fillMask(rng, slotInfo, grid); + var filled = fillMask(rng, slotInfo, grid.lo,grid.hi, grid.g); Assertions.assertTrue(filled.ok(), "Puzzle generation failed (not ok)"); Assertions.assertEquals(17, Slotinfo.wordCount(0, slotInfo), "Number of assigned words changed"); Assertions.assertEquals("BEADEMT", Lemma.asWord(slotInfo[0].assign().w, Export.BYTES.get())); - Assertions.assertEquals(-1L, grid.lo); - Assertions.assertEquals(-1L, grid.hi); + Assertions.assertEquals(74732156493031040L, grid.lo); + Assertions.assertEquals(-63L, grid.hi); var g = new Puzzle(grid, mask.c()); g.gridToString(); var aa = new PuzzleResult(mask, g, slotInfo, filled).exportFormatFromFilled(new Rewards(1, 1, 1)); diff --git a/src/test/java/puzzle/MarkerTest.java b/src/test/java/puzzle/MarkerTest.java index fab0cb6..0928be6 100644 --- a/src/test/java/puzzle/MarkerTest.java +++ b/src/test/java/puzzle/MarkerTest.java @@ -10,7 +10,6 @@ import puzzle.Export.Rewards; import puzzle.Masker.Clues; import puzzle.SwedishGenerator.Assign; import puzzle.SwedishGenerator.FillResult; -import puzzle.SwedishGenerator.FillStats; import puzzle.SwedishGenerator.Lemma; import puzzle.SwedishGenerator.Rng; import puzzle.SwedishGenerator.Slotinfo; @@ -257,7 +256,7 @@ public class MarkerTest { @Test void testCornerDownExtraction() { - var slots = Masker.slots(Signa.of(r0c0d4).c(), DictData950.DICT950.index()); + var slots = Masker.slots(Signa.of(r0c0d4).c(), DictData950.DICT950); assertEquals(1, slots.length); assertEquals(r0c0d4.d, Masker.Slot.dir(slots[0].key())); } @@ -303,7 +302,7 @@ public class MarkerTest { assertTrue(placeWord(grid.grid(), grid.grid().g, key, lo, 0L, TEST)); - var fillResult = new FillResult(true, 0, 0, 0, 0, new FillStats()); + var fillResult = new FillResult(true, 0, 0, 0, 0); var puzzleResult = new PuzzleResult(clues, grid, new Slotinfo[]{ new Slotinfo(key, lo, 0L, 0, new Assign(TEST), null, 0) }, fillResult); @@ -343,9 +342,9 @@ public class MarkerTest { @Test void testExportFormatEmpty() { - var grid = SwedishGeneratorTest.createEmpty(); + var grid = SwedishGeneratorTest.createEmpty9x8(); val clues = Clues.createEmpty(); - var fillResult = new FillResult(true, 0, 0, 0, 0, new FillStats()); + var fillResult = new FillResult(true, 0, 0, 0, 0); var puzzleResult = new PuzzleResult(new Signa(clues), new Puzzle(grid, clues), new Slotinfo[0], fillResult); var exported = puzzleResult.exportFormatFromFilled(new Rewards(0, 0, 0)); diff --git a/src/test/java/puzzle/PerformanceTest.java b/src/test/java/puzzle/PerformanceTest.java index 7307b54..6fbf44f 100644 --- a/src/test/java/puzzle/PerformanceTest.java +++ b/src/test/java/puzzle/PerformanceTest.java @@ -9,6 +9,7 @@ import puzzle.Export.Clue; import puzzle.Export.Signa; import puzzle.Export.Puzzle; import puzzle.Masker.Clues; +import puzzle.SwedishGenerator.Grid; import puzzle.SwedishGenerator.Rng; import puzzle.SwedishGenerator.Slotinfo; @@ -72,8 +73,9 @@ public class PerformanceTest { var successCount = 0; for (var i = 0; i < iterations; i++) { - val slotInfo = Masker.slots(arr[c], DICT800.index()); - val result = fillMask(rng, slotInfo, Slotinfo.grid(slotInfo)); + val slotInfo = Masker.slots(arr[c], DICT800); + var grid = Slotinfo.grid(slotInfo); + val result = fillMask(rng, slotInfo,grid.lo,grid.hi, grid.g); if (result.ok()) successCount++; totalNodes += result.nodes(); totalBacktracks += result.backtracks(); @@ -100,7 +102,7 @@ public class PerformanceTest { r6c2d1, r7c0d2, r7c1d2, r7c2d1, r7c7d2, r7c8d2 ); - val allSlots = Masker.slots(mask.c(), DICT900.index()); + val allSlots = Masker.slots(mask.c(), DICT900); //mask.toGrid() System.out.println("[DEBUG_LOG] \n--- Incremental Complexity Test ---"); System.out.println("[DEBUG_LOG] Full Slot Layout:"); @@ -121,7 +123,7 @@ public class PerformanceTest { // A single horizontal slot at (0,0) val mask = Signa.of(r0c0d1); - val slots = Masker.slots(mask.c(), DICT800.index()); + val slots = Masker.slots(mask.c(), DICT800); System.out.println("[DEBUG_LOG] \n--- Single Slot Resolution ---"); if (slots.length > 0) { @@ -142,7 +144,8 @@ public class PerformanceTest { // Reset assignments for each iteration for (var s : slots) s.assign().w = 0; - val result = fillMask(rng, slots, Slotinfo.grid(slots)); + var grid = Slotinfo.grid(slots); + val result = fillMask(rng, slots, grid.lo,grid.hi,grid.g); if (result.ok()) { successCount++; } diff --git a/src/test/java/puzzle/SwedishGeneratorTest.java b/src/test/java/puzzle/SwedishGeneratorTest.java index 0e752dd..b14e1d2 100644 --- a/src/test/java/puzzle/SwedishGeneratorTest.java +++ b/src/test/java/puzzle/SwedishGeneratorTest.java @@ -7,6 +7,7 @@ import anno.LemmaGen; import lombok.val; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import precomp.Neighbors9x8; import precomp.Neighbors9x8.rci; import puzzle.DictJavaGeneratorMulti.DictEntryDTO.IntListDTO; import puzzle.Export.Signa; @@ -37,6 +38,9 @@ import static puzzle.LemmaData.INER; import static puzzle.LemmaData.INEREN; import static puzzle.LemmaData.INERENA; import static puzzle.LemmaData.INERENAE; +import static puzzle.LemmaData.WORD_A; +import static puzzle.LemmaData.WORD_C; +import static puzzle.LemmaData.WORD_X; import static puzzle.SwedishGenerator.*; @GenerateNeighbors(@GenerateNeighbor(C = 4, R = 3, packageName = "precomp", className = "Neighbors4x3", MIN_LEN = 2)) @LemmaGen( @@ -52,10 +56,7 @@ import static puzzle.SwedishGenerator.*; ) public class SwedishGeneratorTest { - public static final long WORD_A = Lemma.from("A"); - public static final long WORD_C = Lemma.from("C"); - public static final long WORD_X = Lemma.from("X"); - static Grid createEmpty() { return new Grid(new byte[SIZE], X, X); } + static Grid createEmpty9x8() { return new Grid(new byte[Neighbors9x8.SIZE], X, X); } record Context(long[] bitset) { public Context() { this(new long[2500]); } @@ -86,26 +87,10 @@ public class SwedishGeneratorTest { INERENA, INERENAE }; - static final byte LETTER_A = ((byte) 'A') & 31; - static final byte LETTER_P = ((byte) 'P') & 31; - static final byte LETTER_L = ((byte) 'L') & 31; - static final byte LETTER_B = ((byte) 'B') & 31; - static final byte LETTER_C = ((byte) 'C') & 31; - static final byte LETTER_E = ((byte) 'E') & 31; - static final byte LETTER_I = ((byte) 'I') & 31; - static final byte LETTER_N = ((byte) 'N') & 31; - static final byte LETTER_X = ((byte) 'X') & 31; - static final byte LETTER_R = ((byte) 'R') & 31; - static final byte LETTER_Z = ((byte) 'Z') & 31; - static final byte CLUE_DOWN = 0; - static final byte CLUE_RIGHT = 1; - static final byte CLUE_UP = 2; - static final byte CLUE_LEFT = 3; - @Test void testPatternForSlotAllLetters() { var grid = new Puzzle(Signa.of(r0c0d1)); - GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, (1L << OFF_0_1) | (1L << OFF_0_2) | (1L << OFF_0_3), 0L, ABC); + GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, r0c1.or(r0c2).or(r0c3).lo(), X, ABC); val map = grid.collect(Collectors.toMap(Lettrix::index, Lettrix::letter)); assertEquals(LETTER_A, map.get(OFF_0_1)); assertEquals(LETTER_B, map.get(OFF_0_2)); @@ -114,60 +99,32 @@ public class SwedishGeneratorTest { @Test void testPatternForSlotMixed() { - var grid = createEmpty(); - GridBuilder.placeWord(grid, grid.g, r0c0d1.slotKey, 1L << OFF_0_0, 0, WORD_A); - GridBuilder.placeWord(grid, grid.g, r0c0d1.slotKey, 1L << OFF_2_0, 0, WORD_C); - var key = Slot.packSlotKey(OFF_1_0, CLUE_RIGHT); - var pattern = patternForSlot(grid.lo, grid.hi, grid.g, key, 7L, 0L); + var grid = createEmpty9x8(); + GridBuilder.placeWord(grid, grid.g, r0c0d1.slotKey, r0c0.mask, X, WORD_A); + GridBuilder.placeWord(grid, grid.g, r0c0d1.slotKey, r2c0.mask, X, WORD_C); + var pattern = patternForSlot(grid.lo, grid.hi, grid.g, 7L, X); assertEquals(14081L, pattern); } @Test void testPatternForSlotAllDashes() { - var grid = createEmpty(); - var key = Slot.packSlotKey(1 << Slot.BIT_FOR_DIR, CLUE_RIGHT); - var pattern = patternForSlot(grid.lo, grid.hi, grid.g, key, 7L, 0L); - assertEquals(0L, pattern); + var grid = createEmpty9x8(); + var pattern = patternForSlot(grid.lo, grid.hi, grid.g, 7L, X); + assertEquals(X, pattern); } @Test void testPatternForSlotSingleLetter() { - var grid = createEmpty(); - //Slot.packSlotKey(0, CLUE_RIGHT) - GridBuilder.placeWord(grid, grid.g, r0c0d1.slotKey, 1L << OFF_0_0, 0, WORD_A); - var key = Slot.packSlotKey(1, CLUE_RIGHT); - var pattern = patternForSlot(grid.lo, grid.hi, grid.g, key, 7L, 0L); + var grid = createEmpty9x8(); + GridBuilder.placeWord(grid, grid.g, r0c0d1.slotKey, r0c0.mask, X, WORD_A); + var pattern = patternForSlot(grid.lo, grid.hi, grid.g, 7L, X); assertEquals(1L, pattern); } - @Test - void testRng() { - var rng = new Rng(123); - var val1 = rng.nextU32(); - var val2 = rng.nextU32(); - assertNotEquals(val1, val2); - - var rng2 = new Rng(123); - assertEquals(val1, rng2.nextU32()); - - for (var i = 0; i < 100; i++) { - var r = rng.randomClueDir(); - assertTrue(r >= 0 && r <= 5); - var f = rng.nextFloat(); - assertTrue(f >= 0.0 && f <= 1.0); - } - assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); - assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); - assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); - assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); - assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); - assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); - assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); - } @Test void testGrid() { var grid = new Puzzle(Clues.createEmpty()); - GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, 1L << OFF_0_0, 0, WORD_A); + GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, r0c0d0.mask, X, WORD_A); val arr = grid.collect(Collectors.toMap(Lettrix::index, Lettrix::letter)); assertEquals(1, arr.size()); assertEquals(LETTER_A, arr.get(OFF_0_0)); @@ -210,25 +167,10 @@ public class SwedishGeneratorTest { @Test void testSlot() { - System.out.println("[DEBUG_LOG] Slot.BIT_FOR_DIR = " + Slot.BIT_FOR_DIR); - // key = (r << 8) | (c << 4) | d - var offset = OFF_2_3; - System.out.println("[DEBUG_LOG] Grid.offset(2, 3) = " + offset); - var key = Slot.packSlotKey(offset, CLUE_DOWN); - System.out.println("[DEBUG_LOG] key = " + key); - long lo = 0; - // pos 0: (2, 5) - lo |= 1L << OFF_2_5; - // pos 1: (3, 5) - lo |= 1L << OFF_3_5; - // pos 2: (4, 5) - lo |= 1L << OFF_4_5; - - System.out.println("[DEBUG_LOG] s.dir() = " + Slot.dir(key)); - assertEquals(OFF_2_3, Slot.clueIndex(key)); - assertEquals(CLUE_DOWN, Slot.dir(key)); - assertFalse(Slot.horiz(key)); - var cells = Puzzle.cellWalk((byte) key, lo, 0L).mapToObj(i -> Masker.IT[i]).toArray(rci[]::new); + assertEquals(OFF_2_3, Slot.clueIndex(r2c3d0.slotKey)); + assertEquals(CLUE_DOWN0, Slot.dir(r2c3d0.slotKey)); + assertFalse(Slot.horiz(r2c3d0.slotKey)); + var cells = Puzzle.cellWalk((byte) r2c3d0.slotKey, r2c5.or(r3c5).or(r4c5).lo(), 0L).mapToObj(i -> Masker.IT[i]).toArray(rci[]::new); assertEquals(2, cells[0].r()); assertEquals(3, cells[1].r()); assertEquals(4, cells[2].r()); @@ -236,8 +178,8 @@ public class SwedishGeneratorTest { assertEquals(5, cells[1].c()); assertEquals(5, cells[2].c()); - assertTrue(Slot.horiz(CLUE_RIGHT)); // right - assertFalse(Slot.horiz(CLUE_DOWN)); // down + assertTrue(Slot.horiz(CLUE_RIGHT1)); // right + assertFalse(Slot.horiz(CLUE_DOWN0)); // down } static long packPattern(String s) { @@ -267,13 +209,13 @@ public class SwedishGeneratorTest { void testForEachSlotAndExtractSlots() { // This should detect a slot starting at 0,1 with length 2 (0,1 and 0,2) var dict = DictJavaGeneratorMulti.Dicts.makeDict(WORDS2); - var slots = Masker.extractSlots(Signa.of(r0c0d1).c(), dict.index()); + var slots = Masker.extractSlots(Signa.of(r0c0d1).c(), dict.index(), dict.reversed()); assertEquals(1, slots.length); var s = slots[0]; assertTrue(Slot.length(s.lo(), s.hi()) >= 2); assertEquals(OFF_0_0, Slot.clueIndex(s.key())); - assertEquals(CLUE_RIGHT, Slot.dir(s.key())); + assertEquals(CLUE_RIGHT1, Slot.dir(s.key())); } @Test @@ -292,33 +234,20 @@ public class SwedishGeneratorTest { @Test void testGeneticAlgorithmComponents() { - var rng = new Rng(42); - var gen = new Masker(rng, new int[Masker.STACK_SIZE], Masker.Clues.createEmpty()); - - var c1 = new Signa(gen.randomMask(18)); + var gen = new Masker(new Rng(42), new int[Masker.STACK_SIZE], Masker.Clues.createEmpty()); + var c1 = new Signa(gen.randomMask(18)); assertNotNull(c1); - var g2 = new Signa(gen.mutate(c1.deepCopyGrid().c())); assertNotNull(g2); assertNotSame(c1.c(), g2.c()); - assertNotNull(gen.crossover(c1.c(), g2.c())); - - var g4 = gen.hillclimb(c1.c(), 18, 10); - assertNotNull(g4); + assertNotNull(gen.hillclimb(c1.c(), 18, 10)); } @Test void testPlaceWord() { var grid = new Puzzle(Clues.createEmpty()); - // Slot at OFF_0_0 length 3, horizontal (right) - var key = Slot.packSlotKey(0, CLUE_RIGHT); - var lo = (1L << OFF_0_0) | (1L << OFF_0_1) | (1L << OFF_0_2); - val hi = 0L; - var w1 = ABC; - - // 1. Successful placement in empty grid - assertTrue(GridBuilder.placeWord(grid.grid(), grid.grid().g, key, lo, hi, w1)); + assertTrue(GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, r0c0.or(r0c1).or(r0c2).lo(), X, ABC)); var map = grid.collect(Collectors.toMap(Lettrix::index, Lettrix::letter)); assertEquals(3, map.size()); @@ -327,9 +256,9 @@ public class SwedishGeneratorTest { assertEquals(LETTER_C, map.get(OFF_0_2)); // 2. Successful placement with partial overlap (same characters) - assertTrue(GridBuilder.placeWord(grid.grid(), grid.grid().g, key, lo, hi, w1)); + assertTrue(GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, r0c0.or(r0c1).or(r0c2).lo(), X, ABC)); // 3. Conflict: place "ABD" where "ABC" is - assertFalse(GridBuilder.placeWord(grid.grid(), grid.grid().g, key, lo, hi, ABD)); + assertFalse(GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, r0c0.or(r0c1).or(r0c2).lo(), X, ABD)); // Verify grid is unchanged (still "ABC") map = grid.collect(Collectors.toMap(Lettrix::index, Lettrix::letter)); assertEquals(3, map.size()); @@ -339,8 +268,8 @@ public class SwedishGeneratorTest { // 4. Partial placement then conflict (rollback) grid = new Puzzle(Clues.createEmpty()); - GridBuilder.placeWord(grid.grid(), grid.grid().g, Slot.packSlotKey(0, CLUE_RIGHT), 1L << OFF_0_2, 0, WORD_X); // Conflict at the end - assertFalse(GridBuilder.placeWord(grid.grid(), grid.grid().g, key, lo, hi, w1)); + GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, 1L << OFF_0_2, 0, WORD_X); // Conflict at the end + assertFalse(GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, r0c0.or(r0c1).or(r0c2).lo(), X, ABC)); map = grid.stream().collect(Collectors.toMap(Lettrix::index, Lettrix::letter)); assertEquals(1, map.size()); assertEquals(LETTER_X, map.get(OFF_0_2)); @@ -350,12 +279,9 @@ public class SwedishGeneratorTest { void testBacktrackingHelpers() { var grid = new Puzzle(Clues.createEmpty()); // Slot at 0,1 length 2 - var key = Slot.packSlotKey(0, CLUE_RIGHT); - var lo = (1L << OFF_0_1) | (1L << OFF_0_2); - var w = AZ; val low = grid.grid().lo; val top = grid.grid().hi; - var placed = GridBuilder.placeWord(grid.grid(), grid.grid().g, key, lo, 0L, w); + var placed = GridBuilder.placeWord(grid.grid(), grid.grid().g, r0c0d1.slotKey, r0c1.or(r0c2).lo(), X, AZ); assertTrue(placed); var map = grid.collect(Collectors.toMap(Lettrix::index, Lettrix::letter)); @@ -374,16 +300,16 @@ public class SwedishGeneratorTest { @Test void testInnerWorkings() { // 1. Test Slot.increasing - assertFalse(Slotinfo.increasing(CLUE_LEFT)); // Left - assertTrue(Slotinfo.increasing(CLUE_RIGHT)); // Right - assertTrue(Slotinfo.increasing(CLUE_DOWN)); // Down - assertFalse(Slotinfo.increasing(CLUE_UP)); // Up + assertFalse(Slotinfo.increasing(CLUE_LEFT3)); // Left + assertTrue(Slotinfo.increasing(CLUE_RIGHT1)); // Right + assertTrue(Slotinfo.increasing(CLUE_DOWN0)); // Down + assertFalse(Slotinfo.increasing(CLUE_UP2)); // Up - assertTrue(Slotinfo.increasing(Slot.packSlotKey(0, CLUE_RIGHT))); - assertFalse(Slotinfo.increasing(Slot.packSlotKey(0, CLUE_LEFT))); + assertTrue(Slotinfo.increasing(r0c0d1.slotKey)); + assertFalse(Slotinfo.increasing(r0c0d3.slotKey)); // 2. Test slotScore - val counts = new byte[SIZE]; + val counts = new byte[Neighbors9x8.SIZE]; counts[1] = 2; counts[2] = 3; var dict = DictJavaGeneratorMulti.Dicts.makeDict(WORDS); @@ -415,4 +341,29 @@ public class SwedishGeneratorTest { var fitOne = gen.maskFitness(grid, 18); assertTrue(fitOne < fitEmpty); } + @Test + void testRng() { + var rng = new Rng(123); + var val1 = rng.nextU32(); + var val2 = rng.nextU32(); + assertNotEquals(val1, val2); + + var rng2 = new Rng(123); + assertEquals(val1, rng2.nextU32()); + + for (var i = 0; i < 100; i++) { + var r = rng.randomClueDir(); + assertTrue(r >= 0 && r <= 5); + var f = rng.nextFloat(); + assertTrue(f >= 0.0 && f <= 1.0); + } + assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); + assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); + assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); + assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); + assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); + assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); + assertTrue(rng.biasedIndexPow3(100) >= 0 && rng.biasedIndexPow3(100) < 100); + } + } \ No newline at end of file diff --git a/tools.iml b/tools.iml deleted file mode 100644 index b783b04..0000000 --- a/tools.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file