Use dependency injection to provide various things
This commit is contained in:
parent
b4a061c6d7
commit
9755aed007
7 changed files with 245 additions and 0 deletions
12
driver.rb
Normal file
12
driver.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
#!/usr/bin/env ruby
|
||||
|
||||
require_relative "lib/game"
|
||||
|
||||
game = Game.new
|
||||
|
||||
trap "SIGINT" do
|
||||
game.exit!
|
||||
exit 130
|
||||
end
|
||||
|
||||
game.play
|
91
lib/board/wordle_unlimited.rb
Normal file
91
lib/board/wordle_unlimited.rb
Normal file
|
@ -0,0 +1,91 @@
|
|||
require "capybara"
|
||||
require "selenium-webdriver"
|
||||
require "webdrivers"
|
||||
|
||||
module Board
|
||||
class WordleUnlimited
|
||||
attr :guesses, :session
|
||||
|
||||
def initialize
|
||||
@guesses = []
|
||||
@session = Capybara::Session.new(:selenium_chrome)
|
||||
end
|
||||
|
||||
def start
|
||||
session.visit("https://www.wordleunlimited.com/")
|
||||
end
|
||||
|
||||
def answer(guess)
|
||||
guess.chars.map(&:upcase).each { |letter| click(letter) }
|
||||
click("Enter")
|
||||
|
||||
answer_invalid? ? clear_answer! : @guesses << guess
|
||||
end
|
||||
|
||||
def reset!
|
||||
@guesses = []
|
||||
click("Enter")
|
||||
end
|
||||
|
||||
def winner?
|
||||
session.has_text?(:visible, "Winner!", wait: 0)
|
||||
end
|
||||
|
||||
def loser?
|
||||
session.has_text?(:visible, "You lost!", wait: 0)
|
||||
end
|
||||
|
||||
def allowed_letters
|
||||
(exact_letters + elsewhere_letters).uniq
|
||||
end
|
||||
|
||||
def bad_letters
|
||||
session
|
||||
.find_all('div.Game-keyboard-button.letter-absent', wait: 0)
|
||||
.map(&:text)
|
||||
.map(&:downcase)
|
||||
end
|
||||
|
||||
def close!
|
||||
@session.quit
|
||||
end
|
||||
|
||||
def first_guess?
|
||||
guesses.empty?
|
||||
end
|
||||
|
||||
def correct_answer
|
||||
session.find('div.feedback > div > b').text
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def exact_letters
|
||||
session
|
||||
.find_all('div.Game-keyboard-button.letter-correct', wait: 0)
|
||||
.map(&:text)
|
||||
.map(&:downcase)
|
||||
end
|
||||
|
||||
def elsewhere_letters
|
||||
session
|
||||
.find_all('div.Game-keyboard-button.letter-elsewhere', wait: 0)
|
||||
.map(&:text)
|
||||
.map(&:downcase)
|
||||
end
|
||||
|
||||
def answer_invalid?
|
||||
session.has_text?(:visible, "Not a valid word", wait: 2)
|
||||
end
|
||||
|
||||
def click(key)
|
||||
session
|
||||
.find('div.Game-keyboard-button', text: /\A#{key}\Z/, wait: 0)
|
||||
.click()
|
||||
end
|
||||
|
||||
def clear_answer!
|
||||
5.times { click("⌫") }
|
||||
end
|
||||
end
|
||||
end
|
13
lib/dictionary/dictionary.rb
Normal file
13
lib/dictionary/dictionary.rb
Normal file
|
@ -0,0 +1,13 @@
|
|||
module Dictionary
|
||||
class Dictionary
|
||||
attr_accessor :file
|
||||
|
||||
def initialize(file: "dictionary.txt")
|
||||
@file = file
|
||||
end
|
||||
|
||||
def words
|
||||
@words ||= File.readlines(file).map(&:strip)
|
||||
end
|
||||
end
|
||||
end
|
69
lib/game.rb
Normal file
69
lib/game.rb
Normal file
|
@ -0,0 +1,69 @@
|
|||
require "debug"
|
||||
|
||||
require_relative "outcome"
|
||||
|
||||
require_relative "board/wordle_unlimited"
|
||||
require_relative "dictionary/dictionary"
|
||||
|
||||
require_relative "strategy/naive"
|
||||
require_relative "strategy/wheel_of_fortune"
|
||||
|
||||
class Game
|
||||
attr_reader :board, :dictionary, :start_strategy, :strategy, :outcomes
|
||||
def initialize(
|
||||
board: Board::WordleUnlimited,
|
||||
dictionary: Dictionary::Dictionary,
|
||||
start_strategy: Strategy::WheelOfFortune,
|
||||
strategy: Strategy::Naive
|
||||
)
|
||||
@board = board.new
|
||||
@dictionary = dictionary.new
|
||||
@start_strategy = start_strategy.new(dictionary: @dictionary)
|
||||
@strategy = strategy.new(dictionary: @dictionary)
|
||||
|
||||
@outcomes = []
|
||||
end
|
||||
|
||||
def play
|
||||
board.start
|
||||
|
||||
loop do
|
||||
guess_strategy = board.first_guess? ? start_strategy : strategy
|
||||
|
||||
guess = guess_strategy
|
||||
.guess(
|
||||
good_letters: board.allowed_letters,
|
||||
bad_letters: board.bad_letters,
|
||||
guesses: board.guesses,
|
||||
)
|
||||
|
||||
board.answer(guess)
|
||||
|
||||
if board.winner?
|
||||
@outcomes << Outcome.new(
|
||||
state: :win,
|
||||
correct: board.correct_answer,
|
||||
guesses: board.guesses,
|
||||
)
|
||||
board.reset!
|
||||
elsif board.loser?
|
||||
@outcomes << Outcome.new(
|
||||
state: :loss,
|
||||
correct: board.correct_answer,
|
||||
guesses: board.guesses,
|
||||
)
|
||||
board.reset!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def exit!
|
||||
board.close!
|
||||
|
||||
puts
|
||||
puts "=" * 80
|
||||
puts "Won: #{outcomes.select(&:win?).count}"
|
||||
puts "Lost: #{outcomes.select(&:loss?).count}"
|
||||
puts "=" * 80
|
||||
end
|
||||
end
|
17
lib/outcome.rb
Normal file
17
lib/outcome.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
class Outcome
|
||||
attr :correct, :guesses, :state
|
||||
|
||||
def initialize(state:, correct:, guesses:)
|
||||
@state = state
|
||||
@correct = correct
|
||||
@guesses = guesses
|
||||
end
|
||||
|
||||
def win?
|
||||
state == :win
|
||||
end
|
||||
|
||||
def loss?
|
||||
state == :loss
|
||||
end
|
||||
end
|
19
lib/strategy/naive.rb
Normal file
19
lib/strategy/naive.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
module Strategy
|
||||
class Naive
|
||||
WORD_SIZE = 5
|
||||
|
||||
attr :dictionary
|
||||
|
||||
def initialize(dictionary:)
|
||||
@dictionary = dictionary
|
||||
end
|
||||
|
||||
def guess(good_letters:, bad_letters:, **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 }
|
||||
.sample
|
||||
end
|
||||
end
|
||||
end
|
24
lib/strategy/wheel_of_fortune.rb
Normal file
24
lib/strategy/wheel_of_fortune.rb
Normal file
|
@ -0,0 +1,24 @@
|
|||
module Strategy
|
||||
class WheelOfFortune
|
||||
WORD_SIZE = 5
|
||||
|
||||
attr :dictionary
|
||||
|
||||
def initialize(dictionary:)
|
||||
@dictionary = dictionary
|
||||
end
|
||||
|
||||
def guess(**args)
|
||||
dictionary.words
|
||||
.select { |word| word.length == WORD_SIZE }
|
||||
.select { |word| (start_letters - word.chars).length == 1 }
|
||||
.sample
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def start_letters
|
||||
%w(r s t l n e)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue