Java wordle solver implementation following along with the "roget" implementation stream (in Rust), which implements the 3blue1brown algorithm (video1, video2). The implementation was optimized a bit along the way.
Currently, there are two algorithmic variants of the wordle solver: 1) Entropy (3b1b) and 2) MostFreq.
Follows the 3blue1brown algorithm to choose guesses based on the expected gained information of each word.
Simple guesser that chooses the word with the highest frequency in the dictionary.
The scores as computed against all answers with a max. of 6 guesses each (which is configurable in the source):
- Entropy: avg score: 3.892023, solved: 98.27%
- Mostfreq: avg score: 4.277778, solved: 96.67%
'mostfreq' ran 3.19 ± 0.10 times faster than 'entropy'
So, the Entropy strategy implementation is better but takes nearly 400% as long!
mvn --quiet clean package
bin/jordle
Use hyperfine to compare different implementations.
⌘ hyperfine -w 0 -n entropy 'bin/jordle -a entropy 64' -n mostfreq 'bin/jordle -a mostfreq 64'
Benchmark 1: entropy
Time (mean ± σ): 1.408 s ± 0.044 s [User: 1.439 s, System: 0.265 s]
Range (min … max): 1.357 s … 1.507 s 10 runs
Benchmark 2: mostfreq
Time (mean ± σ): 441.3 ms ± 4.1 ms [User: 615.8 ms, System: 106.6 ms]
Range (min … max): 437.2 ms … 449.8 ms 10 runs
Summary
'mostfreq' ran
3.19 ± 0.10 times faster than 'entropy'
- Other algorithms/implementations from the stream.
- Use test cases from wordle-tests
- Parallelization of candidate evaluation (not games, which is rather trivial).
I tested the implementation under various different GraalVM versions/JDKs: the "old" JDK under Rosetta and a
pre-release for the M1 ARM architecture.
Benchmark results comparing the ARM version compiled to an executable and "standard JAR" can be found in the plot.ipynb
.
- Version: CE 22.0.0.2 (build 17.0.2+8-jvmci-22.0-b05)
Steps to reproduce:
- Install GraalVM under homebrew using a Rosetta-enabled Terminal.app (
arch
should printi386
). It seems that this terminal is only used for installing via homebrew, such that it does not complain about a missing build for the arm64 architecture. Apparently, GraalVM 22.1 (or 22.2 latest) will support M1 natively. - Remove quarantine flag:
sudo xattr -r -d com.apple.quarantine /path/to/graal
. - Set
PATH
to include the GraalVM binaries inbin
andJAVA_HOME
to point to GraalVMHome
. I recommend doing this temporarily, so you can more easily experiment and do not hose your system. - Make sure to check the current Java version
java -version
. It should include "GraalVM". - Install native-image:
gu install native-image
. - Package the project (
mvn clean package
) and compile to a native image:native-image -jar target/release/lib/jordle.jar --install-exit-handlers -H:IncludeResources='.*\.txt$' -H:+ReportUnsupportedElementsAtRuntime
The Rosetta native-image
build takes around 1m 10s on the M1 MacBook Air.
⌘ file jordle
jordle: Mach-O 64-bit executable x86_64
⌘ du -h jordle
15M jordle
NB: "DARWIN does not support building static executable images."
Steps to reproduce below.
Note: I'm using fish
instead of bash
!
Also, I'm setting it up as a custom asdf Java version.
- Download current preview and extract:
$ pushd $HOME/.asdf/installs/java $ curl -sLO https://github.com/graalvm/graalvm-ce-dev-builds/releases/download/22.1.0-dev-20220321_2332/graalvm-ce-java17-darwin-aarch64-dev.tar.gz $ tar xzvf graalvm-ce-java17-darwin-aarch64-dev.tar.gz
- Set up for asdf:
$ cd graalvm-ce-java17-22.1.0-dev $ for d in (ls Contents/Home); ln -s "Contents/Home/$d" $d; end $ asdf reshim
- Make sure it's listed and go back to the code directory:
$ asdf list java $ popd
- Configure as local version and test:
$ asdf local java graalvm-ce-java17-22.1.0-dev $ java -version openjdk version "17.0.3" 2022-04-19 OpenJDK Runtime Environment GraalVM CE 22.1.0-dev (build 17.0.3+4-jvmci-22.1-b03) OpenJDK 64-Bit Server VM GraalVM CE 22.1.0-dev (build 17.0.3+4-jvmci-22.1-b03, mixed mode, sharing)
- Install native-image:
$ gu install native-image $ asdf reshim
- Package the project (
mvn clean package
) and compile to a native image:$ native-image -jar target/release/lib/jordle.jar --install-exit-handlers -H:IncludeResources='.*\.txt$' -H:+ReportUnsupportedElementsAtRuntime
The native native-image
build takes around 21s on the M1 MacBook Air.
⌘ file jordle
jordle: Mach-O 64-bit executable x86_64
⌘ du -h jordle
15M jordle
NB: "DARWIN does not support building static executable images."
Using async-profiler, we can generate flamegraphs pretty easily. Unfortunately, on macOS it seems we're limited to user-space code only :(. Nonetheless, they provide interesting introspection into the running code.
For example, to evaluate a currently running jordle
(from the bin
script, which sets some necessary JVM args), execute:
../async-profiler-2.7-macos/profiler.sh -d 10 -t -f perf-out.html (jps | awk -F ' ' '/jordle/ { print $1}')
After the 10 second sample time, you can then open perf-out.html
in the browser to inspect your flamegraph.