tic_tac_toes 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/Rakefile +2 -2
  4. data/bin/tic_tac_toes +18 -22
  5. data/lib/tic_tac_toes/command_line/menu.rb +55 -0
  6. data/lib/tic_tac_toes/command_line/prompt.rb +29 -0
  7. data/lib/tic_tac_toes/command_line/runner.rb +38 -0
  8. data/lib/tic_tac_toes/core/board.rb +64 -0
  9. data/lib/tic_tac_toes/core/board_factory.rb +11 -0
  10. data/lib/tic_tac_toes/core/game_state.rb +40 -0
  11. data/lib/tic_tac_toes/core/game_state_factory.rb +15 -0
  12. data/lib/tic_tac_toes/core/history.rb +29 -0
  13. data/lib/tic_tac_toes/core/io.rb +93 -0
  14. data/lib/tic_tac_toes/core/move_strategies/easy_ai.rb +13 -0
  15. data/lib/tic_tac_toes/core/move_strategies/hard_ai.rb +89 -0
  16. data/lib/tic_tac_toes/core/move_strategies/human.rb +20 -0
  17. data/lib/tic_tac_toes/core/move_strategies/medium_ai.rb +15 -0
  18. data/lib/tic_tac_toes/core/player.rb +22 -0
  19. data/lib/tic_tac_toes/core/player_factory.rb +30 -0
  20. data/lib/tic_tac_toes/core/rules.rb +66 -0
  21. data/lib/tic_tac_toes/core/strings.rb +106 -0
  22. data/lib/tic_tac_toes/database/pg_wrapper.rb +74 -0
  23. data/lib/tic_tac_toes/ui/adapter.rb +96 -0
  24. data/lib/tic_tac_toes/ui/serializer.rb +0 -0
  25. data/lib/tic_tac_toes/version.rb +1 -1
  26. data/spec/{command_line → tic_tac_toes/command_line}/menu_spec.rb +14 -14
  27. data/spec/{command_line → tic_tac_toes/command_line}/runner_spec.rb +7 -10
  28. data/spec/tic_tac_toes/{board_factory_spec.rb → core/board_factory_spec.rb} +3 -3
  29. data/spec/tic_tac_toes/{board_spec.rb → core/board_spec.rb} +23 -23
  30. data/spec/tic_tac_toes/{game_state_factory_spec.rb → core/game_state_factory_spec.rb} +3 -3
  31. data/spec/tic_tac_toes/core/game_state_spec.rb +129 -0
  32. data/spec/tic_tac_toes/{history_spec.rb → core/history_spec.rb} +3 -3
  33. data/spec/tic_tac_toes/{io_spec.rb → core/io_spec.rb} +7 -7
  34. data/spec/tic_tac_toes/core/move_strategies/easy_ai_spec.rb +19 -0
  35. data/spec/tic_tac_toes/core/move_strategies/hard_ai_spec.rb +121 -0
  36. data/spec/tic_tac_toes/{move_strategies → core/move_strategies}/human_spec.rb +3 -3
  37. data/spec/tic_tac_toes/core/move_strategies/medium_ai_spec.rb +21 -0
  38. data/spec/tic_tac_toes/{player_factory_spec.rb → core/player_factory_spec.rb} +7 -7
  39. data/spec/tic_tac_toes/{player_spec.rb → core/player_spec.rb} +5 -5
  40. data/spec/tic_tac_toes/{rules_spec.rb → core/rules_spec.rb} +34 -34
  41. data/spec/tic_tac_toes/{strings_spec.rb → core/strings_spec.rb} +8 -8
  42. data/spec/{database → tic_tac_toes/database}/pg_wrapper_spec.rb +3 -3
  43. data/spec/tic_tac_toes/test_board_generator.rb +17 -0
  44. data/spec/{ui → tic_tac_toes/ui}/adapter_spec.rb +13 -13
  45. data/spec/tic_tac_toes/ui/serializer_spec.rb +0 -0
  46. metadata +64 -61
  47. data/lib/command_line/menu.rb +0 -53
  48. data/lib/command_line/prompt.rb +0 -27
  49. data/lib/command_line/runner.rb +0 -37
  50. data/lib/database/pg_wrapper.rb +0 -72
  51. data/lib/tic_tac_toes/board.rb +0 -62
  52. data/lib/tic_tac_toes/board_factory.rb +0 -9
  53. data/lib/tic_tac_toes/game_state.rb +0 -27
  54. data/lib/tic_tac_toes/game_state_factory.rb +0 -14
  55. data/lib/tic_tac_toes/history.rb +0 -27
  56. data/lib/tic_tac_toes/io.rb +0 -91
  57. data/lib/tic_tac_toes/move_strategies/easy_ai.rb +0 -11
  58. data/lib/tic_tac_toes/move_strategies/hard_ai.rb +0 -87
  59. data/lib/tic_tac_toes/move_strategies/human.rb +0 -18
  60. data/lib/tic_tac_toes/move_strategies/medium_ai.rb +0 -13
  61. data/lib/tic_tac_toes/player.rb +0 -20
  62. data/lib/tic_tac_toes/player_factory.rb +0 -28
  63. data/lib/tic_tac_toes/rules.rb +0 -64
  64. data/lib/tic_tac_toes/strings.rb +0 -104
  65. data/lib/ui/adapter.rb +0 -94
  66. data/spec/test_board_generator.rb +0 -15
  67. data/spec/tic_tac_toes/game_state_spec.rb +0 -66
  68. data/spec/tic_tac_toes/move_strategies/easy_ai_spec.rb +0 -19
  69. data/spec/tic_tac_toes/move_strategies/hard_ai_spec.rb +0 -121
  70. data/spec/tic_tac_toes/move_strategies/medium_ai_spec.rb +0 -21
  71. /data/lib/{tasks → tic_tac_toes/tasks}/destroy_databases.rake +0 -0
  72. /data/lib/{tasks → tic_tac_toes/tasks}/set_up_databases.rake +0 -0
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tic_tac_toes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Spatafora
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-23 00:00:00.000000000 Z
11
+ date: 2014-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -86,47 +86,49 @@ files:
86
86
  - bin/destroy_ttt_databases
