I'm trying to get a sorted list of Domino with a list of Domino
My code currently looks like:
listdomino(_,[],[],[]).
listdomino([I,J],M,Start,Fin):-
(( member([J,K],M),
delete(M,[J,K],M2),
append([[J,K]],Fin1,Fin),
listdomino([I,K],M2,Start,Fin1)
)
;
( member([K,I],M),
delete(M,[K,I],M2),
append(Start1,[[K,I]],Start),
listdomino([K,J],M2,Start1,Fin)
)
).
listdominoSorted(X,M,Out):-
append(Start,[X],K),
append(K,Fin,Out),
listdomino(X,M,Start,Fin).
Actual outcome:
?- listdominoSorted([1,2],[[2,1],[2,2]],L).
L = [[1, 2], [2, 2], [2, 1]] ;
L = [[2, 1], [1, 2], [2, 2]] ;
L = [[2, 1], [1, 2], [2, 2]] ;
L = [[2, 2], [2, 1], [1, 2]] ;
The program returns [[2, 1], [1, 2], [2, 2]] twice
and doesn't exit after that.
Desired outcome:
?- listdominoSorted([1,2],[[2,1],[2,2]],L).
L = [[1, 2], [2, 2], [2, 1]] ;
L = [[2, 1], [1, 2], [2, 2]] ;
L = [[2, 2], [2, 1], [1, 2]] ;
false
How can I solve this problem?
I looked at your code for a minute or two but after seeing the use of delete/3 the warning bells went off and I looked at other examples. While this related answer does not answer your question, the statement
I suggest instead to have a quick check for validity, and let Prolog work out the insertion points.
lead me to trying a generate and test methodology for which Prolog is well suited.
First the test part:
No dominoes are valid.
domino_test([]).
One domino is valid.
domino_test([[_,_]]).
When ever two dominoes share the same counts (D_1) they are valid.
This is recursively valid.
domino_test([[_,D_1],[D_1,D_2]|T]) :-
domino_test([[D_1,D_2]|T]).
Next to generate the values.
This is really just a permutation of the dominoes.
?- permutation([[1,2],[2,1],[2,2]],P).
P = [[1, 2], [2, 1], [2, 2]] ;
P = [[1, 2], [2, 2], [2, 1]] ;
P = [[2, 1], [1, 2], [2, 2]] ;
P = [[2, 1], [2, 2], [1, 2]] ;
P = [[2, 2], [1, 2], [2, 1]] ;
P = [[2, 2], [2, 1], [1, 2]] ;
false.
Putting the permutation with the test in one predicates gives:
list_domino(L,P) :-
permutation(L,P),
domino_test(P).
All of the code
domino_test([]).
domino_test([[_,_]]).
domino_test([[_,D_1],[D_1,D_2]|T]) :-
domino_test([[D_1,D_2]|T]).
list_domino(L,P) :-
permutation(L,P),
domino_test(P).
Example:
?- list_domino([[1,2],[2,1],[2,2]],P).
P = [[1, 2], [2, 2], [2, 1]] ;
P = [[2, 1], [1, 2], [2, 2]] ;
P = [[2, 2], [2, 1], [1, 2]] ;
false.
I suspect your given test case is a simple case and there needs to be a modification to this, but I will let you check it and see.
Related
Is there a simple way to create pairs from an array?
For example, if I have an array [1,2,3,4] how would I go about trying to return this array?
[[1,2], [1,3], [1,4], [2,1], [2,3], [2,4], [3,1], [3,2], [3,4], [4,1], [4,2], [4,3]]
Every element is paired with every other other element except itself, and duplicates are allowed.
You can use Array#permutation for this:
[1,2,3,4].permutation(2).to_a
# => [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], [3, 1], [3, 2], [3, 4], [4, 1], [4, 2], [4, 3]]
[1,2,3,4].permutation(2).map{ |n| "(#{ n.join(",") })" }
# => ["(1,2)", "(1,3)", "(1,4)", "(2,1)", "(2,3)", "(2,4)", "(3,1)", "(3,2)", "(3,4)", "(4,1)", "(4,2)", "(4,3)"]
I made a little code for creating a matrix of coordinates (like a chessboard), it's the following:
createMatrix(N,M,R) :- creaMatriu(N,M,A), reversed(R,A).
creaMatriu(N,0,[T]) :- creafila(N,0,T),!.
creaMatriu(N,M,[T|C]) :- creafila(N,M,T), M1 is M-1, creaMatriu(N,M1,C).
creafila(0,M,[[M,0]]):-!.
creafila(N,M,[[M,N]|C]) :-N1 is N-1,creafila(N1,M,C).
reversed(A, B) :- reversed(B, [], A).
reversed([A|B], C, D) :- reverse(N,A),reversed(B, [N|C], D).
reversed([], A, A).
The first time I executed it went well, but when i incremented the dimensions of the matrix, the "dots" at the end of the matrix begin to appear incrementing one coordinate as the dimension rises, as like this:
?- createMatrix(1,1,R).
R = [[[0, 0], [0, 1]], [[1, 0], [1, 1]]] .
?- createMatrix(2,1,R).
R = [[[0, 0], [0, 1], [0, 2]], [[1, 0], [1, 1], [1, 2]]] .
?- createMatrix(2,2,R).
R = [[[0, 0], [0, 1], [0, 2]], [[1, 0], [1, 1], [1, 2]], [[2, 0], [2, 1], [2, 2]]] .
?- createMatrix(3,2,R).
R = [[[0, 0], [0, 1], [0, 2], [0, 3]], [[1, 0], [1, 1], [1, 2], [1, 3]], [[2, 0], [2, 1], [2, 2], [2, 3]]] .
?- createMatrix(3,3,R).
R = [[[0, 0], [0, 1], [0, 2], [0, 3]], [[1, 0], [1, 1], [1, 2], [1, 3]], [[2, 0], [2, 1], [2, 2], [2, 3]], [[3, 0], [3, 1], [3, 2], [3|...]]] .
?- createMatrix(4,3,R).
R = [[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4]], [[2, 0], [2, 1], [2, 2], [2, 3], [2|...]], [[3, 0], [3, 1], [3, 2], [3|...], [...|...]]] .
?- createMatrix(4,4,R).
R = [[[0, 0], [0, 1], [0, 2], [0, 3], [0, 4]], [[1, 0], [1, 1], [1, 2], [1, 3], [1, 4]], [[2, 0], [2, 1], [2, 2], [2, 3], [2|...]], [[3, 0], [3, 1], [3, 2], [3|...], [...|...]], [[4, 0], [4, 1], [4|...], [...|...]|...]] .
Anyone have any clue why this happens?
Thank you!
By default, the toplevel loop of SWI prints terms up to depth 10. Deeper parts are replaced by ... You can extend that depth or remove that limit by setting the depth to 0.
?- length(L,10).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I|...].
?- current_prolog_flag(toplevel_print_options,V).
V = [quoted(true),portray(true),max_depth(10),spacing(next_argument)].
?- set_prolog_flag(toplevel_print_options, [quoted(true), portray(true), max_depth(0), spacing(next_argument)]).
true.
?- length(L,10).
L = [_A,_B,_C,_D,_E,_F,_G,_H,_I,_J].
— update: in newer versions of SWI, another flag must be changed:
?- current_prolog_flag(T,V), atom_concat(_,options,T).
T = answer_write_options,
V = [quoted(true),portray(true),max_depth(10),spacing(next_argument)]
; true.
?- set_prolog_flag(answer_write_options, [quoted(true), portray(true), max_depth(0), spacing(next_argument)]).
true.
I have a sparse array, for example:
rare = [[0,1], [2,3], [4,5], [7,8]]
I want to plot a chart with these data, each pair are point coordinates.
As you can see I don't have points for x=1, x=3 , x=5, x=6
I want to fill the array with the previous values, so for the above example I will get:
filled = [[0,1], [1,1], [2,3], [3,3], [4,5], [5,5], [6,5], [7,8]
As you can see, for calculating the y value, I simply take the last y value I used.
What is the best aproach to accomplish this ?
Range.new(*rare.transpose.first.sort.values_at(0,-1)).inject([]){|a,i|
a<<[i, Hash[rare][i] || a.last.last]
}
Step-by-step explanation:
rare.transpose.first.sort.values_at(0,-1) finds min and max x ([0,7] in your example)
Range.new() makes a range out of it (0..7)
inject iterates through the range and for every x returns pair [x,y], where y is:
y from input array, where defined
y from previously evaluated pair, where not
Note: here are some other ways of finding min and max x:
[:min,:max].map{|m| Hash[rare].keys.send m}
rare.map{|el| el.first}.minmax # Ruby 1.9, by steenslag
rare = [[0,1], [2,3], [4,5], [7,8]]
filled = rare.inject([]) do |filled, point|
extras = if filled.empty?
[]
else
(filled.last[0] + 1 ... point[0]).collect do |x|
[x, filled.last[1]]
end
end
filled + extras + [point]
end
p filled
# => [[0, 1], [1, 1], [2, 3], [3, 3], [4, 5], [5, 5], [6, 5], [7, 8]]
An inject solution:
filled = rare.inject([]) do |filled_acc, (pair_x, pair_y)|
padded_pairs = unless filled_acc.empty?
last_x, last_y = filled_acc.last
(last_x+1...pair_x).map { |x| [x, last_y] }
end || []
filled_acc + padded_pairs + [[pair_x, pair_y]]
end
More about Enumerable#inject and functional programming with Ruby here.
irb(main):001:0> rare = [[0,1], [2,3], [4,5], [7,8]]
=> [[0, 1], [2, 3], [4, 5], [7, 8]]
irb(main):002:0> r=rare.transpose
=> [[0, 2, 4, 7], [1, 3, 5, 8]]
irb(main):003:0> iv = (r[0][0]..r[0][-1]).to_a.select {|w| !r[0].include?(w) }
=> [1, 3, 5, 6]
irb(main):004:0> r[1][-1]=r[1][-2]
=> 5
irb(main):005:0> p (iv.zip(r[1]) + rare).sort
[[0, 1], [1, 1], [2, 3], [3, 3], [4, 5], [5, 5], [6, 5], [7, 8]]
=> [[0, 1], [1, 1], [2, 3], [3, 3], [4, 5], [5, 5], [6, 5], [7, 8]]
I have a problem with a problem in Prolog.
Here's some of the code I use.
has_same_elements([X|_],Y) :-
permutation(X,Xnew),
member(Xnew,Y), !.
has_same_elements([_|Tail],Y) :-
has_same_elements(Tail,Y).
This gets two lists of lists as input, and decides whether or not they contain lists with the same elements. E.g. [[1,2],[3,4]] has the same elements as [[2,1],[4,3]]. This works fine.
Now my findall:
findall(V, (verdeling2(S,Perm,V), \+X^(X\=V,verdeling2(S,Perm,X),has_same_elements(X,V))) ,Verd).
All that's important to know is that verdeling2/3 is a clause that returns different lists of lists (as mentioned above), and it's constructed from a permutation of [1,2,3,4,...]
Some different outputs of verdeling2/3 (according to the permutation as input) are:
V = [[[1, 2], [3, 4]]] ;
V = [[[2, 1], [3, 4]]] ;
V = [[[2, 3], [1, 4]]] ;
V = [[[2, 3], [4, 1]]] ;
V = [[[1, 3], [2, 4]]] ;
V = [[[3, 1], [2, 4]]] ;
V = [[[3, 2], [1, 4]]] ;
V = [[[3, 2], [4, 1]]] ;
V = [[[1, 3], [4, 2]]] ;
V = [[[3, 1], [4, 2]]] ;
V = [[[3, 4], [1, 2]]] ;
V = [[[3, 4], [2, 1]]] ;
V = [[[1, 2], [4, 3]]] ;
V = [[[2, 1], [4, 3]]] ;
V = [[[2, 4], [1, 3]]] ;
V = [[[2, 4], [3, 1]]] ;
V = [[[1, 4], [2, 3]]] ;
V = [[[4, 1], [2, 3]]] ;
V = [[[4, 2], [1, 3]]] ;
V = [[[4, 2], [3, 1]]] ;
V = [[[1, 4], [3, 2]]] ;
V = [[[4, 1], [3, 2]]] ;
V = [[[4, 3], [1, 2]]] ;
V = [[[4, 3], [2, 1]]] ;
Now I'd want something that gives me an overview of all lists that don't contain the same elements (using has_same_elements). I thought my use of findall should do the trick, but it returns full packet, instead of filtering the ones I don't want.
I am not assuming that you use some constraint logic programming language
or somesuch so that A\=B does more than only \+ A=B.
I guess the X\=V always fails so that the goals behind it are not executed,
and the negation \+ is always true.
The X\=V always fails, since X=V always succeeds, since X is a fresh
variable in your context.
Probably some reordering would help.
Best Regards
Suppose I have
an_array = [[2, 3], [1, 4], [1, 3], [2, 1], [1, 2]]
I want to sort this array by the first value of each inner array, and then by the second (so the sorted array should look like this: [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3]])
What's the most readable way to do this?
This is the default behavior for sorting arrays (see the Array#<=> method definition for proof). You should just be able to do:
an_array.sort
If you want some non-default behaviour, investigate sort_by (ruby 1.8.7+)
e.g. sort by the second element then by the first
a.sort_by {|e| [e[1], e[0]]} # => [[2, 1], [1, 2], [1, 3], [2, 3], [1, 4]]
or sort by the first element ascending and then the second element descending
a.sort_by {|e| [e[0], -e[1]]} # => [[1, 4], [1, 3], [1, 2], [2, 3], [2, 1]]
an_array.sort