在 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
以避免不必要的更新。
我想在 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
以避免不必要的更新。