games_bfox 0.3.0 → 0.4.0

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -12
  3. data/config/application.yml +5 -0
  4. data/games.gemspec +2 -1
  5. data/lib/games/mastermind/board_builder.rb +6 -2
  6. data/lib/games/mastermind/computer_player_expert.rb +31 -0
  7. data/lib/games/mastermind/computer_player_novice.rb +18 -0
  8. data/lib/games/mastermind/game.rb +69 -15
  9. data/lib/games/mastermind/guess_evaluator.rb +105 -68
  10. data/lib/games/mastermind/guess_evaluator_result.rb +11 -0
  11. data/lib/games/mastermind/human_player.rb +9 -0
  12. data/lib/games/mastermind/io_helpers.rb +65 -0
  13. data/lib/games/mastermind/peg.rb +2 -4
  14. data/lib/games/mastermind/pegs.rb +1 -9
  15. data/lib/games/mastermind/pegs_factory.rb +3 -5
  16. data/lib/games/mastermind/players_factory.rb +32 -8
  17. data/lib/games/mastermind/secret_code.rb +19 -0
  18. data/lib/games/mastermind.rb +9 -2
  19. data/lib/games/shared/game.rb +56 -70
  20. data/lib/games/shared/{input_helper.rb → io_helpers.rb} +40 -32
  21. data/lib/games/shared/player.rb +1 -3
  22. data/lib/games/shared/player_factory.rb +9 -0
  23. data/lib/games/shared/players_factory.rb +9 -0
  24. data/lib/games/tictactoe/board.rb +3 -4
  25. data/lib/games/tictactoe/board_builder.rb +3 -3
  26. data/lib/games/tictactoe/board_presenter_terminal.rb +3 -3
  27. data/lib/games/tictactoe/computer_player_expert.rb +12 -0
  28. data/lib/games/tictactoe/computer_player_novice.rb +10 -0
  29. data/lib/games/tictactoe/game.rb +45 -12
  30. data/lib/games/tictactoe/human_player.rb +9 -0
  31. data/lib/games/tictactoe/io_helpers.rb +81 -0
  32. data/lib/games/tictactoe/player.rb +4 -0
  33. data/lib/games/tictactoe/players_factory.rb +49 -5
  34. data/lib/games/tictactoe/square.rb +0 -3
  35. data/lib/games/tictactoe/squares.rb +1 -1
  36. data/lib/games/tictactoe/squares_factory.rb +7 -11
  37. data/lib/games/tictactoe.rb +9 -2
  38. data/lib/games/version.rb +1 -1
  39. metadata +32 -17
  40. data/lib/games/mastermind/colors.rb +0 -14
  41. data/lib/games/mastermind/game_config.rb +0 -48
  42. data/lib/games/mastermind/game_resetter.rb +0 -19
  43. data/lib/games/mastermind/game_state_changer.rb +0 -41
  44. data/lib/games/mastermind/input_helper.rb +0 -67
  45. data/lib/games/mastermind/move_generator.rb +0 -46
  46. data/lib/games/shared/array_iterator.rb +0 -28
  47. data/lib/games/tictactoe/game_config.rb +0 -73
  48. data/lib/games/tictactoe/game_resetter.rb +0 -16
  49. data/lib/games/tictactoe/game_state_changer.rb +0 -17
  50. data/lib/games/tictactoe/input_helper.rb +0 -87
  51. data/lib/games/tictactoe/move_generator.rb +0 -68
@@ -0,0 +1,19 @@
1
+ module MM
2
+ class SecretCode
3
+ def self.generate(io_helpers, is_code_guesser_human)
4
+ if is_code_guesser_human
5
+ set_secret_code
6
+ else
7
+ io_helpers.get_secret_code_from_user
8
+ end
9
+ end
10
+
11
+ def self.set_secret_code
12
+ secret_code = []
13
+ 4.times do
14
+ secret_code.push((1..6).to_a.sample)
15
+ end
16
+ secret_code
17
+ end
18
+ end
19
+ end
@@ -4,10 +4,17 @@ Dir[File.join(File.expand_path(File.dirname(__FILE__)), 'mastermind', '*.rb')].e
4
4
  class Mastermind
