waylon-wordle 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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