$30 off During Our Annual Pro Sale. View Details »

symfony/pantherでWordleを解いてみた

 symfony/pantherでWordleを解いてみた

PHPカンファレンス沖縄2022 の発表資料です。
https://techplay.jp/event/866236
https://phpcon-okinawa.connpass.com/event/257992/

Takashi Kanemoto

August 27, 2022
Tweet

More Decks by Takashi Kanemoto

Other Decks in Programming

Transcript

  1. / 58 symfony/panther Wordle 2 022 / 08 / 2

    7 #phpcon_okinawa @ttskch 1
  2. Kannade PHPer 10 Symfony頻 https://zenn.dev/topics/symfony @ttskch

  3. / 58 symfony/panther Wordle symfony/panther Wordle 💭 3

  4. / 58 symfony/panther Wordle symfony/panther Wordle 💭 4 😇

  5. / 58 https://github.com/ttskch/wordler 🐙 GitHub 5

  6. / 58 symfony/panther Wordle symfony/panther Wordle Wordle 6 🔖

  7. / 58 symfony/panther Wordle symfony/panther Wordle Wordle 7 🔖

  8. / 58 symfony/panther 8 https://github.com/symfony/panther

  9. / 58 PHP Web e 2 e Symfony WebDriver symfony/panther

    9
  10. / 58 10 symfony/panther $ composer require symfony/panther

  11. / 58 symfony/panther 
 bdi browser-driver-installer 11 $ composer require

    dbrekelmans/bdi $ vendor/bin/bdi detect drivers
  12. / 58 <?php use Symfony\Component\Panther\Client; require_once __DIR__.'/vendor/autoload.php'; $client = Client::createFirefoxClient();

    $client->request('GET', 'https://phpcon.okinawa.jp'); $client->waitForVisibility('#about img'); $client->takeScreenshot(__DIR__.'/screenshot.png'); 12 👨💻
  13. / 58 👨💻 13 screenshot.png 
 🎉

  14. / 58 14

  15. / 58 symfony/panther Wordle symfony/panther Wordle Wordle 15 🔖

  16. / 58 2022 頻 Web 
 Wordle 16

  17. / 58 5 6 1 ⬜ 🟨 🟩 ⾒ 🟩

    🟩 🟩 🟩 🟩 Wordle 17
  18. / 58 Wordle 18 https://www.nytimes.com/games/wordle/index.html

  19. None
  20. None
  21. symfony/panther

  22. / 58 symfony/panther Wordle symfony/panther Wordle Wordle 22 🔖

  23. / 58 23 🖱

  24. / 58 24 Wordle

  25. / 58 25 👨💻symfony/panther

  26. / 58 $client = Client::createFirefoxClient(); $client->request('GET', 'https://www.nytimes.com/games/wordle/index.html'); // ࠷ॳʹ։͍ͨϙοϓΞοϓΛด͡Δ $client->getMouse()

    ->clickTo('[class*="closeIcon"]'); // ϙοϓΞοϓ͕ด͡ΔͷΛ଴ͬͯεΫϦʔϯγϣοτΛࡱΔ sleep(1); $client->takeScreenshot(__DIR__.'/screenshot.png'); 26 1.
  27. / 58 1. 27

  28. / 58 // ԿΒ͔ͷํ๏ͰଧͪࠐΉ୯ޠΛܾΊΔ $candidate = 'world'; // ୯ޠΛଧͪࠐΜͰEnterΩʔΛԡ͢ $client->getCrawler()->sendKeys($candidate)

    ->sendKeys(WebDriverKeys::ENTER); // ϑΟʔυόοΫͷද͕ࣔ׬ྃ͢Δ·Ͱ଴ͬͯεΫϦʔϯγϣοτΛࡱΔ sleep(3); $client->takeScreenshot(__DIR__.'/screenshot.png'); 28 2.
  29. / 58 2. 29

  30. / 58 for ($i = 0; $i < 6; $i++)

    { $candidate = 'world'; $client->getCrawler() ->sendKeys($candidate) ->sendKeys(WebDriverKeys::ENTER); sleep(3); } $client->takeScreenshot(__DIR__.'/screenshot.png'); 30 3. 6
  31. / 58 3. 6 31

  32. / 58 // ShareϘλϯ͕දࣔ͞ΕΔͷΛ଴ͬͯΫϦοΫ sleep(2); $client->getMouse()->clickTo('#share-button'); // ΫϦοϓϘʔυͷ಺༰Λద౰ͳWebϖʔδͷ<textarea>ʹషΓ෇͚ͯऔಘ $client->request(‘GET', ‘https://getbootstrap.com/docs/5.1/forms/form-control/');

    $client->getMouse()->clickTo('textarea'); $client->getKeyboard()->pressKey(WebDriverKeys::COMMAND)->sendKeys('v'); $result = $client->getCrawler()->filter('textarea')->attr('value'); echo "{$result}\n"; 32 4 . Share
  33. / 58 4 . Share 33

  34. / 58 34 🎉🎉🎉

  35. / 58 35 💪

  36. / 58 symfony/panther Wordle symfony/panther Wordle Wordle 36 🔖

  37. / 58 5 
 🧭 37 6

  38. / 58 
 頻 🧭 38 頻

  39. / 58 🖼 頻 39

  40. /xxx class Guesser { private array $characterScores = [ 'a'

    => {είΞ}, 'b' => {είΞ}, ‘c' => {είΞ}, : : ]; public function guess(CandidateProvider $candidateProvider): string { // $candidateProvider͔Β࢒͍ͬͯΔީิ୯ޠΛड͚औΓ // ͢΂ͯͷ୯ޠͷείΞ߹ܭ஋Λܭࢉ͠ // είΞ߹ܭ஋͕࠷΋େ͖͍୯ޠΛฦ͢ // ͨͩ͠ɺείΞ߹ܭ஋Λࢉग़͢Δࡍɺ // ॏෳ͍ͯ͠Δจࣈʹ͍ͭͯ͸είΞΛՃࢉ͠ͳ͍ } }
  41. /xxx class CandidateProvider { public function __construct(private array $candidates) {

    } public function getCandidates(): array { return $this->candidates; } public function applyFeedback(string $word, array $states): void { // ࢼߦͨ͠୯ޠͱͦΕʹର͢ΔϑΟʔυόοΫ಺༰Λड͚औΓ // ਖ਼ղͰͳ͍ͱ൑ผͰ͖ͨ୯ޠΛ$this->candidates͔Β͢΂ͯ࡟আ } }
  42. /xxx // app.php for ($i = 0; $i < 6;

    $i++) { $candidate = $guesser->guess(); // ུ // ֤จࣈͷཁૉͷdata-stateʹϑΟʔυόοΫ಺༰͕͋ΔͷͰͦΕΛऔಘ // ⬜ "absent", 🟨 "present", 🟩 "correct" $states = []; for ($j = 0; $j < 5; $j++) { $states[] = $client->getCrawler() ->filter('CSSηϨΫλʢུʣ')->attr('data-state'); } $candidateProvider->applyFeedback($candidate, $sates); }
  43. / 58 https://github.com/kujirahand/EJDict 🤲 5 43

  44. https://en.wikipedia.org/wiki/Letter_frequency

  45. /xxx class Guesser { private array $characterScores = [ 'a'

    => 7.8, 'b' => 2, 'c' => 4, 'd' => 3.8, 'e' => 11, : : ]; }
  46. /xxx public function guess(CandidateProvider $candidateProvider): string { $candidates = $candidateProvider->getCandidates();

    $primary = ['word' => null, 'score' => 0]; foreach ($candidates as $candidate) { $score = 0; $usedCharacters = []; foreach (str_split($candidate) as $ch) { if (!in_array($ch, $usedCharacters, true)) { $score += $this->characterScores[$ch]; $usedCharacters[] = $ch; } } if ($score > $primary['score']) { $primary['word'] = $candidate; $primary['score'] = $score; } } return $primary['word']; }
  47. / 58 ⬜ 🟨 🟨 🟩 47

  48. / 58 ⬜ 🟨 🟨 🟩 48 skill sisal 🟩

    🟨 ⬜ ⬜ 🟩 Wordle 3 ⬜ s skill 👨💻 s s i a l s
  49. /xxx public function applyFeedback(string $word, array $states): void { $characters

    = str_split($word); foreach ($this->candidates as $i => $candidate) { $candidateCharacters = str_split($candidate); for ($j = 0; $j < 5; $j++) { if ($states[$j] === 'absent') { if (in_array($characters[$j], $candidateCharacters, true)) { for ($k = 0; $k < 5; $k++) { if (in_array($states[$k], ['correct', 'present']) && $characters[$k] === $characters[$j]) { continue 2; } } unset($this->candidates[$i]); break; } } elseif ($states[$j] === 'present') { if (!in_array($characters[$j], $candidateCharacters) || $characters[$j] === $candidateCharacters[$j]) { unset($this->candidates[$i]); break; } } else { // 'correct' if ($characters[$j] !== $candidateCharacters[$j]) { unset($this->candidates[$i]); break; } } } } $this->candidates = array_values($this->candidates); }
  50. / 58 50

  51. / 58 51 🎉🎉🎉🎉🎉

  52. / 58 https://github.com/ttskch/wordler 🐙 GitHub 52

  53. / 58 53 🏃

  54. / 58 54

  55. None
  56. / 58 56

  57. / 58 57 Happy Coding ❤

  58. / 58 58 Thanks! @ttskch