grep で Wordle を作る
ちょっと前に、こういう記事を書いた。
grep で Wordle の問題を解くと簡単すぎてつまらないので、grep で Wordle を実装してみたという内容だ。
このプログラムの趣旨は、Wordle が行っている正誤の判断を正規表現でできないかという実験的なものだ。実際、正解の単語から正規表現を生成して、ヒント情報の表示自体はツールの持っている基本的な機能で実現している。
しかし、隣に表示しているキーマップ情報については違って、実現するためには、わりと当たり前の方法を使って解析している。
便利機能を実装する
試しに作ったプログラムだが、案外使えるのでいろいろと改造していたら、どうも本来の趣旨とはかけ離れたものになってきた。前の記事にも書いたように、Wordle を解くために辞書と grep を活用するのは有効で、だったらわざわざ別の画面で入力したりするよりも、同じ場所で実行できた方が圧倒的に便利なのだ。
ということで、候補となる単語リストから正解のヒントを表示するインタフェースを作った。次の例を使って説明してみよう。
- solid という単語を試す。
- panic という単語を試す。
- hint を表示する。
- 案外たくさんあるので、もう少し絞り込みたい。
- 次は、今までに出てきていない文字を試したいので、solid を含まず (
!solid)、panic も含まない (!panic) 単語で、よく使われそうな文字 eft を含む単語 (=eft) の中から、重複文字を含まないもの (u,uniq) を表示する。 - 4つのの中から wheft を選んで試したところ、候補は datum と tardy の2つに絞られた。
- あとは、1つずつ試して正解の tardy が得られる。
こんな風にフィルターコマンドはパイプライン状に繋げてつかうことができる。grep を次のように使っている感じだ。
grep -v '[solid]' | grep -v '[panic]' | grep '[eft]' | ggrep -vP '(.).*\1'
はっきり言って滅茶苦茶便利である。
ちなみに、ここで候補となる単語を表示するために使われている正規表現は次のものだ。
(?=.*s)(?=.*l)(?=.*p)(?=.*a)(?!.*[oidnc])[^sp]a[^ln][^i][^dc]
上のような使い方以外にもいろいろと応用は効く。また、正解のシリーズを指定できるようになっているので、一日に何回でも練習することができる。デフォルトはシリーズ1で、シリーズ0はオリジナルと同じ。また --randam をつければ、毎回ランダムな問題になる。
結論
サポート機能を実装して滅茶苦茶便利になった代わりに、Wordle がいっそうつまらなくなった。とりあえず、試行回数のデフォルトは5にしていいような気がする。4にすると緊張感が出てくるかと思って試しにランダムに10問やってみたら、8勝2敗だった。
ところで、今となっては greple のモジュールとして実装する意味がほとんどなくなってしまった。逆に行編集が実装しづらいなどの弊害もある。単独のコマンドとして実装した方がいろいろな意味でいいのだが、そこまで手間をかける意味があるのかというのと、だったら perl でなくてもいいんじゃないかという話が...
追記
そうそう、前の記事でオプションハンドリングが面倒という話を書いたのだが、その後、このモジュールは、本体の greple コマンドとは完全に独立したオプション体系を持つ形に変更した。
普通は、モジュールは本体の機能を拡張するために作るのだが、この場合は完全にバックエンドとしてしか使っていない。だから、本体とはまったく異なるオプション体系にしてしまっても問題ないだろうという判断だ。greple のオプションは、初期化の段階で設定するので問題はないし、モジュールが解釈しないオプションはそのままパススルーするようになっている。苦し紛れの小細工をするよりは、この方が潔く見通しもいい形になったと思う。
このモジュールを実装してみて、greple の機能をもっと柔軟に利用できるようになるといいと思った。コードはかなり書き換えたが、メインの流れの部分については30年前から変わらない構造になっている。これがポータブルなオブジェクトで、他のコードからも利用できるような形になっていれば、もっと違う利用の仕方があるのになあと感じた。メイン部分の大改修には腰が重いので考えどころだ。
