How can I code a specific game in Prolog? - prolog

I have a problem with coding the program described below
Consider the following game. A board with three black stones, three white stones and an empty space is given. The goal of the game is to swap places of black pawns with white pawns. Moving rules define the following sentences: Move the white and black pieces alternately. Each pawn can move vertically or horizontally taking up an empty space. Each piece can jump vertically or horizontally over another piece (of any color). Write a program in Prolog to find all possible ways to find a winning sequence. For example, if we ask the question:
? - play (w, s (w, w, w, e, b, b, b), s (b, b, b, e, w, w, w), S, R ).
The prologue should answer, for example:
S = [s (w, w, w, e, b, b, b), s (w, e, w, w, b, b, b), ..., s (b, b, b, e, w, w, w)] R = [[w, 2,4], [b, 6,2], [w, 4,6], ..., [w, 4,6]]
Here [ w, 2,4] means moving the white pawn from position 2 to position 4. Of course Prolog should return both letters S and R in full (without "...").
What is the maximum number of different pawn settings possible on the board? Check the query:
? - play (_, s (w, w, w, e, b, b, b), s (b, b, e, w, w, b, w), _, _).
What does Prolog's answer mean? Hint: solve the problem for play/4 without R first
There's also a game board that looks like this:
I have no clue at all even where to start? How can I do that? Could you guys, help me with this one?

This is a standard state space search, a standard paradigm of GOFAI since the mid 50s at least.
The barebones algorithm:
search(State,Path,Path) :- is_final(State),!. % Done, bounce "Path" term
search(State,PathSoFar,PathOut) :-
generate_applicable_operators(State,Operators),
(is_empty(Operators) -> fail ; true),
select_operator(Operators,Op,PathSoFar),
apply_operator(State,Op,NextState), % depth-first / best first
search(NextState,[[NextState,Op]|PathSoFar],PathOut).
% Called like this, where Path will contain the reverse Path through
% State Space by which one may reach a final state:
search(InitialState,[[InitialState,nop]],Path).
First you need to represent a given state in this case the state of the board (at some time t).
We can either list the board positions and their content (w for white, b for black, e for empty token) or list the tokens and their positions. Let's list the board positions.
In Prolog, a term that can be easily pattern-matched is appropriate. The question already provides something: (w, w, w, e, b, b, b). This seems to be inspired by LISP and is not well adapted to Prolog. Let's use a list instead: [w, w, w, e, b, b, b]
The mapping of board positions to list positions shall be:
+---+---+
| 0 | 1 |
+---+---+---+
| 2 | 3 | 4 |
+---+---+---+
| 5 | 6 |
+---+---+
And we are done with setting up a state description!
Then you need to represent/define the operators (operations?) that can be applied to a state: they transform a valid state into another valid state.
An operator corresponds to "moving a token" and of course not all operators apply to a given state (you cannot move a token from field 1 if there is no token there; you cannot move a token to field 1 if there already is a token there).
So you want to write a predicate that links a board state to the operators applicable to that state: generate_applicable_operators/2
Then you need to select the operator that you want to apply. This can be done randomly, exhaustively, according to some heuristic (for example A*), but definitely needs to examine the path taken through the state space till now to avoid cycles: select_operator/3.
Then you apply the operator to generate the next state: apply_operator/3.
And finally recursively call search/3 to find the next move. This continues until the "final state", in this case [b, b, b, e, w, w, w] has been reached!
You can also use Iterative Deepening if you want to perform "breadth-first search" instead, but for that the algorithm structure must be modified.
And that's it.

Related

How can I add an element to a list using the delete1() predicate in prolog?

