swttt-gem 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.0
1
+ 1.0.0
data/lib/.DS_Store ADDED
Binary file
data/lib/board.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class Board
2
- attr_reader :game_history, :game_board, :player_value, :board, :row_scores,
2
+ attr_reader :game_history, :player_value, :row_scores, :dimension,
3
3
  :column_scores, :left_diagonal_score, :right_diagonal_score
4
4
 
5
5
  def initialize(dimension = 3)
@@ -25,6 +25,10 @@ class Board
25
25
  @game_history.size
26
26
  end
27
27
 
28
+ def value_at(row, column)
29
+ @board[row][column]
30
+ end
31
+
28
32
  def is_empty_at?(row, column)
29
33
  @board[row][column].zero?
30
34
  end
@@ -33,8 +37,8 @@ class Board
33
37
  @game_history.size == @dimension*@dimension
34
38
  end
35
39
 
36
- def dimension
37
- @dimension-1
40
+ def winning_value
41
+ @dimension
38
42
  end
39
43
 
40
44
  def player_value
@@ -43,31 +47,29 @@ class Board
43
47
  return value
44
48
  end
45
49
 
46
- def print
47
- (0...@dimension).each { |row| print_row(row) }
48
- puts "\n"
50
+ def corner_occupied?
51
+ corner_cells.each { |corner| return true if @game_history.include?(corner) }
52
+ return false
49
53
  end
50
54
 
51
- private
52
-
53
- def print_row(row)
54
- puts "\n"
55
- (0...@dimension).each { |column| print_square(row, column) }
55
+ def random_corner_cell
56
+ corner_cells[rand(corner_cells.size)]
56
57
  end
57
58
 
58
- def print_square(row, column)
59
- putc "["
60
- putc "X" if @board[row][column] == 1
61
- putc"O" if @board[row][column] == -1
62
- putc " " if @board[row][column].zero?
63
- putc "]"
59
+ private
60
+
61
+ def corner_cells
62
+ [Move.new(0,0),
63
+ Move.new(0,@dimension-1),
64
+ Move.new(@dimension-1,0),
65
+ Move.new(@dimension-1, @dimension-1)]
64
66
  end
65
67
 
66
68
  def update_sums(row, column, update_value)
67
69
  @row_scores[row] += update_value
68
70
  @column_scores[column] += update_value
69
71
  @left_diagonal_score += update_value if row == column
70
- @right_diagonal_score += update_value if row == dimension - column
72
+ @right_diagonal_score += update_value if row == dimension - column - 1
71
73
  end
72
74
  end
73
75
 
data/lib/game_observer.rb CHANGED
@@ -28,11 +28,11 @@ private
28
28
  end
29
29
 
30
30
  def check_for_winner
31
- (0..@game_board.dimension).each { |index| return true if is_a_win?(yield(index)) }
32
- false
31
+ (0...@game_board.dimension).each { |index| return true if is_a_win?(yield(index)) }
32
+ return false
33
33
  end
34
34
 
35
35
  def is_a_win?(value)
36
- value == @game_board.dimension+1
36
+ value == @game_board.winning_value
37
37
  end
38
38
  end
@@ -2,10 +2,6 @@ class MinimaxComputer
2
2
 
3
3
  def initialize(board, observer)
4
4
  @game_board, @observer = board, observer
5
- @first_move = [Move.new(0,0),
6
- Move.new(0,@game_board.dimension),
7
- Move.new(@game_board.dimension,0),
8
- Move.new(@game_board.dimension, @game_board.dimension)]
9
5
  @my_player_value = @game_board.player_value
10
6
  end
11
7
 
@@ -28,37 +24,29 @@ private
28
24
  @game_board.move(move.row, move.column)
29
25
  end
30
26
 
31
- def select_first_move
32
- return corner_move if all_board_corners_open?
33
- return middle_move
34
- end
35
-
36
- def all_board_corners_open?
37
- !@first_move.include?(@game_board.game_history.first)
38
- end
39
-
40
- def corner_move
41
- @first_move[rand(@first_move.size)]
42
- end
43
-
44
- def middle_move
45
- middle = @game_board.dimension/2
46
- return move = Move.new(middle, middle)
47
- end
48
-
49
27
  def perform_mini_max(iteration)
50
28
  return path_score if @observer.game_over?
51
29
  best_moves = BestMove.new(@game_board, @my_player_value)
