tic_tac_toes 0.0.7 → 0.0.8

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 (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