だいたい初手でアルファベットを絞り込んだらあとは流れで、という感じで解いているのでプログラムに落とし込んだ。実際にはあり得る単語はもうちょっと少ないと思うけど、人間の方も /usr/share/dict/words
を使って解いているし、初手の単語は固定している。単語を与えたら出題側がHIT, BLOWの情報を返してくれるので、それをもとに絞り込んでいく、というのを素朴に書いてみている。
一度使った単語を使わないようにする処理を後から捩じ込んだので不自然にハッシュリファレンスを使っているところが増えた……。グローバル変数があったりなかったりという感じなのでsolverクラスを作って使う形にリファクタリングしたらいいと思う。
せっかくなので勝率を計算してみる。1行に入力した単語とHIT, BLOWの様子が出力されるので行数をカウントすればよい。6より大きければ負けている。
use strict; use warnings; use v5.30; for my $i (1..10000) { my $result = `perl solver.pl`; if ($? > 0) { say -1; next; } say scalar(split /\r?\n/, $result); }
こういうスクリプトを書いて走らせる。出力結果を result.txt
みたいなファイルに溜めて集計してグラフにしてみた。
% sort -n result.txt | uniq -c | awk '{print $2,$1}'
勝率80%弱ぐらい。もうちょっと思考ルーチンを詰めていくとよいのかもしれないけど、素朴に書いても80%ぐらいは勝てることが分かる。
2022/2/8 追記
アルゴリズムをちょっと改良したら勝率が90%ぐらいになった。
Perlテクニック
せっかくなのでWordleソルバを書くにあたって知ったPerlテクニックについても共有します。
chomp
でリストの要素ごとにchompできる
@xs = map { chomp $_; $_ } @words
みたいに書く必要があるのかと思ったけどそういうこともなくて、 chomp @words
のようにリストを直接渡すことができます。
If you chomp a list, each element is chomped, and the total number of characters removed is returned.
chomp - Perldoc Browser
ハマるケースを採取してみたら確かにこういうハマり方をしたことがある、と心当たりがあっておもしろかった。ネタバレにならないように続きを読むに分離した。
arise => BLOW, NONE, NONE, BLOW, BLOW cough => NONE, NONE, NONE, NONE, NONE tapes => NONE, HIT, NONE, HIT, HIT naves => NONE, HIT, NONE, HIT, HIT sales => BLOW, HIT, NONE, HIT, HIT faxes => NONE, HIT, NONE, HIT, HIT bakes => NONE, HIT, NONE, HIT, HIT eases => BLOW, HIT, BLOW, HIT, HIT sades => BLOW, HIT, HIT, HIT, HIT wades => NONE, HIT, HIT, HIT, HIT jades => HIT, HIT, HIT, HIT, HIT