Add some barely intelligent strategies
This commit is contained in:
parent
9595e62282
commit
269f16e837
7 changed files with 116 additions and 13 deletions
|
@ -4,7 +4,7 @@ require "webdrivers"
|
||||||
|
|
||||||
module Board
|
module Board
|
||||||
class WordleUnlimited
|
class WordleUnlimited
|
||||||
attr :guesses, :session
|
attr :session
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@guesses = []
|
@guesses = []
|
||||||
|
@ -50,6 +50,10 @@ module Board
|
||||||
@session.quit
|
@session.quit
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def guesses
|
||||||
|
locked_in.map { |row| row.text.tr("\n", "").downcase }
|
||||||
|
end
|
||||||
|
|
||||||
def first_guess?
|
def first_guess?
|
||||||
guesses.empty?
|
guesses.empty?
|
||||||
end
|
end
|
||||||
|
@ -58,6 +62,21 @@ module Board
|
||||||
session.find('div.feedback > div > b').text
|
session.find('div.feedback > div > b').text
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def exact_letters
|
def exact_letters
|
||||||
|
@ -78,6 +97,10 @@ module Board
|
||||||
session.has_text?(:visible, "Not a valid word", wait: 2)
|
session.has_text?(:visible, "Not a valid word", wait: 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def locked_in
|
||||||
|
session.find_all('div.RowL.RowL-locked-in', wait: 0) || []
|
||||||
|
end
|
||||||
|
|
||||||
def click(key)
|
def click(key)
|
||||||
session
|
session
|
||||||
.find('div.Game-keyboard-button', text: /\A#{key}\Z/, wait: 0)
|
.find('div.Game-keyboard-button', text: /\A#{key}\Z/, wait: 0)
|
||||||
|
|
|
@ -5,7 +5,10 @@ require_relative "outcome"
|
||||||
require_relative "board/wordle_unlimited"
|
require_relative "board/wordle_unlimited"
|
||||||
require_relative "dictionary/dictionary"
|
require_relative "dictionary/dictionary"
|
||||||
|
|
||||||
|
require_relative "strategy/most_common"
|
||||||
require_relative "strategy/naive"
|
require_relative "strategy/naive"
|
||||||
|
require_relative "strategy/template"
|
||||||
|
require_relative "strategy/vowels"
|
||||||
require_relative "strategy/wheel_of_fortune"
|
require_relative "strategy/wheel_of_fortune"
|
||||||
|
|
||||||
class Game
|
class Game
|
||||||
|
@ -13,8 +16,8 @@ class Game
|
||||||
def initialize(
|
def initialize(
|
||||||
board: Board::WordleUnlimited,
|
board: Board::WordleUnlimited,
|
||||||
dictionary: Dictionary::Dictionary,
|
dictionary: Dictionary::Dictionary,
|
||||||
start_strategy: Strategy::WheelOfFortune,
|
start_strategy: Strategy::MostCommon,
|
||||||
strategy: Strategy::Naive
|
strategy: Strategy::Template
|
||||||
)
|
)
|
||||||
@board = board.new
|
@board = board.new
|
||||||
@dictionary = dictionary.new
|
@dictionary = dictionary.new
|
||||||
|
@ -35,6 +38,7 @@ class Game
|
||||||
good_letters: board.allowed_letters,
|
good_letters: board.allowed_letters,
|
||||||
bad_letters: board.bad_letters,
|
bad_letters: board.bad_letters,
|
||||||
guesses: board.guesses,
|
guesses: board.guesses,
|
||||||
|
template: board.template,
|
||||||
)
|
)
|
||||||
|
|
||||||
board.answer(guess)
|
board.answer(guess)
|
||||||
|
|
31
lib/strategy/most_common.rb
Normal file
31
lib/strategy/most_common.rb
Normal file
|
@ -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
|
|
@ -1,16 +1,15 @@
|
||||||
module Strategy
|
module Strategy
|
||||||
class Naive
|
class Naive
|
||||||
WORD_SIZE = 5
|
attr :dictionary, :word_size
|
||||||
|
|
||||||
attr :dictionary
|
def initialize(dictionary:, word_size: 5)
|
||||||
|
|
||||||
def initialize(dictionary:)
|
|
||||||
@dictionary = dictionary
|
@dictionary = dictionary
|
||||||
|
@word_size = word_size
|
||||||
end
|
end
|
||||||
|
|
||||||
def guess(good_letters:, bad_letters:, **args)
|
def guess(good_letters:, bad_letters:, **args)
|
||||||
dictionary.words
|
dictionary.words
|
||||||
.select { |word| word.length == WORD_SIZE }
|
.select { |word| word.length == word_size }
|
||||||
.reject { |word| bad_letters.any? { |letter| word.chars.include?(letter) } }
|
.reject { |word| bad_letters.any? { |letter| word.chars.include?(letter) } }
|
||||||
.select { |word| (good_letters - word.chars).length == 0 }
|
.select { |word| (good_letters - word.chars).length == 0 }
|
||||||
.sample
|
.sample
|
||||||
|
|
24
lib/strategy/template.rb
Normal file
24
lib/strategy/template.rb
Normal file
|
@ -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
|
23
lib/strategy/vowels.rb
Normal file
23
lib/strategy/vowels.rb
Normal file
|
@ -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
|
|
@ -1,16 +1,15 @@
|
||||||
module Strategy
|
module Strategy
|
||||||
class WheelOfFortune
|
class WheelOfFortune
|
||||||
WORD_SIZE = 5
|
attr :dictionary, :word_size
|
||||||
|
|
||||||
attr :dictionary
|
def initialize(dictionary:, word_size: 5)
|
||||||
|
|
||||||
def initialize(dictionary:)
|
|
||||||
@dictionary = dictionary
|
@dictionary = dictionary
|
||||||
|
@word_size = word_size
|
||||||
end
|
end
|
||||||
|
|
||||||
def guess(**args)
|
def guess(**args)
|
||||||
dictionary.words
|
dictionary.words
|
||||||
.select { |word| word.length == WORD_SIZE }
|
.select { |word| word.length == word_size }
|
||||||
.select { |word| (start_letters - word.chars).length == 1 }
|
.select { |word| (start_letters - word.chars).length == 1 }
|
||||||
.sample
|
.sample
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue