Download
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% ECLiPSe library for solving "crossfigures" puzzles.
%
% "Crossfigures" puzzles correspond to problem 21 in the CSPLib.
% See www.csplib.org for more details.
%
% Particular instances can be found at thinks.com/crosswords/xfig.htm.
%
% This module written by Warwick Harvey, IC-Parc, wh@icparc.ic.ac.uk.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
:- module(crossfig).
:- export across/6, down/6, init_matrix/3, print_matrix/1.
:- export square/1, prime/1.
:- lib(fd).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% The problem is modelled using an array `Matrix' to represent the puzzle
% "board". A second array `Template' is used to indicate whether each
% element of `Matrix' should contain a digit or should be blank. This
% information can also be used to perform some integrity checks, to help
% catch errors in the expression of a problem.
%
% The multidigit numbers used in the "clues" (1 across, 7 down, etc.) are
% set up using the predicates `across/6' and `down/6', which relate these
% numbers to the digits in `Matrix'. Once these are all set up,
% `init_matrix/3' should be called to complete the initialisation of
% `Matrix', before the clue constraints are added.
%
% Also provided are a number of predicates which are useful for
% expressing clue constraints such as "A square number" and "A prime
% number".
%
% See one of the accompanying problem modules (cf*.pl) for an example of
% how it all works.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% across(Matrix, Template, Across, Len, Row, Col):
% Constrains `Across' to be equal to the number represented by the
% `Len' digits starting at position (Row, Col) of the array `Matrix'
% and proceeding across.
% `Template' is used for integrity checking, as well as for collecting
% information about which elements of `Matrix' should contain digits,
% and which should be empty.
%
across(Matrix, Template, Across, Len, Row, Col) :-
% Constrain `Across' to be equal to the corresponding digits.
(
for(I, Len-1, 0, -1),
fromto(1, Mult, NewMult, _),
fromto(0, SumIn, SumOut, Across),
param(Matrix, Row, Col)
do
Elem is Matrix[Row, Col + I],
Elem :: [0..9],
SumOut #= SumIn + Mult * Elem,
NewMult is Mult * 10
),
% Integrity checks.
dim(Template, [_Height, Width]),
(
Template[Row, Col .. Col + Len - 1] :: 1,
( Col > 1 -> Template[Row, Col - 1] :: 0 ; true ),
( Col + Len =< Width -> Template[Row, Col + Len] :: 0 ; true )
->
true
;
printf(error, "Crossfigure integrity violation adding "
"an across figure of length %d,%n"
"starting at (%d, %d)%n",
[Len, Row, Col]),
abort
).
%
% down(Matrix, Template, Down, Len, Row, Col):
% Constrains `Down' to be equal to the number represented by the
% `Len' digits starting at position (Row, Col) of the array `Matrix'
% and proceeding down.
% `Template' is used for integrity checking, as well as for collecting
% information about which elements of `Matrix' should contain digits,
% and which should be empty.
%
down(Matrix, Template, Down, Len, Row, Col) :-
% Constrain `Down' to be equal to the corresponding digits.
(
for(I, Len-1, 0, -1),
fromto(1, Mult, NewMult, _),
fromto(0, SumIn, SumOut, Down),
param(Matrix, Row, Col)
do
Elem is Matrix[Row + I, Col],
Elem :: [0..9],
SumOut #= SumIn + Mult * Elem,
NewMult is Mult * 10
),
% Integrity checks.
dim(Template, [Height, _Width]),
(
Template[Row .. Row + Len - 1, Col] :: 1,
( Row > 1 -> Template[Row - 1, Col] :: 0 ; true ),
( Row + Len =< Height -> Template[Row + Len, Col] :: 0 ; true )
->
true
;
printf(error, "Crossfigure integrity violation adding "
"a down figure of length %d,%n"
"starting at (%d, %d)%n",
[Len, Row, Col]),
abort
).
%
% init_matrix(Matrix, Template, Vars):
% Finishes the initialisation of `Matrix', returning a list of all
% the variables in it in `Vars'.
% `Template' is used to determine which elements of `Matrix' should be
% variables, and which ones should be blank. Blank elements are
% filled with a ` '.
%
init_matrix(Matrix, Template, Vars) :-
dim(Matrix, [Row, Col]),
(
for(I, 1, Row),
fromto([], Vars1, Vars4, Vars),
param(Matrix, Template, Col)
do
(
for(J, 1, Col),
fromto(Vars1, Vars2, Vars3, Vars4),
param(Matrix, Template, I)
do
T is Template[I, J],
Elem is Matrix[I, J],
( var(T) ->
T = 0
;
true
),
( T = 0 ->
Elem = ' ',
Vars3 = Vars2
;
Vars3 = [Elem | Vars2]
)
)
).
%
% print_matrix(Matrix):
% Prints `Matrix' in a readable format.
%
print_matrix(Matrix) :-
nl,
(
foreacharg(Row, Matrix)
do
write(' '),
(
foreacharg(Elem, Row)
do
write(Elem)
),
nl
).
%-------- Useful constraints for crossfigure puzzles --------%
%
% square(N):
% Constrains N to be a square number.
%
square(N) :-
N #= T * T.
%
% prime(N):
% Delays until N is ground, and then succeeds if and only if it is
% prime.
%
prime(N) :-
( nonvar(N) ->
is_prime_2(2, N)
;
suspend(prime(N), 2, N->inst)
).
is_prime_2(Q, N) :-
N mod Q =\= 0,
( Q * Q < N ->
Q1 is Q + 1,
is_prime_2(Q1, N)
;
true
).