Puzzle Utilities
The following predicates are used in the puzzle solutions.
Higher-order Predicates
unique_solution( +Goal )
holds when Goal has one ground solution. Operationally, Goal
may produce several solutions, ("don't care" non-deterministically), but
they must all be identical (==).
<syntaxhighlight lang="prolog">unique_solution( Goal ) :-
findall( Goal, Goal, [Solution|Solutions] ), same_solution( Solutions, Solution ), Solution = Goal.
same_solution( [], _Solution ). same_solution( [Solution0|Solutions], Solution ) :-
Solution0 == Solution, same_solution( Solutions, Solution ).</syntaxhighlight>
forall( +Enumerator, +Test )
is true if Enumerator and Test are goals and Test holds everywhere that Enumerator does. NB: forall/2 does not instantiate arguments further.
<syntaxhighlight lang="prolog">forall( Enumerator, Test ) :-
\+ (call(Enumerator), \+ call(Test)).</syntaxhighlight>
count_solutions( +Goal, ?Count )
is true if Count is the number of solutions for Goal. The solutions might not be distinct.
count_solutions/2 enumerates the possible solutions to Goal but does not instantiate Goal's arguments further.
<syntaxhighlight lang="prolog"> count_solutions( Goal, Count ) :-
findall( x, Goal, Xs ), length( Xs, Count ).
</syntaxhighlight>
Lists
member( ?Element, ?List )
holds when Element is a member of List.
<syntaxhighlight lang="prolog">member( H, [H|_] ). member( H, [_|T] ) :-
member( H, T ).</syntaxhighlight>
select( ?Element, ?List0, ?List1 )
is true if List1 is equal to List0 with Element removed.
<syntaxhighlight lang="prolog">select( H, [H|T], T ). select( Element, [H|T0], [H|T1] ) :-
select( Element, T0, T1 ).</syntaxhighlight>
memberchk( +Element, +List )
succeeds (once) if Element is a member of List.
<syntaxhighlight lang="prolog">memberchk( Element, List ) :-
member( Element, List ), !.</syntaxhighlight>
Arithmetic
between( +Lower, +Upper, ?Index )
is true if Lower =< Index =< Upper. Two valid cases are possible:
- Index is already instantiated to an integer, so the checks on order are applied (test).
- Index is a logical variable: a series of alternative solutions may be generated as the monotonic sequence of values between Lower and Upper (non-deterministic generator).
<syntaxhighlight lang="prolog">between( Lower, Upper, Index ) :-
integer( Lower ),
integer( Upper ),
Lower =< Upper,
( integer( Index ) -> % Case 1: "test"
Index >= Lower,
Index =< Upper
; var( Index ) -> % Case 2: "generate".
generate_between( Lower, Upper, Index )
).
generate_between( Lower, Upper, Index ) :-
( Lower =:= Upper ->
Index = Lower
; Index = Lower
; Next is Lower + 1,
Next =< Upper,
generate_between( Next, Upper, Index )
).</syntaxhighlight>
sum( +List, ?Sum )
holds when the List of numbers sum to Sum.
<syntaxhighlight lang="prolog">sum( [H|T], Sum ) :-
sum1( T, H, Sum ).
sum1( [], Sum, Sum ). sum1( [H|T], Sum0, Sum ):-
Sum1 is Sum0 + H, sum1( T, Sum1, Sum ).</syntaxhighlight>
Character Input/Output
put_chars( +Chars )
if Chars is a (possibly empty) list of character codes and the corresponding characters are written to the current output stream.
<syntaxhighlight lang="prolog">put_chars( [] ). put_chars( [Char|Chars] ) :-
put( Char ), put_chars( Chars ).</syntaxhighlight>
get_chars( ?Chars )
if Chars is a (possibly empty) list of character codes read from the current input stream.
<syntaxhighlight lang="prolog">get_chars( Input ) :-
get0( Char ),
( Char > -1 ->
Input = [Char|Chars],
get_chars( Chars )
; otherwise ->
Input = []
).</syntaxhighlight>
The code is available as plain text here.