bashrw-ttt 0.1.1

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.
Files changed (131) hide show
  1. data/bin/play.rb +10 -0
  2. data/lib/bashrw-ttt.rb +3 -0
  3. data/lib/ttt/ai.rb +33 -0
  4. data/lib/ttt/ai_easy.rb +17 -0
  5. data/lib/ttt/ai_hard.rb +21 -0
  6. data/lib/ttt/ai_medium.rb +21 -0
  7. data/lib/ttt/ai_medium_back.rb +58 -0
  8. data/lib/ttt/board.rb +37 -0
  9. data/lib/ttt/config_helper.rb +53 -0
  10. data/lib/ttt/config_options.rb +27 -0
  11. data/lib/ttt/context.rb +214 -0
  12. data/lib/ttt/four_by_four.rb +62 -0
  13. data/lib/ttt/game.rb +94 -0
  14. data/lib/ttt/game_history.rb +37 -0
  15. data/lib/ttt/game_interactor.rb +126 -0
  16. data/lib/ttt/human.rb +12 -0
  17. data/lib/ttt/interfaces/cli/lib/cli/board_selection.rb +34 -0
  18. data/lib/ttt/interfaces/cli/lib/cli/cli_game.rb +186 -0
  19. data/lib/ttt/interfaces/cli/lib/cli/cli_presenter.rb +216 -0
  20. data/lib/ttt/interfaces/cli/lib/cli/clio.rb +17 -0
  21. data/lib/ttt/interfaces/cli/lib/cli/play_again.rb +38 -0
  22. data/lib/ttt/interfaces/cli/lib/cli/player_selection.rb +43 -0
  23. data/lib/ttt/interfaces/cli/lib/cli/selection.rb +8 -0
  24. data/lib/ttt/interfaces/cli/lib/cli/walk_history.rb +48 -0
  25. data/lib/ttt/interfaces/cli/spec/cli/board_selection_spec.rb +29 -0
  26. data/lib/ttt/interfaces/cli/spec/cli/cli_game_spec.rb +376 -0
  27. data/lib/ttt/interfaces/cli/spec/cli/cli_presenter_spec.rb +147 -0
  28. data/lib/ttt/interfaces/cli/spec/cli/play_again_spec.rb +39 -0
  29. data/lib/ttt/interfaces/cli/spec/cli/player_selection_spec.rb +62 -0
  30. data/lib/ttt/interfaces/cli/spec/cli/walk_history_spec.rb +115 -0
  31. data/lib/ttt/interfaces/cli/spec/spec_helper.rb +14 -0
  32. data/lib/ttt/interfaces/limelight/four_by_four/props.rb +1 -0
  33. data/lib/ttt/interfaces/limelight/four_by_four/styles.rb +74 -0
  34. data/lib/ttt/interfaces/limelight/four_by_four_finished/props.rb +1 -0
  35. data/lib/ttt/interfaces/limelight/four_by_four_finished/styles.rb +74 -0
  36. data/lib/ttt/interfaces/limelight/game_list/players/load_button.rb +10 -0
  37. data/lib/ttt/interfaces/limelight/game_list/props.rb +17 -0
  38. data/lib/ttt/interfaces/limelight/game_list/styles.rb +8 -0
  39. data/lib/ttt/interfaces/limelight/main_menu/players/exit_ttt.rb +3 -0
  40. data/lib/ttt/interfaces/limelight/main_menu/players/load_game.rb +3 -0
  41. data/lib/ttt/interfaces/limelight/main_menu/players/new_game.rb +3 -0
  42. data/lib/ttt/interfaces/limelight/main_menu/props.rb +17 -0
  43. data/lib/ttt/interfaces/limelight/new_game/players/board_type.rb +1 -0
  44. data/lib/ttt/interfaces/limelight/new_game/players/new_game.rb +5 -0
  45. data/lib/ttt/interfaces/limelight/new_game/players/player_type.rb +1 -0
  46. data/lib/ttt/interfaces/limelight/new_game/players/setup_button.rb +21 -0
  47. data/lib/ttt/interfaces/limelight/new_game/props.rb +21 -0
  48. data/lib/ttt/interfaces/limelight/new_game/styles.rb +23 -0
  49. data/lib/ttt/interfaces/limelight/partials/board_partial.rb +14 -0
  50. data/lib/ttt/interfaces/limelight/partials/menu_button_partial.rb +5 -0
  51. data/lib/ttt/interfaces/limelight/partials/move_history_partial.rb +6 -0
  52. data/lib/ttt/interfaces/limelight/partials/title_history_partial.rb +10 -0
  53. data/lib/ttt/interfaces/limelight/players/board.rb +3 -0
  54. data/lib/ttt/interfaces/limelight/players/game.rb +4 -0
  55. data/lib/ttt/interfaces/limelight/players/generic_move_history.rb +5 -0
  56. data/lib/ttt/interfaces/limelight/players/generic_player.rb +8 -0
  57. data/lib/ttt/interfaces/limelight/players/left_button.rb +3 -0
  58. data/lib/ttt/interfaces/limelight/players/main_menu.rb +3 -0
  59. data/lib/ttt/interfaces/limelight/players/right_button.rb +3 -0
  60. data/lib/ttt/interfaces/limelight/playscripts/game_playscript.rb +169 -0
  61. data/lib/ttt/interfaces/limelight/production.rb +14 -0
  62. data/lib/ttt/interfaces/limelight/spec/game_playscript_spec.rb +218 -0
  63. data/lib/ttt/interfaces/limelight/spec/main_menu/main_menu_spec.rb +38 -0
  64. data/lib/ttt/interfaces/limelight/spec/new_game/new_game_spec.rb +45 -0
  65. data/lib/ttt/interfaces/limelight/spec/spec_helper.rb +8 -0
  66. data/lib/ttt/interfaces/limelight/stages.rb +6 -0
  67. data/lib/ttt/interfaces/limelight/styles.rb +119 -0
  68. data/lib/ttt/interfaces/limelight/three_by_three/props.rb +1 -0
  69. data/lib/ttt/interfaces/limelight/three_by_three/styles.rb +39 -0
  70. data/lib/ttt/interfaces/limelight/three_by_three_by_three/props.rb +1 -0
  71. data/lib/ttt/interfaces/limelight/three_by_three_by_three/styles.rb +119 -0
  72. data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/props.rb +1 -0
  73. data/lib/ttt/interfaces/limelight/three_by_three_by_three_finished/styles.rb +119 -0
  74. data/lib/ttt/interfaces/limelight/three_by_three_finished/props.rb +1 -0
  75. data/lib/ttt/interfaces/limelight/three_by_three_finished/styles.rb +39 -0
  76. data/lib/ttt/interfaces/rails/app/controllers/application_controller.rb +3 -0
  77. data/lib/ttt/interfaces/rails/app/controllers/ttt_games_controller.rb +86 -0
  78. data/lib/ttt/interfaces/rails/app/helpers/application_helper.rb +2 -0
  79. data/lib/ttt/interfaces/rails/app/models/ttt_game.rb +34 -0
  80. data/lib/ttt/interfaces/rails/app/presenters/web_game_presenter.rb +159 -0
  81. data/lib/ttt/interfaces/rails/autotest/discover.rb +1 -0
  82. data/lib/ttt/interfaces/rails/config/application.rb +67 -0
  83. data/lib/ttt/interfaces/rails/config/boot.rb +6 -0
  84. data/lib/ttt/interfaces/rails/config/environment.rb +5 -0
  85. data/lib/ttt/interfaces/rails/config/environments/development.rb +37 -0
  86. data/lib/ttt/interfaces/rails/config/environments/production.rb +67 -0
  87. data/lib/ttt/interfaces/rails/config/environments/test.rb +37 -0
  88. data/lib/ttt/interfaces/rails/config/initializers/backtrace_silencers.rb +7 -0
  89. data/lib/ttt/interfaces/rails/config/initializers/inflections.rb +15 -0
  90. data/lib/ttt/interfaces/rails/config/initializers/mime_types.rb +5 -0
  91. data/lib/ttt/interfaces/rails/config/initializers/secret_token.rb +7 -0
  92. data/lib/ttt/interfaces/rails/config/initializers/session_store.rb +8 -0
  93. data/lib/ttt/interfaces/rails/config/initializers/wrap_parameters.rb +14 -0
  94. data/lib/ttt/interfaces/rails/config/routes.rb +49 -0
  95. data/lib/ttt/interfaces/rails/db/schema.rb +28 -0
  96. data/lib/ttt/interfaces/rails/db/seeds.rb +7 -0
  97. data/lib/ttt/interfaces/rails/spec/controllers/ttt_games_controller_spec.rb +211 -0
  98. data/lib/ttt/interfaces/rails/spec/models/ttt_game_spec.rb +76 -0
  99. data/lib/ttt/interfaces/rails/spec/presenters/web_game_presenter_spec.rb +52 -0
  100. data/lib/ttt/interfaces/rails/spec/spec_helper.rb +13 -0
  101. data/lib/ttt/interfaces/web_interface/html_generator.rb +76 -0
  102. data/lib/ttt/interfaces/web_interface/web_game_presenter.rb +0 -0
  103. data/lib/ttt/minimax.rb +46 -0
  104. data/lib/ttt/move_history.rb +10 -0
  105. data/lib/ttt/move_traverser.rb +49 -0
  106. data/lib/ttt/player.rb +15 -0
  107. data/lib/ttt/riak_db.rb +53 -0
  108. data/lib/ttt/setup.rb +59 -0
  109. data/lib/ttt/three_by_three.rb +35 -0
  110. data/lib/ttt/three_by_three_by_three.rb +37 -0
  111. data/spec/spec_helper.rb +22 -0
  112. data/spec/ttt/ai_easy_spec.rb +15 -0
  113. data/spec/ttt/ai_hard_spec.rb +76 -0
  114. data/spec/ttt/ai_medium_spec.rb +65 -0
  115. data/spec/ttt/ai_spec.rb +50 -0
  116. data/spec/ttt/board_spec.rb +96 -0
  117. data/spec/ttt/config_helper_spec.rb +54 -0
  118. data/spec/ttt/context_spec.rb +398 -0
  119. data/spec/ttt/four_by_four_spec.rb +112 -0
  120. data/spec/ttt/game_history_spec.rb +41 -0
  121. data/spec/ttt/game_interactor_spec.rb +197 -0
  122. data/spec/ttt/game_spec.rb +246 -0
  123. data/spec/ttt/human_spec.rb +18 -0
  124. data/spec/ttt/move_history_spec.rb +13 -0
  125. data/spec/ttt/move_traverser_spec.rb +75 -0
  126. data/spec/ttt/player_spec.rb +13 -0
  127. data/spec/ttt/riak_db_spec.rb +64 -0
  128. data/spec/ttt/setup_spec.rb +63 -0
  129. data/spec/ttt/three_by_three_by_three_spec.rb +130 -0
  130. data/spec/ttt/three_by_three_spec.rb +110 -0
  131. metadata +239 -0