87
87
  - bin/set_up_ttt_databases
88
88
  - bin/tic_tac_toes
89
- - lib/command_line/menu.rb
90
- - lib/command_line/prompt.rb
91
- - lib/command_line/runner.rb
92
- - lib/database/pg_wrapper.rb
93
- - lib/tasks/destroy_databases.rake
94
- - lib/tasks/set_up_databases.rake
95
- - lib/tic_tac_toes/board.rb
96
- - lib/tic_tac_toes/board_factory.rb
97
- - lib/tic_tac_toes/game_state.rb
98
- - lib/tic_tac_toes/game_state_factory.rb
99
- - lib/tic_tac_toes/history.rb
100
- - lib/tic_tac_toes/io.rb
101
- - lib/tic_tac_toes/move_strategies/easy_ai.rb
102
- - lib/tic_tac_toes/move_strategies/hard_ai.rb
103
- - lib/tic_tac_toes/move_strategies/human.rb
104
- - lib/tic_tac_toes/move_strategies/medium_ai.rb
105
- - lib/tic_tac_toes/player.rb
106
- - lib/tic_tac_toes/player_factory.rb
107
- - lib/tic_tac_toes/rules.rb
108
- - lib/tic_tac_toes/strings.rb
89
+ - lib/tic_tac_toes/command_line/menu.rb
90
+ - lib/tic_tac_toes/command_line/prompt.rb
91
+ - lib/tic_tac_toes/command_line/runner.rb
92
+ - lib/tic_tac_toes/core/board.rb
93
+ - lib/tic_tac_toes/core/board_factory.rb
94
+ - lib/tic_tac_toes/core/game_state.rb
95
+ - lib/tic_tac_toes/core/game_state_factory.rb
96
+ - lib/tic_tac_toes/core/history.rb
97
+ - lib/tic_tac_toes/core/io.rb
98
+ - lib/tic_tac_toes/core/move_strategies/easy_ai.rb
99
+ - lib/tic_tac_toes/core/move_strategies/hard_ai.rb
100
+ - lib/tic_tac_toes/core/move_strategies/human.rb
101
+ - lib/tic_tac_toes/core/move_strategies/medium_ai.rb
102
+ - lib/tic_tac_toes/core/player.rb
103
+ - lib/tic_tac_toes/core/player_factory.rb
104
+ - lib/tic_tac_toes/core/rules.rb
105
+ - lib/tic_tac_toes/core/strings.rb
106
+ - lib/tic_tac_toes/database/pg_wrapper.rb
107
+ - lib/tic_tac_toes/tasks/destroy_databases.rake
108
+ - lib/tic_tac_toes/tasks/set_up_databases.rake
109
+ - lib/tic_tac_toes/ui/adapter.rb
110
+ - lib/tic_tac_toes/ui/serializer.rb
109
111
  - lib/tic_tac_toes/version.rb
