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.
- checksums.yaml +4 -4
- data/README.md +8 -12
- data/config/application.yml +5 -0
- data/games.gemspec +2 -1
- data/lib/games/mastermind/board_builder.rb +6 -2
- data/lib/games/mastermind/computer_player_expert.rb +31 -0
- data/lib/games/mastermind/computer_player_novice.rb +18 -0
- data/lib/games/mastermind/game.rb +69 -15
- data/lib/games/mastermind/guess_evaluator.rb +105 -68
- data/lib/games/mastermind/guess_evaluator_result.rb +11 -0
- data/lib/games/mastermind/human_player.rb +9 -0
- data/lib/games/mastermind/io_helpers.rb +65 -0
- data/lib/games/mastermind/peg.rb +2 -4
- data/lib/games/mastermind/pegs.rb +1 -9
- data/lib/games/mastermind/pegs_factory.rb +3 -5
- data/lib/games/mastermind/players_factory.rb +32 -8
- data/lib/games/mastermind/secret_code.rb +19 -0
- data/lib/games/mastermind.rb +9 -2
- data/lib/games/shared/game.rb +56 -70
- data/lib/games/shared/{input_helper.rb → io_helpers.rb} +40 -32
- data/lib/games/shared/player.rb +1 -3
- data/lib/games/shared/player_factory.rb +9 -0
- data/lib/games/shared/players_factory.rb +9 -0
- data/lib/games/tictactoe/board.rb +3 -4
- data/lib/games/tictactoe/board_builder.rb +3 -3
- data/lib/games/tictactoe/board_presenter_terminal.rb +3 -3
- data/lib/games/tictactoe/computer_player_expert.rb +12 -0
- data/lib/games/tictactoe/computer_player_novice.rb +10 -0
- data/lib/games/tictactoe/game.rb +45 -12
- data/lib/games/tictactoe/human_player.rb +9 -0
- data/lib/games/tictactoe/io_helpers.rb +81 -0
- data/lib/games/tictactoe/player.rb +4 -0
- data/lib/games/tictactoe/players_factory.rb +49 -5
- data/lib/games/tictactoe/square.rb +0 -3
- data/lib/games/tictactoe/squares.rb +1 -1
- data/lib/games/tictactoe/squares_factory.rb +7 -11
- data/lib/games/tictactoe.rb +9 -2
- data/lib/games/version.rb +1 -1
- metadata +32 -17
- data/lib/games/mastermind/colors.rb +0 -14
- data/lib/games/mastermind/game_config.rb +0 -48
- data/lib/games/mastermind/game_resetter.rb +0 -19
- data/lib/games/mastermind/game_state_changer.rb +0 -41
- data/lib/games/mastermind/input_helper.rb +0 -67
- data/lib/games/mastermind/move_generator.rb +0 -46
- data/lib/games/shared/array_iterator.rb +0 -28
- data/lib/games/tictactoe/game_config.rb +0 -73
- data/lib/games/tictactoe/game_resetter.rb +0 -16
- data/lib/games/tictactoe/game_state_changer.rb +0 -17
- data/lib/games/tictactoe/input_helper.rb +0 -87
- 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
|
data/lib/games/mastermind.rb
CHANGED
@@ -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(
|
10
|
-
|
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
|
data/lib/games/shared/game.rb
CHANGED
@@ -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 :
|
10
|
-
|
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
|
32
|
-
|
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
|
-
|
45
|
-
|
46
|
-
|
17
|
+
@io_helpers = args.fetch(:io_helpers)
|
18
|
+
@board_builder = args.fetch(:board_builder)
|
19
|
+
@players_factory = args.fetch(:players_factory)
|
47
20
|
|
48
|
-
|
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
|
-
|
27
|
+
loop do
|
58
28
|
every_time_setup
|
59
29
|
while !over?
|
60
30
|
print_board
|
61
|
-
move =
|
62
|
-
|
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
|
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
|
-
|
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
|
127
|
-
raise 'Called abstract method:
|
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
|
135
|
-
|
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
|
-
|
137
|
+
io_helpers.initial_instructions
|
152
138
|
end
|
153
139
|
|
154
140
|
def winning_prompt
|
155
|
-
|
141
|
+
io_helpers.winning_prompt(current_player_name)
|
156
142
|
end
|
157
143
|
|
158
|
-
def no_winner_prompt
|
159
|
-
|
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
|
-
|
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
|
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
|
10
|
-
|
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
|
data/lib/games/shared/player.rb
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
module Shared
|
2
2
|
class Player
|
3
|
-
attr_accessor :
|
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
|
|
@@ -1,9 +1,8 @@
|
|
1
1
|
module TTT
|
2
2
|
class Board
|
3
|
-
attr_accessor :
|
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
|
32
|
-
|
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(
|
6
|
-
|
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? (
|
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
|
25
|
-
board.
|
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
|
data/lib/games/tictactoe/game.rb
CHANGED
@@ -2,18 +2,37 @@ require_relative '../shared/game'
|
|
2
2
|
|
3
3
|
module TTT
|
4
4
|
class Game < Shared::Game
|
5
|
-
|
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
|
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 ||
|
32
|
+
won_flag || no_more_turns?
|
14
33
|
end
|
15
34
|
|
16
|
-
def
|
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,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
|