I have run across a strange bug I'm not sure how to solve. I am trying to make a program that solves Wordle in the browser using Ruby and Selenium. I noticed that starting with the second guess, the program would just keep guessing the same word instead of incorporating feedback and fetching a new word. So I added a byebug statement to see what was going on, and then it started working. If I remove the byebug statement, the bug appears again. I couldn't believe it so I pushed to Github and cloned on another computer and the same thing happened again. Basically, as long as I put a byebug statement anywhere after line 24, the code works as expected. Here is the code.
require 'webdrivers'
require './words.rb'
require 'byebug'
class WordleSolver
attr_reader :driver
def initialize
options = Selenium::WebDriver::Options.chrome
@driver = Selenium::WebDriver.for :chrome, options: options
@driver.manage.timeouts.implicit_wait = 10
@driver.get 'https://www.nytimes.com/games/wordle/index.html'
@game_div = driver.find_element(css: 'game-app').shadow_root.find_element(css: 'div#game')
@words = PossibleWords::WORDS
@word = ['', '', '', '', '']
@present = {}
@absent = []
@current_row = 1
end
def solve
close_modal
guess('store')
5.times do
get_feedback
break if game_won?
next_guess = formulate_guess
guess(next_guess)
sleep(3)
end
end
def game_won?
@word.each { |letter| return false if letter == '' }
true
end
def close_modal
@game_div.find_element(css: 'game-modal').shadow_root.find_element(css: 'div.close-icon').click
end
def guess(word)
@driver.action.send_keys(word).send_keys(:enter).perform
end
def formulate_guess
@words.each do |word|
return word if valid_guess?(word)
end
'guess'
end
def valid_guess?(word)
@word.each_with_index do |letter, index|
if letter != ''
return false if word[index] != letter
end
end
@absent.each do |letter|
return false if word.include?(letter)
end
@present.each do |letter, incorrect_positions|
return false if !word.include?(letter)
incorrect_positions.each do |position|
return false if word[position] == letter
end
end
end
def get_feedback
row = @game_div.find_element(css: "game-row:nth-of-type(#{@current_row})").shadow_root
1.upto(5) do |n|
tile = row.find_element(css: "game-tile:nth-of-type(#{n})")
letter = tile.attribute("letter")
evaluation = tile.attribute("evaluation")
add_feedback(letter, evaluation, n - 1)
end
@current_row += 1
end
def add_feedback(letter, evaluation, position)
case evaluation
when 'absent'
@absent.push(letter)
when 'present'
if @present[letter]
@present[letter].push(position)
else
@present[letter] = [position]
end
when 'correct'
@present.delete(letter)
@word[position] = letter if @word[position] == ''
end
end
end
begin
solver = WordleSolver.new
solver.solve
sleep(5)
ensure
solver.driver.quit
end
TLDR when I add a byebug statement to my code the bug I was investigating disappears
The comment by BroiSatse solved my issue. By adding a byebug statement I was also causing the program to wait, giving it time to synchronize with the browser, which fixed the bug.