5
5
  def self.run
6
6
  io = Shared::IOTerminal.new
7
+ io_helpers = MM::IOHelpers.new(io)
7
8
  board_presenter = MM::BoardPresenterTerminal.new
9
+ board_builder = MM::BoardBuilder.new
10
+ players_factory = MM::PlayersFactory.new(io_helpers)
8
11
 
9
- game = MM::Game.new(game_module: MM, io: io, board_presenter: board_presenter)
10
- # game.setup
12
+ game = MM::Game.new(
13
+ io_helpers: io_helpers,
14
+ board_presenter: board_presenter,
15
+ board_builder: board_builder,
16
+ players_factory: players_factory
17
+ )
11
18
  game.play
12
19
  end
13
20
  end
@@ -1,4 +1,5 @@
1
1
  Dir[File.join(File.dirname(__FILE__), '*.rb')].each {|file| require file }
2
+ # note the below exclude the game subclasses, because these classes inherit from this class, so if we require these before the parent class is read, an error will be generated.
2
3
  Dir[File.join(File.expand_path("..", File.dirname(__FILE__)), 'tictactoe', '*.rb')].each {|file| require file unless file == File.join(File.expand_path("..", File.dirname(__FILE__)), 'tictactoe', 'game.rb')}
3
4
  Dir[File.join(File.expand_path("..", File.dirname(__FILE__)), 'mastermind', '*.rb')].each {|file| require file unless file == File.join(File.expand_path("..", File.dirname(__FILE__)), 'mastermind', 'game.rb')}
4
5
 
@@ -6,60 +7,29 @@ module Shared
6
7
  class Game
7
8
  attr_accessor :board, :board_presenter, :board_builder
8
9
  attr_accessor :players, :players_factory
9
- attr_accessor :config, :game_state_changer
10
- attr_accessor :number_of_turns_taken
11
- attr_accessor :game_resetter
12
- attr_accessor :move_generator
13
- attr_reader :io, :input_helper, :game_module
10
+ attr_accessor :number_of_turns_taken, :won_flag
11
+ attr_reader :io_helpers
14
12
 
15
- def initialize(args = {})
16
- @game_module = args.fetch(:game_module, nil)
17
- @io = args.fetch(:io, IOTerminal.new)
18
- @board_presenter = args.fetch(:board_presenter, nil)
19
-
20
- @input_helper = game_module::InputHelper.new(@io)
21
- @board_builder = game_module::BoardBuilder.new
22
- @game_state_changer = game_module::GameStateChanger.new
23
- @game_resetter = game_module::GameResetter.new
24
- @move_generator = game_module::MoveGenerator.new
25
- @players_factory = game_module::PlayersFactory.new
26
- @config = game_module::GameConfig.new(@input_helper)
27
-
28
- @number_of_turns_taken = 0
29
- end
30
13
 
31
- def one_time_setup
32
- #setup gets necessary info from user and stores it in config object
33
- config.one_time_setup
34
- end
35
-
36
- def every_time_setup
37
- #setup gets necessary info from user and stores it in config object
38
- config.every_time_setup
39
- self.players = players_factory.generate_players(config)
40
- self.board = board_builder.generate_empty_board(config)
41
- local_setup
42
- end
14
+ def initialize(args = {})
15
+ @board_presenter = args.fetch(:board_presenter)
43
16
 
44
- #to be implemented by subclasses
45
- def local_setup
46
- end
17
+ @io_helpers = args.fetch(:io_helpers)
18
+ @board_builder = args.fetch(:board_builder)
19
+ @players_factory = args.fetch(:players_factory)
47
20
 
