Назначения Ruby Array обновляются, когда это не должно

По сути, я делаю программу, которая может решить для меня головоломку судоку, и я хочу сохранить начальную точку исходной входной матрицы, чтобы иметь возможность сбросить доску и начать снова, если программа застревает в кроличьей норе. . Я хочу сохранить свой оригинал в переменной поля с именем @start и никогда не трогать его в ходе алгоритма.

Есть ли какое-то ключевое слово, которое я должен использовать? Я пробовал .map, пробовал вручную копировать из входной матрицы.

class Game
def initialize(gamematrix)
  @start=gamematrix
  @rows=gamematrix
    puts "rows - #{@rows}"
  @[email protected]
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
            @[email protected]
          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=([email protected]).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| [email protected] }, @cols.all? { |e| [email protected] }].all? { |e| e==true  }
end

end

Тест драйвера таков:

easygame4x4=[[4,ноль,ноль,ноль],[ноль,3,4,ноль],[ноль,1,2,ноль],[ноль,ноль,ноль,1]]

gameone=Game.new(easygame4x4)

gameone.sudku

вы можете запустить это и посмотреть, как это работает, я поместил в него несколько операторов puts и операторов sleep, чтобы провести любого через процесс, проблема в том, что моя матрица @start всегда обновляется матрицей @rows


person matt lao    schedule 23.01.2015    source источник
comment
Должно помочь: github.com/dkubb/adamantium   -  person Eraden    schedule 24.01.2015


Ответы (2)


Используйте методы Ruby clone, < a href="http://ruby-doc.org/core-2.2.0/Object.html#method-i-freeze" rel="nofollow noreferrer">freeze и dup

Пример:

def initialize(gamematrix)
  @start=gamematrix.clone.freeze

Когда вы делаете anything = @start, делайте это так:

@[email protected]

То, что вы видите в своем коде, это 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

Клон делает неглубокую копию, также известную как мелкий клон:

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" 

Что вам нужно для вашего кода, так это глубокая копия, также известная как глубокий клон. Ruby не имеет этого метода (что является ошибкой IMHO), поэтому типичным решением является использование драгоценного камня или методов Ruby Marshall. См. Почему в Ruby нет метода глубокого копирования?< /а>

То, что делает dup, похоже на clone, за исключением того, что dup не копирует замороженное состояние:

s = "foo"
s.clone.frozen?  # true
s.dup.frozen?  # false

Ваше конкретное приложение изменяет строки, поэтому ваша функция сброса должна использовать dup вместо clone.

Если вы пишете свой собственный объектный класс для своей матрицы, вам может понадобиться написать собственный метод 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 определяются каждым классом, поэтому читайте документацию по каждому из них. В общем, clone является надмножеством dup, потому что clone также копирует одноэлементные методы, замороженное состояние и многое другое.

Метод freeze на самом деле не нужен, и он ведет себя неожиданно (ИМХО), но все же стоит использовать этот метод, потому что он немного помогает и показывает другим читателям кода, что вы хотите, чтобы объект был постоянным.

person joelparkerhenderson    schedule 23.01.2015
comment
все еще не сохраняя его, есть ли где-то в коде, которым я манипулирую @star, что я не вижу? - person matt lao; 24.01.2015
comment
Я попробовал это только что, и это все еще не сработало, я добавил метод, чтобы проверить, могут ли быть сохранены мои начальные переменные, и это сработало, в этом методе судоку есть что-то, что запускает его, чтобы обновить его с помощью строк, но я просто могу не заметить его. Может ли быть ошибка в рубине? def original for g в (1..4) помещает строки #{rows.map { |e| электронная карта { |f| g } }} puts start #{start} end end Это дало ожидаемые результаты. - person matt lao; 24.01.2015
comment
@joelparkerhenderson спасибо! github.com/laomatt/rubyexcercises/blob/master/sudoku3.rb - person matt lao; 24.01.2015
comment
Хорошо, я убрал все, что не работает, вы можете увидеть это здесь github.com/laomatt/experimentalruby/blob/master/sudoku4.rb по-видимому, это мой метод GuessNum, который по какой-то причине заставляет его обновляться, потому что, когда я делаю другие вещи с массивом строк, это не влияет на стартовый массив @joelparkerhenderson - person matt lao; 25.01.2015
comment
Обновлено с решением для вас. - person joelparkerhenderson; 25.01.2015

Я понял это: это матричный ввод, поэтому мне нужно .map дважды, чтобы действительно клонировать его.

person matt lao    schedule 26.01.2015