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.
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
- def initialize(type, name, mark)
7
- @name = name
8
- @type = type
9
- @score = 0
10
- @mark = mark
11
- end
12
-
13
- def AddScore()
14
- @score += 1
15
- end
16
-
17
- def ClearScore()
18
- @score = 0
19
- end
20
-
21
- def SwapMark()
22
- if @mark == 'X'
23
- @mark = 'O'
24
- else
25
- @mark = 'X'
26
- end
27
- end
28
-
29
- def Print()
30
- print name + ", type: " + type + ", score: " + score.to_s
31
- end
32
- end
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 = '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 PrintInstructions
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 SelectPlayers(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 SwapPlayers
64
- @player1.SwapMark()
65
- @player2.SwapMark()
66
- end
67
-
68
- def UpdateScore(winner)
69
- #Add a point to the winning player's score
70
- if @player1.mark == winner
71
- @player1.AddScore()
72
- elsif @player2.mark == winner
73
- @player2.AddScore()
74
- else
75
- @cat.AddScore()
76
- end
77
- end
78
-
79
- def ClearScore
80
- @player1.ClearScore
81
- @player2.ClearScore
82
- @cat.ClearScore
83
- end
84
-
85
- def SetDifficulty(difficulty)
86
- if @movenum == 0 or @winner != ''
87
- case difficulty.downcase
88
- when 'easy'
89
- @difficulty = 'easy'
90
- when 'normal'
91
- @difficulty = 'normal'
92
- when 'hard'
93
- @difficulty = 'hard'
94
- else
95
- raise 'Only valid difficulties are easy, medium, and hard'
96
- end
97
- end
98
- end
99
-
100
- #Print outcome of game to players
101
- def PrintWinner
102
- if @winner == 'C'
103
- return "Sorry, cat game."
104
- else
105
- if @player1.mark == @winner
106
- return "Congratulations! " + @player1.name + " wins!"
107
- elsif @player2.mark == @winner and @player2.type == 'human'
108
- return "Congratulations! " + @player2.name + " wins!"
109
- elsif @player2.mark == @winner and @player2.type == 'computer'
110
- #1 player, 'O' won. Do not congratulate player on computer victory.
111
- return "Sorry, " + player2.name + " wins."
112
- end
113
- end
114
- end
115
-
116
- def SwapTurn()
117
- #Toggle current player
118
- if @currentturn == 'X'
119
- @currentturn = 'O'
120
- else
121
- @currentturn = 'X'
122
- end
123
- end
124
-
125
- def SpaceAvailable(move)
126
- if @winner == ''
127
- return @board[move-1] == '_'
128
- else
129
- return false
130
- end
131
- end
132
-
133
- def MakeMove(move)
134
- #store up to 2 moves for undo
135
- @penultimatemoveindex = @lastmoveindex
136
- @lastmoveindex = move-1
137
- #Array index is one less than move space
138
- if @board[@lastmoveindex] == '_'
139
- @board[@lastmoveindex] = @currentturn
140
-
141
- #Increment move counter
142
- @movenum += 1
143
- @movesuccess = true
144
- else
145
- #Do not allow player to choose space that has already been played
146
- @movesuccess = false
147
- end
148
- end
149
-
150
- def ComputerMove()
151
- if @player2.type == 'computer' and @player2.mark == 'O'
152
- return ComputerMoveO()
153
- elsif @player2.type == 'computer' and @player2.mark == 'X'
154
- return ComputerMoveX()
155
- end
156
- end
157
-
158
- def GetLastMove()
159
- return @lastmoveindex
160
- end
161
-
162
- def GetPenultimateMove()
163
- return @penultimatemoveindex
164
- end
165
-
166
- def UndoMove()
167
- if @lastmoveindex == -1
168
- return "Move cannot be undone"
169
- else
170
- if @player2.type=='computer'
171
- if @player2.mark == 'O' or (@player2.mark == 'X' and @movenum > 1)
172
- #Undo computer and player move
173
- #Clear 2 moves from board
174
- @board[@lastmoveindex] = '_'
175
- @board[@penultimatemoveindex] = '_'
176
- @lastmoveindex = -1
177
- @penultimatemoveindex = -1
178
- @movenum -= 2
179
- else
180
- return "Move cannot be undone"
181
- end
182
- else
183
- #Undo player move only
184
- #Clear move
185
- @board[@lastmoveindex] = '_'
186
- @lastmoveindex = -1
187
- #Decrement move counter
188
- @movenum -= 1
189
-
190
- #Toggle current player
191
- if @currentturn == 'X'
192
- @currentturn = 'O'
193
- else
194
- @currentturn = 'X'
195
- end
196
- end
197
- return "Move undone"
198
- end
199
- end
200
-
201
- def ShowComputerMove(move)
202
- #Need to increment index to match normal layout
203
- if @keyboard
204
- movestring = @keyboardboard[move]
205
- elsif @numpad
206
- movestring = @numpadboard[move]
207
- else
208
- movestring = (move+1).to_s
209
- end
210
- return "Computer chooses " + movestring
211
- end
212
-
213
- def CheckWinner(lastmove)
214
- lastmoveindex = lastmove - 1
215
- if @movenum < 3
216
- #Game cannot end in less than 5 moves
217
- #However, computer uses this to check for blocks on move 4
218
- return ''
219
- else
220
- row = lastmoveindex / 3
221
- #Determine row to check using integer division
222
- if (row == 0 and CheckWinTopRow()) or (row == 1 and CheckWinCenterRow()) or (row == 2 and CheckWinBottomRow())
223
- @winner = @currentturn
224
- end
225
-
226
- column = lastmoveindex % 3
227
- #Determine column to check
228
- if (column == 0 and CheckWinLeftColumn()) or (column == 1 and CheckWinMiddleColumn()) or (column == 2 and CheckWinRightColumn())
229
- @winner = @currentturn
230
- end
231
-
232
- if lastmoveindex % 2 == 0
233
- #Determine diagonals to check
234
- if lastmoveindex % 4 == 2
235
- if CheckWinBottomLeftToTopRight() then @winner = @currentturn end
236
- elsif lastmoveindex != 4 and lastmoveindex %4 == 0
237
- if CheckWinTopLeftToBottomRight() then @winner = @currentturn end
238
- elsif lastmoveindex == 4
239
- if CheckWinTopLeftToBottomRight() or CheckWinBottomLeftToTopRight()
240
- @winner = @currentturn
241
- end
242
- end
243
- end
244
- end
245
-
246
- if @movenum == 9 and @winner == ''
247
- #Game over, no winner; cat's game
248
- @winner = 'C'
249
- end
250
-
251
- return @winner
252
- end
253
-
254
-
255
- private
256
-
257
- def ComputerMoveX()
258
-
259
- if @difficulty == 'easy'
260
- #Easy computer moves randomly
261
- move = RandomMove()
262
- elsif @difficulty == 'normal'
263
- #Normal computer moves randomly early on, but looks for wins or blocks as the game progresses
264
- if @movenum < 3
265
- move = RandomMove()
266
- else
267
- #Check for winning move first
268
- move = FindWinningMove()
269
- if move == -1
270
- #No winning move available, try block next
271
- move = FindBlockingMove()
272
- if move == -1
273
- move = RandomMove()
274
- end
275
- end
276
- end
277
- elsif @difficulty == 'hard'
278
- #Hard computer knows what move to make in every situation, until cat game is guaranteed
279
- case movenum
280
- when 0
281
- move = 0
282
- when 2
283
- case @lastmoveindex
284
- when 1,3,5,7
285
- move = 4
286
- when 2,4,6
287
- move = 8
288
- else
289
- move = 2
290
- end
291
- when 4
292
- move = FindWinningMove()
293
- if move == -1
294
- move = FindBlockingMove()
295
- if move == -1
296
- move = 6
297
- end
298
- end
299
- else
300
- move = FindWinningMove()
301
- if move == -1
302
- move = FindBlockingMove()
303
- if move == -1
304
- move = RandomMove()
305
- end
306
- end
307
- end
308
- end
309
- return move + 1
310
- end
311
-
312
- def ComputerMoveO()
313
- if @winner == ''
314
- if @difficulty == 'easy'
315
- #Easy computer moves randomly
316
- move = RandomMove()
317
- elsif @difficulty == 'normal'
318
- #Normal computer moves randomly early on, but looks for wins or blocks as the game progresses
319
- if @movenum < 3
320
- move = RandomMove()
321
- else
322
- #Check for winning move first
323
- move = FindWinningMove()
324
- if move == -1
325
- #No winning move available, try block next
326
- move = FindBlockingMove()
327
- if move == -1 then
328
- move = RandomMove()
329
- end
330
- end
331
- end
332
- elsif @difficulty == 'hard'
333
- #Hard computer knows what move to make in every situation, until cat game is guaranteed
334
- move = -1
335
- if @movenum == 1
336
- if @board[4] == '_'
337
- move = 4
338
- else
339
- move = 0
340
- end
341
- elsif @movenum == 3
342
- if @board[4] == 'X'
343
- if @board[0] != '_' and @board[8] != '_'
344
- move = 2
345
- elsif @board[2] != '_' and @board[6] != '_'
346
- move = 0
347
- end
348
- else
349
- if (@board[1] == 'X' and @board[5] == 'X') or (@board[3] == 'X' and @board[7] == 'X')
350
- move = 0
351
- 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')
352
- move = 1
353
- elsif (@board[1] == 'X' and @board[3] == 'X') or (@board[5] == 'X' and @board[7] == 'X')
354
- move = 2
355
- elsif (@board[2] == 'X' and @board[7] == 'X') or (@board[1] == 'X' and @board[8] == 'X') or (@board[1] == 'X' and @board[7] == 'X')
356
- move = 3
357
- elsif (@board[1] == 'X' and @board[6] == 'X') or (@board[0] == 'X' and @board[7] == 'X')
358
- move = 5
359
- elsif (@board[0] == 'X' and @board[5] == 'X') or (@board[2] == 'X' and @board[3] == 'X')
360
- move = 7
361
- end
362
- end
363
- elsif @movenum == 5
364
- if (@board[4] == 'O' and @board[5] == 'X' and @board[7] == 'X' and @board[1] != '_' and @board[3] != '_')
365
- move = 0
366
- end
367
- end
368
- if move == -1
369
- #Check for winning move first
370
- move = FindWinningMove()
371
- if move == -1
372
- #No winning move available, try block next
373
- move = FindBlockingMove()
374
- if move == -1 then
375
- #puts "Select side"
376
- if @board[1] == '_'
377
- move = 1
378
- elsif @board[3] == '_'
379
- move = 3
380
- elsif @board[5] == '_'
381
- move = 5
382
- elsif @board[7] == '_'
383
- move = 7
384
- end
385
- end
386
- end
387
- end
388
-
389
-
390
- end
391
- return (move+1)
392
- end
393
- end
394
-
395
- def FindWinningMove()
396
- #Pretend O went in any available square and check for win
397
- for i in 0..8
398
- if @board[i] == '_'
399
- @board[i] = @player2.mark
400
- if CheckWinner(i+1) == @player2.mark
401
- @board[i] = '_'
402
- @winner = ''
403
- return i
404
- end
405
- @board[i] = '_'
406
- end
407
- end
408
- return -1
409
- end
410
-
411
- def FindBlockingMove()
412
- #Pretend X went in any available square and check for win; that space necessitates a block
413
- for i in 0..8
414
- if @board[i] == '_'
415
- @board[i] = @player1.mark
416
- #CheckWinner returns currentturn, so it will still be player2
417
- if CheckWinner(i+1) == @player2.mark
418
- @board[i] = '_'
419
- @winner = ''
420
- return i
421
- end
422
- @board[i] = '_'
423
- end
424
- end
425
- return -1
426
- end
427
-
428
- def RandomMove()
429
- #Select random number 0-8 inclusive; this will match board index
430
- move = rand(9)
431
- while @board[move] != '_'
432
- move = rand(9)
433
- end
434
- return move
435
- end
436
-
437
- def CheckWinLeftColumn()
438
- #[0 _ _]
439
- #[3 _ _]
440
- #[6 _ _]
441
- return ((@board[0] == @board[3]) and (@board[0] == @board[6]))
442
- end
443
-
444
- def CheckWinMiddleColumn()
445
- #[_ 1 _]
446
- #[_ 4 _]
447
- #[_ 7 _]
448
- return ((@board[4] == @board[1]) and (@board[4] == @board[7]))
449
- end
450
-
451
- def CheckWinRightColumn()
452
- #[_ _ 2]
453
- #[_ _ 5]
454
- #[_ _ 8]
455
- return ((@board[8] == @board[2]) and (@board[8] == @board[5]))
456
- end
457
-
458
- def CheckWinTopRow()
459
- #[0 1 2]
460
- #[_ _ _]
461
- #[_ _ _]
462
- return ((@board[0] == @board[1]) and (@board[0] == @board[2]))
463
- end
464
-
465
- def CheckWinCenterRow()
466
- #[_ _ _]
467
- #[3 4 5]
468
- #[_ _ _]
469
- return ((@board[4] == @board[3]) and (@board[4] == @board[5]))
470
- end
471
-
472
- def CheckWinBottomRow()
473
- #[_ _ _]
474
- #[_ _ _]
475
- #[6 7 8]
476
- return ((@board[8] == @board[7]) and (@board[8] == @board[6]))
477
- end
478
-
479
- def CheckWinTopLeftToBottomRight()
480
- #[0 _ _]
481
- #[_ 4 _]
482
- #[_ _ 8]
483
- return ((@board[4] == @board[0]) and (@board[4] == @board[8]))
484
- end
485
-
486
- def CheckWinBottomLeftToTopRight()
487
- #[_ _ 2]
488
- #[_ 4 _]
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