Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I want to implement a game loop in Ruby, but my current implementation receives a 'stack level too deep' (SystemStackError).

This is how far I got on my Tetris-like falling block game:

# 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

Produces this error:

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>'

UPDATE

Ruby does not enable Tail Call Optimizations by default, but it can be enabled in the Ruby VM.

RubyVM::InstructionSequence.compile_option = {
  tailcall_optimization: true,
  trace_instruction: false
}
like image 589
wurde Avatar asked May 26 '26 09:05

wurde


1 Answers

Use a while true ... loop instead of recursion. You can also add a short sleep to avoid more updates than necessary.

like image 192
Leo Brito Avatar answered May 28 '26 15:05

Leo Brito



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!