52
- for_each_cell { |row, column| best_moves.add_better_move(best_moves.value, calculate_path_score(row, column,iteration),
30
+ for_each_cell { |row, column| best_moves.add_better_move(calculate_path_score(row, column,iteration),
53
31
  Move.new(row, column)) if @game_board.is_empty_at?(row, column) }
54
32
  return best_moves.value if !iteration.zero?
55
33
  move = best_moves.get_random_move
56
34
  @game_board.move(move.row, move.column)
57
35
  end
58
36
 
59
- def for_each_cell
60
- (0..@game_board.dimension).each do |row|
61
- (0..@game_board.dimension).each { |column| yield(row, column) }
37
+ def select_first_move
38
+ return @game_board.random_corner_cell if !@game_board.corner_occupied?
39
+ return middle_move
40
+ end
41
+
42
+ def middle_move
43
+ middle = @game_board.dimension/2
44
+ return move = Move.new(middle, middle)
45
+ end
46
+
47
+ def for_each_cell
48
+ (0...@game_board.dimension).each do |row|
49
+ (0...@game_board.dimension).each { |column| yield(row, column) }
62
50
  end
63
51
  end
64
52
 
@@ -103,16 +91,16 @@ class BestMove
103
91
  @moves[rand(@moves.size)]
104
92
  end
105
93
 
106
- def add_better_move(best_score, path_score, move)
107
- if better_or_equal_move?(best_score, path_score)
94
+ def add_better_move(path_score, move)
95
+ if better_or_equal_move?(path_score)
108
96
  @moves.clear and @value = path_score if path_score != @value
109
97
  @moves << move
110
98
  end
111
99
  end
112
100
 
113
- def better_or_equal_move?(best_score, path_score)
114
- (best_score.nil?) or
115
- (path_score >= best_score && @game_board.player_value == @my_player_value) or
116
- (path_score <= best_score && @game_board.player_value != @my_player_value)
101
+ def better_or_equal_move?(path_score)
102
+ (@value.nil?) or
103
+ (path_score >= @value && @game_board.player_value == @my_player_value) or
104
+ (path_score <= @value && @game_board.player_value != @my_player_value)
117
105
  end
118
106
  end
data/spec/board_spec.rb CHANGED
@@ -7,20 +7,20 @@ describe Board do
7
7
  end
8
8
 
9
9
  def iterate_board
10
- (0..@my_board.dimension).each do |row|
11
- (0..@my_board.dimension).each do |column|
10
+ (0...@my_board.dimension).each do |row|
11
+ (0...@my_board.dimension).each do |column|
12
12
  yield(row, column)
13
13
  end
14
14
  end
15
15
  end
16
16
 
17
17
  it "should create a board" do
18
- @my_board.nil?.should == false
18
+ @my_board.nil?.should be_false
19
19
  end
20
20
 
21
21
  it "should check for a full board" do
22
22
  iterate_board { |row, column| @my_board.move(row, column) }
23
- @my_board.full?.should == true
23
+ @my_board.full?.should be_true
24
24
  end
25
25
 
26
26
  context "game history" do
@@ -75,20 +75,15 @@ describe Board do
75
75
  @my_board.player_value.should == 1
76
76
  end
77
77
 
78
- it "has a 3x3 board" do
79
- @my_board.board.size.should == 3
80
- @my_board.board[1].size.should == 3
81
- end
82
-
83
78
  it "updates the board when move is called" do
84
79
  @my_board.move(0,0)
85
- @my_board.board[0][0].should == 1
80
+ @my_board.value_at(0,0).should == 1
86
81
  end
87
82
 
88
83
  it "undos the board" do
89
84
  @my_board.move(2,2)
90
85
  @my_board.undo_move
91
- @my_board.board[2][2].should == 0
86
+ @my_board.value_at(2,2).should == 0
92
87
  end
93
88
 
94
89
  context "sum values" do
@@ -126,4 +121,29 @@ describe Board do
126
121
  @my_board.right_diagonal_score.should == 0
127
122
  end
128
123
  end
124
+
125
+ it "has a winning value" do
126
+ @my_board.winning_value.should == 3
127
+ end
128
+
129
+ it "detects if a corner cell is occupied" do
130
+ @my_board.corner_occupied?.should be_false
131
+ @my_board.move(0,0)
132
+ @my_board.corner_occupied?.should be_true
133
+ @my_board.undo_move
134
+ @my_board.move(0,2)
135
+ @my_board.corner_occupied?.should be_true
136
+ @my_board.undo_move
137
+ @my_board.move(2,0)
138
+ @my_board.corner_occupied?.should be_true
139
+ @my_board.undo_move
140
+ @my_board.move(2,2)
141
+ @my_board.corner_occupied?.should be_true
142
+ end
143
+
144
+ it "returns a random corner cell" do
145
+ move = @my_board.random_corner_cell
146
+ @my_board.move(move.row, move.column)
147
+ @my_board.corner_occupied?.should be_true
148
+ end
129
149
  end
@@ -9,7 +9,7 @@ describe GameObserver do
9
9
  end
10
10
 
11
11
  def iterate_row_or_column
12
- (0..@my_board.dimension).each { |position| yield(position) }
12
+ (0...@my_board.dimension).each { |position| yield(position) }
13
13
  end
14
14
 
15
15
  it "detects a horizontal win" do
@@ -28,7 +28,7 @@ describe GameObserver do
28
28
  end
29
29
 
30
30
  it "detects a right diagonal win" do
31
- iterate_row_or_column { |position| @my_board.move(@my_board.dimension-position,position,1) }
31
+ iterate_row_or_column { |position| @my_board.move(@my_board.dimension-position-1,position,1) }
32
32
  @observer.has_winner?.should == true
33
33
  end
34
34
 
data/swttt-gem.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{swttt-gem}
8
- s.version = "0.9.0"
8
+ s.version = "1.0.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Stephen Walker"]
12
- s.date = %q{2011-05-09}
12
+ s.date = %q{2011-05-11}
13
13
  s.description = %q{TTT Gem}
14
14
  s.email = %q{stephenwalker1988@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  "README.rdoc",
26
26
  "Rakefile",
27
27
  "VERSION",
28
+ "lib/.DS_Store",
28
29
  "lib/board.rb",
29
30
  "lib/game_observer.rb",
30
31
  "lib/human_player.rb",
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swttt-gem
3
3
  version: !ruby/object:Gem::Version
4
- hash: 59
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
+ - 1
7
8
  - 0
8
- - 9
9
9
  - 0
10
- version: 0.9.0
10
+ version: 1.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Stephen Walker
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-09 00:00:00 -05:00
18
+ date: 2011-05-11 00:00:00 -05:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -96,6 +96,7 @@ files:
96
96
  - README.rdoc
97
97
  - Rakefile
98
98
  - VERSION
99
+ - lib/.DS_Store
99
100
  - lib/board.rb
100
101
  - lib/game_observer.rb
101
102
  - lib/human_player.rb