chadet 0.0.1
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 +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +2 -0
- data/bin/chadet +272 -0
- data/chadet.gemspec +21 -0
- data/lib/chadet/version.rb +3 -0
- data/lib/chadet.rb +296 -0
- metadata +57 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6cfd2236b309e3803cd4a359698031aa14bc4769
|
4
|
+
data.tar.gz: 482cfc03d09d4d6521d9b132caa172f24cb44929
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 553de67587410c0583ada232854e81061d4da84e22d5f05dfe60d8eeaa5a82da61a6fa647ce09ed862396f5eeb83bc15478ea92f7c354e5d5800a6e5b167adac
|
7
|
+
data.tar.gz: 210db35063e06da63b93862978cc84c7302591900bb50a24b2be7a244f0a944b45ed4b7432b687c703b51ccb248deca02f8996c037ecf8038ad4e7ae7bcd0e29
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 astyd
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Chadet
|
2
|
+
|
3
|
+
Characters Detective. Game of guessing characters intelligently.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'chadet'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install chadet
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Type: 'chadet --help' for options.
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( https://bitbucket.org/astyd/chadet/ )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/chadet
ADDED
@@ -0,0 +1,272 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'optparse' # to parse the command options
|
4
|
+
require 'set' # to check character redundancy
|
5
|
+
require 'chadet'
|
6
|
+
|
7
|
+
class String
|
8
|
+
# define methods for coloring text
|
9
|
+
colors = {:red => 31, :green => 32, :yellow => 33, :blue => 34, :cyan=> 36}
|
10
|
+
colors.each do |k, v|
|
11
|
+
define_method(k) {return "\e[#{v}m#{self}\e[0m" }
|
12
|
+
end
|
13
|
+
|
14
|
+
def flash seconds = 2
|
15
|
+
info = " " + self
|
16
|
+
print info
|
17
|
+
sleep seconds
|
18
|
+
print "\r" + " "*info.gsub(/\e\[\d*m(.*)\e\[0m/, '\1').length
|
19
|
+
print "\r"
|
20
|
+
end
|
21
|
+
|
22
|
+
def blink num_of_times = 4
|
23
|
+
info = " " + self
|
24
|
+
print "\n"
|
25
|
+
x = num_of_times
|
26
|
+
x.times do
|
27
|
+
print info.gsub(/[\w!?\.\'\(\)˚\-。ー\;\/\"\:<>+,★·.·´¯`░]/, " ")
|
28
|
+
sleep 0.18*x/4
|
29
|
+
print (info.lines.length == 1 ? "\r" : "\r\e[#{info.lines.count-1}A")
|
30
|
+
print info.yellow
|
31
|
+
sleep 0.1
|
32
|
+
print (info.lines.length == 1 ? "\r" : "\r\e[#{info.lines.count-1}A")
|
33
|
+
x -= 0.2
|
34
|
+
end
|
35
|
+
puts info.yellow
|
36
|
+
end
|
37
|
+
|
38
|
+
def flash seconds = 2
|
39
|
+
info = " " + self
|
40
|
+
print info
|
41
|
+
sleep seconds
|
42
|
+
print "\r" + " "*info.gsub(/\e\[\d*m(.*)\e\[0m/, '\1').length
|
43
|
+
print "\r"
|
44
|
+
end
|
45
|
+
|
46
|
+
def blink num_of_times = 4
|
47
|
+
info = " " + self
|
48
|
+
print "\n"
|
49
|
+
x = num_of_times
|
50
|
+
x.times do
|
51
|
+
print info.gsub(/[\w!?\.\'\(\)˚\-。ー\;\/\"\:<>+,★·.·´¯`░]/, " ")
|
52
|
+
sleep 0.18*x/4
|
53
|
+
print (info.lines.length == 1 ? "\r" : "\r\e[#{info.lines.count-1}A")
|
54
|
+
print info.yellow
|
55
|
+
sleep 0.1
|
56
|
+
print (info.lines.length == 1 ? "\r" : "\r\e[#{info.lines.count-1}A")
|
57
|
+
x -= 0.2
|
58
|
+
end
|
59
|
+
puts info.yellow
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Specify new Hash to store the options
|
64
|
+
options = {}
|
65
|
+
|
66
|
+
# Create an option parser object to describe the type of options and their description
|
67
|
+
optparse = OptionParser.new do |opts|
|
68
|
+
opts.banner = "Usage:\n\n" \
|
69
|
+
+ " chadet " \
|
70
|
+
+ "[Options] Number... [Options] Characters... [Options]\n\n" \
|
71
|
+
+ "Description:\n\n" \
|
72
|
+
+ " Characters Detective.\n" \
|
73
|
+
+ " Game of guessing characters. The default number of characters is 4 and\n" \
|
74
|
+
+ " the default set of characters is decimal digits from 0 to 9.\n\n" \
|
75
|
+
+ "Options:\n\n"
|
76
|
+
|
77
|
+
opts.on '-r', '--rules', 'How to play this game' do
|
78
|
+
rules_of_play = <<rules
|
79
|
+
-----------------------------------
|
80
|
+
How to play Characters Detective:
|
81
|
+
-----------------------------------
|
82
|
+
+-------------------------------------------------------------+
|
83
|
+
◙ | As the game begins, computer generates a random set of |
|
84
|
+
| characters for you to guess. |
|
85
|
+
+-------------------------------------------------------------+
|
86
|
+
+-------------------------------------------------------------+
|
87
|
+
◙ | This random set of characters is by default a 4 digit |
|
88
|
+
| decimal numbers, or the standard Bulls and Cows game, as |
|
89
|
+
| people know it. To change this behaviour, simply specify |
|
90
|
+
| the '--number=' (or simply '-n') option to change the |
|
91
|
+
| number of characters to guess and/or specify the |
|
92
|
+
| '--characters=' (or '-c') option to change the default set |
|
93
|
+
| of characters to guess. |
|
94
|
+
| |
|
95
|
+
| Example: |
|
96
|
+
| If you type \e[32mchadet --number=2 --characters=abcdef\e[0m you will |
|
97
|
+
| then play the game like this: |
|
98
|
+
| ,¸¸,ø¤º°``°º¤ø,¸¸,ø¤°``°º¤ø,¸¸,ø¤º°``°º¤ø,¸¸,ø¤º°``°º¤ø,¸¸ |
|
99
|
+
| ------------------ ------------------- |
|
100
|
+
| no.| chars cc. cp. |Set of characters| |
|
101
|
+
| ------------------ |to guess with: | |
|
102
|
+
| 1| \e[33mab\e[0m [\e[32m0\e[0m] [\e[32m0\e[0m] ------------------- |
|
103
|
+
| 2| \e[33mcd\e[0m [\e[32m1\e[0m] [\e[32m0\e[0m] |\e[33mabcdef\e[0m | |
|
104
|
+
| \e[32mGuess:\e[0m _ ------------------- |
|
105
|
+
| |
|
106
|
+
| |
|
107
|
+
| For more options, type: \e[32mchadet --help\e[0m |
|
108
|
+
+-------------------------------------------------------------+
|
109
|
+
+-------------------------------------------------------------+
|
110
|
+
◙ | At first, you have to blindly guess the characters. |
|
111
|
+
+-------------------------------------------------------------+
|
112
|
+
+-------------------------------------------------------------+
|
113
|
+
◙ | After each guess, computer will give you answer on how many |
|
114
|
+
| characters you guessed correctly (Correct Characters or |
|
115
|
+
| cc.) and how many characters that their positions you |
|
116
|
+
| guessed correctly (Correct Positions or cp.). |
|
117
|
+
+-------------------------------------------------------------+
|
118
|
+
+-------------------------------------------------------------+
|
119
|
+
◙ | By analizing computer answers in the previous guesses, you |
|
120
|
+
| can guess inteligently next. |
|
121
|
+
+-------------------------------------------------------------+
|
122
|
+
+-------------------------------------------------------------+
|
123
|
+
◙ | You can type \e[32msave\e[0m, \e[32mquit\e[0m, \e[32mload\e[0m or \e[32mhint\e[0m during the game. |
|
124
|
+
| Their names should imply what they can do. |
|
125
|
+
+-------------------------------------------------------------+
|
126
|
+
rules
|
127
|
+
puts rules_of_play
|
128
|
+
exit
|
129
|
+
end
|
130
|
+
|
131
|
+
options[:num_of_chars] = 4
|
132
|
+
opts.on '-n', '--number NUMBER', Integer, 'How many characters you want to play' do |num|
|
133
|
+
options[:num_of_chars] = num
|
134
|
+
end
|
135
|
+
|
136
|
+
options[:characters] = "0123456789"
|
137
|
+
opts.on '-c', '--characters CHARS SET', 'Set of characters you want to play' do |chars|
|
138
|
+
options[:characters] = chars
|
139
|
+
end
|
140
|
+
|
141
|
+
options[:test] = false
|
142
|
+
opts.on '-t', '--test [TEST MODE]', 'Display the characters to guess' do
|
143
|
+
options[:test] = true
|
144
|
+
end
|
145
|
+
|
146
|
+
options[:load] = false
|
147
|
+
opts.on '-g', '--load [LOAD GAME]', 'Load previously saved game' do
|
148
|
+
options[:load] = true
|
149
|
+
end
|
150
|
+
|
151
|
+
opts.on '-h', '--help', 'Display this message' do
|
152
|
+
puts opts
|
153
|
+
puts ""
|
154
|
+
exit
|
155
|
+
end
|
156
|
+
|
157
|
+
opts.on '-v', '--version', 'Display the version of this game' do
|
158
|
+
version = "Chadet v.0.0.1"
|
159
|
+
puts version
|
160
|
+
exit
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Run parse! on the parser object
|
165
|
+
optparse.parse!
|
166
|
+
|
167
|
+
# Set of characters to play with
|
168
|
+
chars_set = options[:characters]
|
169
|
+
if chars_set.length < 2
|
170
|
+
print "Chadet: ".green
|
171
|
+
puts "Cannot play with a set of character less than 2 characters.".red
|
172
|
+
exit
|
173
|
+
end
|
174
|
+
|
175
|
+
# Set number of characters based on option -d given or the default number of 4
|
176
|
+
num_of_chars = options[:num_of_chars]
|
177
|
+
if num_of_chars > chars_set.length
|
178
|
+
num_of_chars = chars_set.length
|
179
|
+
elsif num_of_chars < 1
|
180
|
+
print "Chadet: ".green
|
181
|
+
puts "Cannot play with less than 1 character to guess.".red
|
182
|
+
exit
|
183
|
+
end
|
184
|
+
|
185
|
+
secret_obj = Chadet::SecretCharacters.new(chars_set, num_of_chars)
|
186
|
+
chars_to_guess = secret_obj.secret_chars
|
187
|
+
num_of_chars = secret_obj.num_of_chars
|
188
|
+
|
189
|
+
# Set the number to guess
|
190
|
+
puts "The secret characters are: #{chars_to_guess}".blue if options[:test] == true
|
191
|
+
|
192
|
+
system('clear')
|
193
|
+
play = Chadet::Play.new(secret_obj)
|
194
|
+
play.header
|
195
|
+
play.chars_to_use
|
196
|
+
play.table_header
|
197
|
+
|
198
|
+
go = Chadet::Guess.new(chars_set)
|
199
|
+
|
200
|
+
|
201
|
+
# list of commands
|
202
|
+
load_commands = %w{load laod}
|
203
|
+
save_commands = %w{save svae saev sav sev}
|
204
|
+
exit_commands = %w{quit exit solve solv}
|
205
|
+
cheat_commands = %w{hint hit cheat clue bonus}
|
206
|
+
|
207
|
+
# Play the game until cc. & cp. = num_of_chars
|
208
|
+
begin
|
209
|
+
print "Guess: ".green
|
210
|
+
go.guess = gets.chomp
|
211
|
+
print "\r\e[1A" + " "*(go.guess.length + 7)
|
212
|
+
print "\r"
|
213
|
+
# Check for exit commands
|
214
|
+
if load_commands.include? go.guess.downcase
|
215
|
+
go.guess_num = play.load_game go, secret_obj
|
216
|
+
elsif save_commands.include? go.guess.downcase
|
217
|
+
go.guess_num = play.do_save go.guess_num
|
218
|
+
break if go.guess_num < 0
|
219
|
+
elsif exit_commands.include? go.guess.downcase
|
220
|
+
go.guess_num = play.do_quit go.guess_num
|
221
|
+
break if go.guess_num < 0
|
222
|
+
elsif cheat_commands.include? go.guess.downcase
|
223
|
+
play.do_hint
|
224
|
+
elsif go.guess.length < num_of_chars
|
225
|
+
"Not enough input characters!".red.flash 1
|
226
|
+
elsif go.wrong_input?
|
227
|
+
"Wrong input character!".red.flash 1
|
228
|
+
elsif go.is_redundant?
|
229
|
+
go.handle_redundancy
|
230
|
+
elsif go.guess.length > num_of_chars
|
231
|
+
("We'll take the first#{num_of_chars == 1 ? '' : ' ' + num_of_chars.to_s} "\
|
232
|
+
+ "character#{num_of_chars == 1 ? '' : 's'}.").green.flash 1.5
|
233
|
+
go.guess = go.guess[0...num_of_chars]
|
234
|
+
go.guess_num += 1
|
235
|
+
puts play.answer go.guess, go.guess_num
|
236
|
+
else
|
237
|
+
go.guess = go.guess[0...num_of_chars]
|
238
|
+
go.guess_num += 1
|
239
|
+
puts play.answer go.guess, go.guess_num
|
240
|
+
end
|
241
|
+
end until go.guess == secret_obj.secret_chars
|
242
|
+
|
243
|
+
play.end_game if go.guess_num > 0
|
244
|
+
|
245
|
+
# Congratulate the player for finishing the game
|
246
|
+
save = "Your game has been saved."
|
247
|
+
quit = "Try it again!"
|
248
|
+
lucky = "Wow! (˚o˚) Lucky guess."
|
249
|
+
congratulate = "★·.·´¯`·.·★·.·´¯`·.·★\n ░G░O░O░D░ ░J░O░B░!░\n ★·.·´¯`·.·★·.·´¯`·.·★\n" \
|
250
|
+
+ " You did it in " + go.guess_num.to_s + " steps."
|
251
|
+
a_bit_slow = "(-。ー;) Finally..\n But don't beat yourself up. Try it again!\n I know you "\
|
252
|
+
+ "can do better than " + go.guess_num.to_s + " guesses."
|
253
|
+
|
254
|
+
# To decide what message to display after the game finished
|
255
|
+
case go.guess_num
|
256
|
+
when -2
|
257
|
+
message = save
|
258
|
+
when -1
|
259
|
+
message = quit
|
260
|
+
when 1
|
261
|
+
message = lucky
|
262
|
+
when 2..chars_set.length
|
263
|
+
message = congratulate
|
264
|
+
else
|
265
|
+
message = a_bit_slow
|
266
|
+
end
|
267
|
+
|
268
|
+
if message == a_bit_slow
|
269
|
+
puts "\n " + message.yellow
|
270
|
+
else
|
271
|
+
message.blink
|
272
|
+
end
|
data/chadet.gemspec
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'chadet/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "chadet"
|
8
|
+
spec.version = Chadet::VERSION
|
9
|
+
spec.authors = ["Adrian Setyadi"]
|
10
|
+
spec.email = ["a.styd@yahoo.com"]
|
11
|
+
spec.summary = %q{Characters Detective. Game of guessing characters intelligently.}
|
12
|
+
spec.description = %q{Computer will generate a random set of characters. The default number of characters is 4 and the default set of characters is decimal digits from 0 to 9. After each guess you make, computer will tell you how many characters you guessed correctly and how many characters that their position you guessed correctly.}
|
13
|
+
spec.homepage = "https://bitbucket.org/astyd"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
end
|
data/lib/chadet.rb
ADDED
@@ -0,0 +1,296 @@
|
|
1
|
+
require "chadet/version"
|
2
|
+
|
3
|
+
module Chadet
|
4
|
+
class Play
|
5
|
+
def initialize secret_chars_object
|
6
|
+
@chars_set = secret_chars_object.chars_set
|
7
|
+
@num_of_chars = secret_chars_object.num_of_chars
|
8
|
+
@secret_chars = secret_chars_object.secret_chars
|
9
|
+
@loaded = false
|
10
|
+
@used_true = ""
|
11
|
+
@used_false = ""
|
12
|
+
@max_hint = (@chars_set.length/@num_of_chars).to_i
|
13
|
+
@hint_used = 0
|
14
|
+
@moves = ""
|
15
|
+
end
|
16
|
+
|
17
|
+
def header
|
18
|
+
puts "Type: " + "chadet --help".green + " in the terminal to see more options.\n"\
|
19
|
+
+ "To quit this game at any time, type: " + "quit".green + "\n"
|
20
|
+
puts ",¸¸,ø¤º°``°º¤ø,¸¸,ø¤°``°º¤ø,¸¸,ø¤º°``°º¤ø,¸¸,ø¤º°``°º¤ø,¸¸"
|
21
|
+
end
|
22
|
+
|
23
|
+
def chars_to_use
|
24
|
+
@chars_set.length >= 17 ? box_width = @chars_set.length + 2 : box_width = 19
|
25
|
+
end_pos = 58
|
26
|
+
start_pos = end_pos - box_width
|
27
|
+
puts " "*start_pos + "+" + "-"*(box_width-2) + "+" + "\n"\
|
28
|
+
+ " "*start_pos + "|Set of characters" + " "*(box_width - 19) + "|\n" \
|
29
|
+
+ " "*start_pos + "|to guess with:" + " "*(box_width - 16) + "|\n" \
|
30
|
+
+ " "*start_pos + "+" + "-"*(box_width-2) + "+" + "\n" \
|
31
|
+
+ " "*start_pos + "|" + @chars_set.yellow + " "*(box_width - @chars_set.length - 2) + "|\n" \
|
32
|
+
+ " "*start_pos + "+" + "-"*(box_width-2) + "+"
|
33
|
+
print "\r\e[6A"
|
34
|
+
end
|
35
|
+
|
36
|
+
def table_header
|
37
|
+
chars_pos = (5 + @num_of_chars - "chars".length)/2
|
38
|
+
cc_pos = 10 + @num_of_chars
|
39
|
+
cp_pos = 12 + @num_of_chars + 2*@num_of_chars.to_s.length
|
40
|
+
table_width = cp_pos + 2
|
41
|
+
puts " " + "-"*table_width + "\n"\
|
42
|
+
+ " no.|" + " "*chars_pos + "chars" + " "*(cc_pos - chars_pos - "chars".length - " no.|".length) \
|
43
|
+
+ "cc." + " "*(cp_pos - cc_pos - "cc.".length)\
|
44
|
+
+ "cp." + "\n"\
|
45
|
+
+ " " + "-"*table_width
|
46
|
+
end
|
47
|
+
|
48
|
+
def end_game
|
49
|
+
# table bottom horizontal line
|
50
|
+
cp_pos = 12 + @num_of_chars + 2*@num_of_chars.to_s.length
|
51
|
+
table_width = cp_pos + 2
|
52
|
+
puts " " + "-"*table_width
|
53
|
+
end
|
54
|
+
|
55
|
+
def answer guess, guess_num
|
56
|
+
# Display number of correct characters and number of correct positions
|
57
|
+
_G_ = guess_num.abs.to_s
|
58
|
+
_g_ = _G_.length
|
59
|
+
_N_ = @num_of_chars.to_s
|
60
|
+
_n_ = _N_.length
|
61
|
+
_B_ = checkCC(guess).to_s
|
62
|
+
_b_ = _B_.length
|
63
|
+
_U_ = checkCO(guess).to_s
|
64
|
+
_u_ = _U_.length
|
65
|
+
output = (guess_num == -1 ? ' XXX' : " "*(4-_g_) + _G_) + "| #{guess.yellow}" \
|
66
|
+
+ " [" + ("0"*(_n_-_b_) + _B_).green + "] [" \
|
67
|
+
+ ("0"*(_n_-_u_) + _U_).green + "]"
|
68
|
+
@moves << (output + "\n")
|
69
|
+
if _U_ == _N_ && @loaded == true
|
70
|
+
filename = ".filename"
|
71
|
+
work_dir = File.dirname(__FILE__)
|
72
|
+
file = work_dir + "/" + filename + ".4dig"
|
73
|
+
File.delete(file) if File.exists?(file)
|
74
|
+
end
|
75
|
+
return output
|
76
|
+
end
|
77
|
+
|
78
|
+
# Method to check how many digits are correctly guessed
|
79
|
+
def checkCC guess
|
80
|
+
cc = 0
|
81
|
+
guess.each_char do |x|
|
82
|
+
if @secret_chars.include? x.to_s
|
83
|
+
cc += 1
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return cc
|
87
|
+
end
|
88
|
+
|
89
|
+
# Method to check how many correct digits are presented in correct positions
|
90
|
+
def checkCO guess
|
91
|
+
co = 0
|
92
|
+
for i in 0...@num_of_chars
|
93
|
+
if @secret_chars[i] == guess[i]
|
94
|
+
co += 1
|
95
|
+
end
|
96
|
+
end
|
97
|
+
return co
|
98
|
+
end
|
99
|
+
|
100
|
+
# Method to display hint
|
101
|
+
def hint
|
102
|
+
picked_number = 0
|
103
|
+
clue = ""
|
104
|
+
chance = rand 1..100
|
105
|
+
if chance < (@num_of_chars.to_f/@chars_set.length.to_f*100) \
|
106
|
+
&& chance > (@num_of_chars.to_f/@chars_set.length.to_f*20) #display one correct number
|
107
|
+
picked_number = rand 0...(@num_of_chars-@used_true.length) || 0
|
108
|
+
true_characters = @secret_chars.tr(@used_true, '')
|
109
|
+
picked_true = true_characters[picked_number] || ""
|
110
|
+
@used_true += picked_true
|
111
|
+
if picked_true == ""
|
112
|
+
clue = "You've already known #{@num_of_chars == 1 ? 'the' : 'all'} true "\
|
113
|
+
+ "character#{'s' unless @num_of_chars == 1}."
|
114
|
+
else
|
115
|
+
clue = "'#{picked_true}' is#{@num_of_chars == 1 ? '' : ' among'} the true "\
|
116
|
+
+ "character#{'s' unless @num_of_chars == 1}."
|
117
|
+
end
|
118
|
+
else
|
119
|
+
picked_number = rand 0...(@chars_set.length - @num_of_chars - @used_false.length) || 0
|
120
|
+
false_characters = @chars_set.tr(@secret_chars, '').tr(@used_false, '') || ""
|
121
|
+
picked_false = false_characters[picked_number] || ""
|
122
|
+
@used_false += picked_false
|
123
|
+
if picked_false == ""
|
124
|
+
clue = "You've already known #{(@chars_set.length - @num_of_chars) == 1 ? 'the' : 'all'} "\
|
125
|
+
+ "false character#{'s' unless (@chars_set.length - @num_of_chars) == 1}."
|
126
|
+
else
|
127
|
+
clue = "One can simply omit '#{picked_false}'."
|
128
|
+
end
|
129
|
+
end
|
130
|
+
return clue.yellow
|
131
|
+
end
|
132
|
+
|
133
|
+
def do_hint
|
134
|
+
if @hint_used != @max_hint
|
135
|
+
hint.flash 1.1
|
136
|
+
@hint_used += 1
|
137
|
+
else
|
138
|
+
("Sorry, you've used #{@max_hint == 1 ? 'the' : 'up all'} #{@max_hint.to_s + " " unless @max_hint == 1}"\
|
139
|
+
+ "hint#{'s' unless @max_hint == 1}.").red.flash 1.2
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def save_game guess_num
|
144
|
+
end_game if guess_num > 0
|
145
|
+
# generate filename
|
146
|
+
time = Time.now
|
147
|
+
work_dir = File.dirname(__FILE__)
|
148
|
+
filename = ".filename" # "."+time.strftime("%y%m%d%H%M%S").to_i.to_s(36)
|
149
|
+
# save file
|
150
|
+
File.open(work_dir + "/" + filename + ".4dig", "w+") do |f|
|
151
|
+
f.write("[set of chars]\n")
|
152
|
+
f.write(@chars_set + "\n"*2)
|
153
|
+
f.write("[secret chars]\n")
|
154
|
+
f.write(@secret_chars + "\n"*2)
|
155
|
+
f.write("[hint used]\n")
|
156
|
+
f.write(@hint_used.to_s + "\n"*2)
|
157
|
+
f.write("[moves]\n")
|
158
|
+
f.write(@moves)
|
159
|
+
end
|
160
|
+
guess_num = -2
|
161
|
+
return guess_num
|
162
|
+
end
|
163
|
+
|
164
|
+
def do_save guess_num
|
165
|
+
if guess_num > 0
|
166
|
+
guess_num = save_game guess_num
|
167
|
+
else
|
168
|
+
"No game to save.".red.flash 1
|
169
|
+
end
|
170
|
+
return guess_num
|
171
|
+
end
|
172
|
+
|
173
|
+
def quit_game guess_num
|
174
|
+
print "\r"
|
175
|
+
"¯\\(°_o)/¯ I give up.".yellow.flash 1
|
176
|
+
guess_num = -1
|
177
|
+
puts answer @secret_chars, guess_num
|
178
|
+
end_game
|
179
|
+
return guess_num
|
180
|
+
end
|
181
|
+
|
182
|
+
def do_quit guess_num
|
183
|
+
if guess_num > 0
|
184
|
+
yes_commands = %w{yes yse ys ye y save saev seav sav sev s}
|
185
|
+
print "\r "
|
186
|
+
print "\r " + "Save game? (yes/no): ".yellow
|
187
|
+
save = gets.chomp
|
188
|
+
print "\r\e[1A" + " "*25
|
189
|
+
print "\r"
|
190
|
+
if yes_commands.include? save.downcase
|
191
|
+
guess_num = do_save guess_num
|
192
|
+
else
|
193
|
+
guess_num = quit_game guess_num
|
194
|
+
end
|
195
|
+
else
|
196
|
+
guess_num = quit_game guess_num
|
197
|
+
end
|
198
|
+
return guess_num
|
199
|
+
end
|
200
|
+
|
201
|
+
def load_game guess_object, secret_object
|
202
|
+
filename = ".filename"
|
203
|
+
work_dir = File.dirname(__FILE__)
|
204
|
+
if File.exists?(work_dir + "/" + filename + ".4dig")
|
205
|
+
@loaded = true
|
206
|
+
table_width = 15 + @num_of_chars + 2*@num_of_chars.to_s.length
|
207
|
+
print "\r\e[#{guess_object.guess_num+3}A"
|
208
|
+
print (" "*table_width + "\n")*(guess_object.guess_num+3)
|
209
|
+
print "\r\e[#{guess_object.guess_num+3}A"
|
210
|
+
saved_game = File.read(work_dir + "/" + filename + ".4dig")
|
211
|
+
saved_game_arr = saved_game.split("\n")
|
212
|
+
@chars_set = saved_game_arr[1]
|
213
|
+
@secret_chars = saved_game_arr[4]
|
214
|
+
secret_object.secret_chars = @secret_chars
|
215
|
+
@num_of_chars = @secret_chars.length
|
216
|
+
@hint_used = saved_game_arr[7].to_i
|
217
|
+
@max_hint = (@chars_set.length/@num_of_chars).to_i
|
218
|
+
@moves = saved_game_arr[10..-1]
|
219
|
+
guess_object.guess_num = @moves.length
|
220
|
+
chars_to_use
|
221
|
+
table_header
|
222
|
+
@moves = @moves.inject("") {|result, line| result + line + "\n"}
|
223
|
+
puts @moves
|
224
|
+
else
|
225
|
+
"No saved game found.".yellow.flash 1.5
|
226
|
+
end
|
227
|
+
return guess_object.guess_num
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
class SecretCharacters
|
232
|
+
attr_reader :num_of_chars, :chars_set, :max_hint
|
233
|
+
attr_accessor :secret_chars
|
234
|
+
|
235
|
+
# default chars = "0123456789" and default num = 4, see option parser.
|
236
|
+
def initialize chars_set, num_of_chars
|
237
|
+
@num_of_chars = num_of_chars
|
238
|
+
@chars_set = chars_set
|
239
|
+
@secret_chars = do_shuffle
|
240
|
+
end
|
241
|
+
|
242
|
+
# Shuffle a set of number from 0-9
|
243
|
+
def do_shuffle
|
244
|
+
prep_chars = @chars_set.chars.to_a.shuffle
|
245
|
+
secret_chars = prep_chars[0, @num_of_chars].join.to_s
|
246
|
+
return secret_chars
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
class Guess
|
251
|
+
# check if guess has redundant characters
|
252
|
+
attr_accessor :guess, :guess_num, :chars_set
|
253
|
+
def initialize chars_set
|
254
|
+
@guess = ""
|
255
|
+
@guess_num = 0
|
256
|
+
@chars_set = chars_set
|
257
|
+
end
|
258
|
+
|
259
|
+
def is_redundant?
|
260
|
+
redundant = false
|
261
|
+
a = @guess.split("").to_set.length
|
262
|
+
b = @guess.length
|
263
|
+
redundant = true if a < b
|
264
|
+
return redundant
|
265
|
+
end
|
266
|
+
|
267
|
+
def handle_redundancy
|
268
|
+
char_freq = {}
|
269
|
+
@guess.each_char do |char|
|
270
|
+
char_freq[char] ? char_freq[char] += 1 : char_freq[char] = 1
|
271
|
+
end
|
272
|
+
redundant_char = char_freq.select {|k, v| v > 1}
|
273
|
+
sorted_red_char = redundant_char.sort_by {|k, v| v}
|
274
|
+
sorted_red_char.reverse! unless sorted_red_char[1].nil? || sorted_red_char[0][1] == sorted_red_char[1][1]
|
275
|
+
redundant = sorted_red_char[0][0]
|
276
|
+
frequency = sorted_red_char[0][1]
|
277
|
+
if frequency == 2
|
278
|
+
freq_string = "twice"
|
279
|
+
else
|
280
|
+
freq_string = "#{frequency} times"
|
281
|
+
end
|
282
|
+
"Redundant: you mentioned \"#{redundant}\" #{freq_string}.".yellow.flash 1.1
|
283
|
+
end
|
284
|
+
|
285
|
+
# Check if wrong character is input
|
286
|
+
def wrong_input?
|
287
|
+
wrong_char = false
|
288
|
+
error_num = 0
|
289
|
+
@guess.each_char do |char|
|
290
|
+
error_num += 1 unless chars_set.include? char
|
291
|
+
end
|
292
|
+
wrong_char = true if error_num > 0
|
293
|
+
return wrong_char
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
metadata
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: chadet
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adrian Setyadi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-08-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Computer will generate a random set of characters. The default number
|
14
|
+
of characters is 4 and the default set of characters is decimal digits from 0 to
|
15
|
+
9. After each guess you make, computer will tell you how many characters you guessed
|
16
|
+
correctly and how many characters that their position you guessed correctly.
|
17
|
+
email:
|
18
|
+
- a.styd@yahoo.com
|
19
|
+
executables:
|
20
|
+
- chadet
|
21
|
+
extensions: []
|
22
|
+
extra_rdoc_files: []
|
23
|
+
files:
|
24
|
+
- ".gitignore"
|
25
|
+
- Gemfile
|
26
|
+
- LICENSE.txt
|
27
|
+
- README.md
|
28
|
+
- Rakefile
|
29
|
+
- bin/chadet
|
30
|
+
- chadet.gemspec
|
31
|
+
- lib/chadet.rb
|
32
|
+
- lib/chadet/version.rb
|
33
|
+
homepage: https://bitbucket.org/astyd
|
34
|
+
licenses:
|
35
|
+
- MIT
|
36
|
+
metadata: {}
|
37
|
+
post_install_message:
|
38
|
+
rdoc_options: []
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
requirements: []
|
52
|
+
rubyforge_project:
|
53
|
+
rubygems_version: 2.2.2
|
54
|
+
signing_key:
|
55
|
+
specification_version: 4
|
56
|
+
summary: Characters Detective. Game of guessing characters intelligently.
|
57
|
+
test_files: []
|