48
- #overriding so that io and input_helper always in harmony
49
- def io=(new_io)
50
- @io = new_io
51
- self.input_helper = game_module::InputHelper.new(new_io)
21
+ @number_of_turns_taken = 0
52
22
  end
53
23
 
54
24
  def play
55
25
  initial_instructions
56
26
  one_time_setup
57
- while true
27
+ loop do
58
28
  every_time_setup
59
29
  while !over?
60
30
  print_board
61
- move = move_generator.get_player_choice(self)
62
- game_state_changer.change_game_state(move, self)
31
+ move = current_player.make_move(self)
32
+ change_game_state(move)
63
33
  end
64
34
 
65
35
  #need to print_final_iteration of board
@@ -67,12 +37,12 @@ module Shared
67
37
 
68
38
  if won?
69
39
  winning_prompt
70
- elsif over_with_no_winner?
71
- no_winner_prompt
40
+ elsif no_more_turns?
41
+ no_winner_prompt(self)
72
42
  custom_final_message(self)
73
43
  end
74
44
 
75
- game_resetter.reset_game(self)
45
+ reset_game
76
46
  new_game_starting_graphic
77
47
  end
78
48
  end
@@ -85,26 +55,10 @@ module Shared
85
55
  current_player.name
86
56
  end
87
57
 
88
- def current_player_human?
89
- current_player.type == :human
90
- end
91
-
92
- def current_player_computer?
93
- current_player.type == :computer
94
- end
95
-
96
58
  def move_forward_one_turn
97
59
  self.number_of_turns_taken += 1
98
60
  end
99
61
 
100
- def generate_empty_board(config)
101
- board_builder.generate_empty_board(config)
102
- end
103
-
104
- def change_game_state(available_choice, game)
105
- game_state_changer.change_game_state(available_choice, game)
106
- end
107
-
108
62
  def winner
109
63
  #each move is immediately proceeded by an increment to number_of_selections_made; therefore, need to rewind won to find winner
110
64
  if !won?
@@ -117,22 +71,50 @@ module Shared
117
71
  board.display_values
118
72
  end
119
73
 
74
+
75
+ def computer_choosing_graphic
76
+ io_helpers.computer_choosing_graphic
77
+ end
78
+
120
79
  private
121
80
 
81
+ #hook
82
+ def one_time_setup
83
+ end
84
+
85
+ #hook
86
+ def every_time_setup
87
+ end
88
+
89
+
90
+ def second_player_expert_computer?
91
+ players[1].kind_of?(TTT::ComputerPlayerExpert)
92
+ end
93
+
94
+ #overriding so that io and io_helpers always in harmony
95
+
122
96
  def over?
123
97
  raise 'Called abstract method: over?'
124
98
  end
125
99
 
126
- def over_with_no_winner?
127
- raise 'Called abstract method: draw?'
100
+ def no_more_turns?
101
+ raise 'Called abstract method: no_more_turns?'
128
102
  end
129
103
 
130
104
  def won?
131
105
  raise 'Called abstract method: won?'
132
106
  end
133
107
 
134
- def custom_final_message(game)
135
- input_helper.custom_final_message(game)
108
+ def change_game_state(move)
109
+ raise 'Called abstract method: change_game_state'
110
+ end
111
+
112
+ def reset_game
113
+ raise 'Called abstract method: reset_game'
114
+ end
115
+
116
+ def reset_board
117
+ raise 'Called abstract method: reset_board'
136
118
  end
137
119
 
138
120
  def print_board
@@ -147,20 +129,24 @@ module Shared
147
129
  (number_of_turns_taken % number_of_players)
148
130
  end
149
131
 
132
+ def custom_final_message(game)
133
+ io_helpers.custom_final_message(game)
134
+ end
135
+
150
136
  def initial_instructions
151
- input_helper.initial_instructions
137
+ io_helpers.initial_instructions
152
138
  end
153
139
 
154
140
  def winning_prompt
