Algorithm to create subgroups of people - algorithm

we are looking for an algorithm that could help us creating subgroups of people. I'll explain it better with an example:
We have a group of 5 students, let's call them A, B, C, D, E. Given a number (call it n) smaller than the number of students (<5), we would like to create a subgroup of n elements per each student.
For example, given n = 3 we need to create 3 subgroups (SG1, SG2 and SG3) and a possible result would be
STUDENT - SG1 - SG2 - SG3
A B - C - D
B C - D - E
C A - E - B
D E - B - A
E D - A - C
Each column must have all elements and they cannot repeat in the same row.
Many thanks in advance!

Why don't you just always do the following order, MUCH easier to generate:
a - b,c,d
b - c,d,e
c - d,e,a
d - e,a,b
e - a,b,c
//aka
( 0 - 1,2,3 ) %5
( 1 - 2,3,4 ) %5
( 2 - 3,4,5 ) %5
( 3 - 4,5,6 ) %5
( 4 - 5,6,7 ) %5
I've created a generating form similar to the above but utilizing modulo in C. You can try it online here:
http://ideone.com/n6qBzN
Code for reference:
main() {
char *myString = "ABCDEFGHIJKLMNOP4583";
int characters = mystrlen(myString);
int i = 0;
while (i < characters) {
printf("%c", myString[i]);
printf(" - ");
int a = 1;
while (a <= characters-2) {
printf("%c, ", myString[(i+a)%characters]);
a++;
}
printf("\n");
i++;
}
}
int mystrlen(char *s) {//arbitrary function for determining number of characters in a string (your initial group set)
int i =0;
while (*s++) i++;
return i;
}
So you can see in the above code that the initial list of people groups is ABCDEFGHIJKLMNOP4583 and it generates the following table:
A - B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, 4, 5, 8,
B - C, D, E, F, G, H, I, J, K, L, M, N, O, P, 4, 5, 8, 3,
C - D, E, F, G, H, I, J, K, L, M, N, O, P, 4, 5, 8, 3, A,
D - E, F, G, H, I, J, K, L, M, N, O, P, 4, 5, 8, 3, A, B,
E - F, G, H, I, J, K, L, M, N, O, P, 4, 5, 8, 3, A, B, C,
F - G, H, I, J, K, L, M, N, O, P, 4, 5, 8, 3, A, B, C, D,
G - H, I, J, K, L, M, N, O, P, 4, 5, 8, 3, A, B, C, D, E,
H - I, J, K, L, M, N, O, P, 4, 5, 8, 3, A, B, C, D, E, F,
I - J, K, L, M, N, O, P, 4, 5, 8, 3, A, B, C, D, E, F, G,
J - K, L, M, N, O, P, 4, 5, 8, 3, A, B, C, D, E, F, G, H,
K - L, M, N, O, P, 4, 5, 8, 3, A, B, C, D, E, F, G, H, I,
L - M, N, O, P, 4, 5, 8, 3, A, B, C, D, E, F, G, H, I, J,
M - N, O, P, 4, 5, 8, 3, A, B, C, D, E, F, G, H, I, J, K,
N - O, P, 4, 5, 8, 3, A, B, C, D, E, F, G, H, I, J, K, L,
O - P, 4, 5, 8, 3, A, B, C, D, E, F, G, H, I, J, K, L, M,
P - 4, 5, 8, 3, A, B, C, D, E, F, G, H, I, J, K, L, M, N,
4 - 5, 8, 3, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O,
5 - 8, 3, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P,
8 - 3, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, 4,
3 - A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, 4, 5,

Related

heapify prolog implementation

