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