155
- input_helper.winning_prompt(current_player_name)
141
+ io_helpers.winning_prompt(current_player_name)
156
142
  end
157
143
 
158
- def no_winner_prompt
159
- input_helper.no_winner_prompt
144
+ def no_winner_prompt(game)
145
+ io_helpers.no_winner_prompt(game)
160
146
  end
161
147
 
162
148
  def new_game_starting_graphic
163
- input_helper.new_game_starting_graphic
149
+ io_helpers.new_game_starting_graphic
164
150
  end
165
151
  end
166
152
  end
@@ -1,46 +1,24 @@
1
+ require 'paint'
2
+
1
3
  module Shared
2
- class InputHelper
4
+ class IOHelpers
3
5
  attr_accessor :io
4
6
 
5
7
  def initialize(io)
6
8
  @io = io
7
9
  end
8
10
 
9
- def get_game
10
- user_choice = get_user_input("Please enter \"M\" if you would like to play Mastermind. Enter \"T\" if you would like to play Tic Tac Toe.", "Invalid character. Please enter either M (Mastermind) or T (Tic Tac Toe).") do |input|
11
- input == 'm' || input == 'M' || input == 't' || input == 'T'
12
- end
13
- user_choice = user_choice.upcase
14
- if user_choice == "M"
15
- :mastermind
16
- elsif user_choice == "T"
17
- :tictactoe
18
- end
11
+ def initial_instructions
12
+ raise 'Called abstract method: initial_instructions'
19
13
  end
20
14
 
21
15
  def get_player_1_name
22
- user_choice = get_user_input("Player 1, please enter your name", "Please re-enter your name, using only letters") do |input|
16
+ user_choice = get_user_input("Player 1, please enter your name:", "Please re-enter your name, using only letters") do |input|
23
17
  input =~ /^[a-zA-Z]+$/
24
18
  end
25
19
  user_choice.capitalize
26
20
  end
27
21
 
28
- def get_user_input(prompt, reprompt, &block_validation)
29
- io.present_with_new_line(prompt)
30
- user_choice = nil
31
- while true
32
- user_choice = io.receive
33
- if user_choice.to_s.upcase == "EXIT"
34
- #http://blog.honeybadger.io/how-to-exit-a-ruby-program/
35
- exit(0)
36
- end
37
- #breaks out of input loop if input is valid (the block validation makes sure some rule is true)
38
- break if block_validation.call(user_choice)
39
- puts reprompt
40
- end
41
- user_choice
42
- end
43
-
44
22
  def computer_choosing_graphic
45
23
  io.present("Computer choosing.")
46
24
  3.times do
@@ -62,6 +40,40 @@ module Shared
62
40
  io.present("\n")
63
41
  end
64
42
 
43
+ def winning_prompt(current_player_name)
44
+ if current_player_name == "Computer"
45
+ io.present_with_new_line(Paint["#{current_player_name} wins!", :red, :bold])
46
+ else
47
+ io.present_with_new_line(Paint["#{current_player_name} wins!", :green, :bold])
48
+ end
49
+ end
50
+
51
+ def no_winner_prompt
52
+ raise 'Called abstract method: no_winner_prompt'
53
+ end
54
+
55
+ def custom_final_message(game)
56
+ #hook
57
+ end
58
+
59
+ private
60
+
61
+ def get_user_input(prompt, reprompt, &block_validation)
62
+ io.present_with_new_line(prompt)
63
+ user_choice = nil
64
+ while true
65
+ user_choice = io.receive
66
+ if user_choice.to_s.upcase == "EXIT"
67
+ #http://blog.honeybadger.io/how-to-exit-a-ruby-program/
68
+ exit(0)
69
+ end
70
+ #breaks out of input loop if input is valid (the block validation makes sure some rule is true)
71
+ break if block_validation.call(user_choice)
72
+ puts reprompt
73
+ end
74
+ user_choice
75
+ end
76
+
65
77
  def marching_dots
