tictactoe-randall 0.0.1 → 0.0.2
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/bin/Board.rb +304 -305
- data/bin/ModalWindow.rb +25 -25
- data/bin/player.rb +33 -32
- data/bin/tictactoe.rb +488 -492
- data/{tictactoe_randall → tictactoe} +13 -13
- metadata +20 -28
data/bin/ModalWindow.rb
CHANGED
@@ -1,25 +1,25 @@
|
|
1
|
-
|
2
|
-
##
|
3
|
-
# This is a modal window. In glade, you'll see that the "Modal"
|
4
|
-
# setting is true (default in VR). This means that everything
|
5
|
-
# will halt until it finishes.
|
6
|
-
#
|
7
|
-
# Notice that this window doesn't need to set a parent window
|
8
|
-
# because having it close with its parent isn't an issue--the user is
|
9
|
-
# forced to terminate this window first.
|
10
|
-
#
|
11
|
-
# Note: The "Cancel" button on this window is directly linked to the
|
12
|
-
# destroy_window method (in GladeGUI), so you don't need to write your own method to
|
13
|
-
# handle when the Cancel button is clicked.
|
14
|
-
#
|
15
|
-
|
16
|
-
class ModalWindow #(change name)
|
17
|
-
|
18
|
-
include GladeGUI
|
19
|
-
|
20
|
-
def show(parent)
|
21
|
-
load_glade(__FILE__, parent)
|
22
|
-
show_window()
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
1
|
+
|
2
|
+
##
|
3
|
+
# This is a modal window. In glade, you'll see that the "Modal"
|
4
|
+
# setting is true (default in VR). This means that everything
|
5
|
+
# will halt until it finishes.
|
6
|
+
#
|
7
|
+
# Notice that this window doesn't need to set a parent window
|
8
|
+
# because having it close with its parent isn't an issue--the user is
|
9
|
+
# forced to terminate this window first.
|
10
|
+
#
|
11
|
+
# Note: The "Cancel" button on this window is directly linked to the
|
12
|
+
# destroy_window method (in GladeGUI), so you don't need to write your own method to
|
13
|
+
# handle when the Cancel button is clicked.
|
14
|
+
#
|
15
|
+
|
16
|
+
class ModalWindow #(change name)
|
17
|
+
|
18
|
+
include GladeGUI
|
19
|
+
|
20
|
+
def show(parent)
|
21
|
+
load_glade(__FILE__, parent)
|
22
|
+
show_window()
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/bin/player.rb
CHANGED
@@ -1,32 +1,33 @@
|
|
1
|
-
class Player
|
2
|
-
attr_reader :score
|
3
|
-
attr_reader :type
|
4
|
-
attr_reader :name
|
5
|
-
attr_reader :mark
|
6
|
-
|
7
|
-
|
8
|
-
@
|
9
|
-
@
|
10
|
-
@
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
1
|
+
class Player
|
2
|
+
attr_reader :score
|
3
|
+
attr_reader :type
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :mark
|
6
|
+
|
7
|
+
def initialize(type, name, mark)
|
8
|
+
@name = name
|
9
|
+
@type = type
|
10
|
+
@score = 0
|
11
|
+
@mark = mark
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_score()
|
15
|
+
@score += 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def clear_score()
|
19
|
+
@score = 0
|
20
|
+
end
|
21
|
+
|
22
|
+
def swap_mark()
|
23
|
+
if @mark == :x
|
24
|
+
@mark = :o
|
25
|
+
else
|
26
|
+
@mark = :x
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def print()
|
31
|
+
print "#{@name}, type: #{@type}, score: #{@score}"
|
32
|
+
end
|
33
|
+
end
|
data/bin/tictactoe.rb
CHANGED
@@ -1,492 +1,488 @@
|
|
1
|
-
class TicTacToe
|
2
|
-
|
3
|
-
#Read access to some class variables
|
4
|
-
attr_reader :winner
|
5
|
-
attr_reader :movenum
|
6
|
-
attr_reader :player1
|
7
|
-
attr_reader :player2
|
8
|
-
attr_reader :cat
|
9
|
-
attr_reader :currentturn
|
10
|
-
attr_reader :difficulty
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
#Set starting values for class variables
|
14
|
-
#@board = ['_','_','_','_','_','_','_','_','_']
|
15
|
-
@board = Array.new(9,'_')
|
16
|
-
#Keep track of current player
|
17
|
-
@currentturn =
|
18
|
-
@winner = ''
|
19
|
-
@movenum = 0
|
20
|
-
@lastmoveindex = -1
|
21
|
-
@penultimatemoveindex = -1
|
22
|
-
@difficulty =
|
23
|
-
@movesuccess = false
|
24
|
-
@alternate = true
|
25
|
-
end
|
26
|
-
|
27
|
-
def
|
28
|
-
#Reset game specific variables
|
29
|
-
@board = Array.new(9,'_')
|
30
|
-
@currentturn =
|
31
|
-
@winner = ''
|
32
|
-
@movenum = 0
|
33
|
-
@lastmoveindex = -1
|
34
|
-
@playagain = true
|
35
|
-
end
|
36
|
-
|
37
|
-
def
|
38
|
-
if player1.mark ==
|
39
|
-
return player1.name + ' (X) goes first'
|
40
|
-
else
|
41
|
-
return player2.name + ' (X) goes first'
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def
|
46
|
-
if @movenum == 0 or @winner != '' then
|
47
|
-
if numplayers == 1
|
48
|
-
@player1 = Player.new('human','Player'
|
49
|
-
@player2 = Player.new('computer','Computer'
|
50
|
-
@cat = Player.new('cat', 'Cat',
|
51
|
-
elsif numplayers == 2
|
52
|
-
@player1 = Player.new('human', 'Player 1'
|
53
|
-
@player2 = Player.new('human', 'Player 2'
|
54
|
-
@cat = Player.new('cat', 'Cat',
|
55
|
-
else
|
56
|
-
raise 'Invalid number of players: ' + numplayers
|
57
|
-
end
|
58
|
-
else
|
59
|
-
raise "Cannot change players during game"
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def
|
64
|
-
@player1.
|
65
|
-
@player2.
|
66
|
-
end
|
67
|
-
|
68
|
-
def
|
69
|
-
#Add a point to the winning player's score
|
70
|
-
if @player1.mark == winner
|
71
|
-
@player1.
|
72
|
-
elsif @player2.mark == winner
|
73
|
-
@player2.
|
74
|
-
else
|
75
|
-
@cat.
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def
|
80
|
-
@player1.
|
81
|
-
@player2.
|
82
|
-
@cat.
|
83
|
-
end
|
84
|
-
|
85
|
-
def
|
86
|
-
if @movenum == 0 or @winner != ''
|
87
|
-
case difficulty
|
88
|
-
when
|
89
|
-
@difficulty =
|
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
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
@
|
140
|
-
|
141
|
-
#
|
142
|
-
@
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
end
|
157
|
-
|
158
|
-
def
|
159
|
-
return @
|
160
|
-
end
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
@
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
#
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
movestring =
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
#
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
if
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
if
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
move
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
move =
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
move
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
move = 0
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
move =
|
351
|
-
elsif (@board[
|
352
|
-
move =
|
353
|
-
elsif (@board[1] ==
|
354
|
-
move =
|
355
|
-
elsif (@board[
|
356
|
-
move =
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
end
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
move =
|
378
|
-
elsif @board[
|
379
|
-
move =
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
move
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
#[6 _ _]
|
490
|
-
return ((@board[4] == @board[2]) and (@board[4] == @board[6]))
|
491
|
-
end
|
492
|
-
end
|
1
|
+
class TicTacToe
|
2
|
+
|
3
|
+
#Read access to some class variables
|
4
|
+
attr_reader :winner
|
5
|
+
attr_reader :movenum
|
6
|
+
attr_reader :player1
|
7
|
+
attr_reader :player2
|
8
|
+
attr_reader :cat
|
9
|
+
attr_reader :currentturn
|
10
|
+
attr_reader :difficulty
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
#Set starting values for class variables
|
14
|
+
#@board = ['_','_','_','_','_','_','_','_','_']
|
15
|
+
@board = Array.new(9,'_')
|
16
|
+
#Keep track of current player
|
17
|
+
@currentturn = :x
|
18
|
+
@winner = ''
|
19
|
+
@movenum = 0
|
20
|
+
@lastmoveindex = -1
|
21
|
+
@penultimatemoveindex = -1
|
22
|
+
@difficulty = :easy
|
23
|
+
@movesuccess = false
|
24
|
+
@alternate = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def reset
|
28
|
+
#Reset game specific variables
|
29
|
+
@board = Array.new(9,'_')
|
30
|
+
@currentturn = :x
|
31
|
+
@winner = ''
|
32
|
+
@movenum = 0
|
33
|
+
@lastmoveindex = -1
|
34
|
+
@playagain = true
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_instructions
|
38
|
+
if player1.mark == :x
|
39
|
+
return player1.name + ' (X) goes first'
|
40
|
+
else
|
41
|
+
return player2.name + ' (X) goes first'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def select_players(numplayers)
|
46
|
+
if @movenum == 0 or @winner != '' then
|
47
|
+
if numplayers == 1
|
48
|
+
@player1 = Player.new('human','Player',:x)
|
49
|
+
@player2 = Player.new('computer','Computer',:o)
|
50
|
+
@cat = Player.new('cat', 'Cat', :c)
|
51
|
+
elsif numplayers == 2
|
52
|
+
@player1 = Player.new('human', 'Player 1',:x)
|
53
|
+
@player2 = Player.new('human', 'Player 2',:o)
|
54
|
+
@cat = Player.new('cat', 'Cat', :c)
|
55
|
+
else
|
56
|
+
raise 'Invalid number of players: ' + numplayers
|
57
|
+
end
|
58
|
+
else
|
59
|
+
raise "Cannot change players during game"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def swap_players
|
64
|
+
@player1.swap_mark()
|
65
|
+
@player2.swap_mark()
|
66
|
+
end
|
67
|
+
|
68
|
+
def update_score(winner)
|
69
|
+
#Add a point to the winning player's score
|
70
|
+
if @player1.mark == winner
|
71
|
+
@player1.add_score()
|
72
|
+
elsif @player2.mark == winner
|
73
|
+
@player2.add_score()
|
74
|
+
else
|
75
|
+
@cat.add_score()
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def clear_score
|
80
|
+
@player1.clear_score
|
81
|
+
@player2.clear_score
|
82
|
+
@cat.clear_score
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_difficulty(difficulty)
|
86
|
+
if @movenum == 0 or @winner != ''
|
87
|
+
case difficulty
|
88
|
+
when :easy, :normal, :hard
|
89
|
+
@difficulty = difficulty
|
90
|
+
else
|
91
|
+
raise 'Only valid difficulties are easy, medium, and hard'
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#Print outcome of game to players
|
97
|
+
def print_winner
|
98
|
+
if @winner == :c
|
99
|
+
return "Sorry, cat game."
|
100
|
+
else
|
101
|
+
if @player1.mark == @winner
|
102
|
+
return "Congratulations! " + @player1.name + " wins!"
|
103
|
+
elsif @player2.mark == @winner and @player2.type == 'human'
|
104
|
+
return "Congratulations! " + @player2.name + " wins!"
|
105
|
+
elsif @player2.mark == @winner and @player2.type == 'computer'
|
106
|
+
#1 player, 'O' won. Do not congratulate player on computer victory.
|
107
|
+
return "Sorry, " + player2.name + " wins."
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def swap_turn()
|
113
|
+
#Toggle current player
|
114
|
+
if @currentturn == :x
|
115
|
+
@currentturn = :o
|
116
|
+
else
|
117
|
+
@currentturn = :x
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def space_available(move)
|
122
|
+
if @winner == ''
|
123
|
+
return @board[move-1] == '_'
|
124
|
+
else
|
125
|
+
return false
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def make_move(move)
|
130
|
+
#store up to 2 moves for undo
|
131
|
+
@penultimatemoveindex = @lastmoveindex
|
132
|
+
@lastmoveindex = move-1
|
133
|
+
#Array index is one less than move space
|
134
|
+
if @board[@lastmoveindex] == '_'
|
135
|
+
@board[@lastmoveindex] = @currentturn
|
136
|
+
|
137
|
+
#Increment move counter
|
138
|
+
@movenum += 1
|
139
|
+
@movesuccess = true
|
140
|
+
else
|
141
|
+
#Do not allow player to choose space that has already been played
|
142
|
+
@movesuccess = false
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def computer_move()
|
147
|
+
if @player2.type == 'computer' and @player2.mark == :o
|
148
|
+
return computer_move_o()
|
149
|
+
elsif @player2.type == 'computer' and @player2.mark == :x
|
150
|
+
return computer_move_x()
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def get_last_move()
|
155
|
+
return @lastmoveindex
|
156
|
+
end
|
157
|
+
|
158
|
+
def get_penultimate_move()
|
159
|
+
return @penultimatemoveindex
|
160
|
+
end
|
161
|
+
|
162
|
+
def undo_move()
|
163
|
+
if @lastmoveindex == -1
|
164
|
+
return "Move cannot be undone"
|
165
|
+
else
|
166
|
+
if @player2.type=='computer'
|
167
|
+
if @player2.mark == :o or (@player2.mark == :x and @movenum > 1)
|
168
|
+
#Undo computer and player move
|
169
|
+
#Clear 2 moves from board
|
170
|
+
@board[@lastmoveindex] = '_'
|
171
|
+
@board[@penultimatemoveindex] = '_'
|
172
|
+
@lastmoveindex = -1
|
173
|
+
@penultimatemoveindex = -1
|
174
|
+
@movenum -= 2
|
175
|
+
else
|
176
|
+
return "Move cannot be undone"
|
177
|
+
end
|
178
|
+
else
|
179
|
+
#Undo player move only
|
180
|
+
#Clear move
|
181
|
+
@board[@lastmoveindex] = '_'
|
182
|
+
@lastmoveindex = -1
|
183
|
+
#Decrement move counter
|
184
|
+
@movenum -= 1
|
185
|
+
|
186
|
+
#Toggle current player
|
187
|
+
if @currentturn == :x
|
188
|
+
@currentturn = :o
|
189
|
+
else
|
190
|
+
@currentturn = :x
|
191
|
+
end
|
192
|
+
end
|
193
|
+
return "Move undone"
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def show_computer_move(move)
|
198
|
+
#Need to increment index to match normal layout
|
199
|
+
if @keyboard
|
200
|
+
movestring = @keyboardboard[move]
|
201
|
+
elsif @numpad
|
202
|
+
movestring = @numpadboard[move]
|
203
|
+
else
|
204
|
+
movestring = (move+1).to_s
|
205
|
+
end
|
206
|
+
return "Computer chooses " + movestring
|
207
|
+
end
|
208
|
+
|
209
|
+
def check_winner(lastmove)
|
210
|
+
lastmoveindex = lastmove - 1
|
211
|
+
if @movenum < 3
|
212
|
+
#Game cannot end in less than 5 moves
|
213
|
+
#However, computer uses this to check for blocks on move 4
|
214
|
+
return ''
|
215
|
+
else
|
216
|
+
row = lastmoveindex / 3
|
217
|
+
#Determine row to check using integer division
|
218
|
+
if (row == 0 and check_win_top_row()) or (row == 1 and check_win_center_row()) or (row == 2 and check_win_bottom_row())
|
219
|
+
@winner = @currentturn
|
220
|
+
end
|
221
|
+
|
222
|
+
column = lastmoveindex % 3
|
223
|
+
#Determine column to check
|
224
|
+
if (column == 0 and check_win_left_column()) or (column == 1 and check_win_middle_column()) or (column == 2 and check_win_right_column())
|
225
|
+
@winner = @currentturn
|
226
|
+
end
|
227
|
+
|
228
|
+
if lastmoveindex % 2 == 0
|
229
|
+
#Determine diagonals to check
|
230
|
+
if lastmoveindex % 4 == 2
|
231
|
+
if check_win_bottom_left_to_top_right() then @winner = @currentturn end
|
232
|
+
elsif lastmoveindex != 4 and lastmoveindex %4 == 0
|
233
|
+
if check_win_top_left_to_bottom_right() then @winner = @currentturn end
|
234
|
+
elsif lastmoveindex == 4
|
235
|
+
if check_win_top_left_to_bottom_right() or check_win_bottom_left_to_top_right()
|
236
|
+
@winner = @currentturn
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
if @movenum == 9 and @winner == ''
|
243
|
+
#Game over, no winner; cat's game
|
244
|
+
@winner = :c
|
245
|
+
end
|
246
|
+
|
247
|
+
return @winner
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
private
|
252
|
+
|
253
|
+
def computer_move_x()
|
254
|
+
|
255
|
+
if @difficulty == :easy
|
256
|
+
#Easy computer moves randomly
|
257
|
+
move = random_move()
|
258
|
+
elsif @difficulty == :normal
|
259
|
+
#Normal computer moves randomly early on, but looks for wins or blocks as the game progresses
|
260
|
+
if @movenum < 3
|
261
|
+
move = random_move()
|
262
|
+
else
|
263
|
+
#Check for winning move first
|
264
|
+
move = find_winning_move()
|
265
|
+
if move == -1
|
266
|
+
#No winning move available, try block next
|
267
|
+
move = find_blocking_move()
|
268
|
+
if move == -1
|
269
|
+
move = random_move()
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
elsif @difficulty == :hard
|
274
|
+
#Hard computer knows what move to make in every situation, until cat game is guaranteed
|
275
|
+
case movenum
|
276
|
+
when 0
|
277
|
+
move = 0
|
278
|
+
when 2
|
279
|
+
case @lastmoveindex
|
280
|
+
when 1,3,5,7
|
281
|
+
move = 4
|
282
|
+
when 2,4,6
|
283
|
+
move = 8
|
284
|
+
else
|
285
|
+
move = 2
|
286
|
+
end
|
287
|
+
when 4
|
288
|
+
move = find_winning_move()
|
289
|
+
if move == -1
|
290
|
+
move = find_blocking_move()
|
291
|
+
if move == -1
|
292
|
+
move = 6
|
293
|
+
end
|
294
|
+
end
|
295
|
+
else
|
296
|
+
move = find_winning_move()
|
297
|
+
if move == -1
|
298
|
+
move = find_blocking_move()
|
299
|
+
if move == -1
|
300
|
+
move = random_move()
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
end
|
305
|
+
return move + 1
|
306
|
+
end
|
307
|
+
|
308
|
+
def computer_move_o()
|
309
|
+
if @winner == ''
|
310
|
+
if @difficulty == :easy
|
311
|
+
#Easy computer moves randomly
|
312
|
+
move = random_move()
|
313
|
+
elsif @difficulty == :normal
|
314
|
+
#Normal computer moves randomly early on, but looks for wins or blocks as the game progresses
|
315
|
+
if @movenum < 3
|
316
|
+
move = random_move()
|
317
|
+
else
|
318
|
+
#Check for winning move first
|
319
|
+
move = find_winning_move()
|
320
|
+
if move == -1
|
321
|
+
#No winning move available, try block next
|
322
|
+
move = find_blocking_move()
|
323
|
+
if move == -1 then
|
324
|
+
move = random_move()
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
328
|
+
elsif @difficulty == :hard
|
329
|
+
#Hard computer knows what move to make in every situation, until cat game is guaranteed
|
330
|
+
move = -1
|
331
|
+
if @movenum == 1
|
332
|
+
if @board[4] == '_'
|
333
|
+
move = 4
|
334
|
+
else
|
335
|
+
move = 0
|
336
|
+
end
|
337
|
+
elsif @movenum == 3
|
338
|
+
if @board[4] == :x
|
339
|
+
if @board[0] != '_' and @board[8] != '_'
|
340
|
+
move = 2
|
341
|
+
elsif @board[2] != '_' and @board[6] != '_'
|
342
|
+
move = 0
|
343
|
+
end
|
344
|
+
else
|
345
|
+
if (@board[1] == :x and @board[5] == :x) or (@board[3] == :x and @board[7] == :x)
|
346
|
+
move = 0
|
347
|
+
elsif (@board[3] == :x and @board[8] == :x) or (@board[5] == :x and @board[6] == :x) or (@board[3] == :x and @board[5] == :x) or (@board[0] == :x and @board[8] == :x) or (@board[2] == :x and @board[6] == :x)
|
348
|
+
move = 1
|
349
|
+
elsif (@board[1] == :x and @board[3] == :x) or (@board[5] == :x and @board[7] == :x)
|
350
|
+
move = 2
|
351
|
+
elsif (@board[2] == :x and @board[7] == :x) or (@board[1] == :x and @board[8] == :x) or (@board[1] == :x and @board[7] == :x)
|
352
|
+
move = 3
|
353
|
+
elsif (@board[1] == :x and @board[6] == :x) or (@board[0] == :x and @board[7] == :x)
|
354
|
+
move = 5
|
355
|
+
elsif (@board[0] == :x and @board[5] == :x) or (@board[2] == :x and @board[3] == :x)
|
356
|
+
move = 7
|
357
|
+
end
|
358
|
+
end
|
359
|
+
elsif @movenum == 5
|
360
|
+
if (@board[4] == :o and @board[5] == :x and @board[7] == :x and @board[1] != '_' and @board[3] != '_')
|
361
|
+
move = 0
|
362
|
+
end
|
363
|
+
end
|
364
|
+
if move == -1
|
365
|
+
#Check for winning move first
|
366
|
+
move = find_winning_move()
|
367
|
+
if move == -1
|
368
|
+
#No winning move available, try block next
|
369
|
+
move = find_blocking_move()
|
370
|
+
if move == -1 then
|
371
|
+
#puts "Select side"
|
372
|
+
if @board[1] == '_'
|
373
|
+
move = 1
|
374
|
+
elsif @board[3] == '_'
|
375
|
+
move = 3
|
376
|
+
elsif @board[5] == '_'
|
377
|
+
move = 5
|
378
|
+
elsif @board[7] == '_'
|
379
|
+
move = 7
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
|
386
|
+
end
|
387
|
+
return (move+1)
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def find_winning_move()
|
392
|
+
#Pretend O went in any available square and check for win
|
393
|
+
for i in 0..8
|
394
|
+
if @board[i] == '_'
|
395
|
+
@board[i] = @player2.mark
|
396
|
+
if check_winner(i+1) == @player2.mark
|
397
|
+
@board[i] = '_'
|
398
|
+
@winner = ''
|
399
|
+
return i
|
400
|
+
end
|
401
|
+
@board[i] = '_'
|
402
|
+
end
|
403
|
+
end
|
404
|
+
return -1
|
405
|
+
end
|
406
|
+
|
407
|
+
def find_blocking_move()
|
408
|
+
#Pretend X went in any available square and check for win; that space necessitates a block
|
409
|
+
for i in 0..8
|
410
|
+
if @board[i] == '_'
|
411
|
+
@board[i] = @player1.mark
|
412
|
+
#CheckWinner returns currentturn, so it will still be player2
|
413
|
+
if check_winner(i+1) == @player2.mark
|
414
|
+
@board[i] = '_'
|
415
|
+
@winner = ''
|
416
|
+
return i
|
417
|
+
end
|
418
|
+
@board[i] = '_'
|
419
|
+
end
|
420
|
+
end
|
421
|
+
return -1
|
422
|
+
end
|
423
|
+
|
424
|
+
def random_move()
|
425
|
+
#Select random number 0-8 inclusive; this will match board index
|
426
|
+
move = rand(9)
|
427
|
+
while @board[move] != '_'
|
428
|
+
move = rand(9)
|
429
|
+
end
|
430
|
+
return move
|
431
|
+
end
|
432
|
+
|
433
|
+
def check_win_left_column()
|
434
|
+
#[0 _ _]
|
435
|
+
#[3 _ _]
|
436
|
+
#[6 _ _]
|
437
|
+
return ((@board[0] == @board[3]) and (@board[0] == @board[6]))
|
438
|
+
end
|
439
|
+
|
440
|
+
def check_win_middle_column()
|
441
|
+
#[_ 1 _]
|
442
|
+
#[_ 4 _]
|
443
|
+
#[_ 7 _]
|
444
|
+
return ((@board[4] == @board[1]) and (@board[4] == @board[7]))
|
445
|
+
end
|
446
|
+
|
447
|
+
def check_win_right_column()
|
448
|
+
#[_ _ 2]
|
449
|
+
#[_ _ 5]
|
450
|
+
#[_ _ 8]
|
451
|
+
return ((@board[8] == @board[2]) and (@board[8] == @board[5]))
|
452
|
+
end
|
453
|
+
|
454
|
+
def check_win_top_row()
|
455
|
+
#[0 1 2]
|
456
|
+
#[_ _ _]
|
457
|
+
#[_ _ _]
|
458
|
+
return ((@board[0] == @board[1]) and (@board[0] == @board[2]))
|
459
|
+
end
|
460
|
+
|
461
|
+
def check_win_center_row()
|
462
|
+
#[_ _ _]
|
463
|
+
#[3 4 5]
|
464
|
+
#[_ _ _]
|
465
|
+
return ((@board[4] == @board[3]) and (@board[4] == @board[5]))
|
466
|
+
end
|
467
|
+
|
468
|
+
def check_win_bottom_row()
|
469
|
+
#[_ _ _]
|
470
|
+
#[_ _ _]
|
471
|
+
#[6 7 8]
|
472
|
+
return ((@board[8] == @board[7]) and (@board[8] == @board[6]))
|
473
|
+
end
|
474
|
+
|
475
|
+
def check_win_top_left_to_bottom_right()
|
476
|
+
#[0 _ _]
|
477
|
+
#[_ 4 _]
|
478
|
+
#[_ _ 8]
|
479
|
+
return ((@board[4] == @board[0]) and (@board[4] == @board[8]))
|
480
|
+
end
|
481
|
+
|
482
|
+
def check_win_bottom_left_to_top_right()
|
483
|
+
#[_ _ 2]
|
484
|
+
#[_ 4 _]
|
485
|
+
#[6 _ _]
|
486
|
+
return ((@board[4] == @board[2]) and (@board[4] == @board[6]))
|
487
|
+
end
|
488
|
+
end
|