From b4a061c6d7bce413978ba2be10e5d42468cc6bf4 Mon Sep 17 00:00:00 2001 From: Andrew Tomaka Date: Wed, 26 Jan 2022 23:16:38 -0500 Subject: [PATCH] Initial commit --- .gitignore | 4 ++ Gemfile | 7 +++ Gemfile.lock | 54 ++++++++++++++++++++ finder.rb | 140 +++++++++++++++++++++++++++++++++++++++++++++++++++ manual.rb | 53 +++++++++++++++++++ 5 files changed, 258 insertions(+) create mode 100644 .gitignore create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100755 finder.rb create mode 100644 manual.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac3f340 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +dictionary.txt +bad-in-dictionary.txt + +*.log diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..a5e9418 --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +source "https://rubygems.org" + +gem "pry" + +gem "capybara" +gem "selenium-webdriver" +gem "webdrivers" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..2905875 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,54 @@ +GEM + remote: https://rubygems.org/ + specs: + addressable (2.8.0) + public_suffix (>= 2.0.2, < 5.0) + capybara (3.36.0) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + childprocess (4.1.0) + coderay (1.1.3) + matrix (0.4.2) + method_source (1.0.0) + mini_mime (1.1.2) + nokogiri (1.13.1-x86_64-linux) + racc (~> 1.4) + pry (0.14.1) + coderay (~> 1.1) + method_source (~> 1.0) + public_suffix (4.0.6) + racc (1.6.0) + rack (2.2.3) + rack-test (1.1.0) + rack (>= 1.0, < 3) + regexp_parser (2.2.0) + rexml (3.2.5) + rubyzip (2.3.2) + selenium-webdriver (4.1.0) + childprocess (>= 0.5, < 5.0) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2) + webdrivers (5.0.0) + nokogiri (~> 1.6) + rubyzip (>= 1.3.0) + selenium-webdriver (~> 4.0) + xpath (3.2.0) + nokogiri (~> 1.8) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + capybara + pry + selenium-webdriver + webdrivers + +BUNDLED WITH + 2.2.22 diff --git a/finder.rb b/finder.rb new file mode 100755 index 0000000..5bd4a96 --- /dev/null +++ b/finder.rb @@ -0,0 +1,140 @@ +#!/usr/bin/env ruby + +require "pry" +require "logger" + +require "capybara" +require "selenium-webdriver" +require "webdrivers" + +@logger = Logger.new("run.log") +@logger.info("Beginning new run") + +def measure(label, &block) + start = Process.clock_gettime(Process::CLOCK_MONOTONIC) + result = yield + finish = Process.clock_gettime(Process::CLOCK_MONOTONIC) + + # @logger.info("#{label.to_s}: #{finish - start} seconds") + + result +end + +bad_words = File.readlines("bad-in-dictionary.txt").map(&:strip) +all_words = File.readlines("dictionary.txt").map(&:strip) - bad_words +word_size = 5 +ignore = [] + +session = Capybara::Session.new(:selenium_chrome) +session.visit "https://www.wordleunlimited.com/" + +loop do + bad_letters = measure(:bad) do + session + .find_all('div.Game-keyboard-button.letter-absent', wait: 0) + .map(&:text) + .map(&:downcase) + end + exact_letters = measure(:exact) do + session + .find_all('div.Game-keyboard-button.letter-correct', wait: 0) + .map(&:text) + .map(&:downcase) + end + elsewhere_letters = measure(:elsewhere) do + session + .find_all('div.Game-keyboard-button.letter-elsewhere', wait: 0) + .map(&:text) + .map(&:downcase) + end + letters = exact_letters + elsewhere_letters + locked_in = measure(:locked) do + session.find_all('div.RowL.RowL-locked-in', wait: 0) + end + guesses = locked_in.map { |row| row.text.tr("\n", "").downcase } + template = measure(:template) do + if 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 + else + Array.new(5, "*") + end + end + elsewhere_template = Array.new(5) { [] } + measure(:block_letters) do + if locked_in.any? + locked_in.each do |guess| + guess + .find_all('div.RowL-letter', wait: 0).each_with_index do |letter, index| + if letter.[]("class").split.include?("letter-elsewhere") || letter.[]("class").split.include?("letter-absent") + elsewhere_template[index] << letter.text.downcase + end + end + end + end + end + if template.none? { |letter| letter == "*" } + @logger.info("You won with #{guesses.join(', ')}") + session.find('div.Game-keyboard-button', text: 'Enter', wait: 0).click() + next + end + + if letters.none? && locked_in.none? + letters = "aetsr".chars + end + + if locked_in.count == 6 + @logger.info("You lost #{guesses.join(', ')}") + session.find('div.Game-keyboard-button', text: 'Enter', wait: 0).click() + next + end + + guess = all_words + .select { |word| word.length == word_size } + .reject { |word| bad_letters.any? { |letter| word.chars.include?(letter) } } + .select { |word| (letters - word.chars).length == 0 } + .reject { |word| ignore.include?(word) } + .reject { |word| guesses.include?(word) } + .select do |word| + template.each_with_index.all? do |letter, index| + letter == "*" || letter == word.chars[index] + end + end + .select do |word| + word.chars.each_with_index.all? do |letter, index| + (elsewhere_template[index] - [letter]) == elsewhere_template[index] + end + end + .sample + + measure(:guess) do + guess.chars.map(&:upcase).each do |letter| + session + .find('div.Game-keyboard-button', text: /\A#{letter}\Z/, wait: 0) + .click() + end + session + .find('div.Game-keyboard-button', text: 'Enter', wait: 0) + .click() + end + + measure(:not_found) do + if session.has_text?(:visible, "Not a valid word", wait: 2) + ignore << guess + File.open('bad-in-dictionary.txt', 'a') do |file| + file.write("#{guess}\n") + end + 5.times do + session.find('div.Game-keyboard-button', text: '⌫', wait: 0).click() + end + end + end +end diff --git a/manual.rb b/manual.rb new file mode 100644 index 0000000..3dff4a6 --- /dev/null +++ b/manual.rb @@ -0,0 +1,53 @@ +#!/usr/bin/env ruby + +require 'pry' + +all_words = File.readlines("dictionary.txt") +lower = ('a'..'z').to_a +upper = ('A'..'Z').to_a + +guesses = [] +letters = [] +bad_letters = [] +template = [] +while guesses.size < 6 + print "Your guess: " + guess = gets.strip + print "New bad letters: " + new_bad_letters = gets.strip.chars + + if guesses.size == 0 + guesses << guess + length = guess.length + template = Array.new(length, "*") + end + + if guess == "X" + guesses.pop + else + bad_letters += new_bad_letters + letters += guess.chars + .reject { |letter| new_bad_letters.include?(letter) } + .map(&:downcase) + + guess.chars.each_with_index do |letter, index| + template[index] = letter if upper.include?(letter) + end + end + + guesses << all_words + .map(&:strip) + .select { |word| word.length == length } + .reject { |word| bad_letters.any? { |letter| word.chars.include?(letter) } } + .select { |word| (letters - word.chars).length == 0 } + .select do |word| + template.map(&:downcase).each_with_index.all? do |letter, index| + letter == "*" || letter == word[index] + end + end.sample + + puts "You should guess '#{guesses.last}'" +end + + +puts guesses