66
78
  sleep(0.2)
67
79
  io.present(".")
@@ -70,9 +82,5 @@ module Shared
70
82
  sleep(0.1)
71
83
  io.present(".")
72
84
  end
73
-
74
- def custom_final_message(game)
75
-
76
- end
77
85
  end
78
86
  end
@@ -1,11 +1,9 @@
1
1
  module Shared
2
2
  class Player
3
- attr_accessor :value, :name, :type, :difficulty_level
3
+ attr_accessor :name
4
4
 
5
5
  def initialize(args = {})
6
6
  @name = args.fetch(:name, "Player 1")
7
- @type = args.fetch(:type, :human)
8
- @difficulty_level = args.fetch(:difficulty_level, nil)
9
7
  post_initialize(args)
10
8
  end
11
9
 
@@ -0,0 +1,9 @@
1
+ module Shared
2
+ class PlayerFactory
3
+ attr_accessor :io_helpers
4
+
5
+ def initialize(io_helpers)
6
+ @io_helpers = io_helpers
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Shared
2
+ class PlayersFactory
3
+ attr_accessor :io_helpers
4
+
5
+ def initialize(io_helpers)
6
+ @io_helpers = io_helpers
7
+ end
8
+ end
9
+ end
@@ -1,9 +1,8 @@
1
1
  module TTT
2
2
  class Board
3
- attr_accessor :rows_and_cols, :squares
3
+ attr_accessor :squares
4
4
 
5
5
  def initialize(args = {})
6
- @rows_and_cols = args[:rows_and_cols]
7
6
  @squares = args[:squares]
8
7
  end
9
8
 
@@ -28,8 +27,8 @@ module TTT
28
27
  return squares.available_choices
29
28
  end
30
29
 
31
- def number_of_rows
32
- rows_and_cols
30
+ def number_of_rows_cols
31
+ squares.number_of_rows_cols
33
32
  end
34
33
 
35
34
  private
@@ -1,10 +1,10 @@
1
+ require_relative 'board'
1
2
  require_relative 'squares_factory'
2
3
 
3
4
  module TTT
4
5
  class BoardBuilder
5
- def generate_empty_board(config)
6
- number_of_rows_cols = config.number_of_rows_cols
7
- Board.new(rows_and_cols: number_of_rows_cols, squares: SquaresFactory.build_empty_squares(number_of_rows_cols) )
6
+ def generate_empty_board(number_of_rows_cols)
7
+ Board.new(squares: SquaresFactory.build_empty_squares(number_of_rows_cols) )
8
8
  end
9
9
  end
10
10
  end
@@ -13,7 +13,7 @@ module TTT
13
13
  end
14
14
  print "\n"
15
15
  #row_number starts at 0
16
- puts "_"*(row.size * 5) unless row_number.equal? (number_of_rows - 1)
16
+ puts "_"*(row.size * 5) unless row_number.equal? (number_of_rows_cols - 1)
17
17
  end
18
18
  end
19
19
 
@@ -21,8 +21,8 @@ module TTT
21
21
  board.display_values
22
22
  end
23
23
 
24
- def number_of_rows
25
- board.number_of_rows
24
+ def number_of_rows_cols
25
+ board.number_of_rows_cols
26
26
  end
27
27
  end
28
28
  end
@@ -0,0 +1,12 @@
1
+ require_relative '../tictactoe/player'
2
+
3
+ module TTT
4
+ class ComputerPlayerExpert < TTT::Player
5
+ def make_move(game)
6
+ game.computer_choosing_graphic
7
+ minimax = TTT::Minimax.new(game.board, game.number_of_turns_taken, game.player_1_value, game.player_2_value)
8
+ minimax.run_minimax
9
+ minimax.choice
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ require_relative '../tictactoe/player'
2
+
3
+ module TTT
4
+ class ComputerPlayerNovice < TTT::Player
5
+ def make_move(game)
6
+ game.computer_choosing_graphic
7
+ game.available_choices.sample
8
+ end
9
+ end
10
+ end
@@ -2,18 +2,37 @@ require_relative '../shared/game'
2
2
 