110
- - lib/ui/adapter.rb
111
- - spec/command_line/menu_spec.rb
112
- - spec/command_line/runner_spec.rb
113
- - spec/database/pg_wrapper_spec.rb
114
- - spec/test_board_generator.rb
115
- - spec/tic_tac_toes/board_factory_spec.rb
116
- - spec/tic_tac_toes/board_spec.rb
117
- - spec/tic_tac_toes/game_state_factory_spec.rb
118
- - spec/tic_tac_toes/game_state_spec.rb
119
- - spec/tic_tac_toes/history_spec.rb
120
- - spec/tic_tac_toes/io_spec.rb
121
- - spec/tic_tac_toes/move_strategies/easy_ai_spec.rb
122
- - spec/tic_tac_toes/move_strategies/hard_ai_spec.rb
123
- - spec/tic_tac_toes/move_strategies/human_spec.rb
124
- - spec/tic_tac_toes/move_strategies/medium_ai_spec.rb
125
- - spec/tic_tac_toes/player_factory_spec.rb
126
- - spec/tic_tac_toes/player_spec.rb
127
- - spec/tic_tac_toes/rules_spec.rb
128
- - spec/tic_tac_toes/strings_spec.rb
129
- - spec/ui/adapter_spec.rb
112
+ - spec/tic_tac_toes/command_line/menu_spec.rb
113
+ - spec/tic_tac_toes/command_line/runner_spec.rb
114
+ - spec/tic_tac_toes/core/board_factory_spec.rb
115
+ - spec/tic_tac_toes/core/board_spec.rb
116
+ - spec/tic_tac_toes/core/game_state_factory_spec.rb
117
+ - spec/tic_tac_toes/core/game_state_spec.rb
118
+ - spec/tic_tac_toes/core/history_spec.rb
119
+ - spec/tic_tac_toes/core/io_spec.rb
120
+ - spec/tic_tac_toes/core/move_strategies/easy_ai_spec.rb
121
+ - spec/tic_tac_toes/core/move_strategies/hard_ai_spec.rb
122
+ - spec/tic_tac_toes/core/move_strategies/human_spec.rb
123
+ - spec/tic_tac_toes/core/move_strategies/medium_ai_spec.rb
124
+ - spec/tic_tac_toes/core/player_factory_spec.rb
125
+ - spec/tic_tac_toes/core/player_spec.rb
126
+ - spec/tic_tac_toes/core/rules_spec.rb
127
+ - spec/tic_tac_toes/core/strings_spec.rb
128
+ - spec/tic_tac_toes/database/pg_wrapper_spec.rb
129
+ - spec/tic_tac_toes/test_board_generator.rb
130
+ - spec/tic_tac_toes/ui/adapter_spec.rb
131
+ - spec/tic_tac_toes/ui/serializer_spec.rb
130
132
  - tic_tac_toes.gemspec
131
133
  homepage: http://github.com/bspatafora/tic_tac_toes
132
134
  licenses:
@@ -153,22 +155,23 @@ signing_key:
153
155
  specification_version: 4
154
156
  summary: The game Tic-tac-toe, featuring an unbeatable AI
155
157
  test_files:
