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
@@ -1,18 +0,0 @@
1
- module TicTacToes
2
- module MoveStrategies
3
- class Human
4
- def initialize(io)
5
- @io = io
6
- end
7
-
8
- def move(board, players)
9
- @io.move_solicitation
10
-
11
- Integer(@io.solicit_input)
12
- rescue ArgumentError
13
- @io.not_an_integer_error
14
- move(board, players)
15
- end
16
- end
17
- end
18
- end
@@ -1,13 +0,0 @@
1
- require 'tic_tac_toes/move_strategies/easy_ai'
2
- require 'tic_tac_toes/move_strategies/hard_ai'
3
-
4
- module TicTacToes
5
- module MoveStrategies
6
- module MediumAI
7
- def self.move(board, players)
8
- move_strategy = [EasyAI, HardAI, HardAI].sample
9
- move_strategy.move(board, players)
10
- end
11
- end
12
- end
13
- end
@@ -1,20 +0,0 @@
1
- module TicTacToes
2
- class Player
3
- attr_reader :move_strategy, :token, :needs_to_think
4
-
5
- def initialize(move_strategy, token, needs_to_think, io)
6
- @move_strategy = move_strategy
7
- @token = token
8
- @needs_to_think = needs_to_think
9
- @io = io
10
- end
11
-
12
- def place_and_return_move(board, players)
13
- loop do
14
- space = @move_strategy.move(board, players)
15
- break [@token, space] if board.place(self, space)
16
- @io.invalid_move_error
17
- end
18
- end
19
- end
20
- end
@@ -1,28 +0,0 @@
1
- require 'tic_tac_toes/move_strategies/human'
2
- require 'tic_tac_toes/move_strategies/easy_ai'
3
- require 'tic_tac_toes/move_strategies/medium_ai'
4
- require 'tic_tac_toes/move_strategies/hard_ai'
5
- require 'tic_tac_toes/player'
6
-
7
- module TicTacToes
8
- class PlayerFactory
9
- def initialize(io)
10
- @io = io
11
- end
12
-
13
- AIS = {
14
- easy: ::TicTacToes::MoveStrategies::EasyAI,
15
- medium: ::TicTacToes::MoveStrategies::MediumAI,
16
- hard: ::TicTacToes::MoveStrategies::HardAI }
17
-
18
- def generate_human_player(token)
19
- needs_to_think = false
20
- Player.new(TicTacToes::MoveStrategies::Human.new(@io), token, needs_to_think, @io)
21
- end
22
-
23
- def generate_computer_player(token, difficulty)
24
- needs_to_think = true
25
- Player.new(AIS[difficulty], token, needs_to_think, @io)
26
- end
27
- end
28
- end
@@ -1,64 +0,0 @@
1
- require 'tic_tac_toes/player_factory'
2
-
3
- module TicTacToes
4
- module Rules
5
- ROW_SIZE_RANGE = (2..10)
6
-
7
- def self.row_size_valid?(row_size)
8
- row_size.between?(ROW_SIZE_RANGE.min, ROW_SIZE_RANGE.max)
9
- end
10
-
11
- def self.token_valid?(token, taken_tokens)
12
- correct_length = token.length == 1
13
- untaken = !taken_tokens.include?(token)
14
-
15
- correct_length && untaken
16
- end
17
-
18
- def self.difficulty_valid?(difficulty)
19
- PlayerFactory::AIS.include? difficulty
20
- end
21
-
22
- def self.game_over?(board, players)
23
- winner = !determine_winner(board, players).nil?
24
- tie = board.full?
25
-
26
- winner || tie
27
- end
28
-
29
- def self.determine_winner(board, players)
30
- winner = nil
31
-
32
- players.each do |player|
33
- player_has_won = win?(board, player)
34
- winner = player.token if player_has_won
35
- end
36
-
37
- winner
38
- end
39
-
40
- def self.win?(board, player)
41
- diagonal_win?(board, player) ||
42
- horizontal_win?(board, player) ||
43
- vertical_win?(board, player)
44
- end
45
-
46
- private
47
-
48
- def self.diagonal_win?(board, player)
49
- set_win?(board.diagonals, player)
50
- end
51
-
52
- def self.horizontal_win?(board, player)
53
- set_win?(board.rows, player)
54
- end
55
-
56
- def self.vertical_win?(board, player)
57
- set_win?(board.columns, player)
58
- end
59
-
60
- def self.set_win?(sets, player)
61
- sets.any? { |set| set.all? { |space| space.token == player.token unless space.nil? } }
62
- end
63
- end
64
- end
@@ -1,104 +0,0 @@
1
- require 'command_line/prompt'
2
- require 'tic_tac_toes/rules'
3
-
4
- module TicTacToes
5
- module Strings
6
- smallest_row_size = Rules::ROW_SIZE_RANGE.min
7
- largest_row_size = Rules::ROW_SIZE_RANGE.max
8
-
9
- NOT_AN_INTEGER = "Input must be an integer"
10
- INVALID_ROW_SIZE = "Input must be between #{smallest_row_size} and #{largest_row_size}"
11
- INVALID_TOKEN = "Input must be a single, untaken character"
12
- INVALID_DIFFICULTY = "Input must be a valid difficulty"
13
- INVALID_MOVE = "Input must be a space that is on the board and untaken"
14
- ROW_SIZE_SOLICITATION = "Pick row size of board:"
15
- DIFFICULTY_SOLICITATION = "Pick difficulty (easy, medium, hard):"
16
- MOVE_SOLICITATION = "Pick a space:"
17
- THINKING = "Thinking..."
18
-
19
- def self.token_solicitation(player)
20
- "Pick #{player} token:"
21
- end
22
-
23
- def self.game_over_notification(winner)
24
- "#{winner} wins!"
25
- end
26
-
27
- def self.board(board)
28
- board_string = ""
29
- board.rows.each_with_index do |row, index|
30
- row_start_index = (index * board.row_size).to_i
31
- at_last_row = index == board.row_size - 1
32
- board_string << "\n"
33
- board_string << row(row, row_start_index, board.size)
34
- board_string << "\n"
35
- board_string << horizontal_divider(board.row_size, board.size) unless at_last_row
36
- end
37
- board_string << "\n"
38
- end
39
-
40
- private
41
-
42
- def self.row(row, row_start_index, board_size)
43
- row_array = []
44
- row.each_with_index do |space, index|
45
- if space.nil?
46
- board_index = index + row_start_index
47
- row_array << empty_space(board_index, board_size)
48
- else
49
- row_array << token(space, board_size)
50
- end
51
- end
52
- row_array.join("|")
53
- end
54
-
55
- def self.empty_space(board_index, board_size)
56
- if space_needs_buffer?(board_index, board_size)
57
- "[ #{board_index}]"
58
- else
59
- "[#{board_index}]"
60
- end
61
- end
62
-
63
- def self.token(space, board_size)
64
- token = get_colored_token(space)
65
-
66
- if double_digit_board?(board_size)
67
- " #{token} "
68
- else
69
- " #{token} "
70
- end
71
- end
72
-
73
- def self.get_colored_token(player)
74
- if player.needs_to_think
75
- return CommandLine::Prompt.red(player.token)
76
- else
77
- return CommandLine::Prompt.blue(player.token)
78
- end
79
- end
80
-
81
- def self.space_needs_buffer?(board_index, board_size)
82
- is_double_digit_board = double_digit_board?(board_size)
83
- is_single_digit_space = board_index < 10
84
-
85
- is_double_digit_board && is_single_digit_space
86
- end
87
-
88
- def self.double_digit_board?(board_size)
89
- board_size > 10
90
- end
91
-
92
- def self.horizontal_divider(row_size, board_size)
93
- horizontal_divider = ""
94
- divider_unit = "-"
95
- divider_units_per_space = double_digit_board?(board_size) ? 5 : 4
96
- extra_units_per_row = 1
97
-
98
- raw_length = (row_size * divider_units_per_space).to_i
99
- truncated_length = raw_length - extra_units_per_row
100
- truncated_length.times { horizontal_divider << divider_unit }
101
- horizontal_divider
102
- end
103
- end
104
- end
data/lib/ui/adapter.rb DELETED
@@ -1,94 +0,0 @@
1
- require 'tic_tac_toes/board'
2
- require 'tic_tac_toes/game_state'
3
- require 'tic_tac_toes/player_factory'
4
- require 'tic_tac_toes/rules'
5
-
6
- module UI
7
- module Adapter
8
- def self.new_board_structure
9
- board = TicTacToes::Board.new
10
- board.spaces
11
- end
12
-
13
- def self.make_move(board_structure, move, listener)
14
- move = move.to_i
15
- game_state = game_state_from_board_structure(board_structure)
16
-
17
- human_player = game_state.players.first
18
- game_state.board.place(human_player, move)
19
-
20
- if TicTacToes::Rules.game_over?(game_state.board, game_state.players)
21
- return listener.game_is_over(game_state_to_board_structure(game_state), "Game over")
22
- end
23
-
24
- game_state.turn_over(move)
25
-
26
- computer_player = game_state.players.first
27
- computer_player.place_and_return_move(game_state.board, game_state.players)
28
-
29
- if TicTacToes::Rules.game_over?(game_state.board, game_state.players)
30
- return listener.game_is_over(game_state_to_board_structure(game_state), "Game over")
31
- end
32
-
33
- listener.move_was_valid(game_state_to_board_structure(game_state))
34
- end
35
-
36
- def self.game_state_from_board_structure(board_structure)
37
- player_factory = TicTacToes::PlayerFactory.new('unused_io')
38
- human_player = player_factory.generate_human_player('X')
39
- computer_player = player_factory.generate_computer_player('O', :hard)
40
- players = [human_player, computer_player]
41
-
42
- board_structure_with_players = replace_tokens_with_players(board_structure, human_player, computer_player)
43
- board = board_from_structure(board_structure_with_players)
44
-
45
- TicTacToes::GameState.new(board, players, NullHistory.new)
46
- end
47
-
48
- def self.game_state_to_board_structure(game_state)
49
- structure_with_players = game_state.board.spaces
50
-
51
- replace_players_with_tokens(structure_with_players)
52
- end
53
-
54
- private
55
-
56
- def self.replace_tokens_with_players(board_structure, human_player, computer_player)
57
- board_structure.map do |space|
58
- case space
59
- when 'X'
60
- human_player
61
- when 'O'
62
- computer_player
63
- else
64
- nil
65
- end
66
- end
67
- end
68
-
69
- def self.replace_players_with_tokens(board_structure)
70
- board_structure.map { |space| space.token unless space.nil? }
71
- end
72
-
73
- def self.board_from_structure(board_structure)
74
- row_size = Math.sqrt(board_structure.count).to_i
75
- board = TicTacToes::Board.new(row_size: row_size)
76
-
77
- board_structure.each_with_index do |player, index|
78
- board.place(player, index)
79
- end
80
-
81
- board
82
- end
83
- end
84
-
85
- class NullHistory
86
- def record_board_size(size)
87
- nil
88
- end
89
-
90
- def record_move(move)
91
- nil
92
- end
93
- end
94
- end
@@ -1,15 +0,0 @@
1
- require 'tic_tac_toes/board'
2
-
3
- module TestBoardGenerator
4
- def self.generate(structure)
5
- board_size = structure.count
6
- row_size = Math.sqrt(board_size)
7
- board = TicTacToes::Board.new(row_size: row_size)
8
-
9
- structure.each_with_index do |player, index|
10
- board.place(player, index)
11
- end
12
-
13
- board
14
- end
15
- end
@@ -1,66 +0,0 @@
1
- require 'tic_tac_toes/game_state'
2
-
3
- describe TicTacToes::GameState do
4
- describe '@initialize' do
5
- it "records its board's size" do
6
- size = 5
7
- board = double(size: size)
8
- history = double
9
-
10
- expect(history).to receive(:record_board_size).with(size)
11
- TicTacToes::GameState.new(board, 'players', history)
12
- end
13
- end
14
-
15
- describe '#current_player' do
16
- it 'returns the first item of its players array' do
17
- history = double(record_board_size: true)
18
- players = ['first_player', 'second_player']
19
- game_state = TicTacToes::GameState.new('board', players, history)
20
-
21
- current_player = game_state.current_player
22
- expect(current_player).to eq('first_player')
23
- end
24
- end
25
-
26
- describe '#turn_over' do
27
- it 'records the last move' do
28
- move = double
29
- players = double(rotate!: true)
30
- history = double(record_board_size: true)
31
- game_state = TicTacToes::GameState.new('board', players, history)
32
-
33
- expect(history).to receive(:record_move).with(move)
34
- game_state.turn_over(move)
35
- end
36
-
37
- it 'rotates its player array' do
38
- players = ['first_player', 'second_player']
39
- history = double(record_board_size: true, record_move: true)
40
- game_state = TicTacToes::GameState.new('board', players, history)
41
-
42
- game_state.turn_over('move')
43
- expect(game_state.current_player).to eq('second_player')
44
- end
45
- end
46
-
47
- describe '#game_over' do
48
- it 'records the winner' do
49
- winner = double
50
- history = double(record_board_size: true, persist: true)
51
- game_state = TicTacToes::GameState.new('board', 'players', history)
52
-
53
- expect(history).to receive(:record_winner).with(winner)
54
- game_state.game_over(winner)
55
- end
56
-
57
- it 'persists its history' do
58
- winner = double
59
- history = double(record_board_size: true, record_winner: true)
60
- game_state = TicTacToes::GameState.new('board', 'players', history)
61
-
62
- expect(history).to receive(:persist)
63
- game_state.game_over(winner)
64
- end
65
- end
66
- end
@@ -1,19 +0,0 @@
1
- require 'test_board_generator'
2
- require 'tic_tac_toes/move_strategies/easy_ai'
3
-
4
- describe TicTacToes::MoveStrategies::EasyAI do
5
- describe '#move' do
6
- let(:players) { double("players") }
7
- let(:easy_ai) { TicTacToes::MoveStrategies::EasyAI }
8
-
9
- it "returns a randomly-selected valid move" do
10
- board = TestBoardGenerator.generate([ :O, nil, nil,
11
- nil, :X, nil,
12
- nil, :X, nil])
13
- valid_moves = [1, 2, 3, 5, 6, 8]
14
-
15
- move = easy_ai.move(board, players)
16
- expect(valid_moves).to include(move)
17
- end
18
- end
19
- end
@@ -1,121 +0,0 @@
1
- require 'test_board_generator'
2
- require 'tic_tac_toes/move_strategies/hard_ai'
3
- require 'tic_tac_toes/player'
4
-
5
- describe TicTacToes::MoveStrategies::HardAI do
6
- let(:hard_ai) { TicTacToes::MoveStrategies::HardAI }
7
- let(:x) { TicTacToes::Player.new("human", "x", false, "io") }
8
- let(:o) { TicTacToes::Player.new(hard_ai, "o", true, "io") }
9
- let(:players) { [o, x] }
10
-
11
-
12
- describe '#move' do
13
- it "returns the best move" do
14
- board = TestBoardGenerator.generate([x, nil, nil,
15
- o, o, nil,
16
- x, nil, x])
17
- best_move = 5
18
-
19
- expect(hard_ai.move(board, players)).to eql(best_move)
20
- end
21
-
22
- context "when playing on a 3x3 board" do
23
- it "returns 4 when the opponent’s first move was a corner" do
24
- board = TestBoardGenerator.generate([nil, nil, nil,
25
- nil, nil, nil,
26
- nil, nil, x])
27
-
28
- expect(hard_ai.move(board, players)).to eq(4)
29
- end
30
-
31
- it "returns 4 when the opponent’s first move was an edge" do
32
- board = TestBoardGenerator.generate([nil, nil, nil,
33
- nil, nil, x,
34
- nil, nil, nil])
35
-
36
- expect(hard_ai.move(board, players)).to eq(4)
37
- end
38
-
39
- it "returns 0 when the opponent’s first move was the center" do
40
- board = TestBoardGenerator.generate([nil, nil, nil,
41
- nil, x, nil,
42
- nil, nil, nil])
43
-
44
- expect(hard_ai.move(board, players)).to eq(0)
45
- end
46
- end
47
- end
48
-
49
-
50
- describe '#minimax' do
51
- it "returns the correct score for a pre-win board" do
52
- board = TestBoardGenerator.generate([x, nil, nil,
53
- o, o, nil,
54
- x, nil, x])
55
- win_score = 1
56
-
57
- expect(hard_ai.minimax(board, :max, players)).to eql(win_score)
58
- end
59
-
60
- it "returns the correct score for a pre-loss board" do
61
- board = TestBoardGenerator.generate([ o, o, x,
62
- nil, nil, nil,
63
- x, nil, x])
64
- loss_score = -1
65
-
66
- expect(hard_ai.minimax(board, :max, players)).to eql(loss_score)
67
- end
68
-
69
- it "returns the correct score for a pre-draw board" do
70
- board = TestBoardGenerator.generate([x, x, o,
71
- o, nil, x,
72
- x, o, x])
73
- draw_score = 0
74
-
75
- expect(hard_ai.minimax(board, :max, players)).to eql(draw_score)
76
- end
77
- end
78
-
79
-
80
- describe '#generate_board' do
81
- it "returns a board based on a token, a space, and an existing board" do
82
- token, space = o, 3
83
- board = TestBoardGenerator.generate([ x, nil, nil,
84
- nil, o, nil,
85
- x, nil, nil])
86
-
87
- new_board = hard_ai.generate_board(token, space, board)
88
- expect(new_board.space(space)).to eql(token)
89
- end
90
- end
91
-
92
-
93
- describe '#score' do
94
- it "returns the correct score when HardAI has won" do
95
- board = TestBoardGenerator.generate([ o, nil, nil,
96
- nil, o, nil,
97
- nil, nil, o])
98
- win_score = 1
99
-
100
- expect(hard_ai.score(board, players)).to eql(win_score)
101
- end
102
-
103
- it "returns the correct score when no one has won" do
104
- board = TestBoardGenerator.generate([o, o, x,
105
- x, x, o,
106
- o, x, o])
107
- draw_score = 0
108
-
109
- expect(hard_ai.score(board, players)).to eql(draw_score)
110
- end
111
-
112
- it "returns the correct score when the opponent has won" do
113
- board = TestBoardGenerator.generate([ x, nil, nil,
114
- nil, x, nil,
115
- nil, nil, x])
116
- loss_score = -1
117
-
118
- expect(hard_ai.score(board, players)).to eql(loss_score)
119
- end
120
- end
121
- end
@@ -1,21 +0,0 @@
1
- require 'test_board_generator'
2
- require 'tic_tac_toes/move_strategies/medium_ai'
3
-
4
- describe TicTacToes::MoveStrategies::MediumAI do
5
- let(:medium_ai) { TicTacToes::MoveStrategies::MediumAI }
6
- let(:x) { TicTacToes::Player.new("human", "x", false, "io") }
7
- let(:o) { TicTacToes::Player.new(medium_ai, "o", true, "io") }
8
- let(:players) { [x, o] }
9
-
10
- describe '#move' do
11
- it "returns a valid move (based on either EasyAI or HardAI)" do
12
- board = TestBoardGenerator.generate([ o, o, x,
13
- nil, x, nil,
14
- nil, x, nil])
15
- valid_moves = [3, 5, 6, 8]
16
-
17
- move = medium_ai.move(board, players)
18
- expect(valid_moves).to include(move)
19
- end
20
- end
21
- end