/* Purpose: Solve the box packing problem. Author: Neng-Fa Zhou, 2002 Platform: B-Prolog 6.1 or up Description: The dimensions of the boxes are give by the relation box/1 and the layout area is defined by the predicate area/2. For each box, let W and H be the width and the height, respectively, and AreaW and AreaH be the width and height of the layout area, respectively. The domain of positions for the box is: [(0,0),...,(AreaW-W,AreaH-H)] This program implements the forward checking algorithm. Once a box is laid out, all the no good points are excluded from the domains of the remaining variables. */ go:- solve(Boxes), visualize(Boxes). visualize(Boxes):- cgWindow(Win,"boxLayout"), handleWindowClosing(Win), createRects(Boxes,Os), cgSame(Os,window,Win), cgPack(Os), cgMove(Os,30,30), cgShow(Os). handleWindowClosing(Win),{windowClosing(Win)} => cgClose(Win). createRects([],[]). createRects([box(W,H,(X,Y),C)|Boxes],[Rect|Rects]):- cgRectangle(Rect), Rect^width #= 10*W, Rect^height #= 10*H, Rect^x #= 10*X, Rect^y #= 10*Y, Rect^color #= C, createRects(Boxes,Rects). /* pack the boxes */ solve(Boxes):- findall(box(W,H,_,C),box(W,H,C),Boxes), %box(Width,Height,PosVar) area(AreaW,AreaH), % layout area createPosVars(Boxes,AreaW,AreaH), placeBoxes(Boxes), write(Boxes),nl. createPosVars([],AreaW,AreaH). createPosVars([box(W,H,Pos,Color)|Boxes],AreaW,AreaH):- MaxX is AreaW-W, MaxY is AreaH-H, allPoints(0,0,MaxX,MaxY,D), Pos :: D, createPosVars(Boxes,AreaW,AreaH). allPoints(X0,Y0,MaxX,MaxY,D):- % D=[(0,0),...,(0,MaxY),(1,0),...,(1,MaxY),...,(MaxX,0),...,(MaxX,MaxY)] range(X0,MaxX,Xs), range(Y0,MaxY,Ys), pair(Xs,Ys,D). pair([],Ys,D):-D=[]. pair([X|Xs],Ys,D):- pair1(X,Ys,D,D1), pair(Xs,Ys,D1). pair1(X,[],D,DRest):-D=DRest. pair1(X,[Y|Ys],D,DRest):-D=[(X,Y)|D1],pair1(X,Ys,D1,DRest). range(I,Max,Xs):-I>Max,!,Xs=[]. range(I,Max,Xs):-Xs=[I|Xs1],I1 is I+1,range(I1,Max,Xs1). placeBoxes([]). placeBoxes([Box|Boxes]):- Box=box(W,H,_,_), Dim is W*H, selectLargest(Boxes,Box,Dim,box(BW,BH,BPos,_),Rest), indomain(BPos), % get a candidate position notOverlap(BW,BH,BPos,Rest), placeBoxes(Rest). selectLargest([],Cur,Dim,Largest,Rest):-Largest=Cur,Rest=[]. selectLargest([Box|Boxes],Cur,Dim,Largest,Rest):- Box=box(W,H,_,_), Dim1 is W*H, (Dim1>Dim->LargerBox=Box,Rest=[Cur|Rest1],LargerDim=Dim1; LargerBox=Cur,LargerDim=Dim,Rest=[Box|Rest1]), selectLargest(Boxes,LargerBox,LargerDim,Largest,Rest1). %The area of a laid out box as well as the left and top surrounding areas cannot be used for other boxes % _______________ % |D | C | % --------------- % | | | % |B | A | % | | | % --------------- notOverlap(W,H,(X,Y),Boxes):- MaxX is X+W-1, MaxY is Y+H-1, allPoints(X,Y,MaxX,MaxY,PointsA), notOverlap(PointsA,X,Y,MaxX,MaxY,Boxes). notOverlap(PointsA,X,Y,MaxX,MaxY,[]). notOverlap(PointsA,X,Y,MaxX,MaxY,[box(W,H,PosVar,_)|Boxes]):- PosVar notin PointsA, X0 is X-W+1, Y0 is Y-H+1, allPoints(X0,Y,X,MaxY,PointsB), PosVar notin PointsB, % allPoints(X0,Y0,MaxX,Y,PointsCD), PosVar notin PointsCD, % notOverlap(PointsA,X,Y,MaxX,MaxY,Boxes). area(30,21). box(3,9,darkGray). box(6,6,blue). box(9,6,cyan). box(9,3,orange). box(12,3,lightGray). box(12,6,pink). box(3,12,magenta). box(6,9,gray). box(6,12,green). box(6,3,red). box(21,3,black). box(9,9,red). box(3,18,yellow).