waylon-wordle 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6db7ed70378421cf71a537df618751aaeb7ce1bf203248dbc9bb480acabc5d67
4
- data.tar.gz: 8413894c357ff8c94c4e30a1cb0ef23f0f3c2ec3f4b481413674aed3a8324b70
3
+ metadata.gz: 9b2f1328994cbe7a3b0aa4c1425893e23e53971b07b39f86019d6702379c9815
4
+ data.tar.gz: d81c4633ed5dbb9e2a4ad6512184351a6ed0c3b401ae72cdc0ed4b5ed8971a11
5
5
  SHA512:
6
- metadata.gz: a3b47236b1eec73f56138ca62f85be4f68cbf302555321374dd4128f563aa6c08d8ccd104730cca2b18ff556e0114cf6ac9e7ea0e66c47f4daf394f70b2a57b8
7
- data.tar.gz: e827295dc9c1599243ebf462b649ba00c5b32d67ec45ea7764967abb1b3e4f74c4b7c435fc2bc98511baa9bd23e0093046c52988b422c4f255b1e2bcf1159409
6
+ metadata.gz: e5b0562471f6855464c9aaae9c62e13b60cd5f15041f807c41caa859e6202c012d0d9f204d58763dd4509cca69a41d63107b6b59b1f55942fc6b0f183befe01d
7
+ data.tar.gz: 863e0b7e98e16a3c977b7ca9cd01e0475050b962e0edcaaf5ca8abf250e4f68a384d977a9c326c91e0e83be6b701903821a22d186a131d3225b64c1264592b0f
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- waylon-wordle (0.2.0)
4
+ waylon-wordle (0.3.0)
5
5
  waylon-core (~> 0.1)
6
6
 
7
7
  GEM
@@ -24,7 +24,7 @@ module Waylon
24
24
 
25
25
  def todays_wordle
26
26
  solution = solve_todays_wordle
27
- case solution.size
27
+ case solution.attempts.size
28
28
  when 1..2
29
29
  reply("I got *really* lucky today!")
30
30
  when 3
@@ -32,44 +32,40 @@ module Waylon
32
32
  when 4..5
33
33
  reply("I managed to figure it out.")
34
34
  when 6
35
- reply("I barely solved it!")
36
- else
37
- reply("Unfortunately, I didn't solve it.")
35
+ if solution.last_attempted_word == Waylon::Wordle.for_today
36
+ reply("I barely solved it!")
37
+ else
38
+ reply("Unfortunately, I didn't solve it.")
39
+ end
38
40
  end
39
41
 
40
- reply(formatted_wordle_score(solution))
42
+ reply(formatted_wordle_score(solution.attempts.map { _1[:result] }))
41
43
  end
42
44
 
43
45
  def spoil_wordle
44
46
  threaded_reply("Here's what my attempt looked like...")
45
47
  threaded_reply(
46
48
  codify(
47
- JSON.pretty_generate(solve_todays_wordle.map { |w| w.join.upcase })
49
+ JSON.pretty_generate(solve_todays_wordle.attempts.map { |w| w[:word].upcase })
48
50
  )
49
51
  )
50
52
  end
51
53
 
52
54
  private
53
55
 
54
- def formatted_wordle_score(solution)
55
- miss = "⬛"
56
- hit = "🟩"
57
- near_hit = "🟨"
58
- todays_answer = Waylon::Wordle.for_today.chars
59
- solved_in = solution.include?(todays_answer) ? solution.size : "X"
56
+ def formatted_wordle_score(scores)
57
+ translation = {
58
+ miss: "",
59
+ hit: "🟩",
60
+ near_hit: "🟨"
61
+ }
62
+
63
+ solved_in = scores.last.map(&:to_sym) == %i[hit hit hit hit hit] ? scores.size : "X"
60
64
 
61
65
  lines = ["Wordle #{Waylon::Wordle.todays_number} #{solved_in}/6"]
62
66
  lines << ""
63
- solution.each do |word|
64
- lines << word.map.with_index do |letter, index|
65
- if letter == todays_answer[index]
66
- hit
67
- elsif todays_answer.include?(letter)
68
- near_hit
69
- else
70
- miss
71
- end
72
- end.join
67
+ scores.each do |score|
68
+ lines << score.map { translation[_1.to_sym] }.join
73
69
  end
74
70
  lines.join("\n")
75
71
  end
@@ -78,6 +74,7 @@ module Waylon
78
74
  cache("solution_#{DateTime.now.new_offset("-05:00").to_date}", expires: 24 * 60 * 60) do
79
75
  solver = Waylon::Wordle::Solver.new(Waylon::Wordle.random_startword)