3
3
  module TTT
4
4
  class Game < Shared::Game
5
- attr_accessor :won_flag
5
+ def one_time_setup
6
+ self.players = players_factory.generate_players
7
+ number_of_rows_cols = get_board_rows
8
+ self.board = board_builder.generate_empty_board(number_of_rows_cols)
9
+ end
6
10
 
7
- def local_setup
11
+ def every_time_setup
8
12
  self.won_flag = false
9
13
  end
10
14
 
15
+ def get_board_rows
16
+ #need this if else logic because if computer is difficult, it runs minimax, which is too slow to allow for more than 3 rows/cols
17
+ if second_player_expert_computer?
18
+ io_helpers.get_number_of_rows_cols_max_3
19
+ else
20
+ io_helpers.get_number_of_rows_cols_max_9
21
+ end
22
+ end
23
+
24
+ def change_game_state(move)
25
+ change_square(move, current_player_value)
26
+ if !won?
27
+ move_forward_one_turn
28
+ end
29
+ end
11
30
 
12
31
  def over?
13
- won_flag || over_with_no_winner?
32
+ won_flag || no_more_turns?
14
33
  end
15
34
 
16
- def over_with_no_winner?
35
+ def no_more_turns?
17
36
  board.full?
18
37
  end
19
38
 
@@ -29,6 +48,24 @@ module TTT
29
48
  end
30
49
  end
31
50
 
51
+ def reset_game
52
+ reset_board
53
+ self.number_of_turns_taken = 0
54
+ self.won_flag = false
55
+ end
56
+
57
+ def reset_board
58
+ self.board = generate_empty_board(number_of_rows_cols)
59
+ end
60
+
61
+ def number_of_rows_cols
62
+ board.number_of_rows_cols
63
+ end
64
+
65
+ def generate_empty_board(number_of_rows_cols)
66
+ board_builder.generate_empty_board(number_of_rows_cols)
67
+ end
68
+
32
69
  def available_choices
33
70
  board.available_choices
34
71
  end
@@ -45,16 +82,12 @@ module TTT
45
82
  current_player.value
46
83
  end
47
84
 
48
- def current_player_difficult_computer?
49
- current_player_computer? && current_player.difficulty_level == :difficult
50
- end
51
-
52
- def current_player_easy_computer?
53
- current_player_computer? && current_player.difficulty_level == :easy
54
- end
55
-
56
85
  def change_square(display_value, current_player_value)
57
86
  board.change_square(display_value, current_player_value)
58
87
  end
88
+
89
+ def get_player_choice(current_player_name, available_choices)
90
+ io_helpers.get_player_choice(current_player_name, available_choices)
91
+ end
59
92
  end
60
93
  end
