96 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Prolog
		
	
	
	
	
	
| % Utility Predicates
 | |
| 
 | |
| % The following predicates are used in the puzzle solutions. 
 | |
| % 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 (==). 
 | |
| 
 | |
| 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 ).
 | |
| 
 | |
| % forall( +Enumerator, +Test ) is true if Enumerator and Test are goals and Test holds everywhere
 | |
| % that Enumerator does. NB: does not further instantiate arguments.
 | |
| 
 | |
| %% forall( Enumerator, Test ) :-
 | |
| %% 	\+ (call(Enumerator), \+ call(Test)).
 | |
| 
 | |
| % member( ?Element, ?List ) holds when Element is a member of List. 
 | |
| member( H, [H|_] ).
 | |
| member( H, [_|T] ):-
 | |
| 	member( H, T ).
 | |
| 
 | |
| % select( ?Element, ?List0, ?List1 ) is true if List1 is equal to List1 with Element removed.
 | |
| 
 | |
| select( H, [H|T], T ).
 | |
| select( Element, [H|T0], [H|T1] ):-
 | |
| 	select( Element, T0, T1 ).
 | |
| 
 | |
| % memberchk( +Element, +List ) succeeds (once) if Element is a member of List. 
 | |
| memberchk( Element, List ):-
 | |
| 	member( Element, List ),
 | |
| 	!.
 | |
| 
 | |
| % 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 so a series of alternative solutions is generated as the
 | |
| %   monotonic sequence of values between Lower and Upper (non-deterministic generator).
 | |
| 
 | |
| %% 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 )
 | |
| 	).
 | |
| 
 | |
| % sum( +List, ?Sum ) holds when the List of numbers sum to Sum.
 | |
| 
 | |
| sum( [H|T], Sum ) :-
 | |
| 	sum1( T, H, Sum ).
 | |
| 
 | |
| sum1( [], Sum, Sum ).
 | |
| sum1( [H|T], Sum0, Sum ):-
 | |
| 	Sum1 is Sum0 + H,
 | |
| 	sum1( T, Sum1, Sum ).
 | |
| 
 | |
| % put_chars( +Chars ) if Chars is a (possibly empty) list of character codes and the
 | |
| % corresponding characters are written to the current output stream.
 | |
| 
 | |
| put_chars( [] ).
 | |
| put_chars( [Char|Chars] ) :-
 | |
| 	put( Char ),
 | |
| 	put_chars( Chars ).
 | |
| 
 | |
| % get_chars( ?Chars ) if Chars is a (possibly empty) list of character codes read
 | |
| % from the current input stream.
 | |
| 
 | |
| get_chars( Input ) :-
 | |
| 	get0( Char ),
 | |
| 	( Char > -1 ->
 | |
| 		Input = [Char|Chars],
 | |
| 		get_chars( Chars )
 | |
| 	; otherwise ->
 | |
| 		Input = []
 | |
| 	).
 | |
|    
 |