问题
I've been building an intelligent Mastermind game in Ruby. In my game, if you select the option of having the computer play the role of code breaker, the computer makes educated guesses at what the code maker's code is.
As part of my algorithm, the computer first looks at the entire list of ALL POSSIBLE CODES.
For example, if there are 6 colors to choose from (red orange blue green purple yellow) and the code is made up of 4 colors (repeats are allowed), then to view all possible codes, you can do this:
valid_colors = %w(red orange blue green purple yellow)
all_possible_codes = valid_colors.repeated_permutation(4).to_a
And all_possible_codes
will be an array filled with arrays representing every possible code. The computer then eliminates codes from this list as it gets feedback from each of its guesses.
The next thing I'm working on, however, requires me to use JRuby 1.6.6, which uses Ruby 1.8.7, which does NOT have a repeated_permutation
method. I need to write my own method with the same functionality.
So I went to the source code found here: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-repeated_permutation
Unfortunately, I don't understand what they're doing or how I could go about solving this by writing a method of my own. I'm fairly new to programming and haven't been able to figure this out. Any help with understanding that source code would be greatly appreciated!
回答1:
The code you linked calls rpermute0 which does most the work, source code for rpermute0 in Array.c is
static void
rpermute0(long n, long r, long *p, long index, VALUE values)
{
long i, j;
for (i = 0; i < n; i++) {
p[index] = i;
if (index < r-1) { /* if not done yet */
rpermute0(n, r, p, index+1, values); /* recurse */
}
else {
/* We have a complete permutation of array indexes */
/* Build a ruby array of the corresponding values */
/* And yield it to the associated block */
VALUE result = rb_ary_new2(r);
VALUE *result_array = RARRAY_PTR(result);
const VALUE *values_array = RARRAY_PTR(values);
for (j = 0; j < r; j++) result_array[j] = values_array[p[j]];
ARY_SET_LEN(result, r);
rb_yield(result);
if (RBASIC(values)->klass) {
rb_raise(rb_eRuntimeError, "repeated permute reentered");
}
}
}
}
Basially a brute force, starting from 0 returning one permutation each iteration. ruby version is something like
require 'pp'
def rpermute(numRepeat, pArray, index, originArray)
0.upto(originArray.length-1) do |i|
pArray[index] = i
if index < numRepeat-1
rpermute(numRepeat, pArray, index+1, originArray)
else
result = Array.new
0.upto(numRepeat-1) do |j|
result[j] = originArray[pArray[j]]
end
pp result
end
end
end
originArray1 = [1,2,3,4,5]
originArray2 = ['a','b','c','d','e']
pArray = []
rpermute(4, pArray, 0, originArray1)
rpermute(4, pArray, 0, originArray2)
I tested above code and it prints out all permutation of length 4, u might want to put them into array.
回答2:
Thanks yngum!
Just to expand on your answer, I renamed some variables to make it more Ruby-esque, more clear, descriptive, and explicit. I also changed a few things so the return value of the method would be the answer, an array that contains each of the possible permutations.
def repeated_permutations(original_array, length_of_each_permutation, list_of_permutations, index_positions, index)
0.upto(original_array.length - 1) do |index1|
index_positions[index] = index1
if index < length_of_each_permutation - 1
repeated_permutations(original_array, length_of_each_permutation, list_of_permutations, index_positions, index + 1)
else
permutation = Array.new
0.upto(length_of_each_permutation - 1) do |index2|
permutation[index2] = original_array[index_positions[index2]]
end
list_of_permutations.push(permutation)
end
end
list_of_permutations
end
I don't love naming it index_positions
, but couldn't think of a better name. The above method will return an array filled with arrays of all possible permutations with repetition allowed.
To implement:
valid_colors = %w(red orange blue green purple yellow)
repeated_permutations(valid_colors, 4, [], [], 0)
来源:https://stackoverflow.com/questions/12161627/understanding-the-source-code-for-rubys-repeated-permutation-method