ruby-wordle 0.9.2 → 1.0.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.
@@ -1,48 +0,0 @@
1
- #! /usr/bin/env ruby
2
-
3
- NUM_LETTERS = 5
4
-
5
- HOME_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
6
-
7
- original_word_list = File.readlines("#{HOME_DIR}/word-lists/word-list-original.txt")
8
- basic_word_list = File.readlines("#{HOME_DIR}/word-lists/word-list-basic.txt")
9
- n_letter_dir = "#{HOME_DIR}/word-lists/#{NUM_LETTERS}-letters"
10
-
11
- unless Dir.exist? n_letter_dir
12
- Dir.mkdir File.expand_path(n_letter_dir)
13
- end
14
-
15
- n_letter_word_file = File.new(File.join(n_letter_dir, "word-list.txt"), "w")
16
- uniq_n_letter_word_file = File.new(File.join(n_letter_dir, "word-list-uniq-letters.txt"), "w")
17
- basic_n_letter_word_file = File.new(File.join(n_letter_dir, "word-list-basic.txt"), "w")
18
- uniq_basic_n_letter_word_file = File.new(File.join(n_letter_dir, "word-list-basic-uniq-letters.txt"), "w")
19
-
20
- original_word_list.sort!.uniq!
21
- original_word_list.each do |line|
22
- chars = line.strip.split(//)
23
- if chars.size == NUM_LETTERS
24
- line.downcase!
25
- n_letter_word_file.write line
26
- if chars.uniq.size == chars.size
27
- uniq_n_letter_word_file.write line
28
- end
29
- end
30
- end
31
-
32
- basic_word_list.sort!.uniq!
33
- basic_word_list.each do |line|
34
- chars = line.strip.split(//)
35
- if chars.size == NUM_LETTERS
36
- line.downcase!
37
- basic_n_letter_word_file.write line
38
- if chars.uniq.size == chars.size
39
- uniq_basic_n_letter_word_file.write line
40
- end
41
- end
42
- end
43
-
44
- n_letter_word_file.close
45
- uniq_n_letter_word_file.close
46
- basic_n_letter_word_file.close
47
- uniq_basic_n_letter_word_file.close
48
-
@@ -1,124 +0,0 @@
1
- #! /usr/bin/env ruby
2
-
3
- require "readline"
4
- require "script-solver"
5
-
6
- module RubyWordlePlay
7
- NUM_LETTERS = 5
8
- NUM_ATTEMPTS = 6
9
-
10
- LPAD = " " * 1
11
- PROMPT = "〉".bold.red
12
-
13
- @word_list_basic = File.readlines("#{HOME_DIR}/word-lists/#{NUM_LETTERS}-letters/word-list-basic.txt").map(&:strip)
14
- @word_list_original = File.readlines("#{HOME_DIR}/word-lists/#{NUM_LETTERS}-letters/word-list.txt").map(&:strip)
15
- @word = @word_list_basic.sample
16
- @not_used = []
17
- @not_used_here = {1 => [], 2 => [], 3 => [], 4 => [], 5 => []}
18
- @letters_known = ".....".split(//)
19
-
20
- def self.check_dict(attempt)
21
- @word_list_original.include?(attempt)
22
- end
23
-
24
- def self.evaluate(attempt)
25
- puts
26
- @letters_known = attempt.split(//)
27
- correct = []
28
- wrong = []
29
- @word.split(//).each_with_index do |l, i|
30
- if attempt[i] == l
31
- correct << i
32
- else
33
- wrong << i
34
- @letters_known[i] = '.'
35
- end
36
- end
37
- attempt.split(//).each_with_index do |l, i|
38
- if correct.include?(i)
39
- print " #{@word[i]} ".upcase.bg_green
40
- else
41
- elsewhere = wrong.map{|i|@word[i]}.index(l)
42
- if elsewhere
43
- print " #{l} ".upcase.bg_brown
44
- @not_used_here[i + 1] << l unless @not_used_here[i + 1].include? l
45
- else
46
- print " ".bg_gray
47
- @not_used << attempt[i] if /[a-z]/ =~ attempt[i]
48
- @not_used.uniq!
49
- @not_used.sort!
50
- end
51
- end
52
- end
53
- puts
54
- correct.size == NUM_LETTERS
55
- end
56
-
57
- def self.get_help
58
- letters_used = []
59
- @not_used_here.each do |k, v|
60
- v.each do |r|
61
- letters_used << [k - 1, r]
62
- end
63
- end
64
- RubyWordleSolver.solve_wordle(@letters_known.join, letters_used, @not_used, :basic, @word)
65
- end
66
-
67
- def self.ask_for_attempt(str)
68
- puts
69
- print " #{str} ".bold.bg_cyan + " "
70
- attempt = Readline.readline(LPAD + PROMPT, true).strip.downcase
71
- if attempt == "quit" || attempt == "q"
72
- exit
73
- elsif attempt == "help" || attempt == "h" || attempt == "?"
74
- get_help
75
- attempt = ask_for_attempt(str)
76
- end
77
-
78
- unless /\A[a-z]{5}\z/ =~ attempt
79
- puts
80
- puts LPAD + "Sorry,".red + " the input format is not right"
81
- puts
82
- attempt = ask_for_attempt(str)
83
- end
84
-
85
- unless check_dict(attempt)
86
- puts
87
- puts LPAD + "Sorry,".red + " it's not listed in the dictionary"
88
- puts
89
- attempt = ask_for_attempt(str)
90
- end
91
- attempt
92
- end
93
-
94
- def self.draw_decorated_border
95
- puts
96
- puts (' '.bg_green * 5 + ' '.bg_gray * 3 + ' '.bg_brown * 5 + ' '.bg_gray * 3) * 4
97
- puts
98
- end
99
-
100
- def play_wordle
101
- draw_decorated_border;
102
- puts "Input a word of 5 letters and press \"↵\"".cyan.bold
103
- puts "Type \"?↵\" for help, \"quit↵\" to exit".gray
104
-
105
- NUM_ATTEMPTS.times do |i|
106
- attempt = ask_for_attempt("#{i + 1}/#{NUM_ATTEMPTS}")
107
- result = evaluate(attempt)
108
- puts
109
- if result
110
- puts "C O R R E C T !".upcase.bg_magenta
111
- exit
112
- elsif i + 1 == NUM_ATTEMPTS
113
- puts " ANSWER: #{@word} ".upcase.bg_red
114
- exit
115
- else
116
- puts @not_used.uniq.map{|l| " #{l.upcase} "}.join.bg_black if !@not_used.empty?
117
- puts
118
- end
119
- end
120
- draw_decorated_border
121
- end
122
-
123
- module_function :play_wordle
124
- end
@@ -1,179 +0,0 @@
1
- #! /usr/bin/env ruby
2
-
3
- HOME_DIR = File.expand_path(File.join(File.dirname(__FILE__), "..", ".."))
4
-
5
- require "readline"
6
- require "script-utils"
7
-
8
- module RubyWordleSolver
9
- NUM_LETTERS = 5
10
- MAX_SUGGESTIONS = 128
11
-
12
- LPAD = " " * 7
13
- PROMPT = "〉".bold.red
14
-
15
- @word_list = File.readlines("#{HOME_DIR}/word-lists/#{NUM_LETTERS}-letters/word-list.txt").map(&:strip)
16
- @word_list_basic = File.readlines("#{HOME_DIR}/word-lists/#{NUM_LETTERS}-letters/word-list-basic.txt").map(&:strip)
17
-
18
- @basic_word_list = {}
19
- File.readlines("#{HOME_DIR}/word-lists/#{NUM_LETTERS}-letters/word-list-basic.txt").map(&:strip).each do |b|
20
- @basic_word_list[b] = true
21
- end
22
-
23
- @basic_word_uniq_list = {}
24
- File.readlines("#{HOME_DIR}/word-lists/#{NUM_LETTERS}-letters/word-list-basic-uniq-letters.txt").map(&:strip).each do |b|
25
- @basic_word_uniq_list[b] = true
26
- end
27
-
28
- @letters_known = nil
29
- @letters_used = nil
30
- @letters_not_used = nil
31
-
32
- def self.get_letters_known
33
- puts
34
- puts "STEP 1".bold.bg_green + " Input " + "known letters".underline + " using alphabets and dots"
35
- puts LPAD + "Then press \"↵\" (Type \"quit↵\" to exit)"
36
- if @letters_known
37
- puts LPAD + "Last time: #{@letters_known.bg_green}"
38
- else
39
- puts LPAD + "Example: #{'s...h'.bg_green}"
40
- end
41
-
42
- letters_known = Readline.readline(LPAD + PROMPT, true).strip.downcase
43
-
44
- exit if letters_known == "quit" || letters_known == "q"
45
- unless /\A[a-z\.]{5}\z/ =~ letters_known
46
- puts LPAD + "Sorry,".red + " the input format is not right"
47
- letters_known = get_letters_known
48
- end
49
- letters_known
50
- end
51
-
52
- def self.get_letters_used
53
- puts
54
- puts "STEP 2".bold.bg_brown + " Input pairs of " + "a position and a letter".underline
55
- puts LPAD + "Then press \"↵\" (Type \"quit↵\" to exit)"
56
- if @letters_used
57
- puts LPAD + "Last time: #{@letters_used.map{|p, l| (p + 1).to_s + l}.join(' ').bg_brown}"
58
- else
59
- puts LPAD + "Example: #{'1g 2e 5a'.bg_brown}"
60
- end
61
-
62
- letters_used = Readline.readline(LPAD + PROMPT, true).strip.downcase
63
-
64
- exit if letters_used == "quit" || letters_used == "q"
65
- if letters_used.strip == ""
66
- array_letters_used = []
67
- elsif /\A(?:[1-5][a-z][\s,]*)+\z/ =~ letters_used
68
- array_letters_used = []
69
- letters_used.gsub(/\s+/, "").split(//).each_slice(2) do |k, v|
70
- array_letters_used << [k.to_i - 1, v]
71
- end
72
- else
73
- puts LPAD + "Sorry,".red + " the input format is not right"
74
- array_letters_used = get_letters_used
75
- end
76
- array_letters_used
77
- end
78
-
79
- def self.get_letters_not_used
80
- puts
81
- puts "STEP 3".bold.bg_gray + " Input " + "letters not used".underline + " in the word"
82
- puts LPAD + "Then press \"↵\" (Type \"quit↵\" to exit)"
83
- if @letters_not_used
84
- puts LPAD + "Last time: #{@letters_not_used.join.bg_gray}"
85
- else
86
- puts LPAD + "Example: #{'ieagh'.bg_gray}"
87
- end
88
-
89
- letters_not_used = Readline.readline(LPAD + PROMPT, true).strip.downcase
90
-
91
- exit if letters_not_used == "quit" || letters_not_used == "q"
92
- if letters_not_used.strip == ""
93
- array_letters_not_used = []
94
- elsif /\A[a-z\s]+\z/ =~ letters_not_used
95
- array_letters_not_used = letters_not_used.split(//)
96
- else
97
- puts LPAD + "Sorry,".red + " the input format is not right"
98
- array_letters_not_used = get_letters_not_used
99
- end
100
- array_letters_not_used
101
- end
102
-
103
- def self.draw_decorated_border
104
- puts; puts (' '.bg_green * 5 + ' '.bg_gray * 3 + ' '.bg_brown * 5 + ' '.bg_gray * 3) * 4; puts
105
- end
106
-
107
- def solve_wordle(letters_known, letters_used, letters_not_used, mode = :original, answer = nil)
108
- word_list = mode == :original ? @word_list : @word_list_basic
109
- indices_unknown_letters = (0 ... letters_known.length).find_all { |i| letters_known[i, 1] == '.' }
110
-
111
- word_list_a = word_list.select do |word|
112
- Regexp.compile(letters_known) =~ word
113
- end
114
-
115
- word_list_b = word_list_a.select do |word|
116
- word_letters = word.split(//)
117
- letters_in_candidate = word_letters.values_at(*indices_unknown_letters) - letters_used.map{|l| l[1]}
118
- cond1 = letters_used.all? do |position, letter|
119
- word_letters[position] != letter
120
- end
121
- cond2 = (letters_used.map{|l| l[1]} - word_letters).empty?
122
- cond3 = (letters_in_candidate - letters_not_used).size == letters_in_candidate.size
123
- cond1 && cond2 && cond3
124
- end
125
-
126
- if answer
127
- word_list_b.delete(answer)
128
- reduced_list = word_list_b.sample(MAX_SUGGESTIONS - 1)
129
- reduced_list << answer
130
- else
131
- reduced_list = word_list_b.sample(MAX_SUGGESTIONS)
132
- end
133
-
134
- results = reduced_list.sort.map do |word|
135
- if @basic_word_uniq_list[word]
136
- mode == :original ? word.red.bold : word.red
137
- elsif @basic_word_list[word]
138
- mode == :original ? word.blue.bold : word.blue
139
- else
140
- word
141
- end
142
- end
143
- puts
144
- results.each_with_index do |word, i|
145
- if (i + 1) % 8 == 0 || results.size == i + 1
146
- print word + "\n"
147
- else
148
- print word + " "
149
- end
150
- end
151
- word_list_b
152
- end
153
-
154
- def run_interactively
155
- draw_decorated_border
156
- @letters_known = get_letters_known
157
- @letters_used = get_letters_used
158
- @letters_not_used = get_letters_not_used
159
- results = solve_wordle(@letters_known, @letters_used, @letters_not_used)
160
- draw_decorated_border
161
-
162
- exit if results.size < 2
163
-
164
- puts " ? ".bold.bg_magenta + " Press \"↵\" to continue."
165
- puts LPAD + "Type \"quit↵\" to exit."
166
-
167
- response = Readline.readline(LPAD + PROMPT, true).strip.downcase
168
-
169
- if response == "quit" || response == "q"
170
- exit
171
- else
172
- run_interactively
173
- end
174
- end
175
-
176
- module_function :run_interactively
177
- module_function :solve_wordle
178
- end
179
-
@@ -1,23 +0,0 @@
1
- class String
2
- def black; "\e[30m#{self}\e[0m" end
3
- def red; "\e[31m#{self}\e[0m" end
4
- def green; "\e[32m#{self}\e[0m" end
5
- def brown; "\e[33m#{self}\e[0m" end
6
- def blue; "\e[34m#{self}\e[0m" end
7
- def magenta; "\e[35m#{self}\e[0m" end
8
- def cyan; "\e[36m#{self}\e[0m" end
9
- def gray; "\e[37m#{self}\e[0m" end
10
- def bg_black; "\e[40m#{self}\e[0m" end
11
- def bg_red; "\e[41m#{self}\e[0m" end
12
- def bg_green; "\e[42m#{self}\e[0m" end
13
- def bg_brown; "\e[43m#{self}\e[0m" end
14
- def bg_blue; "\e[44m#{self}\e[0m" end
15
- def bg_magenta; "\e[45m#{self}\e[0m" end
16
- def bg_cyan; "\e[46m#{self}\e[0m" end
17
- def bg_gray; "\e[47m#{self}\e[0m" end
18
- def bold; "\e[1m#{self}\e[22m" end
19
- def italic; "\e[3m#{self}\e[23m" end
20
- def underline; "\e[4m#{self}\e[24m" end
21
- def blink; "\e[5m#{self}\e[25m" end
22
- def reverse_color; "\e[7m#{self}\e[27m" end
23
- end
data/ruby-wordle.gemspec DELETED
@@ -1,21 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
-
4
- require "ruby-wordle/version"
5
-
6
- Gem::Specification.new do |s|
7
- s.name = "ruby-wordle"
8
- s.version = RubyWordle::VERSION
9
- s.authors = ["Yoichiro Hasebe"]
10
- s.email = ["yohasebe@gmail.com"]
11
- s.homepage = "http://github.com/yohasebe/ruby-wordle"
12
- s.summary = %q{A set of ruby scripts to generate word-lists, solve Wordle, and play Wordle}
13
- s.description = %q{A set of ruby scripts to generate word-lists, solve Wordle, and play Wordle}
14
- s.licenses = ["MIT"]
15
- s.files = `git ls-files`.split("\n")
16
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
- s.require_paths = ["lib"]
18
-
19
- # specify any dependencies here; for example:
20
- s.add_runtime_dependency 'readline'
21
- end