alpar@1
|
1 |
/* Numbrix, Number Placement Puzzle */
|
alpar@1
|
2 |
|
alpar@1
|
3 |
/* Written in GNU MathProg by Robert Wood <rwood@targus.com> */
|
alpar@1
|
4 |
|
alpar@1
|
5 |
/* Numbrix is a logic-based number-placement puzzle.[1]
|
alpar@1
|
6 |
* The objective is to fill the grid so that each cell contains
|
alpar@1
|
7 |
* digits in sequential order taking a horizontal or vertical
|
alpar@1
|
8 |
* path; diagonal paths are not allowed. The puzzle setter
|
alpar@1
|
9 |
* provides a grid often with the outer most cells completed.
|
alpar@1
|
10 |
*
|
alpar@1
|
11 |
* Completed Numbrix puzzles are usually a square of numbers
|
alpar@1
|
12 |
* in order from 1 to 64 (8x8 grid) or from 1 to 81 (9x9 grid),
|
alpar@1
|
13 |
* following a continuous path in sequence.
|
alpar@1
|
14 |
*
|
alpar@1
|
15 |
* The modern puzzle was invented by Marilyn vos Savant in 2008
|
alpar@1
|
16 |
* and published by Parade Magazine under the name "Numbrix",
|
alpar@1
|
17 |
* near her weekly Ask Marilyn article.
|
alpar@1
|
18 |
*
|
alpar@1
|
19 |
* http://en.wikipedia.org/wiki/Numbrix */
|
alpar@1
|
20 |
|
alpar@1
|
21 |
set I := {1..9};
|
alpar@1
|
22 |
set J := {1..9};
|
alpar@1
|
23 |
set VALS := {1..81};
|
alpar@1
|
24 |
|
alpar@1
|
25 |
param givens{I, J}, integer, >= 0, <= 81, default 0;
|
alpar@1
|
26 |
/* the "givens" */
|
alpar@1
|
27 |
|
alpar@1
|
28 |
param neighbors{i in I,j in J, i2 in I, j2 in J} , binary :=
|
alpar@1
|
29 |
(if abs(i - i2) + abs(j -j2) == 1 then
|
alpar@1
|
30 |
1
|
alpar@1
|
31 |
else
|
alpar@1
|
32 |
0
|
alpar@1
|
33 |
);
|
alpar@1
|
34 |
/* defines which spots are the boards are neighbors */
|
alpar@1
|
35 |
|
alpar@1
|
36 |
var x{i in I, j in J, k in VALS}, binary;
|
alpar@1
|
37 |
/* x[i,j,k] = 1 means cell [i,j] is assigned number k */
|
alpar@1
|
38 |
|
alpar@1
|
39 |
s.t. fa{i in I, j in J, k in VALS: givens[i,j] != 0}:
|
alpar@1
|
40 |
x[i,j,k] = (if givens[i,j] = k then 1 else 0);
|
alpar@1
|
41 |
/* assign pre-defined numbers using the "givens" */
|
alpar@1
|
42 |
|
alpar@1
|
43 |
s.t. fb{i in I, j in J}: sum{k in VALS} x[i,j,k] = 1;
|
alpar@1
|
44 |
/* each cell must be assigned exactly one number */
|
alpar@1
|
45 |
|
alpar@1
|
46 |
s.t. singleNum {k in VALS}: sum{i in I, j in J} x[i,j,k] = 1;
|
alpar@1
|
47 |
/* a value can only occur once */
|
alpar@1
|
48 |
|
alpar@1
|
49 |
s.t. neighborContraint {i in I, j in J, k in 1..80}:
|
alpar@1
|
50 |
x[i,j,k] <= sum{i2 in I, j2 in J} x[i2,j2,k+1] * neighbors[i,j,i2,j2];
|
alpar@1
|
51 |
/* each cell must have a neighbor with the next higher value */
|
alpar@1
|
52 |
|
alpar@1
|
53 |
|
alpar@1
|
54 |
/* there is no need for an objective function here */
|
alpar@1
|
55 |
|
alpar@1
|
56 |
|
alpar@1
|
57 |
solve;
|
alpar@1
|
58 |
|
alpar@1
|
59 |
for {i in I}
|
alpar@1
|
60 |
{ for {0..0: i = 1 or i = 4 or i = 7}
|
alpar@1
|
61 |
printf " +----------+----------+----------+\n";
|
alpar@1
|
62 |
for {j in J}
|
alpar@1
|
63 |
{ for {0..0: j = 1 or j = 4 or j = 7} printf(" |");
|
alpar@1
|
64 |
printf " %2d", sum{k in VALS} x[i,j,k] * k;
|
alpar@1
|
65 |
for {0..0: j = 9} printf(" |\n");
|
alpar@1
|
66 |
}
|
alpar@1
|
67 |
for {0..0: i = 9}
|
alpar@1
|
68 |
printf " +----------+----------+----------+\n";
|
alpar@1
|
69 |
}
|
alpar@1
|
70 |
|
alpar@1
|
71 |
data;
|
alpar@1
|
72 |
|
alpar@1
|
73 |
param givens : 1 2 3 4 5 6 7 8 9 :=
|
alpar@1
|
74 |
1 . . . . . . . . .
|
alpar@1
|
75 |
2 . 11 12 15 18 21 62 61 .
|
alpar@1
|
76 |
3 . 6 . . . . . 60 .
|
alpar@1
|
77 |
4 . 33 . . . . . 57 .
|
alpar@1
|
78 |
5 . 32 . . . . . 56 .
|
alpar@1
|
79 |
6 . 37 . . . . . 73 .
|
alpar@1
|
80 |
7 . 38 . . . . . 72 .
|
alpar@1
|
81 |
8 . 43 44 47 48 51 76 77 .
|
alpar@1
|
82 |
9 . . . . . . . . . ;
|
alpar@1
|
83 |
|
alpar@1
|
84 |
end;
|