中野智文のブログ

データ・マエショリストのメモ

wordle をruby のワンライナーでズルする

背景

wordle をエンジニアっぽく rubyワンライナーでズルしたい

戦略

  • /usr/share/dict/words を使う
  • ヒントから可能性のある単語のリストを抽出する。ヒントがない場合は5文字の全単語。
  • もし単語が一語であればそれが解で終了。
  • そうでない場合、その可能性のある単語のリストから頻度の高いアルファベットを抽出し、
  • それらのアルファベットを含む語彙を全体の単語のリスト(可能性のある単語のリストではない)から見つけ出して使う。
  • これを繰り返す。

方法

5文字単語のリスト

$ ruby -ne 'puts $_ if $_=~/^[a-z]{5}$/' < /usr/share/dict/words

本当は複数形を除きたいし、コーパスなどから出現頻度を求めたいが、今後の課題ということで。

どのアルファベットが最も多く出現するか

$ ruby -ne 'puts $_ if $_=~/^[a-z]{5}$/' < /usr/share/dict/words | ruby -ne 'BEGIN{$w=Hash.new(0)}; $_.chomp.chars.each{|x|$w[x]+=1}; END{puts $w.sort_by{|_,v|-v}.to_h;}'
{"a"=>4467, "e"=>4255, "r"=>3043, "o"=>2801, "i"=>2581, "s"=>2383, "t"=>2381, "l"=>2368, "n"=>2214, "u"=>1881, "y"=>1605, "c"=>1546, "d"=>1399, "h"=>1323, "m"=>1301, "p"=>1293, "b"=>1162, "g"=>1102, "k"=>882, "w"=>685, "f"=>661, "v"=>466, "z"=>250, "x"=>189, "j"=>163, "q"=>84}

特定のアルファベットが含まれる単語

下記の場合、["a", "e", "r", "o", "s"]の5つのアルファベットが含まれる単語を抽出。

$ ruby -ne 'puts $_ if $_=~/^[a-z]{5}$/' < /usr/share/dict/words | ruby -ne 'puts $_ if "aeros".chars.all?{|x| $_.chomp.chars.include?(x)}'
arose

特定の位置に特定のアルファベットがあり、かつ、特定のアルファベットが含まれない単語を抽出

下記は、a_o__ である単語で、"r", "s", "e" が含まれない語彙のリスト。

$ ruby -ne 'puts $_ if $_=~/^a[a-z]o[a-z]{2}$/' < /usr/share/dict/words | ruby -ne 'puts $_ if "rse".chars.all?{|x| not $_.chomp.chars.include?(x)}'
abody
...
...
azoxy

その、アルファベットの頻度

$ ruby -ne 'puts $_ if $_=~/^a[a-z]o[a-z]{2}$/' < /usr/share/dict/words | ruby -ne 'puts $_ if "rse".chars.all?{|x| not $_.chomp.chars.include?(x)}'|ruby -ne 'BEGIN{$w=Hash.new(0)}; $_.chomp.chars.each{|x|$w[x]+=1}; END{puts $w.sort_by{|_,v|-v}.to_h;}'
{"o"=>52, "a"=>51, "l"=>16, "n"=>14, "y"=>13, "d"=>11, "t"=>11, "i"=>9, "m"=>8, "c"=>7, "b"=>6, "f"=>6, "g"=>6, "z"=>5, "h"=>5, "p"=>5, "u"=>4, "x"=>3, "w"=>1, "k"=>1, "v"=>1}

"o", "a" は既出なので、"l", "n", "y", "d", "t" が含まれる単語を抽出したい。

特定の位置に特定のアルファベットがあり、かつ、特定のアルファベットが含まれず、かつ、どこかに特定のアルファベットが含まれる単語

下記は、a_o__ である単語で、"r", "s", "e", "i", "n", "y" が含まれず、どこかに"l", "t"が含まれる単語

$ ruby -ne 'puts $_ if $_=~/^a[a-z]o[a-z]{2}$/' < /usr/share/dict/words | ruby -ne 'puts $_ if "rseiny".chars.all?{|x| not $_.chomp.chars.include?(x)}' | ruby -ne 'puts $_ if "lt".chars.all?{|x| $_.chomp.chars.include?(x)}'
a?o??
a?o??

敢えて隠しました。どっちかは運と思います。 自分は運に負けました。

まとめ

どっちも知らない単語。

追記

修正版

最近ではこんな感じ。(情報量導入)

$ ruby -ne 'puts $_ if ($_=~/^[^a][^r][^o]..$/ and "se".chars.all?{|x| not $_.chomp.chars.include?(x)} and "aro".chars.all?{|x| $_.chomp.chars.include?(x)})' < wordles.txt | ruby -ne 'BEGIN{$w=Hash.new(0);$t=0}; $_.chomp.chars.uniq.each{|x|$w[x]+=1.0};$t+=1; END{puts $w.map{|k,v|[k,v/$t]}.map{|k,p| [k, -p*Math.log(p) + (p==1.0 ? 0 : -(1-p)*Math.log(1-p))]}.sort_by{|_,v|-v}.to_h}'

4文字の組み合わせを含む単語を見つける。

ruby -ne '"pvbwcdy".chars.combination(4).to_a.each{|y| puts $_ if ($_=~/^.....$/ and y.all?{|x| $_.chomp.chars.include?(x)})}' < wordles.txt

wordle の語彙は次でダウンロード

curl https://slc.is/data/wordles.txt