我试图制作一个方法,当它们为零时拉出瓷砖时,我会触发无休止的递归。我在irb中输入以下内容进行测试:
class Board
attr_accessor :size, :board
def initialize(size = gets.chomp.to_i)
@size = size
@board = (1..@size).map { |x| ["L"] * @size }
end
def print_board
@board.map { |row| puts row.join }
end
end
class Mine
attr_accessor :proxi, :row, :col
def initialize(proxi)
@proxi = proxi
@row = 0
@col = 0
@random = Random.new
check_position
end
def check_position
if @proxi.board[@row - 1][@col - 1] != "L"
@row = @random.rand(1..@proxi.board.length)
@col = @random.rand(1..@proxi.board[0].length)
check_position
else
map_position
end
end
def map_position
@proxi.board[@row - 1][@col - 1] = "*"
end
end
b = Board.new(20)
m = (1..b.size * 2).map { |i| i = Mine.new(b) }
class Detector
attr_accessor :board, :proxi, :row, :col, :value
def initialize(board, proxi)
@board = board
@proxi = proxi
@row = 0
@col = 0
@value = 0
end
def mine?
if @proxi.board[@row - 1][@col - 1] == "*"
true
else
false
end
end
def detect
(@row - 1..@row + 1).each do |r|
(@col - 1..@col + 1).each do |c|
unless (r - 1 < 0 || r - 1 > @proxi.size - 1) || (c - 1 < 0 || c - 1 > @proxi.size - 1)
@value += 1 if @proxi.board[r - 1][c - 1] == "*"
end
end
end
end
def map_position
@proxi.board[@row - 1][@col - 1] = @value
@board.board[@row - 1][@col - 1] = @value
end
def recursion
if @proxi.board[@row - 1][@col - 1] == 0
(@row - 1..@row + 1).each do |r|
(@col - 1..@col + 1).each do |c|
unless (r - 1 < 0 || r - 1 > @proxi.size - 1) || (c - 1 < 0 || c - 1 > @proxi.size - 1)
@row, @col = r, c
detect
map_position
recursion
end
end
end
end
end
def reset
@row, @col, @value = 0, 0, 0
end
end
d = Detector.new(b, b)
b.print_board
如果输出在右上角有足够的空间,则继续粘贴下一部分,否则重新进行。
d.row = 1
d.col = 1
d.mine?
d.detect
d.map_position
d.recursion
b.print_board
在递归方法中,如果堆栈级别太深,则会出错。我知道这是因为它有结束递归模式的问题。我认为我的两个除非声明阻止它从电路板上搜索,否则会限制它在电路板上的区域。此外,地雷会迫使它限制在它可能暴露的零点。也许是以某种方式在董事会上写下空格或覆盖董事会上的东西?
答案 0 :(得分:0)
这里不需要递归。只需检查每个位置周围的地雷:
请始终使用基于0的数组来消除大量@blah - 1
。
在detect
中,如果有我的话需要立即返回,否则设置@value
:
def detect
return if @proxi.board[@row][@col] == '*'
value = 0 # no need to be global anymore
(@row - 1..@row + 1).each do |r|
(@col - 1..@col + 1).each do |c|
unless r < 0 || r >= @proxi.size || c < 0 || c >= @proxi.size
value += 1 if @proxi.board[r][c] == "*"
end
end
end
@proxi.board[@row][@col] = value
end
现在你根本不需要map_position
方法。只需检查所有单元格:
def check
(0..@proxi.size - 1).each do |r|
(0..@proxi.size - 1).each do |c|
@row, @col = r, c
detect
end
end
end
希望它有所帮助。
答案 1 :(得分:0)
超过堆栈大小通常表示递归没有正确的终止条件。在您的情况下,有哪种机制可以阻止recursion
使用相同的@row
@col
对多次调用(@row - 1..@row + 1)
?请注意,在(@col - 1..@col + 1)
@row
生成的9对中,其中一对是@col
revealed
本身。该函数将无限次地调用自己!
解决此问题的一种简单方法是使用recursion
数组来跟踪被访问的单元格。然后recursion
会将其访问的每个单元格标记为已访问,如果在已访问的单元格上调用它,则会立即返回。
此外,您在此处使用实例变量非常脆弱。递归依赖于每个函数调用都有自己的作用域这一事实,但{{1}}的每次调用都共享相同的实例变量 - 您用它来传递参数!您应该使用方法参数来保持范围不同。