在 Ruby 中构建事件循环时如何避免无限递归?

How do I avoid infinite recursion when building an event loop in Ruby?

我想在 Ruby 中实现一个游戏循环,但我当前的实现收到一个 'stack level too deep' (SystemStackError)。

这是我在类似俄罗斯方块的下落方块游戏中的进展:

# falling block game
class Tetris
  class EndGame < StandardError; end

  def start
    @canvas = Canvas.new
    @canvas.banner = "New game"
    @canvas.draw
    update
  end

  def update
    step
    update
  rescue EndGame
    puts "Game over!"
  end

  def step
    puts "Take one step..."
    # TODO: do stuff here
  end

  # draws our game board
  class Canvas
    SIZE = 10

    attr_accessor :banner, :board

    def initialize
      @board = SIZE.times.map { Array.new(SIZE) }
    end

    def update(point, marker)
      x, y = point
      @board[x, y] = marker
    end

    alias_method :draw, :to_s
    def draw
      [banner, separator, body, separator].join("\n")
    end

    private

    def separator
      "=" * SIZE
    end

    def body
      @board.map do |row|
        row.map { |e| e || " " }.join
      end.join("\n")
    end
  end
end

game = Tetris.new
game.start

产生此错误:

Take one step...
Take one step...
Take one step...
Take one step...
Take one step...
Take one step...
Take one step...
Take one step...
Take one step...
Take one step...
gameloop.rb:20:in `puts': stack level too deep (SystemStackError)
    from gameloop.rb:20:in `puts'
    from gameloop.rb:20:in `step'
    from gameloop.rb:13:in `update'
    from gameloop.rb:14:in `update'
    from gameloop.rb:14:in `update'
    from gameloop.rb:14:in `update'
    from gameloop.rb:14:in `update'
    from gameloop.rb:14:in `update'
     ... 10067 levels...
    from gameloop.rb:14:in `update'
    from gameloop.rb:14:in `update'
    from gameloop.rb:9:in `start'
    from gameloop.rb:59:in `<main>'

更新

Ruby 默认不启用尾调用优化,但可以在 Ruby VM 中启用。

RubyVM::InstructionSequence.compile_option = {
  tailcall_optimization: true,
  trace_instruction: false
}

使用 while true ... 循环而不是递归。您还可以添加一个简短的 sleep 以避免不必要的更新。