wordle_decoder 0.1.1 → 0.1.4
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 +4 -4
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +6 -2
- data/Gemfile.lock +1 -1
- data/README.md +22 -5
- data/Rakefile +2 -2
- data/bin/wordle_decoder +94 -76
- data/lib/wordle_decoder/version.rb +1 -1
- data/lib/wordle_decoder/word.rb +1 -1
- data/lib/wordle_decoder/word_search.rb +1 -1
- data/lib/wordle_decoder/wordle_share.rb +40 -4
- data/lib/wordle_decoder.rb +8 -12
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b287c675238c8e02b76dd2fcb7c6811837831e2245954a9465a2f1d6634ecb5
|
4
|
+
data.tar.gz: 1d0f11cdd67b6443ebc6362daf666e82006c361b23a9847ee8c1a3020eeea1ad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4dcdc6aa0b31fd576fc973bd35ff7681ae4e054009d62f81afa00a25088e06e81e4c128068de5c524d4e30668b49bd0847e2354f5f614e80fab0e48a7c56c75d
|
7
|
+
data.tar.gz: d414927380ff8e1832c7eb70b1e9f632dc41357d586f1f9674cda5f8161e0d6e2c3ff393677b45fab47155d2b56dac1f6edf4a446003da4b4b2fdbf2399af6aa
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
-
## [0.1.
|
3
|
+
## [0.1.4] - 2022-03-06
|
4
4
|
|
5
|
-
-
|
5
|
+
- Deal with weird input chars - https://github.com/mattruzicka/wordle_decoder/issues/2
|
6
|
+
|
7
|
+
## [0.1.3] - 2022-03-05
|
8
|
+
|
9
|
+
- Support shortcode emojis - https://github.com/mattruzicka/wordle_decoder/pull/1
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,19 +1,36 @@
|
|
1
1
|
# Wordle Decoder
|
2
2
|
|
3
|
-
It guesses your guesses based on all those little
|
3
|
+
It guesses your guesses based on all those little square emojis that we now love to share.
|
4
4
|
|
5
|
-
Given your Wordle share
|
5
|
+
Given your Wordle share, the decoder will spit back the five-letter words it thinks you played with some degree of confidence.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
|
+
Have Ruby 2.7 or later installed, then run the following at the command line:
|
10
|
+
|
9
11
|
$ gem install wordle_decoder
|
10
12
|
|
11
13
|
## Usage
|
12
14
|
|
13
|
-
After
|
15
|
+
After installing the gem, run `wordle_decoder` at the command line like so:
|
14
16
|
|
15
17
|
$ wordle_decoder
|
16
18
|
|
17
|
-
|
19
|
+
You'll be prompted to share your wordle. Go ahead and paste in your wordle share text. The share text should look something like this:
|
20
|
+
|
21
|
+
```
|
22
|
+
Wordle 258 3/6
|
23
|
+
|
24
|
+
⬛⬛🟨⬛🟨
|
25
|
+
⬛🟩🟩🟩⬛
|
26
|
+
🟩🟩🟩🟩🟩
|
27
|
+
```
|
28
|
+
You'll then be prompted to confirm the word of the day, or if it couldn't figure it out, you'll be asked for it. After that, it'll _try_ to guess your guesses.
|
29
|
+
|
30
|
+
## Why?
|
31
|
+
|
32
|
+
I wasn't sure if something like this was possible and thought it'd be a fun project to build. It does a pretty good job, at least some of the time... I built an excuse to play Wordle.
|
33
|
+
|
34
|
+
Enjoy,
|
18
35
|
|
19
|
-
|
36
|
+
[@mattruzicka](https://twitter.com/mattruzicka)
|
data/Rakefile
CHANGED
@@ -20,7 +20,7 @@ task default: %i[test rubocop]
|
|
20
20
|
task :create_word_search_files do
|
21
21
|
sorted_words = load_words_sorted_by_frequency
|
22
22
|
most_common_words = sorted_words.pop(3_000)
|
23
|
-
most_common_words, less_common_words = most_common_words.partition { |r| r.
|
23
|
+
most_common_words, less_common_words = most_common_words.partition { |r| r.chars.uniq.count == 5 }
|
24
24
|
File.write(lib_path("most_common_words.txt"), most_common_words.join("\n"))
|
25
25
|
File.write(lib_path("less_common_words.txt"), less_common_words.join("\n"))
|
26
26
|
File.write(lib_path("least_common_words.txt"), sorted_words.join("\n"))
|
@@ -29,7 +29,7 @@ end
|
|
29
29
|
task :output_most_common_letters do
|
30
30
|
words = load_wordle_words("allowed_answers.txt")
|
31
31
|
words.concat load_wordle_words("allowed_guesses.txt")
|
32
|
-
letter_count_tally = words.flat_map { _1.
|
32
|
+
letter_count_tally = words.flat_map { _1.chars }.tally
|
33
33
|
letter_count_tally = letter_count_tally.sort_by { -_2 }
|
34
34
|
puts letter_count_tally.first(10).map { _1.first }.join(" ")
|
35
35
|
end
|
data/bin/wordle_decoder
CHANGED
@@ -8,16 +8,28 @@ require "cli/ui"
|
|
8
8
|
|
9
9
|
CLI::UI::StdoutRouter.enable
|
10
10
|
|
11
|
-
print CLI::UI.fmt("\n
|
11
|
+
print CLI::UI.fmt("\n Share your wordle:\n\n{{blue:>}} ")
|
12
12
|
|
13
13
|
input_lines = []
|
14
14
|
until WordleDecoder::WordleShare.final_line?(input_line = gets)
|
15
15
|
input_lines << input_line
|
16
|
+
if WordleDecoder::WordleShare.exit_program?(input_line)
|
17
|
+
puts "\n Goodbye!\n\n"
|
18
|
+
return
|
19
|
+
elsif WordleDecoder::WordleShare.needs_help?(input_line)
|
20
|
+
help_text = WordleDecoder::WordleShare.help_to_terminal
|
21
|
+
input_lines << "\n"
|
22
|
+
input_lines << help_text
|
23
|
+
input_lines << "\n"
|
24
|
+
print CLI::UI.fmt(help_text)
|
25
|
+
elsif input_lines.all? { |l| l.strip.empty? }
|
26
|
+
print CLI::UI.fmt("{{blue:>}} ")
|
27
|
+
end
|
16
28
|
end
|
17
29
|
input_lines << input_line
|
18
30
|
|
19
|
-
clear_pasted_text_lines = input_lines.reverse_each.map { |line| "\033[A\r
|
20
|
-
clear_pasted_text_lines << "\033[A\r"
|
31
|
+
clear_pasted_text_lines = input_lines.reverse_each.map { |line| "\033[A\r #{" " * line.length}" }
|
32
|
+
clear_pasted_text_lines << "\033[A\r "
|
21
33
|
puts clear_pasted_text_lines.join
|
22
34
|
|
23
35
|
wordle_share = WordleDecoder::WordleShare.new(input_lines)
|
@@ -47,78 +59,84 @@ CLI::UI::Spinner.spin("Acting like I'm doing something.") do |spinner|
|
|
47
59
|
end
|
48
60
|
spinner.update_title("Fine, I'll do it")
|
49
61
|
|
50
|
-
decoder.
|
51
|
-
|
62
|
+
if decoder.best_guess
|
63
|
+
spinner.update_title("\r I decoded your wordle hints!}}")
|
64
|
+
else
|
65
|
+
no_guess_messages = ["You stumped me!", "Are you messing with me?", "Are you sure that was the word of the day?"]
|
66
|
+
spinner.update_title("\r 🤨 #{no_guess_messages.sample}}}")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
if decoder.best_guess
|
71
|
+
puts CLI::UI.fmt("\n {{blue:{{underline:Guesses}} {{underline:Confidence}}}}")
|
72
|
+
puts CLI::UI.fmt(decoder.to_terminal)
|
52
73
|
end
|
53
74
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
puts CLI::UI.fmt("\n #{comments.sample}\n " \
|
124
|
-
"{{blue:https://github.com/mattruzicka/wordle_decoder}}}}\n\n")
|
75
|
+
salutations = ["Maybe some of those are your words!",
|
76
|
+
"I tried!",
|
77
|
+
"How'd I do?",
|
78
|
+
"Did I get it?",
|
79
|
+
"I'm also guessing you're great!",
|
80
|
+
"Don't spill your coffee.",
|
81
|
+
"Shout out to friends for sending me their wordles.",
|
82
|
+
"Shout out to https://www.youtube.com/watch?v=v68zYyaEmEA for word frequency source.",
|
83
|
+
"I hope you had a great time.",
|
84
|
+
"Hope to see you again.",
|
85
|
+
"Was great guessing you.",
|
86
|
+
"Thinking about heading to sleep.",
|
87
|
+
"Sometimes I just throw out mostly random stuff.",
|
88
|
+
"I didn't mean to offend.",
|
89
|
+
"I try not to be random...",
|
90
|
+
"I'm open source :)",
|
91
|
+
"I'd fork you to make me better.",
|
92
|
+
"TLDR: Another programmer played wordle.",
|
93
|
+
"How was I with my words?",
|
94
|
+
"I'm written in Ruby and bite like a python.",
|
95
|
+
"Here's an emoji ❤️",
|
96
|
+
"🤔 🤨 🧐",
|
97
|
+
"All my thinking to you.",
|
98
|
+
"I've learned about wordle and your people.",
|
99
|
+
"I'm not learning anything at the moment.",
|
100
|
+
"I wish I had time to machine learn you ;)",
|
101
|
+
"No, you have a great personality!",
|
102
|
+
"This one might be weird, if it's your first.",
|
103
|
+
"Is my strategy as good as yours?",
|
104
|
+
"I'm biased, but so are you!",
|
105
|
+
"I'd love to learn your strategy ;)",
|
106
|
+
"I'd grow neurons for you.",
|
107
|
+
"How well can you play without me guessing?",
|
108
|
+
"If you're seeing this, we probably know each other.",
|
109
|
+
"I hope things aren't getting too weird.",
|
110
|
+
"❤️ ❤️ ❤️",
|
111
|
+
"No, you're great!",
|
112
|
+
"Do you decode often?",
|
113
|
+
"All the best five-letter words to you!",
|
114
|
+
"My friends call me the wordle decoder.",
|
115
|
+
"Everything I am is written.",
|
116
|
+
"May my written code speak truly.",
|
117
|
+
"Who guessed better?",
|
118
|
+
"No excuse, but my thoughts are in a constant array.",
|
119
|
+
"Your words complete me.",
|
120
|
+
"Like peering into a soul.",
|
121
|
+
"I hope I didn't embarass myself.",
|
122
|
+
"I hope I didn't embarrass myself.",
|
123
|
+
"I hope I didn't embaras myself.",
|
124
|
+
"Can you decode my five letter word?",
|
125
|
+
"Sometimes I'm off by one...",
|
126
|
+
"Something's fishy...",
|
127
|
+
"Did you put something on me?",
|
128
|
+
"I'm only wrong about five letter words...",
|
129
|
+
"Your words are beautiful.",
|
130
|
+
"You make this wordle a better place!",
|
131
|
+
"What in the wordle was I thinking?",
|
132
|
+
"Those words you gave me were so good.",
|
133
|
+
"I truly enjoyed those words, thank you!",
|
134
|
+
"What lovely words you have!",
|
135
|
+
"I hope my words were as good as yours!",
|
136
|
+
"Please enjoy the rest of your day!",
|
137
|
+
"I may not be positive about your words, but I am about you!",
|
138
|
+
"Thank you for spending time with me!",
|
139
|
+
"I enjoyed our time together!"].freeze
|
140
|
+
|
141
|
+
puts CLI::UI.fmt("\n\n #{salutations.sample}\n " \
|
142
|
+
"{{blue:https://github.com/mattruzicka/wordle_decoder}}}}\n\n")
|
data/lib/wordle_decoder/word.rb
CHANGED
@@ -2,12 +2,31 @@
|
|
2
2
|
|
3
3
|
class WordleDecoder
|
4
4
|
class WordleShare
|
5
|
-
ANSWER_LINES = ["🟩🟩🟩🟩🟩",
|
5
|
+
ANSWER_LINES = ["🟩🟩🟩🟩🟩",
|
6
|
+
"ggggg",
|
7
|
+
":large_green_square:" * 5].freeze
|
6
8
|
|
7
9
|
def self.final_line?(input_lines)
|
8
10
|
ANSWER_LINES.any? { input_lines.include?(_1) }
|
9
11
|
end
|
10
12
|
|
13
|
+
NEEDS_HELP_INPUTS = %w[help what wordle wat ? man okay yes no test].freeze
|
14
|
+
|
15
|
+
def self.needs_help?(input)
|
16
|
+
NEEDS_HELP_INPUTS.include?(input.strip.downcase)
|
17
|
+
end
|
18
|
+
|
19
|
+
EXIT_PROGRAM_INPUTS = %w[exit no nvm].freeze
|
20
|
+
|
21
|
+
def self.exit_program?(input)
|
22
|
+
EXIT_PROGRAM_INPUTS.include?(input.strip)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.help_to_terminal
|
26
|
+
"\n {{italic:Copy and paste those 🟨, 🟩, and ⬛" \
|
27
|
+
" emojis from your wordle share.}} \n\n{{blue:>}} "
|
28
|
+
end
|
29
|
+
|
11
30
|
def self.wordle_answers
|
12
31
|
@wordle_answers ||= load_worldle_ansers
|
13
32
|
end
|
@@ -36,12 +55,14 @@ class WordleDecoder
|
|
36
55
|
|
37
56
|
def find_answer
|
38
57
|
title_line = input_lines.detect { |line| line.match?(GAME_DAY_REGEX) }
|
58
|
+
return unless title_line
|
59
|
+
|
39
60
|
game_day = title_line.match(GAME_DAY_REGEX).captures.first&.to_i
|
40
61
|
self.answer = self.class.wordle_answers[game_day]
|
41
62
|
end
|
42
63
|
|
43
64
|
def answer_chars
|
44
|
-
@answer_chars ||= answer&.strip&.
|
65
|
+
@answer_chars ||= answer&.strip&.chars
|
45
66
|
end
|
46
67
|
|
47
68
|
def hint_lines
|
@@ -80,11 +101,26 @@ class WordleDecoder
|
|
80
101
|
VALID_HINT_CHARS = WordPosition::EMOJI_HINT_CHARS.to_a.flatten.uniq
|
81
102
|
|
82
103
|
def parse_wordle_lines!
|
83
|
-
input_lines.
|
84
|
-
line
|
104
|
+
input_lines.filter_map do |line|
|
105
|
+
line = normalize_wordle_line(line)
|
106
|
+
line if line.each_char.all? { |c| VALID_HINT_CHARS.include?(c) }
|
85
107
|
end
|
86
108
|
end
|
87
109
|
|
110
|
+
def normalize_wordle_line(line)
|
111
|
+
line = translate_emoji_shortcodes(line)
|
112
|
+
line.each_grapheme_cluster.map { |cluster| cluster.codepoints.first }.pack("U*")
|
113
|
+
end
|
114
|
+
|
115
|
+
SHORTCODES_TO_EMOJIS = { ":black_large_square:" => "⬛",
|
116
|
+
":white_large_square:" => "⬜",
|
117
|
+
":large_green_square:" => "🟩",
|
118
|
+
":large_yellow_square:" => "🟨" }.freeze
|
119
|
+
|
120
|
+
def translate_emoji_shortcodes(line)
|
121
|
+
SHORTCODES_TO_EMOJIS.reduce(line) { |acc, (key, val)| acc.gsub(key, val) }
|
122
|
+
end
|
123
|
+
|
88
124
|
def parse_input_lines!
|
89
125
|
case input
|
90
126
|
when String
|
data/lib/wordle_decoder.rb
CHANGED
@@ -14,10 +14,6 @@ class WordleDecoder
|
|
14
14
|
@wordle_share = wordle_share
|
15
15
|
end
|
16
16
|
|
17
|
-
def to_terminal
|
18
|
-
@to_terminal ||= format_to_terminal
|
19
|
-
end
|
20
|
-
|
21
17
|
def best_guess
|
22
18
|
@best_guess ||= guesses.first
|
23
19
|
end
|
@@ -38,6 +34,14 @@ class WordleDecoder
|
|
38
34
|
lines.join("\n")
|
39
35
|
end
|
40
36
|
|
37
|
+
def to_terminal
|
38
|
+
str = +"\n"
|
39
|
+
best_guess.words_with_scores.reverse_each do |word, guess_score|
|
40
|
+
str << " #{word.to_terminal} #{word.confidence_score(guess_score)}\n"
|
41
|
+
end
|
42
|
+
str << " {{green:#{@wordle_share.answer}}}\n"
|
43
|
+
end
|
44
|
+
|
41
45
|
private
|
42
46
|
|
43
47
|
def initialize_and_sort_guesses
|
@@ -55,12 +59,4 @@ class WordleDecoder
|
|
55
59
|
WordPosition.new(line, index, @wordle_share.answer_chars)
|
56
60
|
end
|
57
61
|
end
|
58
|
-
|
59
|
-
def format_to_terminal
|
60
|
-
str = +"\n"
|
61
|
-
best_guess.words_with_scores.reverse_each do |word, guess_score|
|
62
|
-
str << " #{word.to_terminal} #{word.confidence_score(guess_score)}\n"
|
63
|
-
end
|
64
|
-
str << " {{green:#{@wordle_share.answer}}}\n\n"
|
65
|
-
end
|
66
62
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wordle_decoder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matt Ruzicka
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cli-ui
|
@@ -24,7 +24,7 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.5'
|
27
|
-
description: Given your Wordle share text, with some degree of confidence,
|
27
|
+
description: Given your Wordle share text, with some degree of confidence,the decoder
|
28
28
|
will spit back the five-letter words it thinks you played.
|
29
29
|
email:
|
30
30
|
executables:
|
@@ -59,6 +59,7 @@ licenses:
|
|
59
59
|
metadata:
|
60
60
|
homepage_uri: https://github.com/mattruzicka/wordle_decoder
|
61
61
|
source_code_uri: https://github.com/mattruzicka/wordle_decoder
|
62
|
+
rubygems_mfa_required: 'true'
|
62
63
|
post_install_message:
|
63
64
|
rdoc_options: []
|
64
65
|
require_paths:
|