games_bfox 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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