@@ -0,0 +1,9 @@
1
+ require_relative '../tictactoe/player'
2
+
3
+ module TTT
4
+ class HumanPlayer < TTT::Player
5
+ def make_move(game)
6
+ game.get_player_choice(game.current_player_name, game.available_choices)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,81 @@
1
+ require_relative '../shared/io_helpers'
2
+ require 'paint'
3
+
4
+ module TTT
5
+ class IOHelpers < Shared::IOHelpers
6
+ def initial_instructions
7
+ io.present_with_new_line(Paint["-" * 60 + "TIC TAC TOE" + "-" * 60, :blue, :bold, :bright, :underline])
8
+ io.present_with_new_line(Paint["INSTRUCTIONS: ", :green] + "Try to fill a row, a column, or a diagonal with only your token value.")
9
+ io.present_with_new_line("-" * 131)
10
+ io.present_with_new_line(Paint["Type ",:red] + Paint["\"Exit\" ", :red, :bold] + Paint["to quit the game.", :red])
11
+ io.present_with_new_line("_" * 131)
12
+ end
13
+
14
+ def no_winner_prompt(game)
15
+ io.present_with_new_line(Paint["Draw! Please try again.", :red, :bold])
16
+ end
17
+
18
+ def get_number_of_rows_cols_max_3
19
+ get_user_input("Please choose how many squares you would like in each row.", "Please choose number between 2 and 3.") do |input|
20
+ input.to_i >=2 && input.to_i <=3
21
+ end
22
+ end
23
+
24
+ def get_number_of_rows_cols_max_9
25
+ get_user_input("Please choose how many squares you would like in each row.", "Please choose number between 2 and 3.") do |input|
26
+ input.to_i >=2 && input.to_i <=9
27
+ end
28
+ end
29
+
30
+ def get_player_2_name
31
+ user_choice = get_user_input("Player 2, please enter your name:", "Please re-enter your name, using only letters") do |input|
32
+ input =~ /^[a-zA-Z]+$/
33
+ end
34
+ user_choice.capitalize
35
+ end
36
+
37
+ def get_player_value(player_name = "Player 1", taken_value = "")
38
+ user_choice = get_user_input("#{player_name}, please enter your preferred token value, consisting of one letter only. For example, " + Paint["\"X\" ", :blue, :bold] + "and " + Paint["\"O\" ", :blue, :bold] + " are the most common token values in Tic Tac Toe.", "Invalid entry. Must be one letter. Please re-enter.") do |input|
39
+ (input =~ /^[a-zA-Z]$/ && input.upcase != taken_value.upcase)
40
+ end
41
+ user_choice.upcase
42
+ end
43
+
44
+ # def get_player_2_name
45
+ # user_choice = get_user_input("Player 2, please enter your name", "Please re-enter your name, using only letters") do |input|
46
+ # input =~ /^[a-zA-Z]+$/
47
+ # end
48
+ # user_choice.capitalize
49
+ # end
50
+
51
+ def get_player_2_type
52
+ user_choice = get_user_input("Please enter " + Paint["\"C\" ", :blue, :bold] + "if you would like to play the Computer. Enter " + Paint["\"H\" ", :blue, :bold] + "if you would like to play the human sitting next to you:", "Invalid character. Please enter either C(Computer) or H(Human).") do |input|
53
+ input == 'c' || input == 'C' || input == 'h' || input == 'H'
54
+ end
55
+ user_choice = user_choice.upcase
56
+ if user_choice == "C"
57
+ :computer
58
+ elsif user_choice == "H"
59
+ :human
60
+ end
61
+ end
62
+
63
+ def get_computer_knowledge_level
64
+ user_choice = get_user_input("Please enter " + Paint["\"E\" ", :blue, :bold] + "if you would like to play an easy Computer. Enter " + Paint["\"D\" ", :blue, :bold] +"if you would like to play an extremely difficult computer.", "Invalid character. Please enter either E (Easy) or D (Difficult).") do |input|
65
+ input == 'd' || input == 'D' || input == 'e' || input == 'E'
66
+ end
67
+ user_choice = user_choice.upcase
68
+ if user_choice == "D"
69
+ :expert
70
+ elsif user_choice == "E"
71
+ :novice
72
+ end
73
+ end
74
+
75
+ def get_player_choice(current_player_name, available_choices)
76
+ get_user_input("#{current_player_name}, please enter the number of the square that you would like to change.", "Invalid entry. Please try again.") do |input|
77
+ available_choices.include?(input)
78
+ end
79
+ end
80
+ end
81
+ end
@@ -7,5 +7,9 @@ module TTT
7
7
  def post_initialize(args = {})
8
8
  @value = args.fetch(:value, "X")
9
9
  end
10
+
11
+ def make_move
12
+ raise 'Called abstract method: make_move'
13
+ end
10
14
  end
11
15
  end