I currently have to make some sort of Wumpus World implementation in SWI Prolog and give all possible paths over a board of size NxN, I have done several prolog tutorials but I can't figure how to solve this particular task in Prolog. I'm trying to get all possible paths for my agent to the gold and nothing else. It has to start from the initial position (X0, Y0).
I attach the code that I've managed to write so far. I have tried to do a simple DFS which sort of works but I struggle with the variable "parsing" to complete the code.
:- dynamic getAllPathsRec/2, agent/2, visited/2, visited/2.
gold(5,5).
worldSize(10).
agent(1,1).
getAllPaths :-
getAllPathsRec(1,1).
getAllPathsRec(X,Y) :-
format(X), format(Y), format('~n'),
gold(X1,Y1),
\+visited(X,Y),
assert(visited(X,Y)),
(X = X1, Y = Y1) -> print('Found GOLD');
move(_,X,Y).
move(right, X, Y) :-
X1 is X + 1,
X1 > 0 , X1 < 11,
getAllPathsRec(X1,Y).
move(left, X, Y) :-
X1 is X - 1,
X1 > 0 , X1 < 11,
getAllPathsRec(X1,Y).
move(up, X, Y) :-
Y1 is Y + 1,
Y1 > 0 , Y1 < 11,
getAllPathsRec(X,Y1).
move(down, X, Y) :-
Y1 is Y - 1,
Y1 > 0 , Y1 < 11,
getAllPathsRec(X,Y1).
I expect to find the gold in any possible way, ideally printing each path the algorithm has taken. Thank you in advance.
EDIT:
I've noticed that this solution has some efficiency problems for boards of enough size. It's being discussed here. I'll update the answer when we come up with a result.
Take care with assert/1 predicate, as it adds the fact to the knowledge base permanently and it's not undone while trying other combinations, so you won't be able to visit the same cell twice.
Instead of that, I approached it with an extra parameter V (that stands for visited), in which you can append the element treated in each exploration step. Also I stored the chosen directions in every step into a list L to print it when the target is found.
The or operator ; allows to not keep exploring the same path once the target is found and goes back to keep trying other combinations.
Notes:
If you face any use case where you can use assert/1, take care, because it's deprecated.
The _ variable it's not necessary in the move function as you can simply add 4 different "implementations" and just append the four directions.
As an advice use the facts or knowledge (a.k.a. World Size, Target position and Player position) as variables and don't hard code it. It'll be easier to debug and try different parameters.
Here you have the working code and some output example:
:- dynamic
getAllPathsRec/2,
agent/2,
visited/2.
gold(3, 3).
worldSize(5).
agent(1, 1).
getAllPaths :-
agent(X, Y),
getAllPathsRec(X, Y, [], []).
getAllPathsRec(X, Y, V, L) :-
hashPos(X, Y, H), \+member(H, V), append(V, [H], VP),
((gold(X, Y), print(L)) ; move(X, Y, VP, L)).
% Hash H from h(X, Y)
hashPos(X, Y, H) :- H is (X*100 + Y).
% Left
move(X, Y, V, L) :-
XP is X - 1, XP > 0,
append(L, [l], LP),
getAllPathsRec(XP, Y, V, LP).
% Right
move(X, Y, V, L) :-
XP is X + 1, worldSize(MS), XP =< MS,
append(L, [r], LP),
getAllPathsRec(XP, Y, V, LP).
% Up
move(X, Y, V, L) :-
YP is Y + 1, worldSize(MS), YP =< MS,
append(L, [u], LP),
getAllPathsRec(X, YP, V, LP).
% Down
move(X, Y, V, L) :-
YP is Y - 1, YP > 0,
append(L, [d], LP),
getAllPathsRec(X, YP, V, LP).
?- getAllPaths.
[r,r,r,r,u,l,l,l,l,u,r,r]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,r,d,l,l,d]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,r,d,l,d,l]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,r,d,d,l,l]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,r,d,d,l,u,l,d]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,d,l,d]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,d,r,d,l,l]
true ;
[r,r,r,r,u,l,l,l,l,u,r,u,l,u,r,r,r,d,d,l]
...
Related
Suppose, we have the following game:
There is a pair of numbers (x, y), 2 players are making moves. During the move a player can increase any number by 1 or multiply it by 2.
The player, who makes a move after which (x + y) >= 77 wins.
The initial position is (8, x), find the minimal x such as the second player wins in minimal number of turns.
This problem can be easily solved analytically: both players multiply x by 2 and we get the following inequality:
8 + 2*2*x >= 77 => 4*x >= 69 => x >= (69 / 4) => x >= 17,25
x = ceil(17,25)
x = 18
Now we tried to solve it using Prolog:
:- use_module(library(clpfd)).
top(77).
% possible moves for player
next_state(X1, X2, Y1, Y2) :- Y1 #= X1 + 1,
Y2 #= X2.
next_state(X1, X2, Y1, Y2) :- Y1 #= X1,
Y2 #= X2 + 1.
next_state(X1, X2, Y1, Y2) :- Y1 #= 2*X1,
Y2 #= X2.
next_state(X1, X2, Y1, Y2) :- Y1 #= X1,
Y2 #= 2*X2.
% winning pair
win(X1, X2) :- top(X),
X1 + X2 #>= X.
% we have a sequence of states
sequence_correct([[X1, X2]]) :- win(X1, X2).
sequence_correct([[X1, X2], [Y1, Y2] | T]) :- next_state(X1, X2, Y1, Y2),
sequence_correct([[Y1, Y2] | T]).
% find X such as there is a sequence of 3 states, and there is no Y such as
% Y < X => X is minimum
min(X) :- sequence_correct([[8, X], _, _]), \+ (sequence_correct([[8, Y], _, _]), Y #< X).
But unfortunately when we try to find minimal X, it fails:
?- min(X).
false.
?- min(18). % <- this is good
true.
?- min(17).
false.
?- min(19).
false.
What is wrong?
How to fix?
You are using (\+)/1 which explains:
?- min(X).
false.
No position is negative [X0,Y0] ins 0..sup. Assuming the game doesn't start in the winning position (X0+Y0 #< 77), only the last move is winning (X+Y #>= 77).
move_(s(X,Y), s(X0,Y0), s(X,Y)) :-
[X0,Y0] ins 0..sup,
X0+Y0 #< 77,
next_state(X0, Y0, X, Y).
moves([S0|Ss]) :-
foldl(move_, Ss, S0, s(X,Y)),
X+Y #>= 77.
min(Y) :-
Y0 in 0..77,
labeling([min], [Y0]),
moves([s(8,Y0),_,_]),
!, % commit to the minimum.
Y = Y0.
The search for the minimum is done with labeling([min], [Y0]).
Improved solution for any depth:
move_(s(P,X,Y), s(P0,X0,Y0), s(P,X,Y)) :-
P #= 1-P0,
X0+Y0 #< 77,
next_state(X0, Y0, X, Y).
min(Depth, s(P0,X0,Y0), s(P,X,Y)) :-
[X0,Y0] ins 0..sup,
X0+Y0 #< 77,
length(Ss, Depth),
foldl(move_, Ss, s(P0,X0,Y0), s(P,X,Y)),
X+Y #>= 77.
min(Y) :-
length(_, Depth),
Y0 in 0..77,
labeling([min], [Y0]),
min(Depth, s(0,8,Y0), s(P,_,_)), % Start with player 0. Player 1-P wins.
P = 0,
!, % commit to the minimum.
Y = Y0.
Without clpfd:
move(A, B, A1, B1) :-
( move_num(A, A1), B1 = B
; move_num(B, B1), A1 = A
).
move_num(N, N1) :-
( N1 is N + 1
; N1 is N * 2
).
won(A, B) :-
Tot is A + B,
% Fast integer comparison
Tot #>= 77.
turns(v(A, B), []) :-
% Second player has won
won(A, B).
turns(v(A, B), [state(first(A1,B1),second(A2,B2))|T]) :-
% First player
move(A, B, A1, B1),
\+ won(A1, B1),
% Second player
move(A1, B1, A2, B2),
turns(v(A2, B2), T).
?- time(findall(v(N, Len), (between(0, 20, N), once(( length(T, Len), turns(v(8, N), T) )) ), Vs)).
% 9,201 inferences, 0.001 CPU in 0.001 seconds (99% CPU, 17290920 Lips)
Vs = [v(0,2),v(1,2),v(2,2),v(3,2),v(4,2),v(5,2),v(6,2),v(7,2),v(8,2),v(9,2),v(10,2),v(11,2),v(12,2),v(13,2),v(14,2),v(15,2),v(16,2),v(17,2),v(18,1),v(19,1),v(20,1)].
... which shows that N=18 is the first to have length 1.
Could then use e.g. https://www.swi-prolog.org/pldoc/man?predicate=aggregate_all/3
Can improve efficiency by restricting the length of the turns to be best-so-far:
under_best_length(Len) :-
nb_getval(best_turns, Best),
( integer(Best) ->
Len is Best - 1
; Len = inf
).
best_length_update(Len, N) :-
nb_getval(best_turns, Best),
once(Best == undefined ; Len < Best),
nb_setval(best_turns, Len),
% Potentially useful
nb_setval(best_n, N).
Result in swi-prolog, annotated:
?- nb_setval(best_turns, undefined), between(-80, 80, N),
under_best_length(Best),
once(( between(1, Best, Len), length(T, Len), turns(v(8, N), T) )),
best_length_update(Len, N).
% The first solution becomes best-so-far
N = -80,
Best = inf,
Len = 3,
T = [state(first(9,-80),second(10,-80)),state(first(20,-80),second(40,-80)),state(first(80,-80),second(160,-80))] ;
% Narrowing down to length 2
N = -51,
Best = Len, Len = 2,
T = [state(first(16,-51),second(32,-51)),state(first(64,-51),second(128,-51))] ;
% Length 1 is first seen with N=18
N = 18,
Best = Len, Len = 1,
T = [state(first(8,36),second(8,72))] ;
% There is no solution with a length lower than 1
false.
Here is a one-liner to show the desired 18 answer:
?- time(( nb_setval(best_turns, undefined), between(0, 78, N),
under_best_length(Best),
once(( between(1, Best, Len), length(T, Len), turns(v(8, N), T) )),
best_length_update(Len, N), false ; nb_getval(best_n, BestN) )).
% 3,789 inferences, 0.001 CPU in 0.001 seconds (99% CPU, 5688933 Lips)
BestN = 18.
I want to find the minimum value of all permutations called from main predicate. For simplicity, I have removed my entire code, assume that I just want to find the minimum of head elements of all permutations.
appendlist([], X, X).
appendlist([T|H], X, [T|L]) :- appendlist(H, X, L).
permutation([], []).
permutation([X], [X]) :-!.
permutation([T|H], X) :- permutation(H, H1), appendlist(L1, L2, H1), appendlist(L1, [T], X1), appendlist(X1, L2, X).
%min(X, A, B) X is the minimum of A, B
min(X, X, Y) :- X =< Y.
min(Y, X, Y) :- Y < X.
solve([Head|Rest], Head):-
writeln([Head|Rest]).
main :-
Sort = [1, 2, 3],
PrvAns is 1000,
permutation(Sort, X),
solve(X, Here),
min(Ans, Here, PrvAns),
writeln(Ans),
PrvAns = Ans,
!, fail;
true,
writeln(PrvAns).
I want to calculate the minimum on fly for each permutation. Now, permute is working fine, and you can see that solve prints all permutations and even returns the first value Head properly, but PrvAns = Ans is wrong.
Expected output PrvAns : 1
I'm sorry if I didn't understand properly (and tell me, so I can help you), but, you mean something like this?
findMinHead(X,Z):-
findall( Y, ( permutation(X,[Y|_]) ), Z1 ),
min_list(Z1,Z).
in this predicate we find all the Y values where Y is the head of a permutation of X, put all that values in a bag, and then find the min.
The title kind of says it all. I'm looking to compute the GCD of two polynomials. Is there any way this can be done in Prolog? If so, what's a good starting point? Specifically, I'm having trouble with how to implement polynomial division using Prolog.
Edit to include example input and output:
Example input:
?- GCD(x^2 + 7x + 6, x2 − 5x − 6, X).
Example output:
X = x + 1.
Solution
On the off chance that someone else needs to do this, here's my final solution:
tail([_|Tail], Tail).
head([Head | _], Head).
norm(Old, N, New) :-
length(Tail, N),
append(New, Tail, Old).
norm(Old, N, []) :-
length(Old, L),
N > L.
mult_GCD(List, GCD) :- length(List, L),
L > 2, tail(List, Tail),
mult_GCD(Tail, GCD).
mult_GCD([H | T], GCD) :-
length(T, L),
L == 1, head(T, N),
gcd(H, N, GCD).
lead(List, List) :-
length(List, L),
L == 1.
lead([0 | Tail], Out) :-
!, lead(Tail, Out).
lead([Head | Tail], [Head | Tail]) :- Head =\= 0.
poly_deg([], 0).
poly_deg(F, D) :-
lead(F, O),
length(O, N),
D is N - 1.
poly_red([0], [0]).
poly_red(Poly, Out) :-
mult_GCD(Poly, GCD),
scal_div(Poly, GCD, Out).
poly_sub(Poly,[],Poly) :- Poly = [_|_].
poly_sub([],Poly,Poly).
poly_sub([P1_head|P1_rest], [P2_head|P2_rest], [PSub_head|PSub_rest]) :-
PSub_head is P1_head-P2_head,
poly_sub(P1_rest, P2_rest, PSub_rest).
scal_prod([],_Sc,[]).
scal_prod([Poly_head|Poly_rest], Sc, [Prod_head|Prod_rest]) :-
Prod_head is Poly_head*Sc,
scal_prod(Poly_rest, Sc, Prod_rest).
scal_div([],_,[]).
scal_div([Poly_head|Poly_rest], Sc, [Prod_head|Prod_rest]) :-
Prod_head is Poly_head / Sc,
scal_div(Poly_rest, Sc, Prod_rest).
poly_div(Num, Den, OutBuild, Out) :-
poly_deg(Num, X),
poly_deg(Den, Y),
X < Y,
Out = OutBuild.
poly_div(INum, IDen, OutBuild, Out) :-
lead(INum, [NumHead | NumTail]), lead(IDen, [DenHead | DenTail]),
Q is NumHead / DenHead,
append(OutBuild, [Q], Out1),
append([DenHead], DenTail, DenNorm), append([NumHead], NumTail, Num),
scal_prod(DenNorm, Q, DenXQ),
poly_sub(Num, DenXQ, N),
poly_div(N, IDen, Out1, Out).
poly_mod(Num, Den, Out) :-
poly_deg(Num, X), poly_deg(Den, Y),
X < Y,
lead(Num, Out1),
poly_red(Out1, Out2),
lead(Out2, Out).
poly_mod(INum, IDen, Out) :-
lead(INum, [NumHead | NumTail]), lead(IDen, [DenHead | DenTail]),
Q is NumHead / DenHead,
append([DenHead], DenTail, DenNorm), append([NumHead], NumTail, Num),
scal_prod(DenNorm, Q, DenXQ),
poly_sub(Num, DenXQ, N),
poly_mod(N, IDen, Out).
poly_gcd(X, Y, X):- poly_deg(Y, O), O == 0, !.
poly_gcd(Y, X, X):- poly_deg(Y, O), O == 0, !.
poly_gcd(X, Y, D):- poly_deg(X, Xd), poly_deg(Y, Yd), Xd > Yd, !, poly_mod(X, Y, Z), poly_gcd(Y, Z, D).
poly_gcd(X, Y, D):- poly_mod(Y, X, Z), poly_gcd(X, Z, D).
gcd(X, Y, Z) :-
X < 0, X > Y, !,
X1 is X - Y,
gcd(-X, Y, Z).
gcd(X, Y, Z) :-
Y < 0, Y >= X, !,
Y1 is Y - X,
gcd(X, -Y, Z).
gcd(X, 0, X).
gcd(0, Y, Y).
gcd(X, Y, Z) :-
X > Y, Y > 0,
X1 is X - Y,
gcd(Y, X1, Z).
gcd(X, Y, Z) :-
X =< Y, X > 0,
Y1 is Y - X,
gcd(X, Y1, Z).
gcd(X, Y, Z) :-
X > Y, Y < 0,
X1 is X + Y,
gcd(Y, X1, Z).
gcd(X, Y, Z) :-
X =< Y, X < 0,
Y1 is Y + X,
gcd(X, Y1, Z).
This answer is meant as a push in the right direction.
First, forget for a moment that you need to parse an expression like x^2 + 7x + 6; this isn't even a proper term in Prolog yet. If you tried to write it on the top level, you will get an error:
?- Expr = x^2 + 7x + 6.
ERROR: Syntax error: Operator expected
ERROR: Expr = x^2 +
ERROR: ** here **
ERROR: 7x + 6 .
Prolog doesn't know how to deal with the 7x you have there. Parsing the expression is a question of its own, and maybe it is easier if you assumed you have already parsed it and gotten a representation that looks for example like this:
[6, 7, 1]
Similarly, x^2 − 5x − 6 becomes:
[-6, -5, 1]
and to represent 0 you would use the empty list:
[]
Now, take a look at the algorithm at the Wikipedia page. It uses deg for the degree and lc for the leading coefficient. With the list representation above, you can define those as:
The degree is one less then the length of the list holding the coefficients.
poly_deg(F, D) :-
length(F, N),
D is N - 1.
The leading coefficient is the last element of the list.
poly_lc(F, C) :-
last(F, C).
You also need to be able to do simple arithmetic with polynomials. Using the definitions on the Wikipedia page, we see that for example adding [] and [1] should give you [1], multiplying [-2, 2] with [1, -3, 1] should give you [-2, 8, -8, 2]. A precursory search gave me this question here on Stackoverflow. Using the predicates defined there:
?- poly_prod([-2,2], [1, -3, 1], P).
P = [-2.0, 8.0, -8.0, 2] .
?- poly_sum([], [1], S).
S = [1].
From here on, it should be possible for you to try and implement polynomial division as outlined in the Wiki article I linked above. If you get into more trouble, you should edit your question or ask a new one.
I tried to write a code in Prolog for finding GCD (without using modulo)
can anyone tell me what's wrong with this program?
gcd(X,Y,Z):- X>=Y, X1=X-Y, gcd(X1,Y,Z).
gcd(X,Y,Z):- X<Y, X1=Y- X, gcd(X1,X,Z).
gcd(0,X,X):- X>0.
As to why the original implementation doesn't work, there are two reasons:
The predicate =/2 is for unification, not arithmetic assignment
The expression X1 = X - Y doesn't subtract Y from X and store the result in X1. Rather, it unifies X1 with the term, -(X,Y). If, for example, X=5 and Y=3, then the result would be, X1=5-3, not X1=2. The solution is to use is/2 which assigns evaluated arithmetic expressions: X1 is X - Y.
Other predicates, besides the base case predicate, successfully match the base case
The clause, gcd(0,X,X) :- X > 0. is a reasonable base case, but it is never attempted because the second clause (gcd(X,Y,Z):- X<Y,...) will always successfully match the same conditions first, leading to infinite recursion and a stack overflow.
One way to fix this is to move the base case to the first clause, and use a cut to avoid backtracking after it successfully executes:
gcd(0, X, X):- X > 0, !.
gcd(X, Y, Z):- X >= Y, X1 is X-Y, gcd(X1,Y,Z).
gcd(X, Y, Z):- X < Y, X1 is Y-X, gcd(X1,X,Z).
This will work now:
| ?- gcd(10,6,X).
X = 2 ? ;
(1 ms) no
| ?- gcd(10,5,X).
X = 5 ? ;
no
(NOTE: the "no" here means no more solutions found after finding the first one)
ADDENDUM
There are still a couple of remaining "gaps" in the above implementation. One is that it doesn't handle gcd(0, 0, R) gracefully (it overflows). Secondly, it doesn't handle negative values. One possible solution would be to elaborate these cases:
gcd(X, Y, Z) :-
X < 0, !,
gcd(-X, Y, Z).
gcd(X, Y, Z) :-
Y < 0, !,
gcd(X, -Y, Z).
gcd(X, 0, X) :- X > 0.
gcd(0, Y, Y) :- Y > 0.
gcd(X, Y, Z) :-
X > Y, Y > 0,
X1 is X - Y,
gcd(Y, X1, Z).
gcd(X, Y, Z) :-
X =< Y, X > 0,
Y1 is Y - X,
gcd(X, Y1, Z).
Try the following instead:
gcd(X, 0, X):- !.
gcd(0, X, X):- !.
gcd(X, Y, D):- X =< Y, !, Z is Y - X, gcd(X, Z, D).
gcd(X, Y, D):- gcd(Y, X, D).
Taken from rosettacode.org on GCD in all kinds of languages.
Prolog code for GCD
gcd(X,Y,G) :- X=Y, G=X.
gcd(X,Y,G) :- X<Y, Y1 is Y-X, gcd(X,Y1,G).
gcd(X,Y,G) :- X>Y ,gcd(Y,X,G).
?- gcd(24,16,G).
G = 8
gc(X,Y,Z):- (
X=0 -> (
Z is Y
);
Y=0 -> (
Z is X
);
X=Y -> (
Z is X
);
X>Y -> (
Y1 is X-Y,
gc(Y1,Y,Z)
);
X<Y->(
Y1 is Y-X,
gc(X,Y1,Z)
)
).
gcd(A,B,X):- B=0,X=A.
gcd(A,B,X):- A>B, gcd(B, A, X).
gcd(A,B,X) :- A<B, T is B mod A, gcd(A, T, X).
prolog answer is:-
gcd(X,0,X).
gcd(X,Y,R):-
Y>0,
X1 is X mod Y,
gcd(Y,X1,R).
Simple and Readable Prolog Code for GCD of Two Numbers using the Euclidean Algorithm.
gcd(A,B,X):- A=0,X=B. % base case
gcd(A,B,X):- B=0,X=A. % base case
gcd(A,B,X):- A>B, gcd(B, A, X).
gcd(A,B,X):- A<B, T is B mod A, gcd(A, T, X).
Query as follows:
gcd(147,210,GCD).
Output:
GCD = 21
This code worked.
gcd(X,X,X).
gcd(X,Y,D):-X<Y, Y1 is Y-X, gcd(X,Y1,D).
gcd(X,Y,D):-Y<X, gcd(Y,X,D).
I have build a code in prolog to find a series of legal moves in which the knight lands on each square of the chessboard(8x8) exactly once.
I have used a logic like below:
There 8 types of knight moves:
right 1 down 2
left 1 down 2
right 2 down 1
left 2 down 1
right 1 up 2
left 1 up 2
right 2 up 1
left 2 up 1
right 1 down 2 moves:
move(X,Y) :-
C_X is X mod 8,
R_X is X // 8,
C_Y is C_X + 1, % 1 right
C_Y < 8,
R_Y is R_X + 2, % 2 down
R_Y < 8,
Y is R_Y * 8 + C_Y,
Y >= 0,
X >= 0,
X < 64,
Y < 64.
And this is repeated for all 8 types of moves
The problem is that my code is not efficient, it takes too much steps to find the right path.
Does anyone know an efficient way of solving this problem?
To be able to solve 8x8 Knight's tour puzzle in a feasible amount of time Warnsdorff's rule is probably a must.
I've created a program in B-Prolog which solves the puzzle quite fast. If you need the program to be in some other Prolog - it's not too hard to translate it or just use some ideas from it.
knight_moves(X, Y, NewX, NewY) :-
( NewX is X - 1, NewY is Y - 2
; NewX is X - 1, NewY is Y + 2
; NewX is X + 1, NewY is Y - 2
; NewX is X + 1, NewY is Y + 2
; NewX is X - 2, NewY is Y - 1
; NewX is X - 2, NewY is Y + 1
; NewX is X + 2, NewY is Y - 1
; NewX is X + 2, NewY is Y + 1 ).
possible_knight_moves(R, C, X, Y, Visits, NewX, NewY) :-
knight_moves(X, Y, NewX, NewY),
NewX > 0, NewX =< R,
NewY > 0, NewY =< C,
\+ (NewX, NewY) in Visits.
possible_moves_count(R, C, X, Y, Visits, Count) :-
findall(_, possible_knight_moves(R, C, X, Y, Visits, _NewX, _NewY), Moves),
length(Moves, Count).
:- table warnsdorff(+,+,+,+,+,-,-,min).
warnsdorff(R, C, X, Y, Visits, NewX, NewY, Score) :-
possible_knight_moves(R, C, X, Y, Visits, NewX, NewY),
possible_moves_count(R, C, NewX, NewY, [(NewX, NewY) | Visits], Score).
knight(R, C, X, Y, Visits, Path) :-
length(Visits, L),
L =:= R * C - 1,
NewVisits = [(X, Y) | Visits],
reverse(NewVisits, Path).
knight(R, C, X, Y, Visits, Path) :-
length(Visits, L),
L < R * C - 1,
warnsdorff(R, C, X, Y, Visits, NewX, NewY, _Score),
NewVisits = [(X, Y) | Visits],
knight(R, C, NewX, NewY, NewVisits, Path).
| ?- time(knight(8, 8, 1, 1, [], Path)).
CPU time 0.0 seconds.
Path = [(1,1),(2,3),(1,5),(2,7),(4,8),(6,7),(8,8),(7,6),(6,8),(8,7),(7,5),(8,3),(7,1),(5,2),(3,1),(1,2),(2,4),(1,6),(2,8),(3,6),(1,7),(3,8),(5,7),(7,8),(8,6),(7,4),(8,2),(6,1),(7,3),(8,1),(6,2),(4,1),(2,2),(1,4),(2,6),(1,8),(3,7),(5,8),(7,7),(8,5),(6,6),(4,7),(3,5),(5,6),(6,4),(4,3),(5,5),(6,3),(5,1),(7,2),(8,4),(6,5),(4,4),(3,2),(5,3),(4,5),(3,3),(2,1),(1,3),(2,5),(4,6),(3,4),(4,2),(5,4)]
yes
Here is an answer set programming (ASP) solution. It can be used to find a first solution to a 24x24 in acceptable time and can be easily adapted to the 8x8 case. It uses Warnsdorff's rule as well, but is a little faster than a backward chaining solution:
Backward Chaining:
?- time(knight_tour((1,1), X)).
% Up 878 ms, GC 32 ms, Thread Cpu 859 ms (Current 10/30/18 20:55:28)
X = [(1,1),(3,2),(5,1),(7,2),(9,1),(11,2),(13,1),(15,2),(17,1), ...
Forward Chaining (With ASP Choice):
?- time(knight_tour((1,1), X)).
% Up 411 ms, GC 0 ms, Thread Cpu 406 ms (Current 10/28/18 20:45:05)
X = [(1,1),(3,2),(5,1),(7,2),(9,1),(11,2),(13,1),(15,2),(17,1), ...
The forward chaining code is faster, since it uses the forward store to check to see whether a move was already done or not. This is faster than using a member predicate for this check. The answer set programming code reads:
:- use_module(library(basic/lists)).
:- use_module(library(minimal/asp)).
knight_tour(Start, Solution) :-
post(go(Start, 1)),
findall(X, go(X,_), Solution).
choose(S) <= posted(go(X,N)), N \== 576,
findall(W-Y, (move(X, Y), weight(Y, X, W)), L),
keysort(L, R),
M is N+1,
strip_and_go(R, M, S).
strip_and_go([_-Y|L], M, [go(Y, M)|R]) :-
strip_and_go(L, M, R).
strip_and_go([], _, []).
weight(X, Z, N) :-
findall(Y, (move(X, Y), Z \== Y), L),
length(L, N).
move(X, Y) :-
knight_move(X, Y),
verify(Y),
\+ clause(go(Y, _), true).
The code uses the new module "asp" from Jekejeke Prolog. The full code with predicates knight_move/2 and verify/1 is on gist here. There one finds the backward chaining code as well so that one can compare the code side by side.