Ruby 数组分配在不应该更新时更新
Ruby Array assignments updating when its not supposed to
基本上我正在制作一个可以为我解决数独谜题的程序,我想保留原始输入矩阵的起点,以便必须选择重置棋盘并重新开始,如果程序得到卡在了兔子洞里。我想将我的原件存储在一个名为@start 的字段变量中,并且在算法过程中永远不会触及它。
是否有某种我必须使用的关键字?我试过 .map,我试过从输入矩阵手动复制它。
class Game
def initialize(gamematrix)
@start=gamematrix
@rows=gamematrix
puts "rows - #{@rows}"
@cols=@rows.transpose
end
def findnils
puts "finding the nils"
sleep 0.1
nilspaces=[]
g=0
while g<@cols.length
puts "3 we parse through col #{g}"
sleep 0.1
p=0
while p<@rows.length
if @rows[g][p]!=nil
puts "4 [#{g}][#{p}]"
end
sleep 0.1
if @rows[g][p]==nil
puts " [#{g}][#{p}] :found a nil!!!"
nilspaces<<[g,p]
end
p+=1
end
g+=1
end
return nilspaces
end
def sudku
puts '1 we\'re in the sudku method'
#sleep 0.8
#update the coordinatebank of nill spaces in the matric
#sleep 0.8
nilspaces=findnils
while !win?
puts '5 now our nilspaces array now looks like this: '
puts "nils: [#{nilspaces}]"
sleep 0.4
#randomly find an empty nil space, find its coordinates in the matrix
current=nilspaces.sample
puts "out current nilspace is [#{current}]"
sleep 0.2
nilspaces.delete_if{|e| e==current}
puts "nils: [#{nilspaces}]"
sleep 0.2
#then use the guessNum method to guess based on the coordinates
guessedN=guessNum(@cols[current[0]], @rows[current[1]])
puts "guessed: #{guessedN}"
sleep 0.2
#assign out guessed number to replace the nil
if guessedN != 999
@rows[current[0]][current[1]]=guessedN
sleep 0.1
puts "guessed rturns a number so @rows is #{@rows[current[0]][current[1]]}"
puts " start matrix: #{@start}"
else
puts "=========================="
#reset
puts "resets everything"
sleep 0.3
@rows=@start
@cols=@rows.transpose
puts "rows: #{@rows}"
puts "cols: #{@cols}"
nilspaces=findnils
puts "=========================="
sleep 0.1
end
display
sleep 0.4
end
end
def guessNum(vset, hset)
#create an array of numbers to choose from
choice=(1..@rows.length).to_a
#subtract everything in the choice array thats in the hset
choice.delete_if {|e| hset.include?(e)}
#subtract everything in the choice array thats in the vset
choice.delete_if {|e| vset.include?(e)}
#if nothing is left in the choice array return a string called empty
#otherwise return a random number from the array (the choice array)
if choice.empty?
return 999
else
return choice.sample
end
end
def display
puts "--------------------"
for g in @rows
out=" "
for l in g
out+= "#{'%03s' % l.to_s}"
end
out+=" \n"
puts out
end
puts "--------------------"
end
def win?
[@rows.all? { |e| e.uniq.length==@rows.length }, @cols.all? { |e| e.uniq.length==@cols.length }].all? { |e| e==true }
end
end
驱动测试是这样的:
easygame4x4=[[4,nil,nil,nil],[nil,3,4,nil],[nil,1,2,nil],[nil,nil,nil,1]]
gameone=Game.new(easygame4x4)
gameone.sudku
你可以 运行 这个看看它是如何工作的,我在里面放了一堆 puts 语句和 sleep 语句来引导任何人完成这个过程,问题是,我的 @start 矩阵总是得到更新@rows 矩阵
使用Ruby方法clone
, freeze
, and dup
示例:
def initialize(gamematrix)
@start=gamematrix.clone.freeze
当你anything = @start
这样做时:
@rows=@start.dup
您在代码中看到的是 Ruby 修改对象:
array1 = ["a"]
array2 = array1 # now these variables point to the same place
array2[0] #=> "a" as you expect
array1[0] = "b"
array2[0] #=> "b" because array1 and array2 point to the same place
clone 做的是浅拷贝,a.k.a。浅克隆:
array1 = ["a"]
array2 = array1.clone # now array2 points to a new place
array2[0] #=> "a" as you expect
array1[0] = "b"
array2 #=> ["a"] because array2 points to its own place, not array1's place
浅拷贝和深拷贝的区别:
array1 = [["a"]]
array2 = array1.clone # array2 points to a new place, which in turn points to the array that contains "a"
array1[0][0] = "b" # you're changing the array that contains "a"
array2 #=> [["b"]] # because array2 points to its own place, which in turn still points to the same array that contained "a"
您的代码需要的是深拷贝,a.k.a。深度克隆。 Ruby 没有此方法(恕我直言,这是一个错误),因此典型的解决方案是使用 gem 或 Ruby Marshall
方法。看
Why isn't there a deep copy method in Ruby?
dup 的作用类似于克隆,只是 dup 不复制冻结状态:
s = "foo"
s.clone.frozen? # true
s.dup.frozen? # false
您的特定应用程序正在修改行,因此您的重置功能应使用 dup
而不是 clone
。
如果您正在为矩阵编写自己的对象 class,那么您可能需要编写自己的 clone
方法,例如:
class GameMatrix
def clone
# create a clone as you want,
# such as initializing a new object,
# and/or cloning sub-objects, etc.,
# including singleton/class methods,
# including frozen state, etc.
end
def dup
# create a duplicate as you want,
# such as initializing a new object,
# and/or duplicating sub-objects, but
# excluding singleton/class methods,
# excluding frozen state, etc.
end
end
附加说明...
clone
和 dup
方法由每个 class 来定义,因此请阅读每个方法的文档。通常,clone
是 dup 的超集,因为 clone
还复制单例方法、冻结状态等。
freeze
方法并不是真正必要的,它的行为出乎意料(恕我直言),但它仍然值得使用该方法,因为它有一点帮助,并向您的其他代码阅读器表明您希望该对象成为常数。
我弄明白了:它是一个矩阵输入,所以我必须将它 .map 两次才能真正克隆它。
基本上我正在制作一个可以为我解决数独谜题的程序,我想保留原始输入矩阵的起点,以便必须选择重置棋盘并重新开始,如果程序得到卡在了兔子洞里。我想将我的原件存储在一个名为@start 的字段变量中,并且在算法过程中永远不会触及它。
是否有某种我必须使用的关键字?我试过 .map,我试过从输入矩阵手动复制它。
class Game
def initialize(gamematrix)
@start=gamematrix
@rows=gamematrix
puts "rows - #{@rows}"
@cols=@rows.transpose
end
def findnils
puts "finding the nils"
sleep 0.1
nilspaces=[]
g=0
while g<@cols.length
puts "3 we parse through col #{g}"
sleep 0.1
p=0
while p<@rows.length
if @rows[g][p]!=nil
puts "4 [#{g}][#{p}]"
end
sleep 0.1
if @rows[g][p]==nil
puts " [#{g}][#{p}] :found a nil!!!"
nilspaces<<[g,p]
end
p+=1
end
g+=1
end
return nilspaces
end
def sudku
puts '1 we\'re in the sudku method'
#sleep 0.8
#update the coordinatebank of nill spaces in the matric
#sleep 0.8
nilspaces=findnils
while !win?
puts '5 now our nilspaces array now looks like this: '
puts "nils: [#{nilspaces}]"
sleep 0.4
#randomly find an empty nil space, find its coordinates in the matrix
current=nilspaces.sample
puts "out current nilspace is [#{current}]"
sleep 0.2
nilspaces.delete_if{|e| e==current}
puts "nils: [#{nilspaces}]"
sleep 0.2
#then use the guessNum method to guess based on the coordinates
guessedN=guessNum(@cols[current[0]], @rows[current[1]])
puts "guessed: #{guessedN}"
sleep 0.2
#assign out guessed number to replace the nil
if guessedN != 999
@rows[current[0]][current[1]]=guessedN
sleep 0.1
puts "guessed rturns a number so @rows is #{@rows[current[0]][current[1]]}"
puts " start matrix: #{@start}"
else
puts "=========================="
#reset
puts "resets everything"
sleep 0.3
@rows=@start
@cols=@rows.transpose
puts "rows: #{@rows}"
puts "cols: #{@cols}"
nilspaces=findnils
puts "=========================="
sleep 0.1
end
display
sleep 0.4
end
end
def guessNum(vset, hset)
#create an array of numbers to choose from
choice=(1..@rows.length).to_a
#subtract everything in the choice array thats in the hset
choice.delete_if {|e| hset.include?(e)}
#subtract everything in the choice array thats in the vset
choice.delete_if {|e| vset.include?(e)}
#if nothing is left in the choice array return a string called empty
#otherwise return a random number from the array (the choice array)
if choice.empty?
return 999
else
return choice.sample
end
end
def display
puts "--------------------"
for g in @rows
out=" "
for l in g
out+= "#{'%03s' % l.to_s}"
end
out+=" \n"
puts out
end
puts "--------------------"
end
def win?
[@rows.all? { |e| e.uniq.length==@rows.length }, @cols.all? { |e| e.uniq.length==@cols.length }].all? { |e| e==true }
end
end
驱动测试是这样的:
easygame4x4=[[4,nil,nil,nil],[nil,3,4,nil],[nil,1,2,nil],[nil,nil,nil,1]]
gameone=Game.new(easygame4x4)
gameone.sudku
你可以 运行 这个看看它是如何工作的,我在里面放了一堆 puts 语句和 sleep 语句来引导任何人完成这个过程,问题是,我的 @start 矩阵总是得到更新@rows 矩阵
使用Ruby方法clone
, freeze
, and dup
示例:
def initialize(gamematrix)
@start=gamematrix.clone.freeze
当你anything = @start
这样做时:
@rows=@start.dup
您在代码中看到的是 Ruby 修改对象:
array1 = ["a"]
array2 = array1 # now these variables point to the same place
array2[0] #=> "a" as you expect
array1[0] = "b"
array2[0] #=> "b" because array1 and array2 point to the same place
clone 做的是浅拷贝,a.k.a。浅克隆:
array1 = ["a"]
array2 = array1.clone # now array2 points to a new place
array2[0] #=> "a" as you expect
array1[0] = "b"
array2 #=> ["a"] because array2 points to its own place, not array1's place
浅拷贝和深拷贝的区别:
array1 = [["a"]]
array2 = array1.clone # array2 points to a new place, which in turn points to the array that contains "a"
array1[0][0] = "b" # you're changing the array that contains "a"
array2 #=> [["b"]] # because array2 points to its own place, which in turn still points to the same array that contained "a"
您的代码需要的是深拷贝,a.k.a。深度克隆。 Ruby 没有此方法(恕我直言,这是一个错误),因此典型的解决方案是使用 gem 或 Ruby Marshall
方法。看
Why isn't there a deep copy method in Ruby?
dup 的作用类似于克隆,只是 dup 不复制冻结状态:
s = "foo"
s.clone.frozen? # true
s.dup.frozen? # false
您的特定应用程序正在修改行,因此您的重置功能应使用 dup
而不是 clone
。
如果您正在为矩阵编写自己的对象 class,那么您可能需要编写自己的 clone
方法,例如:
class GameMatrix
def clone
# create a clone as you want,
# such as initializing a new object,
# and/or cloning sub-objects, etc.,
# including singleton/class methods,
# including frozen state, etc.
end
def dup
# create a duplicate as you want,
# such as initializing a new object,
# and/or duplicating sub-objects, but
# excluding singleton/class methods,
# excluding frozen state, etc.
end
end
附加说明...
clone
和 dup
方法由每个 class 来定义,因此请阅读每个方法的文档。通常,clone
是 dup 的超集,因为 clone
还复制单例方法、冻结状态等。
freeze
方法并不是真正必要的,它的行为出乎意料(恕我直言),但它仍然值得使用该方法,因为它有一点帮助,并向您的其他代码阅读器表明您希望该对象成为常数。
我弄明白了:它是一个矩阵输入,所以我必须将它 .map 两次才能真正克隆它。