Related
On prolog i'm trying to solve the following exercise for connect 4
?- generate_move(2,[[1, 0, 1, 0],[0, 1, 1, 0],[0, 0, 1, 1],[1, 0, 0, 1]],BP).
BP = [[1, 2, 1, 0], [0, 1, 1, 0], [0, 0, 1, 1], [1, 0, 0, 1]] ;
BP = [[1, 0, 1, 2], [0, 1, 1, 0], [0, 0, 1, 1], [1, 0, 0, 1]] ;
BP = [[1, 0, 1, 0], [2, 1, 1, 0], [0, 0, 1, 1], [1, 0, 0, 1]] ;
BP = [[1, 0, 1, 0], [0, 1, 1, 2], [0, 0, 1, 1], [1, 0, 0, 1]] ;
BP = [[1, 0, 1, 0], [0, 1, 1, 0], [2, 0, 1, 1], [1, 0, 0, 1]] ;
BP = [[1, 0, 1, 0], [0, 1, 1, 0], [0, 2, 1, 1], [1, 0, 0, 1]] ;
Where the rule is that is returns every possible move left for a player provided (in this case 2)
I was thinking of using select/4 to find every result possible for each list in the list of lists, then join it. But i'm failing to "condense" results and my second iteration of findall fails:
generate_move(_,[],[]).
generate_move(Player,[H|T],[FinalLine|FinalBoard]) :-
findall(X0,(select(0, H, Player, X0)),FinalLine),
join_results(FinalLine,T,FinalBoard),
generate_move(Player,T,FinalBoard).
join_results([],[],[]).
join_results([H|T],LeftOvers,FinalBoard) :-
append([H],LeftOvers,FinalBoard),
join_results(T,LeftOvers,FinalBoard).
Any tips? My join_results returns false at the second call and so does my findall.
I am trying to displace an array by adding a value to every element and then adding those new values to the array (array are x,y,z > sketchup) example:
arr = [[2.99213, 0, 0],
[2.93025, 0.0031909, 0],
[2.86903, 0.0127298, 0],
[2.80912, 0.0285154, 0]]
Adding 2 to every first element to get this:
arr = [[4.99213, 0, 0],
[4.93025, 0.0031909, 0],
[4.86903, 0.0127298, 0],
[4.80912, 0.0285154, 0]]
finally, adding the two arrays:
arr = [[2.99213, 0, 0],
[2.93025, 0.0031909, 0],
[2.86903, 0.0127298, 0],
[2.80912, 0.0285154, 0],
[4.99213, 0, 0],
[4.93025, 0.0031909, 0],
[4.86903, 0.0127298, 0],
[4.80912, 0.0285154, 0]]
Like this?
arr = [[2.99213, 0, 0], [2.93025, 0.0031909, 0], [2.86903, 0.0127298, 0], [2.80912, 0.0285154, 0]]
arr + arr.map { |k| [k[0]+2] + k[1..-1] }
# => [[2.99213, 0, 0], [2.93025, 0.0031909, 0], [2.86903, 0.0127298, 0], [2.80912, 0.0285154, 0], [4.9921299999999995, 0, 0], [4.93025, 0.0031909, 0], [4.86903, 0.0127298, 0], [4.80912, 0.0285154, 0]]
Say I have the following input:
inp = [2, 9, 3]
I need output as all tuples in mixed counting, like this:
outp = [[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0], [0, 1, 1], ..., [1, 8, 2]]
I know algorithm from Knuth vol 4a as direct loop solution, but I've heard ruby has some magic inside.
I am mostly C++ developer. My direct solution now looks like:
inparr = [2, 9, 3]
bmix = Array.new(inparr.size) { |i| 0 }
outp = Array.new
loop do
# some debug output
puts bmix.to_s
#visit next tuple
outp << bmix.clone
digit = inparr.size
while digit > 0 do
digit -= 1
if bmix[digit] + 1 < inparr[digit]
bmix[digit] += 1
break
end
bmix[digit] = 0
end
break if (bmix.select{|x| x != 0}.empty?)
end
How to rewrite it in several simple lines?
inp.
map { |i| (0...i).to_a }.
reduce(&:product).
map(&:flatten)
Used operations: Range, Enumerable#map, Enumerable#reduce, Array#product, Array#flatten.
You could use recursion.
def recurse(inp)
first, *rest = inp
rest.empty? ? [*0..first-1] : (0..first-1).flat_map do |e|
recurse(rest).map { |arr| [e, *arr] }
end
end
recurse [2, 4, 3]
#=> [[0, 0, 0], [0, 0, 1], [0, 0, 2],
# [0, 1, 0], [0, 1, 1], [0, 1, 2],
# [0, 2, 0], [0, 2, 1], [0, 2, 2],
# [0, 3, 0], [0, 3, 1], [0, 3, 2],
# [1, 0, 0], [1, 0, 1], [1, 0, 2],
# [1, 1, 0], [1, 1, 1], [1, 1, 2],
# [1, 2, 0], [1, 2, 1], [1, 2, 2],
# [1, 3, 0], [1, 3, 1], [1, 3, 2]]
If first, *rest = [2,4,3], then first #=> 2 and rest #=> [4,3].
See Enumerable#flat_map and Array#map. a ? b : c is called a ternery expression.
If e #=> 1 and arr #=> [2,1] then [e, *arr] #=> [1,2,1].
I will go to great lengths to avoid the use of Array#flatten. It's irrational, but to me it's an ugly method. That's usually possible using flat_map and/or the splat operator *.
Here's a mix of the 2 existing answers. It might be a bit more concise and readable:
head, *rest = inp.map{ |n| n.times.to_a }
head.product(*rest)
As an example:
inp = [2, 4, 3]
# => [2, 4, 3]
head, *rest = inp.map{ |n| n.times.to_a }
# => [[0, 1], [0, 1, 2, 3], [0, 1, 2]]
head.product(*rest)
# => [[0, 0, 0], [0, 0, 1], [0, 0, 2], [0, 1, 0], [0, 1, 1], [0, 1, 2], [0, 2, 0], [0, 2, 1], [0, 2, 2], [0, 3, 0], [0, 3, 1], [0, 3, 2], [1, 0, 0], [1, 0, 1], [1, 0, 2], [1, 1, 0], [1, 1, 1], [1, 1, 2], [1, 2, 0], [1, 2, 1], [1, 2, 2], [1, 3, 0], [1, 3, 1], [1, 3, 2]]
To create a one-dimensional array, I can write:
arr = Array.new(10) { |z| 0 }
#=> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
But I want to know how to initialize an array in more dimensions, e.g.:
#=> [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
This is just an example. I am trying to understand the general case.
You can easily nest multiple Array.new calls:
Array.new(2, 0)
#=> [0, 0]
Array.new(3) { Array.new(2, 0) }
#=> [[0, 0], [0, 0], [0, 0]]
Array.new(4) { Array.new(3) { Array.new(2, 0) } }
#=> [[[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]]]
Note that the non-block version, i.e. Array.new(2, 0), should only be used for immutable objects, because the same object will be used for all elements. See the Common gotchas section for details.
To build an array of arbitrary dimensions, you could use recursion:
def multi_array(sizes, default = nil)
size, *remaining = sizes
if remaining.empty?
Array.new(size, default)
else
Array.new(size) { multi_array(remaining, default) }
end
end
multi_array([4, 3, 2], 0)
#=> [[[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]],
# [[0, 0], [0, 0], [0, 0]]]
You can also do it like:
Array.new(10, 0).each_slice(2).to_a
# => [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
5.times.map{Array.new(2, 0)}
# => [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
If by more dimensions you mean an array of array, you could try:
arr = Array.new(10){|z| z=Array.new(2,0)}
# => [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0,0]]
assuming that your second dimension is 2.
I am trying to understand the general case.
Array.new(n) # where n is natural number 1..n
#=>[nil, nil, nil]
This will create a 1-D Array i:e One dimension array.
Let extends further for a multi-dimensional array i:e Two dimension array .
In ruby, every method accepts a block.
Array.new(3) do
Array.new(3)
end
end
Same can be written In online (macro style) Array.new(3) { Array.new(3) }
[
[nil, nil, nil],
[nil, nil, nil],
[nil, nil, nil]
]
Further, it can extend to initialize each cell value.
Array.new(3) do
Array.new(3) do
0
end
end
[
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]
]
One line micro style Array.new(3) { Array.new(3) { 0 } }
Let extends further three-dimension array.
Array.new(2) do
Array.new(3) do
Array.new(4) do
0
end
end
end
OR
The same can be written as micro-style syntax
Array.new(2) { Array.new(3) { Array.new(4) } {0} }
[
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
]
Here's another way, though I feel the deep copy at every level could somehow be simplified:
def make_multi(dimensions, default)
dimensions.reverse.each_with_index.reduce([]) { |a,(d,i)|
Array.new(d) { i.zero? ? default : Marshal.load(Marshal.dump(a)) } }
end
arr = make_multi [4,3,2,2], 0
#=> [[[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]]]
arr[0][0][0][0] = 1
arr
#=> [[[[1, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]],
# [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]]]
arr = make_multi [4,3,2,2], {}
#=> [[[[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]]],
# [[[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]]],
# [[[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]]],
# [[[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]], [[{}, {}], [{}, {}]]]]
arr[0][0][0][0] = { a: 1 }
arr
#=> [[[[{:a=>1}, {}...] # all but the first are empty hashes
Try it:)
arr = Array.new(10, 0)
UPD: for multidimensional is:
arr = Array.new(10, Array.new(2, 0))
=> [[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]
Supposing we have an array with this shape: [2, 5]. The possible index combinations are:
[
[0, 0],
[0, 1],
[0, 2],
[0, 3],
[0, 4],
[1, 0],
[1, 1],
[1, 2],
[1, 3],
[1, 4]
]
If the array has n dimension(s), is there a simple way to generate the indices in Ruby?
This should work:
def coordinates(first, *others)
(0...first).to_a.product(*others.map { |to| (0...to).to_a })
end
coordinates(2, 5)
#=> [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4],
# [1, 0], [1, 1], [1, 2], [1, 3], [1, 4]]
coordinates(4, 3, 3)
#=> [[0, 0, 0], [0, 0, 1], [0, 0, 2],
# [0, 1, 0], [0, 1, 1], [0, 1, 2],
# [0, 2, 0], [0, 2, 1], [0, 2, 2],
# [1, 0, 0], [1, 0, 1], [1, 0, 2],
# [1, 1, 0], [1, 1, 1], [1, 1, 2],
# [1, 2, 0], [1, 2, 1], [1, 2, 2],
# [2, 0, 0], [2, 0, 1], [2, 0, 2],
# [2, 1, 0], [2, 1, 1], [2, 1, 2],
# [2, 2, 0], [2, 2, 1], [2, 2, 2],
# [3, 0, 0], [3, 0, 1], [3, 0, 2],
# [3, 1, 0], [3, 1, 1], [3, 1, 2],
# [3, 2, 0], [3, 2, 1], [3, 2, 2]]
Here you go. It may not be pretty, but it seems to work.
def gen_indices(dimensions, solutions = [], current=[], level = 0)
if level < dimensions.length
dimensions[level].times do |i|
current << i
if level == dimensions.length - 1
solutions << current.clone
else
gen_indices(dimensions, solutions, current, level + 1)
end
current.pop
end
end
solutions
end
p gen_indices([4,3,2])
Not sure this is totally correct, but it should help you on the right track:
def combinations(dimensions)
dimensions.inject([]){|total, dimension|
dim = (0...dimension).to_a
total.empty? ? dim : total.product(dim)
}.map(&:flatten)
end
p combinations([2, 5]) #=> [[0, 0], [0, 1], [0, 2], [0, 3], [0, 4], [1, 0], [1, 1], [1, 2], [1, 3], [1, 4]]
p combinations([2, 2, 2]) #=> [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1]]
Try:
a = [[0,1],[0,1,2,3,4]]
res = a[0].product(a[1])