:-lib(ic).
:-lib(propia).
:-lib(util).
:-dynamic(box_index/2).
%stack(+Ls,-Lp) is true if
%Ls is a list of N boxes
%Lp is a list of P stacks where the maximum height of the stacks is N/P
stack(Ls,List):-
length(Ls,N),
between(1,N,P),
Tmp is N/P,
ceiling(Tmp,T2),
integer(T2,H),
stack(Ls,P,H,List),!.
%stack(+Ls,+N,+H,-Lp) is true if
%Ls is a list of boxes
%N is the number of stacks we want to create
%H is the maximum height of the stacks
%Stacks is the list of stacks
stack(Ls,N,H,Stacks):-
retractall(box_index(_I,_B)),
length(Ls,Nb),
NbFakeBoxes is N*H - Nb,
fill(Ls,NbFakeBoxes,La),
PlaceInStacks is N*H,
addIndex(La,1),
length(List,PlaceInStacks),
List :: [1..PlaceInStacks],
createConstraints(List,1,H),
alldifferent(List),
(fromto(List,Vars,Rest,[]) do
delete(Var,Vars,Rest,0,first_fail),
indomain(Var,min)
),
produceSolution(List,N,H,Stacks).
%produceSolution(+Li,+N,+H,-Lb) is true if
%Li is a list of box index
%N is a number such that every box with a index < N will be ignored
%H is the maximum height of the stacks
%Lb is a list of stacks
produceSolution([],_,_,[]):-!.
produceSolution(Li,N,H,[L|Lb]):-
produceStack(Li,N,H,L,Rs),
produceSolution(Rs,N,H,Lb).
%produceStack(+Li,+N,+H,-P,-Rs) is true if
%Li is a list of box indexes
%N is a number
%H is the maximum height of the stack
%P is a stack where every box in this stack have a index >= N
%Rs is the list Li where we removed the H first values
produceStack(Li,_,0,[],Li):-!.
produceStack([I|Li],N,H,[C|P],R):-
I>=N,!,box_index(I,C),
H1 is H-1,
produceStack(Li,N,H1,P,R).
produceStack([_I|Li],N,H,P,R):-
H1 is H-1,
produceStack(Li,N,H1,P,R).
%addIndex(+L,+I) is true if
%L is a list of N boxes
%I is a number
%and facts were added in the knowledge base to assign an index to the boxes
% of L. The index of J-th box in L will be I+J (J=0 for the first box)
addIndex([],_I):-!.
addIndex([C|L],I):-
asserta(box_index(I,C)),
I1 is I+1,
addIndex(L,I1).
%constraintBoxes(+I,+J) is true if
%I and J are indexes of boxes
%a constraint was stated that both width and length of box I are greater or
% equal the width and length of box J
constraintBoxes(I,J):-
box_index(I,box(Wi,Li)) infers ic,
box_index(J,box(Wj,Lj)) infers ic,
Wi#>=Wj,
Li#>=Lj.
%createConstraint(+L,+I,+N) is true if
%L is a list of length T of box indexes
%I and N are numbers
%and T+I%N = 1, and constraint where stated on L such that L represent a flatten
%list of stack, where each stack has a height of N
createConstraints([_],N,N):-!.
createConstraints([_,B|Ls],N,N):-!,
createConstraints([B|Ls],1,N).
createConstraints([A,B|Ls],I,N):-
I= 0
%Ls is the list L in wich we added I fake boxes at the beginning of he list
fill(L,0,L):-!.
fill(L,I,[box(0,0)|R]):-I>0, I1 is I-1, fill(L,I1,R).