0

I've recently picked up prolog and am trying to make a program to find a solution for the famous puzzle Knight's Tour [found here]

Using the Warnsdorff algorithm i'm trying to find all the possible moves that can be made from a specific spot on the chess board and then make the move that has the least possible moves once it's made and then repeat the process, however I am having trouble finding said move.

Here is my code so far

possibleKnightMove(I, J, I1, J1) :- I1 is I+1, J1 is J+2.
possibleKnightMove(I, J, I1, J1) :- I1 is I+2, J1 is J+1.
possibleKnightMove(I, J, I1, J1) :- I1 is I+2, J1 is J-1.
possibleKnightMove(I, J, I1, J1) :- I1 is I+1, J1 is J-2.
possibleKnightMove(I, J, I1, J1) :- I1 is I-1, J1 is J-2.
possibleKnightMove(I, J, I1, J1) :- I1 is I-2, J1 is J+1.
possibleKnightMove(I, J, I1, J1) :- I1 is I-2, J1 is J-1.
possibleKnightMove(I, J, I1, J1) :- I1 is I-1, J1 is J+2.

possible_knight_moves(Rows, Columns, X, Y, Visited, NewX, NewY) :-
    possibleKnightMove(X, Y, NewX, NewY),
    NewX > 0, NewX =< Rows,
    NewY > 0, NewY =< Columns,
    \+ member([NewX,NewY], Visited).

possible_moves_count(Rows, Columns, X, Y, Visited, Count) :-
    findall(_, possible_knight_moves(Rows, Columns, X, Y, Visited, _NewX, _NewY), Moves),
    length(Moves, Count).

warnsdorff(Rows, Columns, X, Y, Visited, NewX, NewY, Score) :-
    possible_knight_moves(Rows, Columns, X, Y, Visited, NewX, NewY),
    possible_moves_count(Rows, Columns, NewX, NewY, [[NewX, NewY] | Visited], Score).

Since the number of possible moves is only counted after finding them all then my list is not sorted how I would need it to be.

for example with this input

warnsdorff(8,8,3,5,[[1,1],[2,3],[3,5]], NewX, NewY, Score).

the result should be

NewX = 4,
NewY = 7,
Score = 5

however I get

NewX = 1,
NewY = 4,
Score = 3

If anyone could help me get NewX and NewY with the minimum score that would be great

false
  • 10,264
  • 13
  • 101
  • 209
vega2015
  • 119
  • 3
  • 11
  • What query do you enter? – lurker Jun 07 '16 at 23:39
  • sorry I forgot to mention this, I will edit my question – vega2015 Jun 08 '16 at 00:04
  • What part of your code would you say is expected to enforce that the `Score` be minimum? Also, I'm not sure the code you show is the code you ran. What you show yields an instantiation error with that query. – lurker Jun 08 '16 at 01:13
  • I recall reading the findall sorts the resulting list in witch it stores all the elements that comply with goal, though if this is not the case I´m not sure on how to fix this problem on my own. – vega2015 Jun 08 '16 at 01:34
  • You have `findall/3` confused with `setof/3`. `setof/3` will sort the list and eliminate duplicate elements. `findall/3` just collects the solutions to the goal in the order that they're discovered. But your use of `findall/3` doesn't collect anything but anonymous variables (first argument is `_`). It only counts how many solutions. Is that what you intended? – lurker Jun 08 '16 at 01:35
  • 1
    yes that was the intention, my query actually means if i'm on the (3,5) space witch one out of all the possible moves from this space will have the least possible moves if it is made, so the empty variables actually each represent a move that can be made from this possible move, what i'm trying to get is the x,y that result in the least number of these empty varibles – vega2015 Jun 08 '16 at 01:45
  • Then the fact that `findall/3` doesn't sort isn't relevant in your case, right? If it's only used for counting how many solutions you have to the goal. If it sorted, you'd only be sorting a list of anonymous variables. – lurker Jun 08 '16 at 01:48
  • I see what you are getting at, and yes I did miss this initially, so yes you are right, this isn't relevant, what I am actually asking is who do I sort out this list once I have counted the possible solutions, I will edit the question right now, thank you. – vega2015 Jun 08 '16 at 01:54

1 Answers1

0

A good solution is to represent all possible moves as pairs N-Spot where (for example):

  • N is the number of moves that are still possible from Spot
  • Spot is a place we can move to.

On such a list, you can use keysort/2 to sort the list such that the first element of the pairs are in non-decreasing order. For example, the first element of this list will be the spot that is most constrained in terms of further moves.

You are already quite close to the solution. I suggest you first focus an assessing a single possible move, in terms of a predicate like spot_freedom(S, F) that computes, for a spot S the degrees of freedom F (counting the number of moves that are still possible from S).

Then, you can simply do:

findall(F-S, spot_freedom(S, F), SFs0),
keysort(SFs0, SFs)

and have, in SFs the keysorted list of candidate spots. You can then select (for example) the first element of this list, or use:

member(_-Target, SFs)

to try the available spots in increasing order of freedom on backtracking.

Note that you will likely need additional arguments for spot_freedom, such as the history of moves already made, to detect which spots are already occupied. I leave figuring this out as an exercise.

mat
  • 40,498
  • 3
  • 51
  • 78
  • Thank you, I hadn't thought of using pairs mainly because I am still new to prolog and had no idea they existed, I will try your suggestion and let you know if it ends up working out . – vega2015 Jun 11 '16 at 06:55