Sliding tile puzzle with varying tile size using logic programming

448 views Asked by At

So I am trying to solve this Booth arrangement problem given here. It is basically a sliding tile puzzle where one (booth)tile has to reach a target spot and in the end all other (booths)tiles should be in their original location. Each tile/booth has a dimension and following are the input fact and relation descriptions:

  • One fact of the form room(W,H), which specifies the width W and
    height H of the room (3 ≤ W, H ≤ 20).
  • One fact booths(B), which
    specifies the number of booths (1 ≤ B ≤ 20).
  • A relation that consists of facts of the form dimension(B, W, H), which specifies the width W and height H of booth B.
  • A relation consisting of facts of the form
    position(B, W, H), specifying the initial position (W, H) of booth B.

  • One fact target(B, W, H), specifying the destination (W, H) of the
    target booth B.

  • An additional fact horizon(H) gives an upper bound on the number of moves to be performed.

The program is supposed to read input facts from a file but I am just trying to do the solving so I have just copy pasted one possible input for now, and I have written some basic clauses:

room(3, 3).
booths(3).
dimension(1, 2, 1).
dimension(2, 2, 1).
dimension(3, 1, 1).
position(1, 0, 1).
position(2, 1, 2).
position(3, 0, 0).
target(3, 0, 2).
horizon(10).

xlim(X) :- room(X,_).
ylim(X) :- room(_,X).

sum(X,Y,Z) :- Z is X+Y .

do(position(B,X,Y),movedown,position(B,X,Z)) :- Y > 0 , sum(Y,-1,Z) .
do(position(B,X,Y),moveup,position(B,X,Z)) :- ylim(L), Y < L , sum(Y,1,Z) .
do(position(B,X,Y),moveleft,position(B,Z,Y)) :- X > 0 , sum(X,-1,Z) .
do(position(B,X,Y),moveright,position(B,Z,Y)) :- xlim(L), X < L, sum(X,1,Z) .

noverlap(B1,B2) :- 
    position(B1,X1,Y1), 
    position(B2,X2,Y2), 
    ends(Xe1,Ye1,B1), 
    ends(Xe2,Ye2,B2), 
    ( Xe1 < X2 ; 
      Xe2 < X1 ; 
      Ye1 < Y2 ; 
      Ye2 < Y1 ).

ends(Xe,Ye,B) :- 
    dimension(B,W,H), 
    position(B,X,Y), 
    Xe is X+W-1, 
    Ye is Y+H-1.

between(X,Y,Z) :- 
    X > Y , 
    X < Z .

validMove(M,B) :- do(position(B,X,Y),M,position(B,Xn,Yn)) .

I am new to Prolog and I am stuck on how to go from here, I have the no_overlap rule so I can test if a move is valid or not but I am not sure how with the current clauses that I have. My current clauses for moves do/3 probably needs some modification. Any pointers?.

1

There are 1 answers

2
mat On

You need to express the task in terms of relations between states of the puzzle. Your current clauses determine the validity of a single move, and can also generate possible moves.

However, that is not sufficient: You need to express more than just a single move and its effect on a single tile. You need to encode, in some way, the state of the whole puzzle, and also encode how a single move changes the state of the whole task.

For a start, I recommend you think about a relation like:

world0_move_world(W0, M, W) :- ...

and express the relation between a given "world" W0, a possible move M, and the resulting world W. This relation should be so general as to generate, on backtracking, each move M that is possible in W0. Ideally, it should even work if W0 is a free variable, and for this you may find useful: Constraints allow you to express arithmetic relations in a much more general way than you are currently using.

Once you have such a relation, the whole task is to find a sequence Ms of moves such that any initial world W0 is transformed to a desired state W.

Assuming you have implemented world0_move_world/3 as a building block, you can easily lift this to lists of moves as follows (using ):

moves(W0) --> { desired_world(W0) }.
moves(W0) --> [M], { world0_move_world(W0, M, W) }, moves(W).

You can then use iterative deepening to find a shortest sequence of moves that solves the puzzle:

?- length(Ms, _), initial_world(W0), phrase(moves(W0), Ms).