nick_tac_toe 0.1.4

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/nick_tac_toe ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
4
+
5
+ require 'nick_tac_toe'
6
+
7
+ players = [Human.new("x"), Minimax.new("o")]
8
+ players.shuffle!
9
+ game = Game.new(players.first, players.last)
10
+
11
+ # the main game loop!
12
+ until game.over?
13
+ game.board.print
14
+ game.take_next_turn
15
+ end
16
+
17
+ # displays the winner
18
+ game.board.print
19
+ if game.won? == true
20
+ puts "We have a winner! o__o"
21
+ else
22
+ puts "It is a draw. u__u"
23
+ end
@@ -0,0 +1,140 @@
1
+ class Board
2
+
3
+ attr_accessor :player_one, :player_two, :cells
4
+
5
+ def initialize(player_one, player_two)
6
+ @cells = [empty_spot]*9
7
+ @player_one = player_one
8
+ @player_two = player_two
9
+ end
10
+
11
+ def print
12
+ list = []
13
+ cells.each_with_index do |marker, index|
14
+ if marker == empty_spot
15
+ list << index+1
16
+ else
17
+ list << marker
18
+ end
19
+ end
20
+ list.map! do |m|
21
+ case m
22
+ when 'x'
23
+ "\e[1;36mx\e[0m"
24
+ when 'o'
25
+ "\e[1;33mo\e[0m"
26
+ else
27
+ "\e[1;30m#{m}\e[0m"
28
+ end
29
+ end
30
+ puts "\n#{list[0]} | #{list[1]} | #{list[2]}\n----------\n#{list[3]} | #{list[4]} | #{list[5]}\n----------\n#{list[6]} | #{list[7]} | #{list[8]}\n "
31
+ end
32
+
33
+ def get_cell position
34
+ @cells[position]
35
+ end
36
+
37
+ def set_cell position, team
38
+ @cells[position] = team
39
+ end
40
+
41
+ def rows
42
+ [@cells[0..2], @cells[3..5], @cells[6..8]]
43
+ end
44
+
45
+ def columns
46
+ [
47
+ [@cells[0], @cells[3], @cells[6]],
48
+ [@cells[1], @cells[4], @cells[7]],
49
+ [@cells[2], @cells[5], @cells[8]]
50
+ ]
51
+ end
52
+
53
+ def diagonals
54
+ [
55
+ [@cells[0], @cells[4], @cells[8]],
56
+ [@cells[2], @cells[4], @cells[6]],
57
+ ]
58
+ end
59
+
60
+ def valid_move?(position)
61
+ if [0,1,2,3,4,5,6,7,8].include?(position.to_i-1)
62
+ if get_cell(position-1) == empty_spot
63
+ return true
64
+ end
65
+ else
66
+ return false
67
+ end
68
+ end
69
+
70
+ def blocking_group_for(team)
71
+ 3.times do |i| # rows
72
+ return [3*i, 3*i + 1, 3*i + 2] if rows[i].sort == [empty_spot, opponent_for(team), opponent_for(team)]
73
+ end
74
+
75
+ 3.times do |i| # columns
76
+ return [i, i + 3, i + 6] if columns[i].sort == [empty_spot, opponent_for(team), opponent_for(team)]
77
+ end
78
+
79
+ return [0, 4, 8] if diagonals[0].sort == [empty_spot, opponent_for(team), opponent_for(team)]
80
+ return [2, 4, 6] if diagonals[1].sort == [empty_spot, opponent_for(team), opponent_for(team)]
81
+
82
+ return nil
83
+ end
84
+
85
+ def empty_spot_in_group(group)
86
+ empty_spots = group.select do |position|
87
+ get_cell(position) == empty_spot
88
+ end
89
+ return empty_spots.first
90
+ end
91
+
92
+ def winning_group_for(team)
93
+ blocking_group_for(opponent_for(team))
94
+ end
95
+
96
+ def center
97
+ 4
98
+ end
99
+
100
+ def empty_at_center?
101
+ get_cell(4) == empty_spot
102
+ end
103
+
104
+ def first_empty_cell
105
+ @cells.each_with_index do |cell, index|
106
+ return index if cell == empty_spot
107
+ end
108
+ end
109
+
110
+ def opponent_for(team)
111
+ if team == @player_one
112
+ return @player_two
113
+ else
114
+ return @player_one
115
+ end
116
+ end
117
+
118
+ def remaining_moves
119
+ count = []
120
+ 9.times do |index|
121
+ count << index if @cells[index] == empty_spot
122
+ end
123
+ return count
124
+ end
125
+
126
+ def copy
127
+ new_board = self.dup
128
+ new_board.cells = @cells.dup
129
+ # new_board.player_one = @player_one.dup
130
+ # new_board.player_one = @player_two.dup
131
+ return new_board
132
+ end
133
+
134
+ private ################################
135
+
136
+ def empty_spot
137
+ ""
138
+ end
139
+
140
+ end
@@ -0,0 +1,61 @@
1
+ require 'nick_tac_toe/board'
2
+
3
+ class Game
4
+ attr_reader :board, :current_player, :player_one, :player_two
5
+
6
+ def initialize(player_one, player_two)
7
+ @board = Board.new(player_one.team, player_two.team)
8
+ @player_one = player_one
9
+ @player_two = player_two
10
+ @current_player = player_one
11
+ end
12
+
13
+ def take_next_turn
14
+ make_move(current_player.move_for(board))
15
+ end
16
+
17
+ def make_move(position)
18
+ @board.set_cell(position, current_player.team)
19
+ toggle_current_player
20
+ end
21
+
22
+ def over?
23
+ return true if draw? || won?
24
+ end
25
+
26
+ def draw?
27
+ return false if won?
28
+ return board.cells.all? {|cell| cell == @player_one.team || cell == @player_two.team }
29
+ end
30
+
31
+ def won?
32
+ return true if board.rows.any? { |row| winner_in_group(row) }
33
+ return true if board.columns.any? { |column| winner_in_group(column) }
34
+ return true if board.diagonals.any? { |diagonal| winner_in_group(diagonal) }
35
+ end
36
+
37
+ def winner_in_group(group)
38
+ group == [@player_two.team]*3 || group == [@player_one.team]*3
39
+ end
40
+
41
+ def player_won?(player)
42
+ return true if board.rows.any? { |row| row == [player.team]*3 }
43
+ return true if board.columns.any? { |column| column == [player.team]*3 }
44
+ return true if board.diagonals.any? { |diagonal| diagonal == [player.team]*3 }
45
+ end
46
+
47
+ def winner
48
+ return player_one if player_won?(player_one)
49
+ return player_two if player_won?(player_two)
50
+ end
51
+
52
+ private
53
+
54
+ def toggle_current_player
55
+ if @current_player == @player_one
56
+ @current_player = @player_two
57
+ else
58
+ @current_player = @player_one
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,12 @@
1
+ class Human < Player
2
+ def move_for(board)
3
+ puts "Where will you move? Pick an empty space, 1-9."
4
+ move_choice = gets.chomp.to_i
5
+ while !board.valid_move?(move_choice)
6
+ puts "That is not a valid move!"
7
+ move_choice = gets.chomp.to_i
8
+ end
9
+ return move_choice - 1
10
+ end
11
+ end
12
+
@@ -0,0 +1,58 @@
1
+ class Minimax < Player
2
+ def move_for(board)
3
+ get_max_move(board).position
4
+ end
5
+
6
+
7
+ def get_max_move(board)
8
+ current_max_move = Move.new(0, -1)
9
+ board.remaining_moves.each do |remaining_move|
10
+ new_board = board.copy
11
+ new_board.set_cell(remaining_move, team)
12
+ return Move.new(remaining_move, 1) if player_won?(team, new_board)
13
+ return Move.new(remaining_move, 0) if new_board.cells.all? { |cell| cell == new_board.player_one || cell == new_board.player_two }
14
+ return Move.new(remaining_move, -1) if player_won?(new_board.opponent_for(team), new_board)
15
+ new_rating = get_min_move(new_board).rating
16
+ if new_rating > current_max_move.rating
17
+ current_max_move = Move.new(remaining_move, new_rating)
18
+ end
19
+ end
20
+ return current_max_move
21
+ end
22
+
23
+ def get_min_move(board)
24
+ current_min_move = Move.new(0, 1)
25
+ board.remaining_moves.each do |remaining_move|
26
+ new_board = board.copy
27
+ new_board.set_cell(remaining_move, new_board.opponent_for(team));
28
+ return Move.new(current_min_move.position, 1) if player_won?(team, new_board)
29
+ return Move.new(current_min_move.position, 0) if new_board.cells.all? { |cell| cell == new_board.player_one || cell == new_board.player_two }
30
+ return Move.new(current_min_move.position, -1) if player_won?(new_board.opponent_for(team), new_board)
31
+ new_rating = get_max_move(new_board).rating
32
+ if new_rating < current_min_move.rating
33
+ current_min_move = Move.new(remaining_move, new_rating)
34
+ end
35
+ end
36
+ return current_min_move
37
+ end
38
+
39
+ def player_won?(team, board)
40
+ return true if board.rows.any? { |row| row == [team]*3 }
41
+ return true if board.columns.any? { |column| column == [team]*3 }
42
+ return true if board.diagonals.any? { |diagonal| diagonal == [team]*3 }
43
+ end
44
+
45
+ def computer?
46
+ true
47
+ end
48
+
49
+ private #################
50
+
51
+ def winning_group(board)
52
+ board.winning_group_for(@team)
53
+ end
54
+
55
+ def blocking_group(board)
56
+ board.blocking_group_for(@team)
57
+ end
58
+ end
@@ -0,0 +1,7 @@
1
+ class Move
2
+ attr_accessor :position, :rating
3
+ def initialize(position, rating)
4
+ @position = position
5
+ @rating = rating
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ class Player
2
+ attr_reader :team
3
+
4
+ def initialize(team)
5
+ @team = team
6
+ end
7
+
8
+ def computer?
9
+ false
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ def get_player_team
2
+ puts "Choose a team (x or o)"
3
+ input = gets.chomp
4
+ unless input == "x" || input == "X" || input == "o" || input == "O"
5
+ puts "That is neither x nor o!"
6
+ get_player_team
7
+ else
8
+ input = "x" if input == "X"
9
+ input = "o" if input == "O"
10
+ return input
11
+ end
12
+ end
@@ -0,0 +1,7 @@
1
+ require 'nick_tac_toe/board'
2
+ require 'nick_tac_toe/game'
3
+ require 'nick_tac_toe/player'
4
+ require 'nick_tac_toe/human'
5
+ require 'nick_tac_toe/minimax'
6
+ require 'nick_tac_toe/move'
7
+ require 'nick_tac_toe/setup'
@@ -0,0 +1,255 @@
1
+ require "nick_tac_toe"
2
+
3
+ describe Board do
4
+ it "has a team for the computer player" do
5
+ board = Board.new("o", "x")
6
+ board.player_one.should == "o"
7
+ end
8
+
9
+ it "has a team for the opponent" do
10
+ board = Board.new("o", "x")
11
+ board.player_two.should == "x"
12
+ end
13
+
14
+ it "gets a cell" do
15
+ board = Board.new("o", "x")
16
+ board.get_cell(0).should == ""
17
+ end
18
+
19
+ it "sets a cell" do
20
+ board = Board.new("o", "x")
21
+ board.set_cell(0, "x")
22
+ board.get_cell(0).should == "x"
23
+ end
24
+
25
+ it "returns the board as rows" do
26
+ board = Board.new("o", "x")
27
+ board.set_cell(0, "x")
28
+ board.set_cell(3, "x")
29
+ board.set_cell(6, "x")
30
+ board.rows.should == [["x", "", ""],["x", "", ""],["x", "", ""]]
31
+ end
32
+
33
+ it "returns the board as coulmns" do
34
+ board = Board.new("o", "x")
35
+ board.set_cell(0, "x")
36
+ board.set_cell(3, "x")
37
+ board.set_cell(6, "x")
38
+ board.columns.should == [["x", "x", "x"],["", "", ""],["", "", ""]]
39
+ end
40
+
41
+ it "returns the board as diagonals" do
42
+ board = Board.new("o", "x")
43
+ board.set_cell(0, "x")
44
+ board.set_cell(3, "x")
45
+ board.set_cell(6, "x")
46
+ board.diagonals.should == [["x", "", ""],["", "", "x"]]
47
+ end
48
+
49
+ it "is valid for an in range move on an empty board" do
50
+ board = Board.new("o", "x")
51
+ board.valid_move?(3).should be_true
52
+ end
53
+
54
+ it "is not valid for a move out of range on an empty board" do
55
+ board = Board.new("o", "x")
56
+ board.valid_move?(-1).should be_false
57
+ end
58
+
59
+ it "is not valid for a move to a space that is not empty" do
60
+ board = Board.new("o", "x")
61
+ board.set_cell(4, "x")
62
+ board.valid_move?(5).should be_false
63
+ end
64
+
65
+ it "is not valid for a string to be a move" do
66
+ board = Board.new("o", "x")
67
+ board.valid_move?("s").should be_false
68
+ end
69
+
70
+ context "blocking_group_for" do
71
+ before(:each) do
72
+ @board = Board.new("o", "x")
73
+ end
74
+
75
+ it "finds the first row as a blocking group" do
76
+ @board.set_cell(0, "x")
77
+ @board.set_cell(1, "x")
78
+ @board.blocking_group_for("o").should == [0,1,2]
79
+ end
80
+
81
+ it "returns nothing if there is nowhere to block" do
82
+ @board.blocking_group_for("o").should == nil
83
+ end
84
+
85
+ it "returns the second row" do
86
+ @board.set_cell(3, "x")
87
+ @board.set_cell(4, "x")
88
+ @board.blocking_group_for("o").should == [3,4,5]
89
+ end
90
+
91
+ it "returns the second row if you can block in the center" do
92
+ @board.set_cell(3, "x")
93
+ @board.set_cell(5, "x")
94
+ @board.blocking_group_for("o").should == [3,4,5]
95
+ end
96
+
97
+ it "returns a blocking row for the other team" do
98
+ @board.set_cell(3, "o")
99
+ @board.set_cell(5, "o")
100
+ @board.blocking_group_for("x").should == [3,4,5]
101
+ end
102
+
103
+ it "does not return a row that is full" do
104
+ @board.set_cell(3, "o")
105
+ @board.set_cell(4, "x")
106
+ @board.set_cell(5, "o")
107
+ @board.blocking_group_for("x").should == nil
108
+ end
109
+
110
+ it "finds the first column as a blocking group" do
111
+ @board.set_cell(0, "x")
112
+ @board.set_cell(3, "x")
113
+ @board.blocking_group_for("o").should == [0,3,6]
114
+ end
115
+
116
+ it "finds the second column as a blocking group" do
117
+ @board.set_cell(1, "x")
118
+ @board.set_cell(4, "x")
119
+ @board.blocking_group_for("o").should == [1,4,7]
120
+ end
121
+
122
+ it "finds the third column as a blocking group" do
123
+ @board.set_cell(2, "x")
124
+ @board.set_cell(5, "x")
125
+ @board.blocking_group_for("o").should == [2,5,8]
126
+ end
127
+
128
+ it "finds the first diagonal as a blocking group" do
129
+ @board.set_cell(0, "x")
130
+ @board.set_cell(4, "x")
131
+ @board.blocking_group_for("o").should == [0,4,8]
132
+ end
133
+
134
+ it "finds the other diagonal as a blocking group" do
135
+ @board.set_cell(2, "x")
136
+ @board.set_cell(4, "x")
137
+ @board.blocking_group_for("o").should == [2,4,6]
138
+ end
139
+ end
140
+
141
+ context "empty_spot_in_group" do
142
+ before(:each) do
143
+ @board = Board.new("o", "x")
144
+ end
145
+
146
+ it "returns the first spot" do
147
+ @board.set_cell(1, "x")
148
+ @board.set_cell(2, "o")
149
+ @board.empty_spot_in_group([0,1,2]).should == 0
150
+ end
151
+
152
+ it "returns the first spot" do
153
+ @board.set_cell(0, "x")
154
+ @board.set_cell(2, "o")
155
+ @board.empty_spot_in_group([0,1,2]).should == 1
156
+ end
157
+
158
+ it "returns the third spot" do
159
+ @board.set_cell(2, "x")
160
+ @board.set_cell(4, "o")
161
+ @board.empty_spot_in_group([2,4,6]).should == 6
162
+ end
163
+
164
+ it "returns nil if the row is full" do
165
+ @board.set_cell(0, "x")
166
+ @board.set_cell(1, "x")
167
+ @board.set_cell(2, "o")
168
+ @board.empty_spot_in_group([0,1,2]).should == nil
169
+ end
170
+ end
171
+
172
+ context "winning_group_for" do
173
+ before(:each) do
174
+ @board = Board.new("o", "x")
175
+ end
176
+
177
+ it "finds the first row as a winning group" do
178
+ @board.set_cell(0, "x")
179
+ @board.set_cell(1, "x")
180
+ @board.winning_group_for("x").should == [0,1,2]
181
+ end
182
+
183
+ it "finds the first column as a winning group" do
184
+ @board.set_cell(0, "x")
185
+ @board.set_cell(3, "x")
186
+ @board.winning_group_for("x").should == [0,3,6]
187
+ end
188
+ end
189
+
190
+ context "remaining_moves" do
191
+ before(:each) do
192
+ @board = Board.new("o", "x")
193
+ end
194
+ it "calculates the number of remaining moves when there is one spot left" do
195
+ @board.set_cell(0, "x")
196
+ @board.set_cell(1, "x")
197
+ @board.set_cell(2, "o")
198
+ @board.set_cell(3, "x")
199
+ @board.set_cell(4, "x")
200
+ @board.set_cell(5, "o")
201
+ @board.set_cell(6, "x")
202
+ @board.set_cell(7, "x")
203
+ @board.remaining_moves.should == [8]
204
+ end
205
+
206
+ it "calculates the number of remaining moves when there are two spots left" do
207
+ @board.set_cell(0, "x")
208
+ @board.set_cell(1, "x")
209
+ @board.set_cell(2, "o")
210
+ @board.set_cell(3, "x")
211
+ @board.set_cell(4, "x")
212
+ @board.set_cell(5, "o")
213
+ @board.set_cell(6, "x")
214
+ @board.remaining_moves.should == [7,8]
215
+ end
216
+
217
+ it "calculates the number of remaining moves when there are no spots left" do
218
+ @board.set_cell(0, "x")
219
+ @board.set_cell(1, "x")
220
+ @board.set_cell(2, "o")
221
+ @board.set_cell(3, "x")
222
+ @board.set_cell(4, "x")
223
+ @board.set_cell(5, "o")
224
+ @board.set_cell(6, "x")
225
+ @board.set_cell(7, "x")
226
+ @board.set_cell(8, "x")
227
+ @board.remaining_moves.should == []
228
+ end
229
+ end
230
+
231
+ context "dup" do
232
+ before(:each) do
233
+ @board = Board.new("o", "x")
234
+ end
235
+ it "returns a copy of the board" do
236
+ @board.set_cell(1,"x")
237
+ new_board = @board.copy
238
+ new_board.get_cell(1).should == "x"
239
+ end
240
+
241
+ it "does not affect the original board when changing the new board" do
242
+ @board.set_cell(1,"x")
243
+ new_board = @board.copy
244
+ new_board.set_cell(0, "o")
245
+ @board.get_cell(0).should_not == "o"
246
+ end
247
+
248
+ it "dups players!" do
249
+ new_board = @board.copy
250
+ new_board.player_one = "f"
251
+ @board.player_one.should_not == "f"
252
+ end
253
+
254
+ end
255
+ end
data/spec/game_spec.rb ADDED
@@ -0,0 +1,181 @@
1
+ require "nick_tac_toe"
2
+
3
+ describe "Game" do
4
+
5
+ before(:each) do
6
+ @player_one = Human.new("x")
7
+ @player_two = Human.new("o")
8
+ @game = Game.new(@player_one, @player_two)
9
+ end
10
+
11
+ context "Game over" do
12
+ it "starts with player one as the current player" do
13
+ @game.current_player.should == @player_one
14
+ end
15
+
16
+ it "makes a move on the board" do
17
+ @game.make_move(1)
18
+ @game.board.get_cell(1).should == @player_one.team
19
+ end
20
+
21
+ it "makes a move using player twos team" do
22
+ @game.make_move(1)
23
+ @game.make_move(2)
24
+ @game.board.get_cell(2).should == @player_two.team
25
+ end
26
+
27
+ it "switches to player two's turn" do
28
+ @game.make_move(2)
29
+ @game.current_player.should == @player_two
30
+ end
31
+
32
+ it "switches back to player one" do
33
+ @game.make_move(2)
34
+ @game.make_move(2)
35
+ @game.current_player.should == @player_one
36
+ end
37
+
38
+ it "does not call the game a draw if the board is not full" do
39
+ @game.board.set_cell(0, "x")
40
+ @game.draw?.should be_false
41
+ end
42
+
43
+ it "is not a draw if the game is full with a winner" do
44
+ @game.board.set_cell(0, "o")
45
+ @game.board.set_cell(1, "o")
46
+ @game.board.set_cell(2, "o")
47
+ @game.board.set_cell(3, "o")
48
+ @game.board.set_cell(4, "x")
49
+ @game.board.set_cell(5, "x")
50
+ @game.board.set_cell(6, "o")
51
+ @game.board.set_cell(7, "x")
52
+ @game.board.set_cell(8, "x")
53
+ @game.draw?.should be_false
54
+ end
55
+
56
+ it "has no winner for new game" do
57
+ @game.winner.should be_nil
58
+ end
59
+
60
+ it "has player one as the winner" do
61
+ @game.board.set_cell(0, "x")
62
+ @game.board.set_cell(3, "o")
63
+ @game.board.set_cell(1, "x")
64
+ @game.board.set_cell(4, "o")
65
+ @game.board.set_cell(2, "x")
66
+ @game.winner.should == @game.player_one
67
+ end
68
+
69
+ it "has player two as the winner" do
70
+ @game.board.set_cell(0, "x")
71
+ @game.board.set_cell(3, "o")
72
+ @game.board.set_cell(1, "x")
73
+ @game.board.set_cell(4, "o")
74
+ @game.board.set_cell(8, "x")
75
+ @game.board.set_cell(5, "o")
76
+ @game.winner.should == @game.player_two
77
+ end
78
+
79
+ it "has no winner for draw game" do
80
+ @game.board.set_cell(0, "x")
81
+ @game.board.set_cell(1, "o")
82
+ @game.board.set_cell(2, "x")
83
+ @game.board.set_cell(3, "x")
84
+ @game.board.set_cell(4, "o")
85
+ @game.board.set_cell(5, "o")
86
+ @game.board.set_cell(6, "o")
87
+ @game.board.set_cell(7, "x")
88
+ @game.board.set_cell(8, "x")
89
+ @game.winner.should be_nil
90
+ end
91
+ # new tests end
92
+
93
+
94
+ it "knows that the game a draw if the board is full" do
95
+ # x o x
96
+ # x o o
97
+ # o x x
98
+ @game.board.set_cell(0, "x")
99
+ @game.board.set_cell(1, "o")
100
+ @game.board.set_cell(2, "x")
101
+ @game.board.set_cell(3, "x")
102
+ @game.board.set_cell(4, "o")
103
+ @game.board.set_cell(5, "o")
104
+ @game.board.set_cell(6, "o")
105
+ @game.board.set_cell(7, "x")
106
+ @game.board.set_cell(8, "x")
107
+ @game.draw?.should be_true
108
+ end
109
+
110
+ it "knows that three horizonal marks is a win" do
111
+ @game.board.set_cell(0, "o")
112
+ @game.board.set_cell(1, "o")
113
+ @game.board.set_cell(2, "o")
114
+ @game.won?.should be_true
115
+ end
116
+
117
+ it "knows that three vertical marks is a win" do
118
+ @game.board.set_cell(0, "o")
119
+ @game.board.set_cell(3, "o")
120
+ @game.board.set_cell(6, "o")
121
+ @game.won?.should be_true
122
+ end
123
+
124
+ it "knows that three diagonal marks is a win" do
125
+ @game.board.set_cell(0, "o")
126
+ @game.board.set_cell(4, "o")
127
+ @game.board.set_cell(8, "o")
128
+ @game.won?.should be_true
129
+ end
130
+
131
+ it "knows if there is not a winner in a group" do
132
+ @game.winner_in_group(["x","x","o"]).should be_false
133
+ end
134
+
135
+ it "knows if there is a winner in a group" do
136
+ @game.winner_in_group(["x","x","x"]).should be_true
137
+ end
138
+
139
+ it "knows if a specific player won in a row" do
140
+ @game.board.set_cell(0, @player_one.team)
141
+ @game.board.set_cell(1, @player_one.team)
142
+ @game.board.set_cell(2, @player_one.team)
143
+ @game.player_won?(@player_one).should be_true
144
+ end
145
+
146
+ it "returns false if the other player won in a row" do
147
+ @game.board.set_cell(0, @player_one.team)
148
+ @game.board.set_cell(1, @player_one.team)
149
+ @game.board.set_cell(2, @player_one.team)
150
+ @game.player_won?(@player_two).should be_false
151
+ end
152
+
153
+ it "knows if a specific player won in a column" do
154
+ @game.board.set_cell(0, @player_one.team)
155
+ @game.board.set_cell(3, @player_one.team)
156
+ @game.board.set_cell(6, @player_one.team)
157
+ @game.player_won?(@player_one).should be_true
158
+ end
159
+
160
+ it "returns false if the other player won in a column" do
161
+ @game.board.set_cell(0, @player_one.team)
162
+ @game.board.set_cell(3, @player_one.team)
163
+ @game.board.set_cell(6, @player_one.team)
164
+ @game.player_won?(@player_two).should be_false
165
+ end
166
+
167
+ it "knows if a specific player won in a diagonal" do
168
+ @game.board.set_cell(0, @player_one.team)
169
+ @game.board.set_cell(4, @player_one.team)
170
+ @game.board.set_cell(8, @player_one.team)
171
+ @game.player_won?(@player_one).should be_true
172
+ end
173
+
174
+ it "returns false if the other player won in a diagonal" do
175
+ @game.board.set_cell(0, @player_one.team)
176
+ @game.board.set_cell(4, @player_one.team)
177
+ @game.board.set_cell(8, @player_one.team)
178
+ @game.player_won?(@player_two).should be_false
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,76 @@
1
+ require "nick_tac_toe"
2
+
3
+ describe "Minimax" do
4
+ before(:each) do
5
+ @board = Board.new("o", "x")
6
+ @minimax = Minimax.new("o")
7
+ end
8
+
9
+ it "blocks the opponent" do
10
+ # o - -
11
+ # x x -
12
+ # - - -
13
+ @board.set_cell(0, "o")
14
+ @board.set_cell(3, "x")
15
+ @board.set_cell(4, "x")
16
+ @minimax.move_for(@board).should == 5
17
+ end
18
+
19
+ xit "should win" do
20
+ @board.set_cell(0, "o")
21
+ @board.set_cell(1, "o")
22
+ @minimax.move_for(@board).should == 2
23
+ end
24
+
25
+ it "places a mark in the last available spot on the board" do
26
+ # 0 1 2 x x o
27
+ # 3 4 5 o o x
28
+ # 6 7 8 x o x
29
+ @board.set_cell(0, "x")
30
+ @board.set_cell(1, "x")
31
+ @board.set_cell(2, "o")
32
+ @board.set_cell(3, "o")
33
+ @board.set_cell(4, "o")
34
+ @board.set_cell(5, "x")
35
+ @board.set_cell(6, "x")
36
+ @board.set_cell(8, "x")
37
+ @minimax.move_for(@board).should == 7
38
+ end
39
+
40
+ xit "places in the top left corner if it goes first" do
41
+ @minimax.move_for(@board).should == 0
42
+ end
43
+
44
+ it "avoids this trap I made!" do
45
+ # x 1 2
46
+ # 3 o 5
47
+ # 6 x 8
48
+ @board.set_cell(0, "x")
49
+ @board.set_cell(4, "o")
50
+ @board.set_cell(7, "x")
51
+ @minimax.move_for(@board).should == 3
52
+ end
53
+
54
+ it "avoids the classic trap!" do
55
+ @board.set_cell(0, "x")
56
+ @minimax.move_for(@board).should == 4
57
+ end
58
+
59
+ it "should avoid stage 2 of the classic trap!" do
60
+ @board.set_cell(0, "x")
61
+ @board.set_cell(4, "o")
62
+ @board.set_cell(8, "x")
63
+ @minimax.move_for(@board).should_not == 2
64
+ end
65
+
66
+ it "should avoid stage 2 of the classic trap part 2!" do
67
+ @board.set_cell(0, "x")
68
+ @board.set_cell(4, "o")
69
+ @board.set_cell(8, "x")
70
+ @minimax.move_for(@board).should_not == 6
71
+ end
72
+
73
+ it "is a computer" do
74
+ Minimax.new("o").should be_computer
75
+ end
76
+ end
data/spec/move_spec.rb ADDED
@@ -0,0 +1,13 @@
1
+ require "nick_tac_toe"
2
+
3
+ describe Move do
4
+ it "has a position" do
5
+ move = Move.new("position", nil)
6
+ move.position.should == "position"
7
+ end
8
+
9
+ it "has a rating" do
10
+ move = Move.new(nil, "rating")
11
+ move.rating.should == "rating"
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ require "nick_tac_toe"
2
+
3
+ describe "Player" do
4
+ it "has a team" do
5
+ Player.new("team").team.should == "team"
6
+ end
7
+
8
+ it "is not a computer by default" do
9
+ Player.new(nil).should_not be_computer
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nick_tac_toe
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.4
6
+ platform: ruby
7
+ authors:
8
+ - Nick Meccia
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2011-10-25 00:00:00 -05:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Your mum.
18
+ email: nickmeccia@gmail.com
19
+ executables:
20
+ - nick_tac_toe
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - bin/nick_tac_toe
27
+ - spec/board_spec.rb
28
+ - spec/game_spec.rb
29
+ - spec/minimax_spec.rb
30
+ - spec/move_spec.rb
31
+ - spec/player_spec.rb
32
+ - lib/nick_tac_toe/board.rb
33
+ - lib/nick_tac_toe/game.rb
34
+ - lib/nick_tac_toe/human.rb
35
+ - lib/nick_tac_toe/minimax.rb
36
+ - lib/nick_tac_toe/move.rb
37
+ - lib/nick_tac_toe/player.rb
38
+ - lib/nick_tac_toe/setup.rb
39
+ - lib/nick_tac_toe.rb
40
+ has_rdoc: true
41
+ homepage:
42
+ licenses: []
43
+
44
+ post_install_message:
45
+ rdoc_options: []
46
+
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.6.2
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Yes, sir.
68
+ test_files: []
69
+