80
76
  solver.solve_todays_wordle
77
+ solver
81
78
  end
82
79
  end
83
80
  end
@@ -4,39 +4,81 @@ module Waylon
4
4
  module Wordle
5
5
  # Utility class for solving Wordle puzzles
6
6
  class Solver
7
- attr_reader :startword
7
+ attr_reader :startword, :answer
8
+ attr_accessor :attempts, :hits, :near_hits, :misses
8
9
 
9
10
  def initialize(startword)
10
11
  @startword = startword
12
+ @attempts = []
13
+ @hits = []
14
+ @near_hits = []
15
+ @misses = []
16
+ @answer = Waylon::Wordle.for_today.chars
11
17
  end
12
18
 
13
19
  def solve_todays_wordle
14
- answer = Waylon::Wordle.for_today.chars
15
- attempts = [startword.chars]
16
- attempts << make_attempt(answer, attempts) until attempts.last == answer || attempts.size == 6
20
+ until attempts.any? && (last_attempted_word == answer.join || attempts.size == 6)
21
+ attempts << make_attempt(answer)
22
+ end
17
23
 
18
- attempts.compact
24
+ last_attempted_word == answer.join
19
25
  end
20
26
 
21
- def make_attempt(answer, attempts)
22
- hits = []
23
- near_hits = []
24
- misses = []
25
-
26
- attempts.compact.each do |attempt|
27
- attempt.each_with_index do |letter, index|
28
- if letter == answer[index]
29
- hits[index] = letter
30
- elsif answer.include?(letter) && hits.count(letter) < answer.count(letter)
31
- near_hits[index] ||= []
32
- near_hits[index] << letter
33
- else
34
- misses << letter unless misses.include?(letter)
35
- end
27
+ def make_attempt(answer)
28
+ word = next_word
29
+ attempt = { word: word.join, result: [] }
30
+ word.each_with_index do |letter, index|
31
+ if letter == answer[index]
32
+ add_hit(letter, index, attempt)
33
+ elsif answer.include?(letter)
34
+ add_near_hit(letter, index, word, attempt)
35
+ else
36
+ add_miss(letter, attempt)
36
37
  end
37
38
  end
38
39
 
39
- find_potential_solution(hits, near_hits, misses)
40
+ attempt
41
+ end
42
+
43
+ def find_potential_solution
44
+ potential_solutions = Waylon::Wordle.vocabulary.map(&:chars).reject { _1.intersect?(misses) }
45
+
46
+ potential_solutions.select do |word|
47
+ hits_match?(hits, word) && near_hits_match?(near_hits, word)
48
+ end.sample
49
+ end
50
+
51
+ def last_attempted_word = attempts.last[:word]
52
+
53
+ private
54
+
55
+ def add_hit(letter, index, attempt)
56
+ hits[index] = letter
57
+ attempt[:result] << :hit
58
+ end
59
+
60
+ def add_near_hit(letter, index, word, attempt)
61
+ near_hits[index] ||= []
62
+ near_hits[index] << letter
63
+ attempt[:result] << (counts_as_near_hit?(word, index) ? :near_hit : :miss)
64
+ end
65
+
66
+ def add_miss(letter, attempt)
67
+ misses << letter unless misses.include?(letter)
68
+ attempt[:result] << :miss
69
+ end
70
+
71
+ def next_word = attempts.empty? ? startword.chars : find_potential_solution
72
+
73
+ def counts_as_near_hit?(word, index)
74
+ return false unless answer.include?(word[index])
75
+
76
+ answer_hit_count = answer.count(word[index])
77
+ word_hits = word.each_with_index.with_object([]) do |(letter, idx), indices|
78
+ indices << idx if letter == word[index] && answer[idx] == word[idx]
79
+ end
80
+
81
+ answer_hit_count > word_hits.size
40
82
  end
41
83
 
42
84
  def hits_match?(hits, exploded_word)
@@ -59,16 +101,6 @@ module Waylon
59
101
 
60
102
  true
61
103
  end
62
-
63
- def find_potential_solution(hits, near_hits, misses)
64
- potential_solutions = Waylon::Wordle.vocabulary.map(&:chars).reject do |word|
65
- word.intersect?(misses)
66
- end
67
-
68
- potential_solutions.select do |word|
69
- hits_match?(hits, word) && near_hits_match?(near_hits, word)
70
- end.sample
71
- end
72
104
  end
73
105
  end
74
106
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Waylon
4
4
  module Wordle
5
- VERSION = "0.2.0"
5
+ VERSION = "0.3.0"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waylon-wordle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Gnagy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-11-30 00:00:00.000000000 Z
11
+ date: 2023-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: waylon-core