In the code given below, there is the
! (cut) that prunes the choice point for efficiency. I am pretty certain that the
reverse predicate and the
agent_do_moves predicate are essential.
solve_task_a(Task,[b(0,0,P)],,R,Cost,_NewPos),!, % prune choice point for efficiency
Best How To :
The cut in above examples has the following effect:
Ideally, it commits the search which might happen within
solve_task_a/6 to the first answer found. This frees resources for finding further answers which improves space consumption.
However, at the same time, it might also hide further answers to
agent_current_position/2. Of course, it does not make much sense to have further answers for this goal, but it might be an error that happens to sleep for a while, only to become active but still undiscovered in the worst possible situation.
For this reason, it would be preferable to write instead of the cut
once( solve_task_a( ... ) ),
This limits the scope precisely to what you want to express.
But this is not the only possible source of problems. I see this variable
Cost. Will it be instantiated when you call
solve_task(Task, Cost) or not? I could do a lot of guessing here. But at least this variable might influence the answer Prolog will commit to. So
solve_task(Task, 99) and
solve_task(Task, Cost), Cost = 99 might produce different answers. In fact, the latter might even fail. Predicates that have such problems are said to lack steadfastness.
To illustrate how steadfastness is easily lost in such a situation consider this (runnable) sketch of your (already improved) program:
solve_task_a(_, _, _, _, 20, _).
solve_task_a(_, _, _, _, 30, _).
?- solve_task(a, Cost).
Cost = 20.
?- solve_task(a, 30).
?- solve_task(a, Cost), Cost = 30.
There would be an easy way out of this problem by cleanly testing variable
Cost >= 0 which produces an instantiation error should
Cost be an uninstantiated variable. But if you want (as you indicate in your comment) to determine the cost, you need to put it like so:
CostX = Cost
In this manner we can be sure that
Cost cannot influence the outcome of
solve_task_a/6 (euh - provided there is no aliasing between
Task - but let's assume that for the moment). One says also that output unifications are put behind the commit.
Many people will tell you that such extra care is not needed, as you will never use
solve_task(Task, Cost) with a given cost. That might be the case, but are you sure you will remember it? And are you sure the source code will remember it (without any dynamic check)? Such implicit assumptions easily accumulate to a degree were your mental capacities are overburdened.
There is not always an easy way out. But quite often it is possible to stick to logical purity logical-purity. In that case, you do not have to remember any such assumptions.
In any case, I would recommend that you do not go into these parts of Prolog for the moment. Rather stick to successor-arithmetics, clpfd, and other clean, monotonic programs preserving logical-purity. There is a lot to learn!