1
+ class Mastermind
2
+ LETTERS = [ "R" , "B" , "Y" , "G" , "O" , "P" ]
3
+ attr_accessor :guess
4
+ def initialize
5
+ @mode = 0
6
+ @guess = [ ]
7
+ @hint = [ ]
8
+ @code = [ ]
9
+ @human_player = HumanPlayer . new
10
+ @computer_player = ComputerPlayer . new
11
+ end
12
+
13
+ # This method allows the user to choose the mode they want to play
14
+ # they can either be the code breaker or code maker
15
+ def set_up_game
16
+ system 'clear'
17
+ @human_player . get_name
18
+ choose_mode
19
+ if @mode == 1
20
+ play_as_codebreaker
21
+ elsif @mode == 2
22
+ play_as_codemaker
23
+ end
24
+ end
25
+
26
+
27
+
28
+ # This method makes shows the mode options and makes sure that the mode that the user
29
+ # chooses is valid.
30
+ def choose_mode
31
+ valid = false
32
+ while valid == false
33
+ puts "Hi #{ @human_player . name } do you want to be the code maker or"
34
+ puts "the code breaker?"
35
+ puts "1. for code breaker"
36
+ puts "2. for code maker"
37
+ puts
38
+ print "Please choose an option: "
39
+ @mode = gets . chomp . to_i
40
+
41
+ if @mode > 0 && @mode <= 2
42
+ valid = true
43
+ else
44
+ system 'clear'
45
+ puts "Invalid selection, please choose either option 1 or 2."
46
+ end
47
+ end
48
+ end
49
+
50
+ # This method will be run if the user chooses the code maker mode.
51
+ # it asks the user to enter a 4 letter code and makes sure it is valid
52
+ # the computer then makes a random intial guess from the letters array
53
+ # the results of this guess will be shown
54
+ # the computer then takes the hints into consideration for its next guess
55
+ # if the hints contain any exacts, the computer will keep these
56
+ # if the the hints contain any nears, they will keep them but put them in
57
+ # another random posistion.
58
+ # if they have any nopes they wont use them again
59
+ # this will repeat until the computer has guessed the code directly
60
+ # or if the iteration runs out.
61
+ def play_as_codemaker
62
+ system 'clear'
63
+ puts "Letters to choose from: #{ LETTERS . inspect } "
64
+ print "Please enter your guess for the four letter code: \n "
65
+ @code = @human_player . enter_code
66
+
67
+ puts
68
+ i = 1
69
+ while i < 11
70
+ if i == 1
71
+ @guess = @computer_player . intial_guess
72
+ else
73
+ @guess = @computer_player . final_array
74
+ @computer_player . temp = [ ]
75
+ end
76
+ puts "Guess Number: #{ i } "
77
+ get_results
78
+
79
+
80
+ puts "The computer player is making his guess #{ i } : "
81
+ 3 . times do
82
+ print ( "." )
83
+ sleep ( 1 )
84
+ end
85
+ show_result
86
+ @computer_player . logic ( @hint , @guess )
87
+ @computer_player . any_nil?
88
+ @computer_player . final_array
89
+ if win?
90
+ puts "The computer has won!"
91
+ play_again?
92
+ end
93
+
94
+ i += 1
95
+ end
96
+ puts "You have won!"
97
+ play_again?
98
+
99
+
100
+
101
+
102
+ end
103
+
104
+
105
+
106
+ # This method detemines the hints from the guess array and
107
+ # fills the hints array with the following:
108
+ # The hint will be exact if the guess is the same letter as the code and in the same position
109
+ # the hint will be near if the guess is just the same letter but not in the same position as the code
110
+ # the hint will be nope if the guess letter is not in the code
111
+ def get_results
112
+ i = 0
113
+ while i < @guess . length
114
+ if @guess [ i ] == @code [ i ]
115
+ @hint [ i ] = "Exact"
116
+ elsif @code . include? ( @guess [ i ] )
117
+ @hint [ i ] = "Near"
118
+ else
119
+ @hint [ i ] = "Nope"
120
+ end
121
+ i += 1
122
+ end
123
+ return @hint
124
+ end
125
+
126
+
127
+ # This method outputs the results of the guess to the screen
128
+ # It shows the guess and the coresponding hints below it
129
+ def show_result
130
+ puts "\n "
131
+ puts "\t Choice 1 \t Choice 2\t Choice 3\t Choice 4"
132
+ puts "-" * 70
133
+ puts "Guess |\t #{ @guess [ 0 ] } \t #{ @guess [ 1 ] } \t \t #{ @guess [ 2 ] } \t \t #{ @guess [ 3 ] } "
134
+ puts "Result |\t #{ @hint [ 0 ] } \t #{ @hint [ 1 ] } \t #{ @hint [ 2 ] } \t #{ @hint [ 3 ] } "
135
+ puts "\n "
136
+ end
137
+
138
+
139
+ # This method runs when the user chooses the code breaker mode
140
+ # It first gets the computer to generate a random code from the letters array
141
+ # it then starts a loop, each time it asks for the user to enter thier guess
142
+ # and it will output the results to the screen.
143
+ # it will stop when the user guesses the code correctly or when the iteration reaches 10
144
+ def play_as_codebreaker
145
+ system 'clear'
146
+ i = 1
147
+ @code = @computer_player . generate_code
148
+ while i < 11
149
+ puts "\n "
150
+ puts "Letters to choose from: #{ LETTERS } "
151
+ puts "\n "
152
+ print "Please enter your guess for the four letter code: \n "
153
+ @guess = @human_player . enter_guess
154
+ get_results
155
+ puts "\n "
156
+ puts "Guess Number: #{ i } "
157
+ show_result
158
+
159
+
160
+ if win?
161
+ puts "You have Won!"
162
+ play_again?
163
+ end
164
+
165
+ i += 1
166
+ end
167
+ puts "You have lost!"
168
+ play_again?
169
+ end
170
+
171
+
172
+ # This method checks to see if all the elements in the hint array
173
+ # equal 'Exact' when they do, the method will return true
174
+ def win?
175
+ @hint . all? { |a | a == "Exact" }
176
+ end
177
+
178
+ # This gives the user the option to play again by going by to
179
+ # the set up game method. It also checks to ensure the user has
180
+ # entered a valid option
181
+ def play_again?
182
+ again = false
183
+ while again == false
184
+ print "Do you want to play again? (y/n): "
185
+ input = gets . chomp . downcase
186
+ if input == "y"
187
+ again = true
188
+ load './mastermind.rb'
189
+ system 'clear'
190
+ set_up_game
191
+ elsif input == "n"
192
+ again = true
193
+ exit
194
+ else
195
+ puts "Invalid input, Please enter either 'y' or 'n'."
196
+ end
197
+ end
198
+ end
199
+
200
+
201
+
202
+
203
+
204
+
205
+
206
+
207
+ class HumanPlayer
208
+ attr_accessor :name
209
+ def initialize
210
+ @name = nil
211
+ end
212
+
213
+ def get_name
214
+ print "What is your name: "
215
+ @name = gets . chomp
216
+ end
217
+
218
+ def enter_guess
219
+ guess = [ ]
220
+ i = 0
221
+ while i < 4
222
+ print "Letter #{ i + 1 } : "
223
+ guess [ i ] = gets . chomp . upcase
224
+ if LETTERS . include? ( guess [ i ] )
225
+ i += 1
226
+ else
227
+ puts "Invalid letter please choose again"
228
+ end
229
+ end
230
+ return guess
231
+ end
232
+
233
+ def enter_code
234
+ code = [ ]
235
+ i = 0
236
+
237
+ while i < 4
238
+ print "Letter #{ i + 1 } : "
239
+ code [ i ] = gets . chomp . upcase
240
+ if LETTERS . include? ( code [ i ] )
241
+ i += 1
242
+ else
243
+ puts "Invalid letter please choose again"
244
+ end
245
+ end
246
+ return code
247
+ end
248
+ end
249
+
250
+
251
+ class ComputerPlayer
252
+ attr_accessor :final_array , :temp , :possible_letters
253
+ def initialize
254
+ @temp = Array . new ( 4 )
255
+ @intial_guess = [ ]
256
+ @free_indexes = [ ]
257
+ @final_array = [ ]
258
+ @possible_letters = LETTERS
259
+ end
260
+
261
+
262
+ # This method generates a random code from the letters array
263
+ def generate_code
264
+ LETTERS . sample ( 4 )
265
+ end
266
+
267
+ # This method makes the computers intial guess, 4 random letters from the letters array
268
+ def intial_guess
269
+ while @intial_guess . size < 4
270
+ @intial_guess << LETTERS [ rand ( LETTERS . size ) ]
271
+ @intial_guess . uniq!
272
+ end
273
+ return @intial_guess
274
+ end
275
+
276
+
277
+ # This method contains the logic for the computers guesses
278
+ # It first checks if any of the hints returned are "Exact"
279
+ # if there any, it will add these to a temp array and then
280
+ # check for any hints that are equal to "near" if there are
281
+ # any it will keep them and put them in a different position
282
+ # in the temp array. It will then check if there are any
283
+ # "nope" hints. If there are any it will delete them from the
284
+ # array of possible letters. The final array is then made from
285
+ # the temp array and is returned. This will be used as the
286
+ # computers next guess
287
+ def logic ( hint , guess )
288
+ i = 0
289
+ while i < hint . size
290
+ if hint [ i ] == "Exact"
291
+ @temp [ i ] = guess [ i ]
292
+ @possible_letters . delete ( guess [ i ] )
293
+ elsif hint [ i ] == "Near"
294
+ if @temp . count ( guess [ i ] ) > 1 || @final_array . count ( guess [ 1 ] ) > 1
295
+ find_empty_indexes
296
+ @temp [ @new_index ] = choose_random_letter ( guess [ i ] )
297
+ else
298
+ find_empty_indexes
299
+ @temp [ @new_index ] = guess [ i ]
300
+ end
301
+ elsif hint [ i ] == "Nope"
302
+ @possible_letters . delete ( guess [ i ] )
303
+ @temp [ i ] = @possible_letters [ rand ( @possible_letters . size ) ]
304
+ end
305
+ i += 1
306
+ end
307
+ @final_array = @temp
308
+ return @final_array
309
+ end
310
+
311
+
312
+ # This method checks to see if any elements in the temp array are equal to nil
313
+ # if they are, they will be assigned a new random letter.
314
+ def any_nil?
315
+ i = 0
316
+ while i < 4
317
+ if @temp [ i ] == nil
318
+ @temp [ i ] = @possible_letters [ rand ( @possible_letters . length ) ]
319
+ end
320
+ i += 1
321
+ end
322
+ @final_array = @temp
323
+ return @final_array
324
+ end
325
+
326
+
327
+ # This method chooses a random letter from the possible_letters array
328
+ def choose_random_letter ( letter )
329
+ new_letter = letter
330
+
331
+ while new_letter == letter
332
+ new_letter = @possible_letters [ rand ( @possible_letters . size ) ]
333
+ end
334
+ return new_letter
335
+ end
336
+
337
+
338
+ # This method finds any empty indexes in the temp array
339
+ def find_empty_indexes
340
+ i = 0
341
+ @free_indexes . clear
342
+ while i < 4
343
+ if @temp [ i ] == nil
344
+ @free_indexes << i
345
+ end
346
+ i += 1
347
+ end
348
+ @new_index = @free_indexes [ rand ( @free_indexes . size ) ]
349
+ return @new_index
350
+ end
351
+ end
352
+ end
353
+
354
+
355
+
356
+ mastermind = Mastermind . new
357
+ mastermind . set_up_game
0 commit comments