私が歌川です

@utgwkk が書いている

自分の思考ルーチンに合わせたWordleソルバを書く

だいたい初手でアルファベットを絞り込んだらあとは流れで、という感じで解いているのでプログラムに落とし込んだ。実際にはあり得る単語はもうちょっと少ないと思うけど、人間の方も /usr/share/dict/words を使って解いているし、初手の単語は固定している。単語を与えたら出題側がHIT, BLOWの情報を返してくれるので、それをもとに絞り込んでいく、というのを素朴に書いてみている。

一度使った単語を使わないようにする処理を後から捩じ込んだので不自然にハッシュリファレンスを使っているところが増えた……。グローバル変数があったりなかったりという感じなのでsolverクラスを作って使う形にリファクタリングしたらいいと思う。

github.com

せっかくなので勝率を計算してみる。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}'

f:id:utgwkk:20220206230407p:plain

勝率80%弱ぐらい。もうちょっと思考ルーチンを詰めていくとよいのかもしれないけど、素朴に書いても80%ぐらいは勝てることが分かる。

2022/2/8 追記

f:id:utgwkk:20220207235926p:plain

アルゴリズムをちょっと改良したら勝率が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