mastermind-nowsiany 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.
@@ -0,0 +1,3 @@
1
+ module Mastermind
2
+ VERSION = "1.0.0"
3
+ end
data/lib/mastermind.rb ADDED
@@ -0,0 +1,28 @@
1
+ require "mastermind/version"
2
+
3
+ module Mastermind
4
+ COLORS = ["R", "Y", "G", "B", "P", "M"]
5
+
6
+ COLOR_NAMES = {
7
+ "R" => "(r)ed",
8
+ "Y" => "(y)ellow",
9
+ "G" => "(g)reen",
10
+ "B" => "(b)lue",
11
+ "P" => "(p)ink",
12
+ "M" => "(m)agenta"
13
+ }
14
+
15
+ COLOR_CODES = {
16
+ "R" => :red,
17
+ "Y" => :yellow,
18
+ "G" => :green,
19
+ "B" => :blue,
20
+ "P" => :magenta,
21
+ "M" => :light_magenta
22
+ }
23
+
24
+ def self.color_option_string(num_colors)
25
+ COLOR_NAMES.values.first(num_colors).join(" | ")
26
+ end
27
+
28
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mastermind/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mastermind-nowsiany"
8
+ spec.version = Mastermind::VERSION
9
+ spec.authors = ["Nathan Owsiany"]
10
+ spec.email = ["nowsiany@gmail.com"]
11
+ spec.summary = %q{Command Line Mastermind}
12
+ spec.description = %q{Play Mastermind through your command line... with multiplayer support.}
13
+ spec.homepage = "https://github.com/ndwhtlssthr/mastermind"
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
+ spec.add_dependency "colorize", "~> 0.7"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.7"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "guard", "~> 2.8"
26
+ spec.add_development_dependency "guard-rspec", "~> 4.3"
27
+ end
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'mastermind/cli'
2
+ require 'mastermind/play_game'
3
+ require 'mastermind/interact'
4
+ require 'spec_helper'
5
+ require 'stringio'
6
+
7
+ RSpec.describe Mastermind::CLI do
8
+ it "should be able to quit" do
9
+ stdin = StringIO.new("Q")
10
+ cli = Mastermind::CLI.new(stdin, StringIO.new)
11
+ expect(cli.quit?).to be_falsey
12
+
13
+ cli.get_command
14
+ expect(cli.quit?).to be_truthy
15
+
16
+ stdin.string = "q"
17
+ cli.get_command
18
+ expect(cli.quit?).to be_truthy
19
+ end
20
+
21
+ it "should print intro title and content" do
22
+ stdin = StringIO.new("\nq")
23
+ stdout = StringIO.new()
24
+ cli = Mastermind::CLI.new(stdin, stdout)
25
+ cli.run
26
+ expect(stdout.string).to include("0;32;49m")
27
+ expect(stdout.string).to include("MA1N")
28
+ expect(stdout.string).to include("_/")
29
+ end
30
+
31
+ it "should print instructions when prompted" do
32
+ stdin = StringIO.new("i\nq")
33
+ stdout = StringIO.new()
34
+ cli = Mastermind::CLI.new(stdin, stdout)
35
+ cli.run
36
+ expect(stdout.string).to include("(i)")
37
+ end
38
+
39
+ it "should play the game when prompted" do
40
+ stdin = StringIO.new("p\nq\nq\n")
41
+ stdout = StringIO.new()
42
+ cli = Mastermind::CLI.new(stdin, stdout)
43
+ cli.run
44
+ expect(Mastermind::PlayGame.new(stdin, stdout, Mastermind::Interact.new)).to respond_to(:run)
45
+ end
46
+ end
@@ -0,0 +1,268 @@
1
+ require 'mastermind/player'
2
+ require 'mastermind/game_round'
3
+ require 'mastermind/interact'
4
+ require 'mastermind/processor'
5
+ require 'spec_helper'
6
+ require 'stringio'
7
+
8
+ RSpec.describe Mastermind::GameRound do
9
+ attr_accessor :stdin, :stdout, :interact
10
+ before do
11
+ self.stdin = StringIO.new("\nSimon\nAlvin\n")
12
+ self.stdout = StringIO.new
13
+ self.interact = Mastermind::Interact.new
14
+ end
15
+
16
+ it "should generate a random secret when there is one player" do
17
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
18
+ players = game.player_gen(1)
19
+ round = Mastermind::GameRound.new(stdin, stdout, interact, players)
20
+ expect(round.players[0].secret).to eql(["X", "X", "X", "X"])
21
+ thread = Thread.new do
22
+ round.play
23
+ binding.pry
24
+ end
25
+ sleep(0.1)
26
+ player = round.players[0]
27
+ colors = Mastermind::Processor.colors(6)
28
+ expect(player.secret).to_not eql(["X", "X", "X", "X"])
29
+ expect(Mastermind::Processor.validate(player.secret.join, player.secret, colors)).to be_truthy
30
+ thread.kill
31
+ end
32
+
33
+ context "when generating a single player secret" do
34
+ before do
35
+ @game = Mastermind::PlayGame.new(stdin, stdout, interact)
36
+ @players = @game.player_gen(1)
37
+ @round = Mastermind::GameRound.new(stdin, stdout, interact, @players)
38
+ end
39
+
40
+ it "knows the initial state of the secret is invalid" do
41
+ expect(@round.players[0].secret).to eql(["X", "X", "X", "X"])
42
+ end
43
+
44
+ it "changes the secret from its initial state" do
45
+ thread = Thread.new do
46
+ @round.play
47
+ end
48
+ sleep(0.1)
49
+ player = @round.players[0]
50
+ expect(player.secret).to_not eql(["X", "X", "X", "X"])
51
+ thread.kill
52
+ end
53
+
54
+ it "generates a valid secret" do
55
+ thread = Thread.new do
56
+ @round.play
57
+ end
58
+ sleep(0.1)
59
+ player = @round.players[0]
60
+ colors = Mastermind::Processor.colors(6)
61
+ expect(Mastermind::Processor.validate(player.secret.join, player.secret, colors)).to be_truthy
62
+ thread.kill
63
+ end
64
+ end
65
+
66
+ context "when generating multi player secrets" do
67
+ before do
68
+ stdin.string = "m\nSimon\nTheodore\nrrrr\nrrrr\n"
69
+ @game = Mastermind::PlayGame.new(stdin, stdout, interact)
70
+ @players = @game.player_gen(2)
71
+ @round = Mastermind::GameRound.new(stdin, stdout, interact, @players)
72
+ end
73
+
74
+ it "knows the initial state of each players secret is invalid" do
75
+ expect(@round.players[0].secret).to eql(["X", "X", "X", "X"])
76
+ expect(@round.players[1].secret).to eql(["X", "X", "X", "X"])
77
+ end
78
+
79
+ it "changes the secret from its initial state" do
80
+ thread = Thread.new do
81
+ @round.play
82
+ end
83
+ sleep(0.1)
84
+ player = @round.players[0]
85
+ expect(player.secret).to_not eql(["X", "X", "X", "X"])
86
+ expect(player.secret).to eql(["R", "R", "R", "R"])
87
+ thread.kill
88
+ end
89
+
90
+ it "generates a valid secret" do
91
+ thread = Thread.new do
92
+ @round.play
93
+ end
94
+ sleep(0.1)
95
+ player = @round.players[0]
96
+ colors = Mastermind::Processor.colors(6)
97
+ expect(Mastermind::Processor.validate(player.secret.join, player.secret, colors)).to be_truthy
98
+ thread.kill
99
+ end
100
+ end
101
+
102
+ it "loads a list of valid colors" do
103
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
104
+ players = game.player_gen(1)
105
+ round = Mastermind::GameRound.new(stdin, stdout, interact, players)
106
+ expect(round.valid_colors).to eql(["R", "Y", "G", "B", "P", "M"])
107
+ end
108
+
109
+ it "sets max guesses to 12 for single difficulty model" do
110
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
111
+ players = game.player_gen(1)
112
+ round = Mastermind::GameRound.new(stdin, stdout, interact, players)
113
+ expect(round.max_guesses).to eql(12)
114
+ end
115
+
116
+ context "when resetting a Players' round info before the round" do
117
+ before do
118
+ @game = Mastermind::PlayGame.new(stdin, stdout, interact)
119
+ @players = @game.player_gen(2)
120
+ @round = Mastermind::GameRound.new(stdin, stdout, interact, @players)
121
+ end
122
+
123
+ # NOTE: alternating b/w player 1 and 2 to verify it works for each player
124
+
125
+ it "resets the players password to XXXX" do
126
+ @round.players[0].secret = ["Z", "Z", "Z", "Z"]
127
+ expect(@round.players[0].secret).to_not eql(["X", "X", "X", "X"])
128
+ @round.player_reset
129
+ expect(@round.players[0].secret).to eql(["X", "X", "X", "X"])
130
+ end
131
+
132
+ it "sets the players round_over status to false" do
133
+ @round.players[1].round_over = true
134
+ expect(@round.players[1].round_over).to be_truthy
135
+ @round.player_reset
136
+ expect(@round.players[1].round_over).to be_falsey
137
+ end
138
+
139
+ it "clears the players guess log" do
140
+ @round.players[0].guesses = ["gggg", "gggg"]
141
+ expect(@round.players[0].guesses).to_not be_empty
142
+ @round.player_reset
143
+ expect(@round.players[0].guesses).to be_empty
144
+ end
145
+
146
+ it "it resets the time counter" do
147
+ test_time = Time.now
148
+ @round.player_reset
149
+ expect(@round.players[1].start_time).to be_within(1).of(test_time)
150
+ end
151
+
152
+ it "it resets the completion time to nil" do
153
+ @round.players[0].completion_time = Time.new - 500
154
+ expect(@round.players[0].completion_time).to_not be_nil
155
+ @round.player_reset
156
+ expect(@round.players[0].completion_time).to be_nil
157
+ end
158
+
159
+ it "resets a players turn position" do
160
+ @round.players[1].turn_pos = 1
161
+ expect(@round.players[1].turn_pos).to_not be_nil
162
+ @round.player_reset
163
+ expect(@round.players[1].turn_pos).to be_nil
164
+ end
165
+
166
+ end
167
+
168
+ it "it has a blank global string command to start with" do
169
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
170
+ players = game.player_gen(1)
171
+ round = Mastermind::GameRound.new(stdin, stdout, interact, players)
172
+ expect(round.command).to eql("")
173
+ end
174
+
175
+ it "is not round over by default" do
176
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
177
+ players = game.player_gen(1)
178
+ round = Mastermind::GameRound.new(stdin, stdout, interact, players)
179
+ expect(round.round_over).to be_falsey
180
+ end
181
+
182
+ it "can identify a winning guess" do
183
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
184
+ players = game.player_gen(1)
185
+ round = Mastermind::GameRound.new(stdin, stdout, interact, players)
186
+ round.players[0].secret = ["R", "R", "R", "R"]
187
+ round.players[0].command = "RRRR"
188
+ expect(round.correct_guess?(round.players[0])).to be_truthy
189
+ end
190
+
191
+ it "knows how many guesses have been taken" do
192
+ stdin = StringIO.new("m\nsimon\ntheo\nrrrr\nrrrr\ngggg\nyyyy\nbbbb\n")
193
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
194
+ players = game.player_gen(2)
195
+ round = Mastermind::GameRound.new(stdin, stdout, interact, players)
196
+ thread = Thread.new do
197
+ round.play
198
+ end
199
+ sleep(0.1)
200
+ expect(round.num_guesses(players[0])).to eql(2)
201
+ expect(round.num_guesses(players[1])).to eql(1)
202
+ thread.kill
203
+ end
204
+
205
+ context "when one player guesses correct" do
206
+ before do
207
+ stdin = StringIO.new("m\nsimon\ntheo\nrrrr\nrrrr\nrrrr\nyyyy\nbbbb\n")
208
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
209
+ players = game.player_gen(2)
210
+ @round = Mastermind::GameRound.new(stdin, stdout, interact, players)
211
+ end
212
+
213
+ it "knows that player1's round is over" do
214
+ thread = Thread.new do
215
+ @round.play
216
+ end
217
+ sleep(0.1)
218
+ expect(@round.players[0].round_over).to be_truthy
219
+ thread.kill
220
+ end
221
+
222
+ it "knows that the game round is not over after one player wins" do
223
+ thread = Thread.new do
224
+ @round.play
225
+ end
226
+ sleep(0.1)
227
+ expect(@round.round_over).to be_falsey
228
+ thread.kill
229
+ end
230
+
231
+ it "continues prompting for guesses for the other player" do
232
+ thread = Thread.new do
233
+ @round.play
234
+ end
235
+ sleep(0.1)
236
+ expect(@round.num_guesses(@round.players[1])).to eql(2)
237
+ thread.kill
238
+ end
239
+ end
240
+
241
+ context "when both players guess correctly" do
242
+ before do
243
+ stdin = StringIO.new("m\nsimon\ntheo\nrrrr\nrrrr\nrrrr\nyyyy\nbbbb\nrrrr\n")
244
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
245
+ players = game.player_gen(2)
246
+ @round = Mastermind::GameRound.new(stdin, stdout, interact, players)
247
+ end
248
+
249
+ it "knows that each players' round is over" do
250
+ thread = Thread.new do
251
+ @round.play
252
+ end
253
+ sleep(0.1)
254
+ expect(@round.players[0].round_over).to be_truthy
255
+ expect(@round.players[1].round_over).to be_truthy
256
+ thread.kill
257
+ end
258
+
259
+ it "knows that the game round is over" do
260
+ thread = Thread.new do
261
+ @round.play
262
+ end
263
+ sleep(0.1)
264
+ expect(@round.round_over).to be_truthy
265
+ thread.kill
266
+ end
267
+ end
268
+ end
@@ -0,0 +1,37 @@
1
+ require 'mastermind/interact'
2
+
3
+ RSpec.describe Mastermind::Interact do
4
+ before do
5
+ @interact = Mastermind::Interact.new
6
+ end
7
+
8
+ it 'can return a colored string given a string input' do
9
+ colored = @interact.color_guess("R")
10
+ expect(colored).to eql("\e[0;31;49mR\e[0m")
11
+ end
12
+
13
+ it 'prints an intro title' do
14
+ expect(@interact.print_title).to include("0;32;49m")
15
+ end
16
+
17
+ it 'prints the main menu' do
18
+ expect(@interact.print_intro).to include("(i)")
19
+ end
20
+
21
+ it 'prints an invalid command message' do
22
+ invalid_cmd = "XXXX"
23
+ expect(@interact.print_invalid(invalid_cmd)).to include("not a valid")
24
+ expect(@interact.print_invalid(invalid_cmd)).to include(invalid_cmd)
25
+ end
26
+
27
+ it 'prints a round over message' do
28
+ expect(@interact.print_round_over).to include("Round over")
29
+ end
30
+
31
+ it 'prints an invalid guess message' do
32
+ invalid_cmd = "XXXX"
33
+ expect(@interact.print_invalid_guess(invalid_cmd)).to include("not a valid")
34
+ expect(@interact.print_invalid_guess(invalid_cmd)).to include(invalid_cmd)
35
+ end
36
+
37
+ end
@@ -0,0 +1,90 @@
1
+ require 'mastermind/play_game'
2
+ require 'mastermind/interact'
3
+ require 'mastermind/game_round'
4
+ require 'spec_helper'
5
+ require 'stringio'
6
+ require 'io/console'
7
+
8
+ RSpec.describe Mastermind::PlayGame do
9
+ it "should be able to quit" do
10
+ stdin = StringIO.new("Q")
11
+ stdout = StringIO.new
12
+ interact = Mastermind::Interact.new
13
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
14
+ expect(game.quit?).to be_falsey
15
+
16
+ game.get_command
17
+ expect(game.quit?).to be_truthy
18
+
19
+ stdin.string = "q"
20
+ game.get_command
21
+ expect(game.quit?).to be_truthy
22
+ end
23
+
24
+ it "should print intro title and content" do
25
+ stdin = StringIO.new("q")
26
+ stdout = StringIO.new
27
+ interact = Mastermind::Interact.new
28
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
29
+ game.run
30
+ expect(stdout.string).to include("(s)1nG1e")
31
+ end
32
+
33
+ it "should generate the specified number of players" do
34
+ stdin = StringIO.new("\nSimon\nAlvin\n")
35
+ stdout = StringIO.new
36
+ interact = Mastermind::Interact.new
37
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
38
+ players = game.player_gen(2)
39
+ expect(players.length).to eql(2)
40
+ expect(players[0]).to be_a Mastermind::Player
41
+ end
42
+
43
+ it "gets a valid name" do
44
+ stdin = StringIO.new("\nANameThatIsTooLong\nAlvin\n")
45
+ stdout = StringIO.new
46
+ interact = Mastermind::Interact.new
47
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
48
+ name = game.get_name(1)
49
+ expect(stdout.string).to include("Name")
50
+ expect(name).to eql("Alvin")
51
+ end
52
+
53
+ it "can validate a name" do
54
+ stdin = StringIO.new("\nANameThatIsTooLong\nAlvin\n")
55
+ stdout = StringIO.new
56
+ interact = Mastermind::Interact.new
57
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
58
+ expect(game.valid_name?("ANameThatIsTooLong")).to be_falsey
59
+ expect(game.valid_name?("")).to be_falsey
60
+ expect(game.valid_name?("Theodore")).to be_truthy
61
+ end
62
+
63
+ it "should play a single player game when prompted" do
64
+ stdin = StringIO.new("s\nTheodore\n")
65
+ stdout = StringIO.new()
66
+ interact = Mastermind::Interact.new
67
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
68
+ thread = Thread.new do
69
+ game.run
70
+ end
71
+ players = []
72
+ expect(Mastermind::GameRound.new(stdin, stdout, Mastermind::Interact.new, players)).to respond_to(:play)
73
+ thread.kill
74
+ end
75
+
76
+ # note: undefined method 'noecho' for stringio... not sure how to test this...
77
+ it "should play a multiplayer game when prompted" do
78
+ stdin = StringIO.new("m\nTheodore\nAlvin\n")
79
+ stdout = StringIO.new()
80
+ interact = Mastermind::Interact.new
81
+ players = []
82
+ game = Mastermind::PlayGame.new(stdin, stdout, interact)
83
+ thread = Thread.new do
84
+ game.run
85
+ end
86
+ expect(Mastermind::GameRound.new(stdin, stdout, Mastermind::Interact.new, players)).to respond_to(:play)
87
+ thread.kill
88
+ end
89
+
90
+ end
@@ -0,0 +1,63 @@
1
+ require 'mastermind/processor'
2
+
3
+ RSpec.describe Mastermind::Processor do
4
+ it "generates a random 4 char secret code" do
5
+ secret = Mastermind::Processor.secret(4, 6)
6
+ expect(secret.length).to eql(4)
7
+ expect(Mastermind::Processor.valid_colors?(secret.join(""), Mastermind::Processor.colors(6))).to be_truthy
8
+ end
9
+
10
+ it "can pull the first x numbers" do
11
+ expect(Mastermind::Processor.colors(3)).to eql(["R", "Y", "G"])
12
+ end
13
+
14
+ context "when validating a guess" do
15
+ it "validates that a correct length guess is valid" do
16
+ valid_length = Mastermind::Processor.valid_length?("RBBY", ["R", "G", "R", "R"])
17
+ expect(valid_length).to be_truthy
18
+ end
19
+
20
+ it "says that an input containing only valid colors is valid" do
21
+ valid_color = Mastermind::Processor.valid_colors?("MRRB", ["R", "G", "B", "Y", "P", "M"])
22
+ expect(valid_color).to be_truthy
23
+ end
24
+
25
+ it "says that an input with the correct length and colors is valid" do
26
+ valid = Mastermind::Processor.validate("RGMY", ["R", "G", "B", "Y"], ["R", "G", "B", "Y", "P", "M"])
27
+ expect(valid).to be_truthy
28
+ end
29
+
30
+ it "says that an input that is too long is invalid" do
31
+ invalid = Mastermind::Processor.validate("RG", ["R", "G", "B", "Y"], ["R", "G", "B", "Y", "P", "M"])
32
+ expect(invalid).to be_falsey
33
+ end
34
+
35
+ it "says that an input that is too short is invalid" do
36
+ invalid = Mastermind::Processor.validate("XRESRG", ["R", "G", "B", "Y"], ["R", "G", "B", "Y", "P", "M"])
37
+ expect(invalid).to be_falsey
38
+ end
39
+
40
+ it "says that an input with invalid letters is invalid" do
41
+ invalid = Mastermind::Processor.validate("RRRX", ["R", "G", "B", "Y"], ["R", "G", "B", "Y", "P", "M"])
42
+ expect(invalid).to be_falsey
43
+ end
44
+ end
45
+
46
+ context "when checking a valid guess" do
47
+ it "checks how many colors are correct but not in the correct position once" do
48
+ colors = Mastermind::Processor.num_correct_colors("YBBB", ["B", "P", "P", "Y"])
49
+ expect(colors).to eql(2)
50
+ end
51
+
52
+ it "checks correct_colors again..." do
53
+ colors = Mastermind::Processor.num_correct_colors("RRBB", ["R", "R", "R", "R"])
54
+ expect(colors).to eql(0)
55
+ end
56
+
57
+ it "checks how many colors are in the correct position" do
58
+ positions = Mastermind::Processor.num_correct_pos("RGYM", ["R", "M", "G", "M"])
59
+ expect(positions).to eql(2)
60
+ end
61
+
62
+ end
63
+ end
@@ -0,0 +1,5 @@
1
+ class StringIO
2
+ def noecho
3
+ yield self
4
+ end
5
+ end