156
- - spec/command_line/menu_spec.rb
157
- - spec/command_line/runner_spec.rb
158
- - spec/database/pg_wrapper_spec.rb
159
- - spec/test_board_generator.rb
160
- - spec/tic_tac_toes/board_factory_spec.rb
161
- - spec/tic_tac_toes/board_spec.rb
162
- - spec/tic_tac_toes/game_state_factory_spec.rb
163
- - spec/tic_tac_toes/game_state_spec.rb
164
- - spec/tic_tac_toes/history_spec.rb
165
- - spec/tic_tac_toes/io_spec.rb
166
- - spec/tic_tac_toes/move_strategies/easy_ai_spec.rb
167
- - spec/tic_tac_toes/move_strategies/hard_ai_spec.rb
168
- - spec/tic_tac_toes/move_strategies/human_spec.rb
169
- - spec/tic_tac_toes/move_strategies/medium_ai_spec.rb
170
- - spec/tic_tac_toes/player_factory_spec.rb
171
- - spec/tic_tac_toes/player_spec.rb
172
- - spec/tic_tac_toes/rules_spec.rb
173
- - spec/tic_tac_toes/strings_spec.rb
174
- - spec/ui/adapter_spec.rb
158
+ - spec/tic_tac_toes/command_line/menu_spec.rb
159
+ - spec/tic_tac_toes/command_line/runner_spec.rb
160
+ - spec/tic_tac_toes/core/board_factory_spec.rb
161
+ - spec/tic_tac_toes/core/board_spec.rb
162
+ - spec/tic_tac_toes/core/game_state_factory_spec.rb
163
+ - spec/tic_tac_toes/core/game_state_spec.rb
164
+ - spec/tic_tac_toes/core/history_spec.rb
165
+ - spec/tic_tac_toes/core/io_spec.rb
166
+ - spec/tic_tac_toes/core/move_strategies/easy_ai_spec.rb
167
+ - spec/tic_tac_toes/core/move_strategies/hard_ai_spec.rb
168
+ - spec/tic_tac_toes/core/move_strategies/human_spec.rb
169
+ - spec/tic_tac_toes/core/move_strategies/medium_ai_spec.rb
170
+ - spec/tic_tac_toes/core/player_factory_spec.rb
171
+ - spec/tic_tac_toes/core/player_spec.rb
172
+ - spec/tic_tac_toes/core/rules_spec.rb
173
+ - spec/tic_tac_toes/core/strings_spec.rb
174
+ - spec/tic_tac_toes/database/pg_wrapper_spec.rb
175
+ - spec/tic_tac_toes/test_board_generator.rb
176
+ - spec/tic_tac_toes/ui/adapter_spec.rb
177
+ - spec/tic_tac_toes/ui/serializer_spec.rb
@@ -1,53 +0,0 @@
1
- require 'tic_tac_toes/rules'
2
-
3
- module CommandLine
4
- class Menu
5
- def initialize(io, board_factory, player_factory)
6
- @io = io
7
- @board_factory = board_factory
8
- @player_factory = player_factory
9
- end
10
-
11
- def get_board
12
- @board_factory.generate_board(get_row_size)
13
- end
14
-
15
- def get_players
16
- taken_tokens = []
17
- human_token = get_token(:human, taken_tokens)
18
- taken_tokens << human_token
19
- computer_token = get_token(:computer, taken_tokens)
20
- difficulty = get_difficulty
21
-
22
- human_player = @player_factory.generate_human_player(human_token)
23
- computer_player = @player_factory.generate_computer_player(computer_token, difficulty)
24
- [human_player, computer_player]
25
- end
26
-
27
- private
28
-
29
- def get_row_size
30
- loop do
31
- row_size = @io.get_row_size
32
- break row_size if TicTacToes::Rules.row_size_valid?(row_size)
33
- @io.invalid_row_size_error
34
- end
35
- end
36
-
37
- def get_token(player, taken_tokens)
38
- loop do
39
- token = @io.get_token(player)
40
- break token if TicTacToes::Rules.token_valid?(token, taken_tokens)
41
- @io.invalid_token_error
42
- end
43
- end
44
-
45
- def get_difficulty
46
- loop do
47
- difficulty = @io.get_difficulty
48
- break difficulty if TicTacToes::Rules.difficulty_valid?(difficulty)
49
- @io.invalid_difficulty_error
50
- end
51
- end
52
- end
53
- end
@@ -1,27 +0,0 @@
1
- module CommandLine
2
- module Prompt
3
- def self.solicit_input
4
- gets.chomp
5
- end
6
-
7
- def self.display(message)
8
- puts message
9
- end
10
-
11
- def self.display_red(message)
12
- puts red(message)
13
- end
14
-
15
- def self.red(message)
16
- colorize(message, 31)
17
- end
18
-
19
- def self.blue(message)
20
- colorize(message, 34)
21
- end
22
-
23
- def self.colorize(message, color_code)
24
- "\e[#{color_code}m#{message}\e[0m"
25
- end
26
- end
27
- end
@@ -1,37 +0,0 @@
1
- module CommandLine
2
- class Runner
3
- def initialize(io, menu, game_state_factory, rules)
4
- @io = io
5
- @menu = menu
6
- @game_state_factory = game_state_factory
7
- @rules = rules
8
- end
9
-
10
- def run
11
- board, players = @menu.get_board, @menu.get_players
12
- game_state = @game_state_factory.generate_game_state(board, players)
13
-
14
- take_turn(game_state) until @rules.game_over?(game_state.board, game_state.players)
15
- end_game(game_state)
16
- end
17
-
18
- private
19
-
20
- def take_turn(game_state)
21
- @io.draw_board(game_state.board)
22
- @io.thinking_notification if game_state.current_player.needs_to_think
23
-
24
- move = game_state.current_player.place_and_return_move(game_state.board, game_state.players)
25
- game_state.turn_over(move)
26
- end
27
-
28
- def end_game(game_state)
29
- @io.draw_board(game_state.board)
30
-
31
- winner = @rules.determine_winner(game_state.board, game_state.players)
32
- game_state.game_over(winner)
33
-
34
- @io.game_over_notification(winner)
35
- end
36
- end
37
- end
@@ -1,72 +0,0 @@
1
- require 'pg'
2
- require 'tic_tac_toes/history'
3
-
4
- module Database
5
- class PGWrapper
6
- def initialize(database)
7
- @database = database
8
- end
9
-
10
- def record_game_history(history)
11
- connection = establish_connection
12
- record_board_size_and_winner(history, connection)
13
- record_moves(history, connection)
14
- end
15
-
16
- def read_game_histories
17
- connection = establish_connection
18
- games_result = connection.exec("SELECT * FROM games")
19
- games = []
20
-
21
- games_result.each_row do |row|
22
- game_id = row[0]
23
- board_size = row[1].to_i
24
- winner = row[2]
25
- moves_result = connection.exec("SELECT * FROM moves WHERE game = #{game_id}")
26
-
27
- history = TicTacToes::History.new(self)
28
-
29
- moves_result.each_row do |row|
30
- token, space = row[2], row[3].to_i
31
- history.record_move([token, space])
32
- end
33
- history.record_board_size(board_size)
34
- history.record_winner(winner)
35
-
36
- games << history
37
- end
38
-
39
- games
40
- end
41
-
42
- private
43
-
44
- def establish_connection
45
- PG.connect(dbname: @database)
46
- end
47
-
48
- def record_board_size_and_winner(history, connection)
49
- connection.exec("INSERT INTO games (board_size, winner) VALUES (
50
- #{history.board_size},
51
- '#{history.winner}')")
52
- end
53
-
54
- def record_moves(history, connection)
55
- game_id = read_game_id(connection)
56
-
57
- history.moves.each_with_index do |move, index|
58
- move_number = index + 1
59
- connection.exec("INSERT INTO moves (game, number, token, space) VALUES (
60
- #{game_id},
61
- #{move_number},
62
- '#{move.first}',
63
- #{move.last})")
64
- end
65
- end
66
-
67
- def read_game_id(connection)
68
- result = connection.exec("SELECT currval(pg_get_serial_sequence('games','id'))")
69
- result.getvalue(0,0)
70
- end
71
- end
72
- end
@@ -1,62 +0,0 @@
1
- module TicTacToes
2
- class Board
3
- attr_reader :row_size, :size, :spaces
4
-
5
- def initialize(row_size: 3)
6
- @row_size = row_size
7
- @size = @row_size**2
8
- @spaces = Array.new(@size)
9
- end
10
-
11
- def place(player, space)
12
- @spaces[space] = player if valid?(space)
13
- end
14
-
15
- def space(space)
16
- @spaces[space]
17
- end
18
-
19
- def open_spaces
20
- open_spaces = []
21
-
22
- @spaces.each_with_index do |space, index|
23
- open_spaces << index if space.nil?
24
- end
25
-
26
- open_spaces
27
- end
28
-
29
- def rows
30
- @spaces.each_slice(@row_size).to_a
31
- end
32
-
33
- def columns
34
- rows.transpose
35
- end
36
-
37
- def diagonals
38
- back_diagonal, front_diagonal = [], []
39
-
40
- rows.each_with_index do |row, index|
41
- back_diagonal << row[index]
42
- front_diagonal << row[@row_size - (index + 1)]
43
- end
44
-
45
- [back_diagonal, front_diagonal]
46
- end
47
-
48
- def full?
49
- @spaces.all? { |space| !space.nil? }
50
- end
51
-
52
- private
53
-
54
- def valid?(space)
55
- space_empty = @spaces[space].nil?
56
- board_range = 0..(@size - 1)
57
- on_the_board = board_range.include? space
58
-
59
- space_empty && on_the_board
60
- end
61
- end
62
- end
@@ -1,9 +0,0 @@
1
- require 'tic_tac_toes/board'
2
-
3
- module TicTacToes
4
- class BoardFactory
5
- def generate_board(row_size)
6
- TicTacToes::Board.new(row_size: row_size)
7
- end
8
- end
9
- end
@@ -1,27 +0,0 @@
1
- module TicTacToes
2
- class GameState
3
- attr_reader :board, :players
4
-
5
- def initialize(board, players, history)
6
- @board = board
7
- @players = players
8
- @history = history
9
-
10
- @history.record_board_size(@board.size)
11
- end
12
-
13
- def current_player
14
- @players.first
15
- end
16
-
17
- def turn_over(move)
18
- @history.record_move(move)
19
- @players.rotate!
20
- end
21
-
22
- def game_over(winner)
23
- @history.record_winner(winner)
24
- @history.persist
25
- end
26
- end
27
- end
@@ -1,14 +0,0 @@
1
- require 'tic_tac_toes/game_state'
2
- require 'tic_tac_toes/history'
3
-
4
- module TicTacToes
5
- class GameStateFactory
6
- def initialize(history)
7
- @history = history
8
- end
9
-
10
- def generate_game_state(board, players)
11
- TicTacToes::GameState.new(board, players, @history)
12
- end
13
- end
14
- end
@@ -1,27 +0,0 @@
1
- module TicTacToes
2
- class History
3
- attr_reader :board_size, :moves, :winner
4
-
5
- def initialize(database_wrapper)
6
- @database_wrapper = database_wrapper
7
- end
8
-
9
- def record_board_size(size)
10
- @board_size = size
11
- end
12
-
13
- def record_move(move)
14
- @moves ||= []
15
- @moves << move
16
- end
17
-
18
- def record_winner(winner)
19
- winner = "Draw" if winner.nil?
20
- @winner = winner
21
- end
22
-
23
- def persist
24
- @database_wrapper.record_game_history(self)
25
- end
26
- end
27
- end
@@ -1,91 +0,0 @@
1
- require 'tic_tac_toes/strings'
2
-
3
- module TicTacToes
4
- class IO
5
- def initialize(io_strategy)
6
- @io_strategy = io_strategy
7
- end
8
-
9
- def get_row_size
10
- row_size_solicitation
11
-
12
- Integer(@io_strategy.solicit_input)
13
- rescue ArgumentError
14
- not_an_integer_error
15
- get_row_size
16
- end
17
-
18
- def get_token(player)
19
- token_solicitation(player)
20
- @io_strategy.solicit_input
21
- end
22
-
23
- def get_difficulty
24
- difficulty_solicitation
25
- @io_strategy.solicit_input.downcase.to_sym
26
- end
27
-
28
- def draw_board(board)
29
- @io_strategy.display(Strings.board(board))
30
- end
31
-
32
- def invalid_row_size_error
33
- @io_strategy.display_red(Strings::INVALID_ROW_SIZE)
34
- end
35
-
36
- def invalid_token_error
37
- @io_strategy.display_red(Strings::INVALID_TOKEN)
38
- end
39
-
40
- def invalid_difficulty_error
41
- @io_strategy.display_red(Strings::INVALID_DIFFICULTY)
42
- end
43
-
44
- def invalid_move_error
45
- @io_strategy.display_red(Strings::INVALID_MOVE)
46
- end
47
-
48
- def thinking_notification
49
- @io_strategy.display_red(Strings::THINKING)
50
- end
51
-
52
- def game_over_notification(winner)
53
- winner = "Nobody" if winner.nil?
54
- @io_strategy.display(Strings.game_over_notification(winner))
55
- end
56
-
57
- def move_solicitation
58
- @io_strategy.display(Strings::MOVE_SOLICITATION)
59
- end
60
-
61
- def not_an_integer_error
62
- @io_strategy.display_red(Strings::NOT_AN_INTEGER)
63
- end
64
-
65
- def solicit_input
66
- @io_strategy.solicit_input
67
- end
68
-
69
- def red(message)
70
- @io_strategy.red(message)
71
- end
72
-
73
- def blue(message)
74
- @io_strategy.blue(message)
75
- end
76
-
77
- private
78
-
79
- def row_size_solicitation
80
- @io_strategy.display(Strings::ROW_SIZE_SOLICITATION)
81
- end
82
-
83
- def token_solicitation(player)
84
- @io_strategy.display(Strings.token_solicitation(player))
85
- end
86
-
87
- def difficulty_solicitation
88
- @io_strategy.display(Strings::DIFFICULTY_SOLICITATION)
89
- end
90
- end
91
- end
@@ -1,11 +0,0 @@
1
- require 'tic_tac_toes/board'
2
-
3
- module TicTacToes
4
- module MoveStrategies
5
- module EasyAI
6
- def self.move(board, players)
7
- board.open_spaces.sample
8
- end
9
- end
10
- end
11
- end
@@ -1,87 +0,0 @@
1
- require 'tic_tac_toes/rules'
2
-
3
- module TicTacToes
4
- module MoveStrategies
5
- module HardAI
6
- def self.move(board, players)
7
- return second_move(board) if nine_board_second_move?(board)
8
-
9
- open_spaces = Hash[board.open_spaces.map { |space| [space, nil] }]
10
-
11
- open_spaces.each do |space, score|
12
- score = minimax(generate_board(players.first, space, board), :min, players)
13
- open_spaces[space] = score
14
- end
15
-
16
- best_score = open_spaces.values.max
17
- open_spaces.each { |space, score| return space if score == best_score }
18
- end
19
-
20
- private
21
-
22
- def self.minimax(board, current_player, players)
23
- return score(board, players) if Rules.game_over?(board, players)
24
-
25
- if current_player == :max
26
- best_score = -1
27
- board.open_spaces.each do |space|
28
- score = minimax(generate_board(players.first, space, board), :min, players)
29
- best_score = [best_score, score].max
30
- end
31
- best_score
32
-
33
- elsif current_player == :min
34
- best_score = 1
35
- board.open_spaces.each do |space|
36
- score = minimax(generate_board(players.last, space, board), :max, players)
37
- best_score = [best_score, score].min
38
- end
39
- best_score
40
- end
41
- end
42
-
43
- def self.generate_board(player, space, board)
44
- new_board = Marshal.load(Marshal.dump(board))
45
- new_board.place(player, space)
46
- new_board
47
- end
48
-
49
- def self.score(board, players)
50
- own_token, opponent_token = players.first.token, players.last.token
51
-
52
- case Rules.determine_winner(board, players)
53
- when own_token
54
- 1
55
- when opponent_token
56
- -1
57
- else
58
- 0
59
- end
60
- end
61
-
62
- def self.nine_board_second_move?(board)
63
- board.size == 9 && board.open_spaces.count == 8
64
- end
65
-
66
- def self.second_move(board)
67
- if nine_board_corner_occupied(board) || nine_board_side_occupied(board)
68
- 4
69
- elsif nine_board_center_occupied(board)
70
- 0
71
- end
72
- end
73
-
74
- def self.nine_board_corner_occupied(board)
75
- board.space(0) || board.space(2) || board.space(6) || board.space(8)
76
- end
77
-
78
- def self.nine_board_side_occupied(board)
79
- board.space(1) || board.space(3) || board.space(5) || board.space(7)
80
- end
81
-
82
- def self.nine_board_center_occupied(board)
83
- board.space(4) ? true : false
84
- end
85
- end
86
- end
87
- end