Wordle自動化のすゝめ

これはなに

 最近話題になっている単語当てゲーム「Wordle」を自動化したので、それについて記そうと思います。前回の記事は以下より↓

copynight.hatenablog.com

 

前置き

 前回、Wordleを解くプログラムまでは作りました。詳しいことは上記の記事を読んでもらえればいいのですが、今回のWordle自動化に当たり、いくつか変更点があります。

1.単語リストの再考

前回の単語リストはいくつかのサイトからスクレイピングによって単語を取得しましたが、その中には実用的でなく、Wordleで使うことができない単語が数多く含まれていることが発覚しました。そこで、より良い単語リストを探していたところ、以下の単語リストが(解析的にも)非常に良いのではないか、ということで使うことにしました。

https://seleniumbase.io/cdn/txt/wordle_words.txt

このリストを使うことで単語数も半分となり、より早い解析が可能となりました。

 

2.最初の単語の再考

上記の単語リストを用いて再度解析を行ったところ、最初に入力すべき単語は"arise"よりも"later"の方が(微小な差ですが)良いという結果になったので、"later"を1文字目に入力することにしました。また、これを基にパラメータも計算し直しました。

 

本題

 では今回は、前回のWordleを解くプログラムを用いて、プログラムを起動するだけでその日のWordleを勝手に解くプログラムを作成することを目標とします。今回は前回とは違い、少し技術的な話も交えようと思います。

といっても、解く部分はできているので、必要なことはWordleに対して単語を入力してその結果を読み取り、前回作成したプログラムに放り込むだけです。とはいえ、それなりに苦戦しました。

 

最初に完成したコードを貼っておきます。

github.com

前回同様Pythonを用いています。自動化のためにSeleniumを用いています。SeleniumPythonで1番と言って差し支えないレベルで有名なブラウザ自動化のフレームワークなので、その使い方は調べればいくらでも出てきます。興味があれば触ってみてください。

さて、Wordleですが、普通にSeleniumを用いてもエレメントが取得できません。何故なら、WordleはShadow DOMを用いているためです。これはDOMをカプセル化するためのものですが、要するに開発者しかその中身にアクセスできません。SeleniumはShadow DOM以下のエレメントにはアクセスできないので、その状態でfind_elementを行っても、エレメントを見つけることができません。

ではどうするか、というと、Shadow DOMの処理された内容を結合してしてやればよいのです。そのための処置として、shadow_rootというのを付け加えます。以下はコードの174~178行目です。

ga = driver.find_element(By.TAG_NAME, 'game-app').shadow_root
gm = ga.find_element(By.TAG_NAME, 'game-modal').shadow_root
gm.find_element(By.TAG_NAME, 'game-icon').click()

gk = ga.find_element(By.TAG_NAME, 'game-keyboard').shadow_root

このように、Wordleのキーボードエレメントにアクセスするためには、3段階のShadow Rootを結合すれ必要があります。このことさえ知っていれば、後は普通に処理に必要なエレメントを取得し、ボタンを押すなりクリックするなりの処理を行わせればよいわけです。

 

Wordleに対して入力した文字のレスポンスとして一致・含まれている・含まれていないの色付けが返ってきますが、この色は直接読み取る必要はありません。以下のように、色付けされた枠にはevaluation(評価)というAttributeが追加されています。この値を読み取ることで、色を判断しなくてもレスポンスを取得できるというわけです。

        if gt[n].get_attribute('evaluation') == 'absent': #b
            inp+='b'
        if gt[n].get_attribute('evaluation') == 'present': #o
            inp+='o'
        if gt[n].get_attribute('evaluation') == 'correct': #g
            inp+='g'

 

入力に関してなんですが、Wordleの画面にはキーボードが表示されるので非常に簡単です。このキーボードは左上(つまりQ)からQWERT・・・・・・の順番にID側r降られているので、入力したい文字のIDのボタンを押すことで、入力が完了します。

# wordleに入力
def keyboard_input(b, word):
    for n in range(5):
        time.sleep(0.1)
        if keyboard.index(word[n])>=19:
            b[keyboard.index(word[n])+1].click()
        else:
            b[keyboard.index(word[n])].click()
    b[19].click()

ちなみに入力が速すぎると表示がバグります。そのためのsleep(0.1)です。

 

以上で、文字列の入力、レスポンスの取得、次に入力する単語の解析の全てのキーが揃いました。あとはこれらを結合していくだけです。

 

実際に動いている様子が以下のツイートの動画になります。

 

まとめ

いかがでしたか?ここに書いてある情報(なんならコード自体をさらしている)でWordle自動化が可能となります。あなただけの最適Wordle自動化プログラムを作成してみてください。