swttt-gem 0.7.0 → 0.8.0
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/VERSION +1 -1
- data/lib/board.rb +11 -7
- data/lib/game_observer.rb +13 -9
- data/lib/minimax_computer.rb +22 -13
- data/spec/board_spec.rb +4 -4
- data/spec/game_observer_spec.rb +7 -7
- data/swttt-gem.gemspec +2 -2
- metadata +4 -4
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.8.0
|
data/lib/board.rb
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
class Board
|
|
2
|
-
attr_reader :game_history, :
|
|
3
|
-
:
|
|
2
|
+
attr_reader :game_history, :game_board, :player_value, :board, :row_scores,
|
|
3
|
+
:column_scores, :left_diagonal_score, :right_diagonal_score
|
|
4
4
|
|
|
5
5
|
def initialize(dimension = 3)
|
|
6
6
|
@dimension = dimension
|
|
7
|
-
@game_history, @board = [],
|
|
8
|
-
@row_scores, @column_scores =
|
|
7
|
+
@game_history, @board = [], Array.new(@dimension) {Array.new(@dimension) {0}}
|
|
8
|
+
@row_scores, @column_scores = Array.new(@dimension) {0}, Array.new(@dimension) {0}
|
|
9
9
|
@left_diagonal_score, @right_diagonal_score = 0, 0
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -33,6 +33,10 @@ class Board
|
|
|
33
33
|
@game_history.size == @dimension*@dimension
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
def dimension
|
|
37
|
+
@dimension-1
|
|
38
|
+
end
|
|
39
|
+
|
|
36
40
|
def player_value
|
|
37
41
|
value = -(number_of_moves_made % 2)
|
|
38
42
|
value = 1 if value.zero?
|
|
@@ -40,7 +44,7 @@ class Board
|
|
|
40
44
|
end
|
|
41
45
|
|
|
42
46
|
def print
|
|
43
|
-
(0
|
|
47
|
+
(0..@dimension).each { |row| print_row(row) }
|
|
44
48
|
puts "\n"
|
|
45
49
|
end
|
|
46
50
|
|
|
@@ -48,7 +52,7 @@ private
|
|
|
48
52
|
|
|
49
53
|
def print_row(row)
|
|
50
54
|
puts "\n"
|
|
51
|
-
(0
|
|
55
|
+
(0..@dimension).each { |column| print_square(row, column) }
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
def print_square(row, column)
|
|
@@ -63,7 +67,7 @@ private
|
|
|
63
67
|
@row_scores[row] += update_value
|
|
64
68
|
@column_scores[column] += update_value
|
|
65
69
|
@left_diagonal_score += update_value if row == column
|
|
66
|
-
@right_diagonal_score += update_value if row ==
|
|
70
|
+
@right_diagonal_score += update_value if row == dimension - column
|
|
67
71
|
end
|
|
68
72
|
end
|
|
69
73
|
|
data/lib/game_observer.rb
CHANGED
|
@@ -14,21 +14,25 @@ class GameObserver
|
|
|
14
14
|
|
|
15
15
|
private
|
|
16
16
|
|
|
17
|
-
def loop_array
|
|
18
|
-
(0...@game_board.dimension).each { |index| return true if yield(index) == @game_board.dimension }
|
|
19
|
-
false
|
|
20
|
-
end
|
|
21
|
-
|
|
22
17
|
def horizontal_win?
|
|
23
|
-
|
|
18
|
+
check_for_winner { |row| @game_board.row_scores[row].abs }
|
|
24
19
|
end
|
|
25
20
|
|
|
26
21
|
def vertical_win?
|
|
27
|
-
|
|
22
|
+
check_for_winner { |column| @game_board.column_scores[column].abs }
|
|
28
23
|
end
|
|
29
24
|
|
|
30
25
|
def diagonal_win?
|
|
31
|
-
(@game_board.left_diagonal_score.abs
|
|
32
|
-
@game_board.right_diagonal_score.abs
|
|
26
|
+
(is_a_win?(@game_board.left_diagonal_score.abs) ||
|
|
27
|
+
is_a_win?(@game_board.right_diagonal_score.abs))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def check_for_winner
|
|
31
|
+
(0..@game_board.dimension).each { |index| return true if is_a_win?(yield(index)) }
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def is_a_win?(value)
|
|
36
|
+
value == @game_board.dimension+1
|
|
33
37
|
end
|
|
34
38
|
end
|
data/lib/minimax_computer.rb
CHANGED
|
@@ -3,9 +3,9 @@ class MinimaxComputer
|
|
|
3
3
|
def initialize(board, observer)
|
|
4
4
|
@game_board, @observer = board, observer
|
|
5
5
|
@first_move = [Move.new(0,0),
|
|
6
|
-
Move.new(0,@game_board.dimension
|
|
7
|
-
Move.new(@game_board.dimension
|
|
8
|
-
Move.new(@game_board.dimension
|
|
6
|
+
Move.new(0,@game_board.dimension),
|
|
7
|
+
Move.new(@game_board.dimension,0),
|
|
8
|
+
Move.new(@game_board.dimension, @game_board.dimension)]
|
|
9
9
|
@my_player_value = @game_board.player_value
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -29,12 +29,21 @@ private
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def select_first_move
|
|
32
|
-
if
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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)
|
|
38
47
|
end
|
|
39
48
|
|
|
40
49
|
def perform_mini_max(iteration)
|
|
@@ -43,13 +52,13 @@ private
|
|
|
43
52
|
for_each_cell { |row, column| best_moves.add_better_move(best_moves.value, calculate_path_score(row, column,iteration),
|
|
44
53
|
Move.new(row, column)) if @game_board.is_empty_at?(row, column) }
|
|
45
54
|
return best_moves.value if !iteration.zero?
|
|
46
|
-
move = best_moves.
|
|
55
|
+
move = best_moves.get_random_move
|
|
47
56
|
@game_board.move(move.row, move.column)
|
|
48
57
|
end
|
|
49
58
|
|
|
50
59
|
def for_each_cell
|
|
51
|
-
(0
|
|
52
|
-
(0
|
|
60
|
+
(0..@game_board.dimension).each do |row|
|
|
61
|
+
(0..@game_board.dimension).each { |column| yield(row, column) }
|
|
53
62
|
end
|
|
54
63
|
end
|
|
55
64
|
|
|
@@ -90,7 +99,7 @@ class BestMove
|
|
|
90
99
|
@game_board, @my_player_value = game_board, my_player_value
|
|
91
100
|
end
|
|
92
101
|
|
|
93
|
-
def
|
|
102
|
+
def get_random_move
|
|
94
103
|
@moves[rand(@moves.size)]
|
|
95
104
|
end
|
|
96
105
|
|
data/spec/board_spec.rb
CHANGED
|
@@ -6,9 +6,9 @@ describe Board do
|
|
|
6
6
|
@my_board = Board.new
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def
|
|
10
|
-
(0
|
|
11
|
-
(0
|
|
9
|
+
def iterate_board
|
|
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
|
|
@@ -19,7 +19,7 @@ describe Board do
|
|
|
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
23
|
@my_board.full?.should == true
|
|
24
24
|
end
|
|
25
25
|
|
data/spec/game_observer_spec.rb
CHANGED
|
@@ -8,32 +8,32 @@ describe GameObserver do
|
|
|
8
8
|
@observer = GameObserver.new(@my_board)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def
|
|
12
|
-
(0
|
|
11
|
+
def iterate_row_or_column
|
|
12
|
+
(0..@my_board.dimension).each { |position| yield(position) }
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
it "detects a horizontal win" do
|
|
16
|
-
|
|
16
|
+
iterate_row_or_column { |column| @my_board.move(0,column,1) }
|
|
17
17
|
@observer.has_winner?.should == true
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
it "detects a vertical win" do
|
|
21
|
-
|
|
21
|
+
iterate_row_or_column { |row| @my_board.move(row,0,1) }
|
|
22
22
|
@observer.has_winner?.should == true
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
it "detects a left diagonal win" do
|
|
26
|
-
|
|
26
|
+
iterate_row_or_column { |position| @my_board.move(position,position,1) }
|
|
27
27
|
@observer.has_winner?.should == true
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
it "detects a right diagonal win" do
|
|
31
|
-
|
|
31
|
+
iterate_row_or_column { |position| @my_board.move(@my_board.dimension-position,position,1) }
|
|
32
32
|
@observer.has_winner?.should == true
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it "detects if the game is over" do
|
|
36
|
-
|
|
36
|
+
iterate_row_or_column { |row| iterate_row_or_column { |column| @my_board.move(row, column, 2) } }
|
|
37
37
|
@observer.game_over?.should == true
|
|
38
38
|
end
|
|
39
39
|
end
|
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.
|
|
8
|
+
s.version = "0.8.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-
|
|
12
|
+
s.date = %q{2011-05-09}
|
|
13
13
|
s.description = %q{TTT Gem}
|
|
14
14
|
s.email = %q{stephenwalker1988@gmail.com}
|
|
15
15
|
s.extra_rdoc_files = [
|
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:
|
|
4
|
+
hash: 63
|
|
5
5
|
prerelease:
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
-
-
|
|
8
|
+
- 8
|
|
9
9
|
- 0
|
|
10
|
-
version: 0.
|
|
10
|
+
version: 0.8.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-
|
|
18
|
+
date: 2011-05-09 00:00:00 -05:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|