I'm testing my heapify in prolog but it doesn't work as i expected. In particular it miss some elements i think and it doesn't generate a correct heap.
min_heapify(H, P) :- heap_has_size(H, S), P = S, !.
min_heapify(H, P) :-
R is (2*P)+1,
heap_has_size(H, S), R =< S,
heap_entry(H, P, K1, _V1),
heap_entry(H, R, K2, _V2),
K1 =< K2, !.
min_heapify(H, P) :-
L is 2*P,
heap_has_size(H, S), L =< S,
heap_entry(H, P, K1, V1),
heap_entry(H, L, K2, V2),
K1 > K2,
retract(heap_entry(H, P, K1, V1)),
retract(heap_entry(H, L, K2, V2)),
assert(heap_entry(H, P, K2, V2)),
assert(heap_entry(H, L, K1, V1)),
min_heapify(H, L).
In fact, as I said before in my comment, you never swap a father with a right child.
See your code altered so that it can show you what it is doing at each step (I just included a predicate to show how the heap is modified during the execution).
I think that will help you to understand the problem with your implementation).
Hint: predicate heapify must adjust the heap entries from bottom to top, not from top to bottom (i.e., starting from entry Size//2 and decreasing until entry 1).
:- dynamic heap_entry/4.
min_heapify(H, P) :-
format('~nHeapify node: ~w~n', [P]),
show_tree(H),
get0(_),
fail.
min_heapify(H, P) :-
heap_has_size(H, S),
P = S,
!.
min_heapify(H, P) :-
R is (2*P)+1,
heap_has_size(H, S), R =< S,
heap_entry(H, P, K1, _V1),
heap_entry(H, R, K2, _V2),
K1 =< K2, !.
min_heapify(H, P) :-
L is 2*P,
heap_has_size(H, S), L =< S,
heap_entry(H, P, K1, V1),
heap_entry(H, L, K2, V2),
K1 > K2,
retract(heap_entry(H, P, K1, V1)),
retract(heap_entry(H, L, K2, V2)),
assert(heap_entry(H, P, K2, V2)),
assert(heap_entry(H, L, K1, V1)),
min_heapify(H, L).
heap_has_size(H, S) :-
aggregate_all(count, heap_entry(H,_,_,_), S).
show_tree(H) :-
heap_has_size(H, S),
show_tree(H, S, 1, 0).
show_tree(H, S, I, D) :-
( I =< S
-> R is 2*I + 1,
L is 2*I,
show_tree(H, S, R, D+1),
heap_entry(H, I, K, V),
tab(5*D),
writeln([K,V]),
show_tree(H, S, L, D+1)
; true ).
:- initialization
retractall(heap_entry(_,_,_,_)),
assertz(heap_entry(h1, 1, 16, a)),
assertz(heap_entry(h1, 2, 2, b)),
assertz(heap_entry(h1, 3, 4, c)),
assertz(heap_entry(h1, 4, 3, d)),
assertz(heap_entry(h1, 5, 7, e)),
assertz(heap_entry(h1, 6, 10, f)),
assertz(heap_entry(h1, 7, 9, g)),
assertz(heap_entry(h1, 8, 8, h)),
assertz(heap_entry(h1, 9, 14, i)),
assertz(heap_entry(h1, 10, 1, l)).
Here is the result:
?- min_heapify(h1,1).
Heapify node: 1
[9,g]
[4,c]
[10,f]
[16,a]
[7,e]
[1,l]
[2,b]
[14,i]
[3,d]
[8,h]
|:
Heapify node: 2
[9,g]
[4,c]
[10,f]
[2,b]
[7,e]
[1,l]
[16,a]
[14,i]
[3,d]
[8,h]
|:
Heapify node: 4
[9,g]
[4,c]
[10,f]
[2,b]
[7,e]
[1,l]
[3,d]
[14,i]
[16,a]
[8,h]
|:
Heapify node: 8
[9,g]
[4,c]
[10,f]
[2,b]
[7,e]
[1,l]
[3,d]
[14,i]
[8,h]
[16,a]
|:
false.
An implementation of min_heapify, according to the hint that I gave you before (you can compare it with your implementation and see what you have to modify):
:- dynamic heap_entry/4.
min_heapify(H) :-
heap_has_size(H, S),
N is S//2,
min_heapify_loop(H, S, N).
min_heapify_loop(H, S, N) :-
( N < 1
-> true
; sift_down(H, S, N),
succ(M, N),
min_heapify_loop(H, S, M) ).
heap_has_size(H, S) :-
aggregate_all(count, heap_entry(H,_,_,_), S).
sift_down(H, S, I) :-
( has_smaller_child(H, S, I, J)
-> swap_entries(H, I, J),
sift_down(H, S, J)
; true ).
has_smaller_child(H, S, I, J) :-
2*I =< S,
J1 is 2*I,
J2 is 2*I + 1,
entry_key(H, I, K0),
entry_key(H, J1, K1),
entry_key(H, J2, K2),
( K1 < K2
-> (J, K) = (J1, K1)
; (J, K) = (J2, K2) ),
K < K0.
entry_key(H, I, K) :-
( heap_entry(H, I, K, _)
-> true
; K = +inf ).
swap_entries(H, I, J) :-
retract(heap_entry(H, I, K1, V1)),
retract(heap_entry(H, J, K2, V2)),
assertz(heap_entry(H, I, K2, V2)),
assertz(heap_entry(H, J, K1, V1)).
show_tree(Heap) :-
heap_has_size(Heap, Size),
show_tree(Heap, Size, 1, 0).
show_tree(Heap, Size, Root, Depth) :-
( Root =< Size
-> RightChild is 2*Root + 1,
LeftChild is 2*Root,
show_tree(Heap, Size, RightChild, Depth+1),
heap_entry(Heap, Root, Key, Value),
tab(5*Depth),
writeln([Key, Value]),
show_tree(Heap, Size, LeftChild, Depth+1)
; true ).
:- initialization
retractall(heap_entry(_,_,_,_)),
assertz(heap_entry(h1, 1, 16, a)),
assertz(heap_entry(h1, 2, 2, b)),
assertz(heap_entry(h1, 3, 4, c)),
assertz(heap_entry(h1, 4, 3, d)),
assertz(heap_entry(h1, 5, 7, e)),
assertz(heap_entry(h1, 6, 10, f)),
assertz(heap_entry(h1, 7, 9, g)),
assertz(heap_entry(h1, 8, 8, h)),
assertz(heap_entry(h1, 9, 14, i)),
assertz(heap_entry(h1, 10, 1, l)),
writeln('\nBefore heapify\n'),
show_tree(h1),
min_heapify(h1),
writeln('\nAfter heapify\n'),
show_tree(h1).
Execution result:
Before heapify
[9,g]
[4,c]
[10,f]
[16,a]
[7,e]
[1,l]
[2,b]
[14,i]
[3,d]
[8,h]
After heapify
[9,g]
[4,c]
[10,f]
[1,l]
[7,e]
[16,a]
[2,b]
[14,i]
[3,d]
[8,h]

Iterating into a list within a list in Prolog

I currently have this code that inserts an element into a list:
listpicket(_,[],[k]).
listpicket(K,[H|T],[K,H|L]) :-
listpicket(K,T,L).
It currently produces this result:
L = [k, a, k, b, k, [c, d], k, e, k]
However, I am trying to get the program to insert a k into [c,d] such as shown:
L = [k, a, k, b, k, [k, c, k, d, k], k, e, k]
I have a feeling I'm supposed to use is_list to check if the tail is a proper list or not, and then create another recursion inside to insert the k element just like the outside. However, I'm quite new to Prolog and I'm trying to understand how I can introduce a conditional inside the listpicket method.
You need to check whether the head of the List [k, a, k, b, k, [c, d], k, e, k] contains any list or not. If the head is a list then add k to the list [c,d] the resultant list is [k,c,k,d]. Now add this resultant list to the Main List. My approach is attached below.
is_list1([_|_]).
addK([X],k,[k,X,k]).
addK([H|T],k,[k,H|T1]):- addK(T,k,T1).
addElement([],[]).
addElement([H|T],[H1|Z]):- is_list1(H) , addK(H,k,H1) , addElement(T,Z) .
addElement([H|T],[H|Z]):- \+is_list(H) , addElement(T,Z).
is_list1() function is used to determine whether a given head is a list or not.
addK() function adds k before and after the head to the list given to it.
addElement() is uses all the above functions to achieve the goal you wanted.
OUTPUT
?- addElement([k, a, k, b, k, [c, d], k, e, k],Z).
Z = [k, a, k, b, k, [k, c, k, d, k], k, e, k]
?- addElement([1,2,[3,4,5],4,5],Z).
Z = [1, 2, [k, 3, k, 4, k, 5, k], 4, 5]
what you have to do is append my code to your existing code, which should look like this.
listpicket(_,[],[k]).
listpicket(K,[H|T],[K,H|L]) :-
listpicket(K,T,L).
is_list1([_|_]).
addK([X],k,[k,X,k]).
addK([H|T],k,[k,H|T1]):- addK(T,k,T1).
addElement([],[]).
addElement([H|T],[H1|Z]):- is_list1(H) , addK(H,k,H1) , addElement(T,Z) .
addElement([H|T],[H|Z]):- \+is_list(H) , addElement(T,Z).
goal(X,FinalList):- listpicket(k,X,L) , addElement(L,FinalList).
OUTPUT
?- goal([1,2,[3,4],5],FinalList).
FinalList = [k, 1, k, 2, k, [k, 3, k, 4, k], k, 5, k]
?- goal([a,b,[c,d],e],FinalList).
FinalList = [k, a, k, b, k, [k, c, k, d, k], k, e, k]
Hope this helped you.

How to get the value of many elements of a matrix (list of lists)

I have problems because I want to get the values of many grids of a matrix
Example:
I have this matrix (list of lists)
[[g,z,n,d,o,g,r,o,y,c],
[a,u,u,d,p,o,x,s,t,b],
[u,y,z,r,r,e,m,e,e,o],
[g,v,j,m,x,e,j,e,h,l],
[e,r,u,y,d,z,k,b,r,x],
[e,d,h,n,c,y,q,e,x,i],
[w,f,m,w,x,n,n,m,h,i],
[y,d,g,u,q,d,z,o,n,d],
[g,p,o,u,c,o,n,f,x,q],
[c,y,z,r,i,c,a,t,x,v]]
I want to get the word "dog" from this matrix, this word is in the coordinates (0 3) (0 4) (0 5).
Now the problem is how I can do this in prolog?
My code so far:
selectElementList(0,[H|_],H).
selectElementList(P,[H|T],E):-
length([H|T],Len),
( P < Len
-> P1 is P - 1,
selectElementList(P1,T,E),
!
; E = false,
!
).
With this predicate I get one value of the matrix.
selectGridMatrix(Matrix,X,Y,R):-
selectElementList(X,Matrix,Row), selectElementList(Y,Row,R).
Example:
?- selectGridMatrix([[0,1,2],[3,4,5]],0,0,R).
R = 0 ;
an example, using builtin nth0/3 and library(yall):
?- M= [[g,z,n,d,o,g,r,o,y,c],
[a,u,u,d,p,o,x,s,t,b],
[u,y,z,r,r,e,m,e,e,o],
[g,v,j,m,x,e,j,e,h,l],
[e,r,u,y,d,z,k,b,r,x],
[e,d,h,n,c,y,q,e,x,i],
[w,f,m,w,x,n,n,m,h,i],
[y,d,g,u,q,d,z,o,n,d],
[g,p,o,u,c,o,n,f,x,q],
[c,y,z,r,i,c,a,t,x,v]], maplist({M}/[(R,C),V]>>(nth0(R,M,Row),nth0(C,Row,V)),[(0,3),(0,4),(0,5)],Word).
M = [[g, z, n, d, o, g, r, o|...], [a, u, u, d, p, o, x|...], [u, y, z, r, r, e|...], [g, v, j, m, x|...], [e, r, u, y|...], [e, d, h|...], [w, f|...], [y|...], [...|...]|...],
Word = [d, o, g].
HTH

Trying to solve the peg jump puzzle in Prolog

There are 8 pegs in nine holes. At beginning, the four red pegs on the left and the four blue pegs are on the right, and one empty hole between them. The puzzle is to move all the red to the right, and blue pegs to the left(in other opposite). These are the legal moves to do so:
Pegs may only move forward (red may move right and blue left).
A peg may move forward one step into an open position.
A peg may skip over exactly one peg of the opposite color, if the position beyond it is open.
This is what I wrote, but it doesn't work
% Form of board, b for blue, r for red, o for empty.
% [ [r,r,r,r], [o], [b,b,b,b] ]
% jumps
linjmp([x, x, o | T], [o, o, x | T]).
linjmp([o, x, x | T], [x, o, o | T]).
linjmp([H|T1], [H|T2]) :- linjmp(T1,T2).
% Series of legal boards.
series(From, To, [From, To]) :- jump(From, To).
series(From, To, [From, By | Rest])
:- jump(From, By),
series(By, To, [By | Rest]).
% Print a series of boards. This puts one board per line and looks a lot
% nicer than the jumble that appears when the system simply beltches out
% a list of boards. The write_ln predicate is a built-in which always
% succeeds (is always satisfied), but prints as a side-effect. Therefore
% print_series(Z) will succeed with any list, and the members of the list
% will be printed, one per line, as a side-effect of that success.
print_series_r([]) :-
write_ln('*******************************************************').
print_series_r([X|Y]) :- write_ln(X), print_series_r(Y).
print_series(Z) :-
write_ln('\n*******************************************************'),
print_series_r(Z).
% A solution.
solution(L) :- series([[r,r,r,r], [o], [b,b,b,b]],
[[b,b,b,b], [o], [r,r,r,r]], L).
% Find a print the first solution.
solve :- solution(X), print_series(X).
% Find all the solutions.
solveall :- solve, fail.
% This finds each solution with stepping.
solvestep(Z) :- Z = next, solution(X), print_series(X).
It should be like so when it works:
?- consult(linejump).
% linejump compiled 0.00 sec, 3,612 bytes
true.
?- solve.
*******************************************************
[r, r, r, r, o, b, b, b, b]
[r, r, r, o, r, b, b, b, b]
[r, r, r, b, r, o, b, b, b]
[r, r, r, b, r, b, o, b, b]
[r, r, r, b, o, b, r, b, b]
[r, r, o, b, r, b, r, b, b]
[r, o, r, b, r, b, r, b, b]
[r, b, r, o, r, b, r, b, b]
[r, b, r, b, r, o, r, b, b]
[r, b, r, b, r, b, r, o, b]
[r, b, r, b, r, b, r, b, o]
[r, b, r, b, r, b, o, b, r]
[r, b, r, b, o, b, r, b, r]
[r, b, o, b, r, b, r, b, r]
[o, b, r, b, r, b, r, b, r]
[b, o, r, b, r, b, r, b, r]
[b, b, r, o, r, b, r, b, r]
[b, b, r, b, r, o, r, b, r]
[b, b, r, b, r, b, r, o, r]
[b, b, r, b, r, b, o, r, r]
[b, b, r, b, o, b, r, r, r]
[b, b, o, b, r, b, r, r, r]
[b, b, b, o, r, b, r, r, r]
[b, b, b, b, r, o, r, r, r]
[b, b, b, b, o, r, r, r, r]
*******************************************************
true ;
*******************************************************
[r, r, r, r, o, b, b, b, b]
[r, r, r, r, b, o, b, b, b]
[r, r, r, o, b, r, b, b, b]
[r, r, o, r, b, r, b, b, b]
[r, r, b, r, o, r, b, b, b]
[r, r, b, r, b, r, o, b, b]
[r, r, b, r, b, r, b, o, b]
[r, r, b, r, b, o, b, r, b]
[r, r, b, o, b, r, b, r, b]
[r, o, b, r, b, r, b, r, b]
[o, r, b, r, b, r, b, r, b]
[b, r, o, r, b, r, b, r, b]
[b, r, b, r, o, r, b, r, b]
[b, r, b, r, b, r, o, r, b]
[b, r, b, r, b, r, b, r, o]
[b, r, b, r, b, r, b, o, r]
[b, r, b, r, b, o, b, r, r]
[b, r, b, o, b, r, b, r, r]
[b, o, b, r, b, r, b, r, r]
[b, b, o, r, b, r, b, r, r]
[b, b, b, r, o, r, b, r, r]
[b, b, b, r, b, r, o, r, r]
[b, b, b, r, b, o, r, r, r]
[b, b, b, o, b, r, r, r, r]
[b, b, b, b, o, r, r, r, r]
*******************************************************
true .
?-
A straightforward Prolog code which tries to be the simplest and clearest, and doesn't care about efficiency at all:
start([r,r,r,r,e,b,b,b,b]). % starting position
% can move from a position P1 to position P2
move(P1,P2):- append(A,[r,e|B],P1), append(A,[e,r|B],P2).
move(P1,P2):- append(A,[e,b|B],P1), append(A,[b,e|B],P2).
move(P1,P2):- append(A,[e,r,b|B],P1), append(A,[b,r,e|B],P2).
move(P1,P2):- append(A,[r,b,e|B],P1), append(A,[e,b,r|B],P2).
solved([b,b,b,b,e,r,r,r,r]). % the target position to be reached
pegs :- start(P), solve(P, [], R),
maplist(writeln, R), nl, nl, fail ; true.
% solve( ?InitialPosition, +PreviousPositionsList, ?ResultingPath)
solve(P, Prev, R):-
solved(P) -> reverse([P|Prev], R) ;
move(P, Q), \+memberchk(Q, Prev), solve(Q, [P|Prev], R).
Nothing special about it. Takes whole of 0.08 seconds on Ideone to find two solutions, both of 24 moves.
For an N-pegs problem, we only need to modify the start and solved predicates accordingly.
Kudos go to Cary Swoveland from whose answer I took the notation (that's half the solution). A more efficient code, following mat's answer, building the result list in Prolog's characteristic top-down manner (similar to difference-lists technique, cf. tailrecursion-modulo-cons ):
swap([r,e|B],[e,r|B]).
swap([e,b|B],[b,e|B]).
swap([e,r,b|B],[b,r,e|B]).
swap([r,b,e|B],[e,b,r|B]).
move(A,B):- swap(A,B).
move([A|B],[A|C]):- move(B,C).
moves(S,[S]):- solved(S).
moves(S,[S|B]):- move(S,Q), moves(Q,B).
pegs(PS) :- start(P), moves(P, PS), maplist( writeln, PS), nl.
In general, any board game with positions and moves between them can be seen as a search problem in a search space of positions, defined by the valid moves, that is to take us from the start to the end (final) position. Various search strategies can be used, depth first, breadth first, iterative deepening, best-first heuristics ... This views the search space as a graph where nodes are positions (board configurations), and edges are moves; otherwise we can say this is a transitive closure of a move relation.
Sometimes the move relation is defined such that it produces a new legal configuration (like here); sometimes it is easier to define a general move relation and check the produced position for legality (like in N-queens problem). It is also common to maintain the visited nodes list while searching, and check any newly discovered node for being one of those already visited - discarding that path, to avoid getting into a loop.
Breadth first search will explicitly maintain the frontier of the nodes being discovered, and maintain it as a queue while extending it by one move at a time; depth first as a stack. Best first search will reorder this frontier according to some heuristics. Here, moves/2 is depth-first implicitly, because it relies on Prolog search which is itself depth-first.
Sometimes the search space is guaranteed to not have these cycles (i.e. to be a DAG - directed acyclic graph) so the check for uniqueness is not necessary. As for the final node, sometimes it is defined by value (like here), sometimes we're interested in some condition to hold (like e.g. in chess). See this answer for how to enforce this uniqueness with a lazy all_dif/1 predicate upfront. With the predicates defined in it, this problem becomes simply
pegs(Ps):-
path( move, Ps, [r,r,r,r,e,b,b,b,b], [b,b,b,b,e,r,r,r,r]).
It is always nice to use a dcg when describing lists.
For example:
initial_state([r,r,r,r,o,b,b,b,b]).
final_state([b,b,b,b,o,r,r,r,r]).
move([E|Es]) --> [E], move(Es).
move([r,o|Ls]) --> [o,r], list(Ls).
move([o,b|Ls]) --> [b,o], list(Ls).
move([o,r,b|Ls]) --> [b,r,o], list(Ls).
move([r,b,o|Ls]) --> [o,b,r], list(Ls).
list([]) --> [].
list([L|Ls]) --> [L], list(Ls).
moves(S) --> [S], { final_state(S) }.
moves(S0) --> [S0], { phrase(move(S0), S) }, moves(S).
We can use iterative deepening to find a shortest solution:
?- length(Ms, _),
initial_state(S0),
phrase(moves(S0), Ms),
maplist(writeln, Ms).
[r,r,r,r,o,b,b,b,b]
[r,r,r,r,b,o,b,b,b]
[r,r,r,o,b,r,b,b,b]
[r,r,o,r,b,r,b,b,b]
[r,r,b,r,o,r,b,b,b]
[r,r,b,r,b,r,o,b,b]
[r,r,b,r,b,r,b,o,b]
[r,r,b,r,b,o,b,r,b]
[r,r,b,o,b,r,b,r,b]
[r,o,b,r,b,r,b,r,b]
[o,r,b,r,b,r,b,r,b]
[b,r,o,r,b,r,b,r,b]
[b,r,b,r,o,r,b,r,b]
[b,r,b,r,b,r,o,r,b]
[b,r,b,r,b,r,b,r,o]
[b,r,b,r,b,r,b,o,r]
[b,r,b,r,b,o,b,r,r]
[b,r,b,o,b,r,b,r,r]
[b,o,b,r,b,r,b,r,r]
[b,b,o,r,b,r,b,r,r]
[b,b,b,r,o,r,b,r,r]
[b,b,b,r,b,r,o,r,r]
[b,b,b,r,b,o,r,r,r]
[b,b,b,o,b,r,r,r,r]
[b,b,b,b,o,r,r,r,r]
with additional bindings for the lists of moves Ms and the initial state S0.
a purely syntactic variation of Will Ness's answer:
swap(X,P,Q) :- append([L,X,R],P), reverse(X,Y), append([L,Y,R],Q).
solve(P,Prev,R) :-
solved(P)
-> reverse([P|Prev], R)
; % move(P, Q)
phrase( (swap([r,e])|swap([e,b])|swap([e,r,b])|swap([r,b,e])), P, Q),
\+memberchk(Q, Prev),
solve(Q, [P|Prev], R).
I don't know prolog, but here's a recursive solution using Ruby. Even if you don't know Ruby, you should be able to figure out how the recursion works.
A Ruby primer:
a[space_pos-1], a[space_pos] = a[space_pos], a[space_pos-1] uses parallel assignment to swap the values at array indices space_pos-1 and space_pos without the need for a temporary variable.
FINAL, since it begins with a capital letter, is a constant.
a = arr.dup returns a "shallow" copy of the array arr, so swapping elements of a does not effect arr.
If a method contains no return statement, the value computed in the last line is returned by the method (e.g., the array a in red_slide).
soln=[] in def solve(arr, soln = []) assigns soln to an empty array if solve is called solve(arr).
soln + [:red_slide], where soln is an array and [:red_slide] is an array containing a single symbol (indicated by the colon) is a new array comprised of the elements of soln and the element :red_slide.
you can think of && as "and".
nil is returned by solve if the state of the moves given by solve's argument arr does not lead to a solution.
FINAL = [:b, :b, :b, :b, :e, :r, :r, :r, :r]
SIZE = FINAL.size
def red_slide(arr, space_pos)
a = arr.dup
a[space_pos-1], a[space_pos] = a[space_pos], a[space_pos-1]
a
end
def blue_slide(arr, space_pos)
a = arr.dup
a[space_pos], a[space_pos+1] = a[space_pos+1], a[space_pos]
a
end
def red_jump(arr, space_pos)
a = arr.dup
a[space_pos-2], a[space_pos] = a[space_pos], a[space_pos-2]
a
end
def blue_jump(arr, space_pos)
a = arr.dup
a[space_pos+2], a[space_pos] = a[space_pos], a[space_pos+2]
a
end
def solve(arr, soln = [])
return soln if arr == FINAL
space_pos = arr.index(:e)
# See if can slide red
if space_pos > 0 && arr[space_pos-1] == :r
ret = solve(red_slide(arr, space_pos), soln + [:red_slide])
return ret if ret
end
# See if can slide blue
if space_pos < SIZE-1 && arr[space_pos+1] == :b
ret = solve(blue_slide(arr, space_pos), soln + [:blue_slide])
return ret if ret
end
# See if can jump red over blue
if space_pos > 1 && arr[space_pos-2] == :r && arr[space_pos-1] == :b
ret = solve(red_jump(arr, space_pos), soln + [:red_jump])
return ret if ret
end
# See if can jump blue over red
if space_pos < SIZE-2 && arr[space_pos+2] == :b && arr[space_pos+1] == :r
ret = solve(blue_jump(arr, space_pos), soln + [:blue_jump])
return ret if ret
end
nil
end
solve [:r, :r, :r, :r, :e, :b, :b, :b, :b]
#=> [:red_slide, :blue_jump, :blue_slide, :red_jump, :red_jump, :red_slide,
# :blue_jump, :blue_jump, :blue_jump, :blue_slide, :red_jump, :red_jump,
# :red_jump, :red_jump, :blue_slide, :blue_jump, :blue_jump, :blue_jump,
# :red_slide, :red_jump, :red_jump, :blue_slide, :blue_jump, :red_slide]
I was surprised that it took just a fraction of a second to compute a solution. I guess the number of combinations of moves is not as great as I had imagined.
Note that this solution is for the "N peg problem", not just the "8 peg problem". For example,
FINAL = [:b, :b, :b, :e, :r, :r, :r]
SIZE = FINAL.size
solve [:r, :r, :r, :e, :b, :b, :b]
#=> [:red_slide, :blue_jump, :blue_slide, :red_jump, :red_jump, :red_slide,
# :blue_jump, :blue_jump, :blue_jump, :red_slide, :red_jump, :red_jump,
# :blue_slide, :blue_jump, :red_slide]
Board representation is important, here.
% Form of board, b for blue, r for red, o for empty.
% [r, r, r, r, o, b, b, b, b]
% Legal jumps.
linjmp([r, o | T], [o, r | T]).
linjmp([o, b | T], [b, o | T]).
linjmp([o, r, b | T], [b, r, o | T]).
linjmp([r, b, o | T], [o, b, r | T]).
linjmp([H|T1], [H|T2]) :- linjmp(T1,T2).
% Series of legal boards.
series(From, To, [From, To]) :- linjmp(From, To).
series(From, To, [From, By | Rest])
:- linjmp(From, By),
series(By, To, [By | Rest]).
% Print a series of boards. This puts one board per line and looks a lot
% nicer than the jumble that appears when the system simply beltches out
% a list of boards. The write_ln predicate is a built-in which always
% succeeds (is always satisfied), but prints as a side-effect. Therefore
% print_series(Z) will succeed with any list, and the members of the list
% will be printed, one per line, as a side-effect of that success.
print_series_r([]) :-
write_ln('*******************************************************').
print_series_r([X|Y]) :- write_ln(X), print_series_r(Y).
print_series(Z) :-
write_ln('\n*******************************************************'),
print_series_r(Z).
% A solution.
solution(L) :- series([r, r, r, r, o, b, b, b, b],
[b, b, b, b, o, r, r, r, r], L).
% Find a print the first solution.
solve :- solution(X), print_series(X).
% Find all the solutions.
solveall :- solve, fail.
% This finds each solution with stepping.
solvestep(Z) :- Z = next, solution(X), print_series(X).

GOP Reassemble and display order

How do you display the following transition in MPEG bit code?
I, P, B, B, P, B, B, B, I, P, B, B, B, P, B, P
Thank you
Usually it will be displayed as
I, B, B, P, B, B, B, P, I, B, B, B, P, B, P, P

Resources