【问题标题】:Ruby noobster does not understand arraysRuby noobster 不理解数组
【发布时间】:2014-05-19 07:19:20
【问题描述】:

我不是程序员,但我想成为一名程序员。所以,我看书,做教程,问问题。问题来了:

我正在尝试进行 Ruby 测验 - 使用 Solitaire cypher (http://rubyquiz.com/quiz1.html) 的测验。我编写了一些运行良好的代码,除了在某一时刻它改变了key_deck 数组,该数组应该是对程序结尾的引用。我不知道这发生在哪里或为什么。

这是我的菜鸟代码:

$characters = Array ('A' .. 'Z')

def encode to_encode, input_deck
    trekljdfg = input_deck
    edeck = input_deck
    work_string = ''
    to_encode.upcase.split("").each do |char|
        if $characters.include?(char)
            work_string.concat(char)
        end
    end
    work_string = work_string + ('X' * ((5 - (work_string.length % 5)) % 5))

    keystream_string = ''
    while keystream_string.length < work_string.length do # <-- generate keystream
        edeck = permutation(edeck)
        keystream_string.concat(get_letter(edeck))
    end

    encoded = combine_with_keystream(work_string, keystream_string)
    encoded = split_string_in_groups(encoded)

    return encoded
end

def decode to_decode, input_deck
    ddeck = input_deck
    to_decode = to_decode.delete(' ')
    keystream_string = ''
    while keystream_string.length < to_decode.length do # <-- generate keystream
        ddeck = permutation(ddeck)
        keystream_string.concat(get_letter(ddeck))
    end

    array_to_decode = text_to_numbers to_decode
    array_keystream_string = text_to_numbers keystream_string
    decoded = ''
    for i in 0..(array_to_decode.length-1)
        if array_to_decode[i] >= array_keystream_string[i]
            decoded.concat($characters[(array_to_decode[i] - array_keystream_string[i])-1])
        else
            decoded.concat($characters[(array_to_decode[i] + 26 - array_keystream_string[i])-1])
        end
    end

    decoded = split_string_in_groups decoded

    return decoded
end

def permutation deck_to_change
    deck = deck_to_change
    def swap array, joker
        work_array = array
        joker_position = work_array.index(joker)
        if joker_position == (work_array.length-1)
            temp_array = work_array.slice!(1..(work_array.length-2))
            work_array = work_array + temp_array
        else
            work_array[joker_position], work_array[joker_position+1] = work_array[joker_position+1], work_array[joker_position]
        end
        return work_array
    end

    deck = swap(deck, 'A') # <-- swap first joker
    2.times do # <-- swap second joker
        deck = swap(deck, 'B')
    end

    if deck.index('A') < deck.index('B') # <-- triple cut
        joker_position1 = deck.index('A')
        joker_position2 = deck.index('B') - joker_position1
    else
        joker_position1 = deck.index('B')
        joker_position2 = deck.index('A') - joker_position1
    end
    if joker_position1 == 0
        temp_array1 = []
    else
        temp_array1 = deck.slice!(0..joker_position1-1)
    end
    if joker_position2 == deck.length-1
        temp_array2 = []
    else
        temp_array2 = deck.slice!(joker_position2+1..deck.length-1)
    end
    deck = temp_array2 + deck + temp_array1

    if (deck.last != 'A') | (deck.last != 'B') # <-- count cut
        temp_array1 = deck.slice!(0..deck.last.to_i-1)
        temp_array2 = deck.pop(1)
        deck = deck + temp_array1 + temp_array2
    end
    return deck
end

def get_letter deck
    first = deck.first
    case first
    when 'A'
        first = '53'
    when 'B'
        first = '53'
    end
    if (deck[first.to_i] == 'A') | (deck[first.to_i] == 'B')
        return ''
    else
        return $characters[((deck[first.to_i]).to_i-1) % 26]
    end
end

def text_to_numbers text
    array = []
    text.upcase.split("").each do |char|
        array.push($characters.index(char)+1)
    end
    return array
end

def combine_with_keystream string1, string2
    temp_array1 = text_to_numbers string1
    temp_array2 = text_to_numbers string2

    string = ''
    for i in 0..(temp_array1.length-1)
        tmp =  temp_array1[i] + temp_array2[i]
        if tmp > 26
            tmp = tmp - 26
        end
        string.concat($characters[tmp-1])
    end
    return string
end

def split_string_in_groups string
    return string.scan(/.{1,5}/).join(" ")
end

#-begin-------------------------

key_deck = ('1' .. '52').to_a + ['A', 'B'] # <-- this is the key deck ^^
string_to_encode = 'Code in Ruby live longer!' # <-- this is the string to be encoded
string_to_decode = 'GLNCQ MJAFF FVOMB JIYCB' # <-- this is the string to be decoded
puts "Your encoded text is: #{encode(string_to_encode, key_deck)}"
puts "Your decoded text is: #{decode(string_to_decode, key_deck)}"

【问题讨论】:

    标签: ruby arrays methods


    【解决方案1】:

    您正在使用slice! 查找您的牌组的排列,这会改变输入数组。

    最简单的解决方案是在处理数组之前dup

    def encode to_encode, input_deck
        trekljdfg = input_deck.dup
        edeck = input_deck.dup
        # ..
    end
    
    def decode to_decode, input_deck
        ddeck = input_deck.dup
        # ..
    end
    

    dup 创建数组的副本,您可以安全地对其进行破坏。

    【讨论】:

    • 我明白了。有帮助,谢谢。这可能是猜测,但为什么这种情况也不会发生:code def change_text text1 text1 = 'changed text' return text1 end text = 'original text' change_text text puts text code
    • 在此代码中,您更改了 reference (text1 = ...) 的值。当您使用像 slice!(ruby-doc.org/core-2.0.0/Array.html#method-i-slice-21) 这样的 API 时,您会更改 对象本身 而不是对它的引用,任何持有该引用的人都可以看到。试试text1.gsub!('i', 'I') 看看会发生什么。
    【解决方案2】:

    你的permutation 函数改变了牌组。您将引用传递给原始卡组,因此您对引用所做的任何更改实际上都会更改原始卡组。试试这样的:

    key_deck = [....]
    ...
    puts "#{encode(string_to_encode, key_dec.clone}"
    

    clone 方法将为您创建数组的新副本,因此所有更改将仅应用于副本。

    或者您可以使用Array#shuffle 方法来避免整个问题:

    puts "#{encode(string_to_encode, key_dec.shuffle}"
    

    这将为encode 函数提供一个已经洗牌的牌组。

    【讨论】:

    • 谢谢,它有帮助。关于第二个建议:我需要在原始配置中使用卡组。
    猜你喜欢
    • 1970-01-01
    • 2021-10-24
    • 2021-10-23
    • 2013-04-18
    • 1970-01-01
    • 2013-10-14
    • 2013-03-09
    • 2011-09-11
    • 1970-01-01
    相关资源
    最近更新 更多