From 269f16e8376eb12578e060d206dac27599cbb297 Mon Sep 17 00:00:00 2001 From: Andrew Tomaka Date: Thu, 27 Jan 2022 20:52:13 -0500 Subject: [PATCH] Add some barely intelligent strategies --- lib/board/wordle_unlimited.rb | 25 ++++++++++++++++++++++++- lib/game.rb | 8 ++++++-- lib/strategy/most_common.rb | 31 +++++++++++++++++++++++++++++++ lib/strategy/naive.rb | 9 ++++----- lib/strategy/template.rb | 24 ++++++++++++++++++++++++ lib/strategy/vowels.rb | 23 +++++++++++++++++++++++ lib/strategy/wheel_of_fortune.rb | 9 ++++----- 7 files changed, 116 insertions(+), 13 deletions(-) create mode 100644 lib/strategy/most_common.rb create mode 100644 lib/strategy/template.rb create mode 100644 lib/strategy/vowels.rb diff --git a/lib/board/wordle_unlimited.rb b/lib/board/wordle_unlimited.rb index 5408236..f7fe868 100644 --- a/lib/board/wordle_unlimited.rb +++ b/lib/board/wordle_unlimited.rb @@ -4,7 +4,7 @@ require "webdrivers" module Board class WordleUnlimited - attr :guesses, :session + attr :session def initialize @guesses = [] @@ -50,6 +50,10 @@ module Board @session.quit end + def guesses + locked_in.map { |row| row.text.tr("\n", "").downcase } + end + def first_guess? guesses.empty? end @@ -58,6 +62,21 @@ module Board session.find('div.feedback > div > b').text end + def template + return Array.new(5, "*") unless locked_in.any? + + locked_in + .last + .find_all('div.RowL-letter', wait: 0) + .map do |letter| + if letter.[]("class").split.include?("letter-correct") + letter.text.downcase + else + "*" + end + end + end + private def exact_letters @@ -78,6 +97,10 @@ module Board session.has_text?(:visible, "Not a valid word", wait: 2) end + def locked_in + session.find_all('div.RowL.RowL-locked-in', wait: 0) || [] + end + def click(key) session .find('div.Game-keyboard-button', text: /\A#{key}\Z/, wait: 0) diff --git a/lib/game.rb b/lib/game.rb index 299df17..cdbf3e9 100644 --- a/lib/game.rb +++ b/lib/game.rb @@ -5,7 +5,10 @@ require_relative "outcome" require_relative "board/wordle_unlimited" require_relative "dictionary/dictionary" +require_relative "strategy/most_common" require_relative "strategy/naive" +require_relative "strategy/template" +require_relative "strategy/vowels" require_relative "strategy/wheel_of_fortune" class Game @@ -13,8 +16,8 @@ class Game def initialize( board: Board::WordleUnlimited, dictionary: Dictionary::Dictionary, - start_strategy: Strategy::WheelOfFortune, - strategy: Strategy::Naive + start_strategy: Strategy::MostCommon, + strategy: Strategy::Template ) @board = board.new @dictionary = dictionary.new @@ -35,6 +38,7 @@ class Game good_letters: board.allowed_letters, bad_letters: board.bad_letters, guesses: board.guesses, + template: board.template, ) board.answer(guess) diff --git a/lib/strategy/most_common.rb b/lib/strategy/most_common.rb new file mode 100644 index 0000000..3c859bb --- /dev/null +++ b/lib/strategy/most_common.rb @@ -0,0 +1,31 @@ +module Strategy + class MostCommon + attr :dictionary, :word_size + + def initialize(dictionary:, word_size: 5) + @dictionary = dictionary + @word_size = word_size + end + + def guess(**args) + dictionary.words + .select { |word| word.length == word_size } + .select { |word| (most_common_letters - word.chars).length == 0 } + .sample + end + + private + + def most_common_letters + @most_common_letters ||= dictionary.words + .select { |word| word.length == word_size } + .map(&:chars) + .flatten + .tally + .sort_by { |letter, count| count } + .reverse + .map(&:first) + .first(5) + end + end +end diff --git a/lib/strategy/naive.rb b/lib/strategy/naive.rb index c55280a..984758f 100644 --- a/lib/strategy/naive.rb +++ b/lib/strategy/naive.rb @@ -1,16 +1,15 @@ module Strategy class Naive - WORD_SIZE = 5 + attr :dictionary, :word_size - attr :dictionary - - def initialize(dictionary:) + def initialize(dictionary:, word_size: 5) @dictionary = dictionary + @word_size = word_size end def guess(good_letters:, bad_letters:, **args) dictionary.words - .select { |word| word.length == WORD_SIZE } + .select { |word| word.length == word_size } .reject { |word| bad_letters.any? { |letter| word.chars.include?(letter) } } .select { |word| (good_letters - word.chars).length == 0 } .sample diff --git a/lib/strategy/template.rb b/lib/strategy/template.rb new file mode 100644 index 0000000..0326154 --- /dev/null +++ b/lib/strategy/template.rb @@ -0,0 +1,24 @@ +module Strategy + class Template + attr :dictionary, :word_size + + def initialize(dictionary:, word_size: 5) + @dictionary = dictionary + @word_size = word_size + end + + def guess(good_letters:, bad_letters:, guesses:, template:, **args) + dictionary.words + .select { |word| word.length == word_size } + .reject { |word| bad_letters.any? { |letter| word.chars.include?(letter) } } + .select { |word| (good_letters - word.chars).length == 0 } + .reject { |word| guesses.include?(word) } + .select do |word| + template.each_with_index.all? do |letter, index| + letter == "*" || letter == word.chars[index] + end + end + .sample + end + end +end diff --git a/lib/strategy/vowels.rb b/lib/strategy/vowels.rb new file mode 100644 index 0000000..ce58c72 --- /dev/null +++ b/lib/strategy/vowels.rb @@ -0,0 +1,23 @@ +module Strategy + class Vowels + attr :dictionary, :word_size + + def initialize(dictionary:, word_size: 5) + @dictionary = dictionary + @word_size = word_size + end + + def guess(**args) + dictionary.words + .select { |word| word.length == word_size } + .select { |word| (vowels - word.chars).length <= 2 } + .sample + end + + private + + def vowels + %w(a e i o u y) + end + end +end diff --git a/lib/strategy/wheel_of_fortune.rb b/lib/strategy/wheel_of_fortune.rb index 6008b34..ea0ad56 100644 --- a/lib/strategy/wheel_of_fortune.rb +++ b/lib/strategy/wheel_of_fortune.rb @@ -1,16 +1,15 @@ module Strategy class WheelOfFortune - WORD_SIZE = 5 + attr :dictionary, :word_size - attr :dictionary - - def initialize(dictionary:) + def initialize(dictionary:, word_size: 5) @dictionary = dictionary + @word_size = word_size end def guess(**args) dictionary.words - .select { |word| word.length == WORD_SIZE } + .select { |word| word.length == word_size } .select { |word| (start_letters - word.chars).length == 1 } .sample end