I need to add an element to a list using the delete1 predicate that I have written:
delete1(H,[H|T],T).
delete1(H,[D|X],[D|Y]):-delete1(H,X,Y).
How can I do that? Well, I know how to delete element but can't figure out how to add an element there. I need to show all the possible lists that will be the result of adding 56 to [x,y,z,a] list. Do you have any ideas?
If they are well-programmed, Prolog predicates can run "backwards":
f(X,Y) should be read as X is related to Y via f.
Given an x, on can compute the Y (possibly several Y via backtracking): f(x,Y) is interpreted as The set of Y such that: f(x) = Y.
Given a y, on can compute the X (possibly several X via backtracking): f(X,y) is interpreted as The set of X such that: f(X) = y.
Given an (x,y), on can compute the truth value: f(x,y) interpreted as true if (but not iff) f(x) == y.
(How many Prolog predicates are "well-programmed"? If there is a study about how many Prolog predicates written outside of the classroom can work bidirectionally I would like to know about it; my guess is most decay quickly into unidirectional functions, it's generally not worth the hassle of adding the edge cases and the test code to make predicates work bidirectionally)
The above works best if
f is bijective, i.e.: "no information is thrown away when computing in either direction"
the computation in both directions is tractable (having encryption work backwards is hard)
So, in this case:
delete(Element,ListWith,ListWithout) relates the three arguments (Element,ListWith,ListWithout) as follows:
ListWithout is ListWith without Element.
Note that "going forward" from (Element,ListWith) to ListWithout destroys information, namely the exact position of the deleted element, or even if there was one in the first place. BAD! NOT BIJECTIVE!
To make delete1/3 run backwards we just have to:
?- delete1(56,L,[a,b,c]).
L = [56, a, b, c] ;
L = [a, 56, b, c] ;
L = [a, b, 56, c] ;
L = [a, b, c, 56] ;
There are four solutions to the reverse deletion problem.
And the program misses one:
L = [a, b, c]
or even a few more:
L = [56, a, b, 56, c]
etc.
As you can see, it is important to retain information!

Efficient way of generating graphs from source nodes

Let's say I have a graph G, and around each node I have a few source nodes xs. I have to create a new graph G' using xs=[[a, b, c], [d, e], [f]] nodes such that they won't conflict with grey donuts as shown in the figure below.
Expected output G' is [[a, d, f], [a, e, f], [b, e, f]]; all others are conflicting a gray donut.
I currently solved it by taking all permutation and combination of nodes xs. This works for smaller numbers of nodes, but as my number of nodes xs increases with bigger graph G, it soon becomes 100s of thousands of combination to try.
I am looking for an efficient algorithm which will help me speed things up and get me all the non-conflicting graphs with a minimum number of iterations.
You have a fairly obvious minimum set of edges for each stage of your path. They are both necessary and sufficient for your solution. For notational convenience, I'll label the original graph X--Y--Z. Your corresponding G' nodes are
X a b c
Y d f
Z f
You do this in two steps:
For each edge in G, you must test for validity each possible edge in G`. This consists of
X--Y [a, b, c] X [d, e]
a total of 6 edges; 3 qualify: set XY = [a--d, a--e, b--d]
Y--Z [d, e] X [f]
a total of 2 edges; 2 qualify: set YZ = [d--f, e--f]
Now, you need only generate all combinations of XY x YZ where the Y nodes match. If you sort the lists by the "inner" node, you can do this very quickly as
[a--d, b--d] x [d--f]
[a--e] x [e--f]
Most current languages have modules to perform combinations for you, so the code will be short enough.
Does that get you going?

Prolog graph representation missing fact

I have a graph with edges in Prolog. I'm representing the graph as a set of prolog facts. Where e.g. s(a,b,2). = b is the successor of a. Here are my facts in prolog for this graph.
Facts:
s(a,b,2).
s(a,c,1).
s(b,e,4).
s(b,g,2).
s(c,d,1).
s(c,x,3).
s(x,g,1).
goal(g).
Am I missing a fact here? s(e,g,1).
Where g is the successor of e? Or does it even get searched on this node as "b" only has 2 branches "e" & "g". Can someone please explain this to me? Thanks
We can enumerate the graph for example in a breadth-first [Wiki] fashion, and thus determine that the edges are:
s(a, b, 2).
s(a, c, 1).
s(b, e, 4).
s(b, g, 2),
s(c, d, 1).
s(c, x, 3).
s(e, g, 1).
s(x, g, 1).
goal(g).
If we look at the original source code. The s(e, g, 1). part was missing.

Sliding tile puzzle with varying tile size using logic programming

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?.
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 clpfd 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 dcg):
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).

Prolog confusion. Can someone explain how minimal works?

I understand the code up to minimal but after that there's too many variables and I keep losing track of what each one is doing. If someone could explain it or do it with renamed variables that would be an amazing help, as I think this code will probably come up on my Christmas exam and I want to be able to explain what's going on.
road(a, b, 1).
road(b, c, 1).
road(a, c, 13).
road(d, a, 1).
/*Getting from A to B through a list of places R in N kms*/
route(A,B,R,N) :- travel(A,B,[A],Q,N), reverse(Q,R).
/*Travelling from A to B through P a list of towns B|P of distance L*/
travel(A,B,P,[B|P],Dist) :- road(A,B,Dist).
/*Travelling from A to B through Visited, on your Route R with distance Distance*/
/*Find if there is a road from A to b and store the distance. Make sure C is not equal to B*/
travel(A,B,Visited,R,Distance) :-
road(A,C,Dist), C \== B,
/*Make sure C is not in Visited to avoid infinite loop,
use recursion to find the full route and distance */
\+member(C,Visited), travel(C,B,[C|Visited],R,Dist1), Distance is Dist + Dist1.
/*Find the shortest route from A to B*/
shortest(A,B,R,N) :-
setof([Route,Dist],route(A,B,Route,Dist),Set),
Set = [_|_], minimal(Set,[R,N]).
minimal([F|R],M) :- min(R,F,M).
/*The shortest path*/
min([],M,M).
min([[P,L]|R],[_,M],Min):- L < M, !, min(R,[P,L],Min).
min([_|R],M,Min) :- min(R,M,Min).
since setof gives a sorted list of solutions, it's sufficient to produce solutions of appropriate 'shape', placing first the value you want to minimize: try
shortest(A,B,R,N) :-
setof((Dist,Route), route(A,B,Route,Dist), [(N,R)|_]).

Resources