我对这台国家机器的运作方式存在根本性的误解

时间:2013-06-06 15:53:30

标签: ruby state

我从根本上不明白这里发生了什么。 play 下面是我的状态机。但它不起作用。它要么返回两个选择的反面,一遍又一遍(开始),或'未知命令'。我已经通过在各个点打印变量@next_action的值来测试它,结果是不一致的。有时case语句的结果是 instruct ,但它会打印 display 。有时反之亦然,有时候是未知的命令。是的,我调整代码来产生这些不同的结果。但并不多。从来没有像预期的那样表现。

显然,我不明白我所写的逻辑。我想要做的就是将case语句的结果作为方法调用传递并保持所有循环。我是一个红宝石的新手和那些试图帮助的人,或者以一种我似乎不理解的方式描述事物,或者我在解释/显示我的确切方面做得很差我试图做。

非常感谢任何帮助。

class Foo

  def initialize(start_action)
    @start = start_action
    @users = %w(Adam Sarah Kanye)
    @points = %w(100 200 300)
  end

  def play    
    puts @next_action
    while true
      case @next_action
      when beginning
        beginning
      when "instruct"
        instructions
      when "display"
        display_users
      else
        puts "Unknown command."
        play
      end
      puts "\n----------"
    end
  end

  def prompt
    puts "\n----------"
    print "> "
  end

  def beginning
    puts <<-INTROTEXT
      This is intro text.
    INTROTEXT
    prompt; @next_action = gets.chomp.to_s
  end

  def instructions
    puts <<-INSTRUCT
      These are instructions.
    INSTRUCT
    prompt; @next_action = gets.chomp.to_s
  end

  def display_users
    puts "\nYour users now include:"
    puts "\nName\tPoints"
    puts "----\t------"
    @users.each_with_index do |item, index|
      puts "%s\t%s" % [item, @points[index]]
    end
    prompt; @next_action = gets.chomp
  end
end

start = Foo.new(:beginning)
start.play

2 个答案:

答案 0 :(得分:1)

你会好的,只是DRY事情。此外,您有两个独立的循环结构,这会导致不良行为。您的:play方法包含一个无限循环,它自己将:play作为最后一步。你真的只需要一个或另一个。我已经调整了一些内容来集中:prompt功能并使用一个没有递归的循环(即:play不再调用自身)来实现我认为你期望的行为:

class Foo
  def initialize
    @next_action  = "beginning"
    @users        = %w(Adam Sarah Kanye)
    @points       = [100, 200, 300]
  end

  def play    
    while true
      act
      prompt
    end
  end

  def prompt
    puts "\n----------"
    print "> "
    @next_action = gets.chomp.to_s
  end    

  def act
    case @next_action
    when "beginning"
      beginning
    when "instruct"
      instructions
    when "display"
      display_users
    else
      puts "I don't know how to '#{@next_action}'."
    end
  end

  def beginning
    puts <<-INTROTEXT
      This is intro text.
    INTROTEXT
  end

  def instructions
    puts <<-INSTRUCT
      These are instructions.
    INSTRUCT
  end

  def display_users
    puts "\nYour users now include:"
    puts "\nName\tPoints"
    puts "----\t------"
    @users.each_with_index do |item, index|
      puts "%s\t%s" % [item, @points[index].to_s]
    end
  end
end

Foo.new.play

答案 1 :(得分:0)

案例陈述中的开头应该是:开头即一个符号,否则你正在评估针对某个方法的下一个行动。另外,当你在一个永远不会导致开始的case语句中进行递归时,这可能意味着你最终会进行无限递归。 (道歉,如果开头只是一个错字)

您也在混合符号和字符串(通常应该避免)。在说明中,您将@next_action创建为字符串,但通过Foo.new创建符号。 :开始!=“开始”也。我建议下一个动作永远是一个符号,因为符号(据我所知)用于表示当作为参数传递给函数时,应根据符号采取动作。虽然它基于用户输入,但将它保留为字符串也是有意义的。

也不应该将函数调用play放在case语句之外,然后删除while true。这意味着在创建@next_action之后,程序继续。基本上我不认为这会永远停止,而真正意味着永远持续,你必须提供break来阻止它。我想你会希望它继续下去,除非有一个未知的动作。或者至少重置对未知动作的动作,即:

class Foo

  def initialize(start_action)
    @start = start_action
    @users = %w(Adam Sarah Kanye)
    @points = %w(100 200 300)
  end

如果有人输入错误的指示但是继续

,这个会停止
  def play    
    puts @next_action
    case @next_action
    when :beginning
      beginning
    when :instruct
      instructions
    when :display
      display_users
    else
      puts "Unknown command."
      raise Foo::UnknownCommand
    end
    puts "\n----------"
    play
  end

OR这将永远持续,并在用户输入错误的命令时启动用户。

  def play    
    puts @next_action
    while true
      case @next_action
      when :beginning
        beginning
      when :instruct
        instructions
      when :display
        display_users            
      else
        puts "Unknown command."
        @next_action = :beginning
      end
      puts "\n----------"
    end
  end

和其他

  def prompt
    puts "\n----------"
    print "> "
  end

  def beginning
    puts <<-INTROTEXT
      This is intro text.
    INTROTEXT
    prompt; @next_action = gets.chomp.to_sym
  end

  def instructions
    puts <<-INSTRUCT
      These are instructions.
    INSTRUCT
    prompt; @next_action = gets.chomp.to_sym
  end

  def display_users
    puts "\nYour users now include:"
    puts "\nName\tPoints"
    puts "----\t------"
    @users.each_with_index do |item, index|
      puts "%s\t%s" % [item, @points[index]]
    end
    prompt; @next_action = gets.chomp.to_sym
  end
end

start = Foo.new(:beginning)
start.play

我希望有所帮助。