data/bin/play.rb ADDED
@@ -0,0 +1,10 @@
1
+ #! /usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+ $LOAD_PATH.unshift File.expand_path("../../lib/ttt/interfaces/cli/lib", __FILE__)
4
+ require 'ttt/setup'
5
+ require 'ttt/context'
6
+ require 'cli/cli_game'
7
+
8
+ context = TTT::Context.instance
9
+ context.setup = TTT::Setup
10
+ CLI::CLIGame.new(context, $stdin, $stdout).play
data/lib/bashrw-ttt.rb ADDED
@@ -0,0 +1,3 @@
1
+ Dir.glob(File.expand_path "../ttt/*.rb", __FILE__) do |file|
2
+ require file
3
+ end
data/lib/ttt/ai.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'ttt/player'
2
+ require 'ttt/minimax'
3
+
4
+ module TTT
5
+ class AI < Player
6
+ include Minimax
7
+ attr_accessor :board, :max_ply
8
+
9
+ def move(options)
10
+ self.board = (options[:board].dup)
11
+ end
12
+
13
+ def opposite_side(side)
14
+ side == "x" ? "o" : "x"
15
+ end
16
+
17
+ def available_moves
18
+ board[].each.with_index.map { |element, index| index if element == " " }.compact
19
+ end
20
+
21
+ def undo_move(index)
22
+ board[][index] = " "
23
+ end
24
+
25
+ def no_gui?
26
+ true
27
+ end
28
+
29
+ def prompt
30
+ "Computer thinking."
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,17 @@
1
+ require 'ttt/ai'
2
+ module TTT
3
+ class AIEasy < AI
4
+ def move(options)
5
+ super
6
+ random_move
7
+ end
8
+
9
+ def random_move
10
+ move = nil
11
+ available_moves.each do |square|
12
+ move ||= square if Time.new.usec % 3 == 0
13
+ end
14
+ return(move ? move : available_moves.last)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,21 @@
1
+ require 'ttt/ai'
2
+ module TTT
3
+ class AIHard < AI
4
+
5
+ def move(options)
6
+ super
7
+ self.max_ply = max_ply_for(available_moves.length)
8
+ minimax
9
+ end
10
+
11
+ def max_ply_for(moves)
12
+ if moves > 16
13
+ return 7
14
+ elsif moves > 10
15
+ return 9
16
+ else
17
+ return 11
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'ttt/ai'
2
+ module TTT
3
+ class AIMedium < AI
4
+
5
+ def move(options)
6
+ super
7
+ self.max_ply = set_max_ply(available_moves.length)
8
+ minimax
9
+ end
10
+
11
+ def set_max_ply(moves)
12
+ if moves > 15
13
+ return 3
14
+ elsif moves > 5
15
+ return 5
16
+ else
17
+ return 7
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,58 @@
1
+ require 'ttt/ai'
2
+ module TTT
3
+ class AIMedium < AI
4
+ attr_accessor :max_ply, :best
5
+
6
+ def move(options)
7
+ board(options[:board].dup)
8
+ self.max_ply = set_max_ply(available_moves.length)
9
+ self.best = {}
10
+ self.best[:index] = nil
11
+ self.best[:score] = 0
12
+ minimax
13
+ end
14
+
15
+ def minimax(max_player = true, ply = 0, min_score = 1000, max_score = -1000)
16
+ if board.winner?
17
+ return(max_player ? (-1000 + ply) : (1000 - ply))
18
+ elsif board.draw_game?
19
+ return 0
20
+ end
21
+
22
+ if ply >= max_ply
23
+ return(max_player ? (max_score) : (min_score))
24
+ end
25
+
26
+ best_move = 0
27
+ score = (max_player ? max_score : min_score )
28
+ available_moves.each do |index|
29
+ board[][index] = ( max_player ? side : opposite_side(side) )
30
+ score = minimax(!max_player, ply + 1, min_score, max_score)
31
+ undo_move(index)
32
+ if max_player && score > max_score
33
+ max_score = score
34
+ best_move = index
35
+ elsif !max_player && score < min_score
36
+ min_score = score
37
+ end
38
+ break if max_min_swapped?(max_score, min_score)
39
+ end
40
+
41
+ return( ply == 0 ? best_move : ( max_player ? max_score : min_score ) )
42
+ end
43
+
44
+ def set_max_ply(moves)
45
+ if moves > 15
46
+ return 3
47
+ elsif moves > 5
48
+ return 5
49
+ else
50
+ return 7
51
+ end
52
+ end
53
+
54
+ def max_min_swapped?(max, min)
55
+ max >= min
56
+ end
57
+ end
58
+ end
data/lib/ttt/board.rb ADDED
@@ -0,0 +1,37 @@
1
+ module TTT
2
+ class Board
3
+ attr_accessor :board
4
+
5
+ def []
6
+ board
7
+ end
8
+
9
+ def []=(array)
10
+ self.board = array
11
+ end
12
+
13
+ def update cell, side
14
+ self.board[cell.to_i] = side
15
+ end
16
+
17
+ def empty?
18
+ !(board.include?("x") || board.include?("o"))
19
+ end
20
+
21
+ def full?
22
+ !board.include?(" ")
23
+ end
24
+
25
+ def free?(cell)
26
+ board[cell] == " "
27
+ end
28
+
29
+ def finished?
30
+ draw_game? || winner?
31
+ end
32
+
33
+ def draw_game?
34
+ (!board.include? " ") && !winner?
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,53 @@
1
+ require 'ttt/config_options'
2
+
3
+ module TTT
4
+ class ConfigHelper
5
+ def self.player_types
6
+ ConfigOptions::HUMAN_READABLE_PLAYERS
7
+ end
8
+
9
+ def self.board_types
10
+ ConfigOptions::HUMAN_READABLE_BOARDS
11
+ end
12
+
13
+ def self.bucket
14
+ ConfigOptions::BUCKET
15
+ end
16
+
17
+ def self.port
18
+ ConfigOptions::PORT
19
+ end
20
+
21
+ def self.http_backend
22
+ ConfigOptions::HTTP_BACKEND
23
+ end
24
+
25
+ def self.get_player_const(player_type)
26
+ ConfigOptions::PLAYERS[get_player_index(player_type)]
27
+ end
28
+
29
+ def self.get_board_const(board_type)
30
+ ConfigOptions::BOARDS[get_board_index(board_type)]
31
+ end
32
+
33
+ def self.get_player_index(player_type)
34
+ ConfigOptions::HUMAN_READABLE_PLAYERS.index(player_type)
35
+ end
36
+
37
+ def self.get_board_index(board_type)
38
+ ConfigOptions::HUMAN_READABLE_BOARDS.index(board_type)
39
+ end
40
+
41
+ def self.get_db_const
42
+ ConfigOptions::DB
43
+ end
44
+
45
+ def self.get_history_const
46
+ ConfigOptions::HISTORY
47
+ end
48
+
49
+ def self.get_game_interactor_const
50
+ ConfigOptions::INTERACTOR
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,27 @@
1
+ require 'ttt/ai'
2
+ require 'ttt/ai_easy'
3
+ require 'ttt/ai_medium'
4
+ require 'ttt/ai_hard'
5
+ require 'ttt/human'
6
+ require 'ttt/board'
7
+ require 'ttt/three_by_three'
8
+ require 'ttt/four_by_four'
9
+ require 'ttt/three_by_three_by_three'
10
+ require 'ttt/game_history'
11
+ require 'ttt/riak_db'
12
+ require 'ttt/game_interactor'
13
+
14
+ module TTT
15
+ class ConfigOptions
16
+ BOARDS = [TTT::ThreeByThree, TTT::FourByFour, TTT::ThreeByThreeByThree]
17
+ HUMAN_READABLE_BOARDS = %w(3x3 4x4 3x3x3)
18
+ PLAYERS = [TTT::Human, TTT::AIEasy, TTT::AIMedium, TTT::AIHard]
19
+ HUMAN_READABLE_PLAYERS = ["Human", "AI Easy", "AI Medium", "AI Hard"]
20
+ DB = TTT::RiakDB
21
+ PORT = 8091 # 8098 is default
22
+ HTTP_BACKEND = :Excon
23
+ BUCKET = "ttt_games"
24
+ HISTORY = TTT::GameHistory
25
+ INTERACTOR = TTT::GameInteractor
26
+ end
27
+ end
@@ -0,0 +1,214 @@
1
+ require 'ttt/setup'
2
+
3
+ module TTT
4
+ class Context
5
+ class << self
6
+ def instance
7
+ @instance ||= new
8
+ end
9
+
10
+ private :new
11
+ end
12
+
13
+ def setup=(setup_const)
14
+ @setup = setup_const.new
15
+ end
16
+
17
+ def setup
18
+ @setup
19
+ end
20
+
21
+ def players
22
+ @setup.players
23
+ end
24
+
25
+ def boards
26
+ @setup.boards
27
+ end
28
+
29
+ def create_game(player1, player2, board)
30
+ game = @setup.new_game(:player1 => player1, :player2 => player2, :board => board)
31
+ add_game(game)
32
+ end
33
+
34
+ def add_game(game)
35
+ game_interactor.add_game(game)
36
+ end
37
+
38
+ def get_game(id)
39
+ game_interactor.get_game(id)
40
+ end
41
+
42
+ def save_game(id, game)
43
+ game_interactor.save_game(id, game)
44
+ end
45
+
46
+ def game_list
47
+ game_interactor.game_list
48
+ end
49
+
50
+ def delete_game(id)
51
+ game_interactor.delete_game(id)
52
+ end
53
+
54
+ def update_game(id, move, side)
55
+ if game = db_instance.get_game(id)
56
+ game_interactor.update_game(game, move, side)
57
+ game_interactor.save_game(id, game)
58
+ else
59
+ nil
60
+ end
61
+ end
62
+
63
+ def ai_move?(id)
64
+ if game = db_instance.get_game(id)
65
+ game_interactor.ai_move?(game)
66
+ else
67
+ nil
68
+ end
69
+ end
70
+
71
+ def ai_move(id)
72
+ if game = game_interactor.get_game(id)
73
+ game_interactor.ai_move(id, game)
74
+ else
75
+ nil
76
+ end
77
+ end
78
+
79
+ def finished?(id)
80
+ if game = game_interactor.get_game(id)
81
+ game_interactor.finished?(game)
82
+ else
83
+ nil
84
+ end
85
+ end
86
+
87
+ def winner(id)
88
+ if game = game_interactor.get_game(id)
89
+ game_interactor.winner(game)
90
+ else
91
+ nil
92
+ end
93
+ end
94
+
95
+ def winner?(id)
96
+ if game = game_interactor.get_game(id)
97
+ game_interactor.winner?(game)
98
+ else
99
+ nil
100
+ end
101
+ end
102
+
103
+ def draw?(id)
104
+ if game = game_interactor.get_game(id)
105
+ game_interactor.draw?(game)
106
+ else
107
+ nil
108
+ end
109
+ end
110
+
111
+ def which_board(id)
112
+ if game = game_interactor.get_game(id)
113
+ game_interactor.which_board(game)
114
+ else
115
+ nil
116
+ end
117
+ end
118
+
119
+ def valid_move?(id, move)
120
+ if game = game_interactor.get_game(id)
121
+ game_interactor.valid_move?(game, move)
122
+ else
123
+ nil
124
+ end
125
+ end
126
+
127
+ def adjust_move_index(id, value)
128
+ if game = game_interactor.get_game(id)
129
+ game_interactor.adjust_move_index(game, value)
130
+ game_interactor.save_game(id, game)
131
+ else
132
+ nil
133
+ end
134
+ end
135
+
136
+ def get_history_board(id)
137
+ if game = game_interactor.get_game(id)
138
+ game_interactor.get_history_board(game)
139
+ else
140
+ nil
141
+ end
142
+ end
143
+
144
+ def get_move_traverser(id)
145
+ if game = game_interactor.get_game(id)
146
+ game_interactor.get_move_traverser(game)
147
+ else
148
+ nil
149
+ end
150
+ end
151
+
152
+ def save_move_traverser(id, move_traverser)
153
+ if game = game_interactor.get_game(id)
154
+ game_interactor.save_move_traverser(id, game, move_traverser)
155
+ end
156
+ end
157
+
158
+ def initialize_history(id)
159
+ if game = game_interactor.get_game(id)
160
+ game_interactor.initialize_history(game)
161
+ save_game(id, game)
162
+ else
163
+ nil
164
+ end
165
+ end
166
+
167
+ def get_history_length(id)
168
+ if game = game_interactor.get_game(id)
169
+ game_interactor.get_history_length(game)
170
+ end
171
+ end
172
+
173
+ def get_move_index(id)
174
+ if game = game_interactor.get_game(id)
175
+ game_interactor.get_move_index(game)
176
+ else
177
+ nil
178
+ end
179
+ end
180
+
181
+ def get_history(id)
182
+ if game = game_interactor.get_game(id)
183
+ game_interactor.get_history(game)
184
+ else
185
+ nil
186
+ end
187
+ end
188
+
189
+ def which_current_player?(id)
190
+ if game = game_interactor.get_game(id)
191
+ game_interactor.which_current_player?(game)
192
+ else
193
+ nil
194
+ end
195
+ end
196
+
197
+ def board(id)
198
+ if game = game_interactor.get_game(id)
199
+ game_interactor.board(game)
200
+ else
201
+ nil
202
+ end
203
+ end
204
+
205
+ private
206
+ def db_instance
207
+ @db_instance ||= @setup.new_db
208
+ end
209
+
210
+ def game_interactor
211
+ @game_interactor ||= @setup.new_interactor
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,62 @@
1
+ require 'ttt/board'
2
+ module TTT
3
+ class FourByFour < Board
4
+ attr_accessor :x_arr, :diag_arr, :block_arr
5
+ def initialize
6
+ self.board = Array.new(16, " ")
7
+ self.x_arr = [[0,1,2,3], [4,5,6,7], [8,9,10,11], [12,13,14,15]]
8
+ self.diag_arr = [[0, 5, 10, 15], [3, 6, 9, 12]]
9
+ self.block_arr = [[0,1,4,5], [1,2,5,6], [2,3,6,7], [4,5,8,9], [5,6,9,10], [6,7,10,11], [8,9,12,13], [9,10,13,14], [10,11,14,15]]
10
+ end
11
+
12
+ def winner?
13
+ horizontal_winner? || vertical_winner? || diag_winner? || block_winner?
14
+ end
15
+
16
+ def horizontal_winner?
17
+ x_arr.each do |x_win|
18
+ return true if board[x_win[0]] != " " &&
19
+ board[x_win[0]] == board[x_win[1]] &&
20
+ board[x_win[1]] == board[x_win[2]] &&
21
+ board[x_win[2]] == board[x_win[3]]
22
+ end
23
+ false
24
+ end
25
+
26
+ def vertical_winner?
27
+ x_arr.transpose.each do |y_win|
28
+ return true if board[y_win[0]] != " " &&
29
+ board[y_win[0]] == board[y_win[1]] &&
30
+ board[y_win[1]] == board[y_win[2]] &&
31
+ board[y_win[2]] == board[y_win[3]]
32
+ end
33
+ false
34
+ end
35
+
36
+ def diag_winner?
37
+ diag_arr.each do |diag_win|
38
+ return true if board[diag_win[0]] != " " &&
39
+ board[diag_win[0]] == board[diag_win[1]] &&
40
+ board[diag_win[1]] == board[diag_win[2]] &&
41
+ board[diag_win[2]] == board[diag_win[3]]
42
+
43
+ end
44
+ false
45
+ end
46
+
47
+ def block_winner?
48
+ block_arr.each do |block_win|
49
+ return true if board[block_win[0]] != " " &&
50
+ board[block_win[0]] == board[block_win[1]] &&
51
+ board[block_win[1]] == board[block_win[2]] &&
52
+ board[block_win[2]] == board[block_win[3]]
53
+
54
+ end
55
+ false
56
+ end
57
+
58
+ def board_type
59
+ "four_by_four"
60
+ end
61
+ end
62
+ end
data/lib/ttt/game.rb ADDED
@@ -0,0 +1,94 @@
1
+ module TTT
2
+ class Game
3
+ attr_accessor :board, :player1, :player2, :current_player, :history, :db
4
+
5
+ def initialize(options)
6
+ self.board = options[:board]
7
+ self.player1 = options[:player1]
8
+ self.player2 = options[:player2]
9
+ self.current_player = self.player1
10
+ self.history = options.fetch(:history)
11
+ end
12
+
13
+ def ai_move?
14
+ current_player.no_gui?
15
+ end
16
+
17
+ def which_board
18
+ board.board_type
19
+ end
20
+
21
+ def next_move
22
+ return nil unless ai_move?
23
+ input = current_player.move(:board => board)
24
+ mark_move(input)
25
+ record_move(input)
26
+ switch_player
27
+ input
28
+ end
29
+
30
+ def valid_move?(input)
31
+ input.class == Fixnum && 0 <= input && input <= (board[].length - 1) && board.free?(input.to_i)
32
+ end
33
+
34
+ def mark_move(cell, side = current_player.side)
35
+ board.update(cell, side)
36
+ end
37
+
38
+ def record_move(cell, side = current_player.side)
39
+ history.record_move(cell, side)
40
+ end
41
+
42
+ def show_history
43
+ history.show
44
+ end
45
+
46
+ def adjust_move_index(index_diff)
47
+ history.adjust_move_index(index_diff)
48
+ end
49
+
50
+ def get_history_board(move_number_limit = history.move_traverser.move_index)
51
+ history.get_history_board(board, move_number_limit)
52
+ end
53
+
54
+ def initialize_history
55
+ history.initialize_history
56
+ end
57
+
58
+ def switch_player
59
+ if player1.side == current_player.side
60
+ self.current_player = self.player2
61
+ else
62
+ self.current_player = self.player1
63
+ end
64
+ end
65
+
66
+ def which_current_player?
67
+ current_player.equal?(player1) ? "Player 1" : "Player 2"
68
+ end
69
+
70
+ def last_player
71
+ current_player == player1 ? "Player 2" : "Player 1"
72
+ end
73
+
74
+ def finished?
75
+ board.finished?
76
+ end
77
+
78
+ def not_finished?
79
+ !board.finished?
80
+ end
81
+
82
+ def winner?
83
+ board.winner?
84
+ end
85
+
86
+ def draw?
87
+ board.draw_game?
88
+ end
89
+
90
+ def board_arr
91
+ board[]
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,37 @@
1
+ require 'ttt/move_history'
2
+ require 'ttt/move_traverser'
3
+
4
+ module TTT
5
+ class GameHistory
6
+ attr_accessor :history, :move_traverser
7
+ def initialize
8
+ self.history = []
9
+ self.move_traverser = MoveTraverser.new(self)
10
+ end
11
+
12
+ def record_move(cell, side)
13
+ self.history << MoveHistory.new(:move => cell, :side => side)
14
+ inc_move_index
15
+ end
16
+
17
+ def inc_move_index
18
+ self.move_traverser.move_index = history.length
19
+ end
20
+
21
+ def show
22
+ self.history
23
+ end
24
+
25
+ def adjust_move_index(index_diff)
26
+ move_traverser.adjust_move_index(index_diff)
27
+ end
28
+
29
+ def get_history_board(board, move_number_limit = move_traverser.move_index)
30
+ move_traverser.history_board_builder(board, move_number_limit)
31
+ end
32
+
33
+ def initialize_history
34
+ move_traverser.initialize_history
35
+ end
36
+ end
37
+ end