我用Ruby创建了一个小命令行'Mastermind‘游戏。项目的意图(除了在构建中获得乐趣!)就是学习和强调面向对象的概念和原则。
游戏有一些简单的人工智能到位。如果计算机是进行猜测的播放器,当它们在正确的索引位置得到正确的颜色时,该猜测将锁定为随后的回合。当他们得到正确的颜色,但在一个不正确的索引位置,该颜色将使用在下一轮,但放置在一个不同(和无人)的索引位置。
module Mastermind
class Player
attr_accessor :color_choices
def initialize(color_choices)
@color_choices = color_choices
end
end
class Game
attr_accessor :computer, :human, :color_choices
def initialize
welcome
end
def play_game
@available = [0,1,2,3]
@computer = Player.new(get_random_choice)
human_instructions
choose_message
@human = Player.new(get_human_choice)
compare_with_index
@@guess_iterations = 1
@@guesses_hash = Hash.new
guess_loop_human
end
def comp_guesses
@available = [0,1,2,3]
choose_message
@human = Player.new(get_human_choice)
@computer = Player.new(get_random_choice)
compare_with_index
@@guess_iterations = 1
@@guesses_hash = Hash.new
guess_loop_comp
end
def welcome
puts "Welcome to Mastermind."
puts "========================================================"
who_creates_code
end
def human_instructions
puts "You will be given 12 chances to guess the code that was chosen by the computer."
puts "========================================================"
puts "There are 6 colors from which to choose (Red, Blue, Green, Yellow, Orange, Purple)"
puts "========================================================"
end
def who_creates_code
puts "Would you like to choose the code and have the computer guess? (yes/no)"
chooser = gets.chomp.downcase
input_validation(chooser)
end
def input_validation(response)
if response == "yes"
comp_guesses
elsif response == "no"
play_game
else
puts "Response not valid"
who_creates_code
end
end
def choose_message
puts "Please choose four colors, separated by a comma (ex: B,O,Y,G)"
end
def get_random_choice
puts "The computer is now choosing..."
colors = ["R", "B", "G", "Y", "O", "P"]
choice = colors.sample(4)
end
def get_human_choice
answer = gets.chomp.upcase
human_colors = answer.split(",")
end
def compare_with_index
@count_index = 0
@color_count = 0
computer.color_choices.each_with_index do |n, index|
if human.color_choices[index] == n
@count_index += 1
@available -= [index]
elsif color_match(n) && color_available(n)
@color_count += 1
end
end
@count_index
end
def color_match(color)
human.color_choices.include?(color)
end
def color_available(color)
@available.include?(human.color_choices.index(color))
end
def matches_message
"You have #{@count_index} color(s) in the right spot and #{@color_count} correctly chosen color(s)"
end
def guess_loop_comp
while @@guess_iterations <= 12 && !victory
store_guess_comp
board
puts matches_message
computer.color_choices = new_choice
compare_with_index
@@guess_iterations += 1
end
game_over
end
def guess_loop_human
while @@guess_iterations <= 12 && !victory
store_guess_human
board
puts matches_message
guess_again_message
human.color_choices = get_human_choice
compare_with_index
@@guess_iterations += 1
end
game_over
end
def store_guess_human
@@guesses_hash[human.color_choices] = matches_message
end
def store_guess_comp
@@guesses_hash[computer.color_choices] = matches_message
end
def board
Board.new
end
def guess_again_message
puts "Guess again, please choose four colors, separated by a comma (ex: B,O,Y,G)"
end
def available
@available.shuffle!.pop
end
def new_choice
colors = ["R", "B", "G", "Y", "O", "P"]
new_color = []
computer.color_choices.each_with_index do |n, index|
if human.color_choices[index] != n && !color_available(n)
new_color[index] = colors.sample
else
new_color[index] = n
end
end
new_color
keep_color(new_color)
end
def keep_color(new_array)
computer.color_choices.each do |i|
if color_available(i)
new_array[available.to_i] = i
end
end
p new_array
new_array
end
def victory
if compare_with_index == 4
store_guess_comp
board
puts "Victory!"
true
end
end
def game_over
if @@guess_iterations > 12 && !victory
puts "Game Over"
end
end
end
class Board < Game
def initialize
render_board
end
def render_board
(13- @@guess_iterations.to_i).times do
puts "| X | X | X | X |"
end
display_hash
end
def display_hash
@@guesses_hash.each do |k,v|
puts "================="
puts "| " + k.join(" | ") + " | " + v
puts "================="
end
end
end
end
Mastermind::Game.new发布于 2015-10-01 01:33:35
这只是一个样式问题,但这是我第一次看到Ruby代码在类主体的末尾有空行,这似乎令人困惑,因为您没有以这种方式分隔其他端点:
end
end您有几对几乎相同的方法,如#guess_loop_human和#guess_loop_comp。重复自己是不好的,如果你有两个类HumanPlayer和CPUPlayer,移动特定于玩家的逻辑,并且在游戏类中将玩家称为'player_a‘和'player_b',或者'setter’和'guesser‘,这个问题会得到更好的解决。
module Player # could be a class
# common logic if any
end
class HumanPlayer # and CPUPlayer elsewhere
include Player
def get_choice
# possibly print messages here
end
end
def guess_loop # not guess_loop_human and guess_loop_comp
while @@guess_iterations <= 12 && !victory
store_guess
board
puts matches_message
guesser.get_choice # this works differently for HumanPlayer and CPUPlayer
compare_with_index
@@guess_iterations += 1
end
game_over
end您的@guesses_hash是一个由数组索引的散列。这是非常糟糕的,因为两个相同的数组将被计算为相同的键--如果玩家进行两次相同的猜测,这将扰乱您的逻辑。
您的董事会是游戏的子类,您使用它在它们之间共享类变量。不过,这是没有道理的,因为董事会显然不是一种游戏。更没有意义的是实例化这个类可以画一个板。
上述两个问题都可以通过引入实际的Board类来解决,该类可以跟踪猜测,使这些数据可供游戏使用,并且可以呈现出来。
您的方法的结构有时有些偏离。让我们看看这里:
def input_validation(response)
if response == "yes"
comp_guesses
elsif response == "no"
play_game
else
puts "Response not valid"
who_creates_code
end
end仅仅因为这个方法碰巧是在一个地方调用的,这并不意味着它应该调用在该方法之后应该被调用的方法-相反,这个函数应该返回一个值,它的调用者应该决定如何处理它。这使得这个函数可以重用,以防您想问更多的是\没有问题(比如"Play again?(yes\no)",但是代码的可读性更强)--您的代码的读者不会期望input_validation意味着input_validation_and_than_play_the_game。例如,您可以:
if get_yes_or_no # old name was confusing IMO
comp_guesses
else
play_game
end假设上面的#get_yes_or_no在循环中重复#gets,直到得到有效的答案为止,我想它也应该是调用chomp.upcase的那个。
https://codereview.stackexchange.com/questions/105946
复制相似问题