Peaceful chess queen armies: Difference between revisions
Content added Content deleted
Line 309: | Line 309: | ||
=={{header|ATS}}== |
=={{header|ATS}}== |
||
{{trans|Scheme}} |
{{trans|Scheme}} |
||
<lang ats>(********************************************************************) |
|||
#define ATS_DYNLOADFLAG 0 |
|||
#include "share/atspre_define.hats" |
|||
#include "share/atspre_staload.hats" |
|||
staload UN = "prelude/SATS/unsafe.sats" |
|||
#define NIL list_vt_nil () |
|||
#define :: list_vt_cons |
|||
#ifndef NDEBUG #then |
|||
(* Safety is relatively unimportant in this program. |
|||
Therefore I have made it so you can put ‘-DATS NDEBUG=1’ on |
|||
your patscc command line, to skip some assertloc tests. *) |
|||
#define NDEBUG 0 |
|||
#endif |
|||
(********************************************************************) |
|||
#define EMPTY 0 |
|||
#define BLACK 1 |
|||
#define WHITE ~1 |
|||
stadef is_color (c : int) : bool = (~1 <= c && c <= 1) |
|||
stadef reverse_color (c : int) : int = ~c |
|||
typedef color_t (tk : tkind, c : int) = |
|||
[is_color c] |
|||
g1int (tk, c) |
|||
typedef color_t (tk : tkind) = |
|||
[c : int | is_color c] |
|||
g1int (tk, c) |
|||
fn {tk : tkind} |
|||
reverse_color {c : int | is_color c} |
|||
(c : g1int (tk, c)) :<> |
|||
[c_rev : int | is_color c_rev; |
|||
c_rev == reverse_color c] |
|||
g1int (tk, c_rev) = |
|||
(* This template is a fancy way to say ‘minus’. *) |
|||
~c |
|||
(********************************************************************) |
|||
(* Matrix indices will run from 0..n-1 rather than 1..n. *) |
|||
#define SIDE_MAX 16 (* The maximum side size. For |
|||
efficiency, please make it a |
|||
power of two. *) |
|||
#define BOARD_SIZE 256 (* The storage size for a board. *) |
|||
prval _ = prop_verify {SIDE_MAX * SIDE_MAX == BOARD_SIZE} () |
|||
fn {tk : tkind} |
|||
row_index {k : int | 0 <= k; k < BOARD_SIZE} |
|||
(k : g1int (tk, k)) :<> |
|||
[i : int | 0 <= i; i < SIDE_MAX] |
|||
g1int (tk, i) = |
|||
(* Let the C compiler convert this to bitmasking. *) |
|||
g1int_nmod (k, g1i2i SIDE_MAX) |
|||
fn {tk : tkind} |
|||
column_index {k : int | 0 <= k; k < BOARD_SIZE} |
|||
(k : g1int (tk, k)) :<> |
|||
[i : int | 0 <= i; i < SIDE_MAX] |
|||
g1int (tk, i) = |
|||
(* Let the C compiler convert this to a shift. *) |
|||
k / g1i2i SIDE_MAX |
|||
fn {tk : tkind} |
|||
storage_index {i, j : int | 0 <= i; i < SIDE_MAX; |
|||
0 <= j; j < SIDE_MAX} |
|||
(i : g1int (tk, i), |
|||
j : g1int (tk, j)) :<> |
|||
[k : int | 0 <= k; k < BOARD_SIZE] |
|||
g1int (tk, k) = |
|||
(* Let the C compiler convert this to a shift and add. *) |
|||
i + (j * g1i2i SIDE_MAX) |
|||
(********************************************************************) |
|||
extern fn {tk_index : tkind} |
|||
test_equiv$reindex_i |
|||
{i, j : int | 0 <= i; 0 <= j} |
|||
{n : int | 0 <= n; n <= SIDE_MAX; |
|||
i < n; j < n} |
|||
(i : g1int (tk_index, i), |
|||
j : g1int (tk_index, j), |
|||
n : g1int (tk_index, n)) :<> |
|||
[i1 : int | 0 <= i1; i1 < SIDE_MAX] |
|||
g1int (tk_index, i1) |
|||
extern fn {tk_index : tkind} |
|||
test_equiv$reindex_j |
|||
{i, j : int | 0 <= i; 0 <= j} |
|||
{n : int | 0 <= n; n <= SIDE_MAX; |
|||
i < n; j < n} |
|||
(i : g1int (tk_index, i), |
|||
j : g1int (tk_index, j), |
|||
n : g1int (tk_index, n)) :<> |
|||
[j1 : int | 0 <= j1; j1 < SIDE_MAX] |
|||
g1int (tk_index, j1) |
|||
extern fn {tk_color : tkind} |
|||
test_equiv$recolor |
|||
{c : int | is_color c} |
|||
(c : g1int (tk_color, c)) :<> |
|||
[c1 : int | is_color c1] |
|||
g1int (tk_color, c1) |
|||
fn {tk_index, tk_color : tkind} |
|||
test_equiv {n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
let |
|||
macdef reindex_i = test_equiv$reindex_i<tk_index> |
|||
macdef reindex_j = test_equiv$reindex_j<tk_index> |
|||
macdef recolor = test_equiv$recolor<tk_color> |
|||
fun |
|||
loopj {j : int | ~1 <= j; j < n} .<j + 1>. |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n), |
|||
j : g1int (tk_index, j)) : |
|||
bool = |
|||
if j < g1i2i 0 then |
|||
true |
|||
else |
|||
let |
|||
fun loopi {i : int | ~1 <= i; i < n} .<i + 1>. |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n), |
|||
j : g1int (tk_index, j), |
|||
i : g1int (tk_index, i)) : |
|||
bool = |
|||
if i < g1i2i 0 then |
|||
true |
|||
else |
|||
let |
|||
val ka = storage_index<tk_index> (i, j) |
|||
val color_a = a[ka] |
|||
val i1 = test_equiv$reindex_i<tk_index> (i, j, n) |
|||
val j1 = test_equiv$reindex_j<tk_index> (i, j, n) |
|||
val kb = storage_index<tk_index> (i1, j1) |
|||
val color_b = recolor b[kb] |
|||
in |
|||
if color_a = color_b then |
|||
loopi (a, b, n, j, pred i) |
|||
else |
|||
false |
|||
end |
|||
in |
|||
if loopi (a, b, n, j, g1i2i (pred n)) then |
|||
loopj (a, b, n, pred j) |
|||
else |
|||
false |
|||
end |
|||
in |
|||
loopj (a, b, n, g1i2i (pred n)) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
test_equiv_rotate0 |
|||
{n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
let |
|||
(* No rotations or reflections. *) |
|||
implement |
|||
test_equiv$reindex_i<tk_index> (i, j, n) = i |
|||
implement |
|||
test_equiv$reindex_j<tk_index> (i, j, n) = j |
|||
in |
|||
test_equiv<tk_index, tk_color> (a, b, n) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
test_equiv_rotate90 |
|||
{n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
let |
|||
(* Matrix rotation counterclockwise by 90 degrees. *) |
|||
implement |
|||
test_equiv$reindex_i<tk_index> {i, j} {n} (i, j, n) = pred n - j |
|||
implement |
|||
test_equiv$reindex_j<tk_index> (i, j, n) = i |
|||
in |
|||
test_equiv<tk_index, tk_color> (a, b, n) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
test_equiv_rotate180 |
|||
{n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
let |
|||
(* Matrix rotation by 180 degrees. *) |
|||
implement |
|||
test_equiv$reindex_i<tk_index> {i, j} {n} (i, j, n) = pred n - i |
|||
implement |
|||
test_equiv$reindex_j<tk_index> {i, j} {n} (i, j, n) = pred n - j |
|||
in |
|||
test_equiv<tk_index, tk_color> (a, b, n) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
test_equiv_rotate270 |
|||
{n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
let |
|||
(* Matrix rotation counterclockwise by 270 degrees. *) |
|||
implement |
|||
test_equiv$reindex_i<tk_index> (i, j, n) = j |
|||
implement |
|||
test_equiv$reindex_j<tk_index> {i, j} {n} (i, j, n) = pred n - i |
|||
in |
|||
test_equiv<tk_index, tk_color> (a, b, n) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
test_equiv_reflecti |
|||
{n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
let |
|||
(* Reverse the order of the rows. *) |
|||
implement |
|||
test_equiv$reindex_i<tk_index> {i, j} {n} (i, j, n) = pred n - i |
|||
implement |
|||
test_equiv$reindex_j<tk_index> (i, j, n) = j |
|||
in |
|||
test_equiv<tk_index, tk_color> (a, b, n) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
test_equiv_reflectj |
|||
{n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
let |
|||
(* Reverse the order of the columns. *) |
|||
implement |
|||
test_equiv$reindex_i<tk_index> (i, j, n) = i |
|||
implement |
|||
test_equiv$reindex_j<tk_index> {i, j} {n} (i, j, n) = pred n - j |
|||
in |
|||
test_equiv<tk_index, tk_color> (a, b, n) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
test_equiv_reflect_diag_down |
|||
{n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
let |
|||
(* Transpose the matrix around its main diagonal. *) |
|||
implement |
|||
test_equiv$reindex_i<tk_index> (i, j, n) = j |
|||
implement |
|||
test_equiv$reindex_j<tk_index> (i, j, n) = i |
|||
in |
|||
test_equiv<tk_index, tk_color> (a, b, n) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
test_equiv_reflect_diag_up |
|||
{n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
let |
|||
(* Transpose the matrix around its main skew diagonal. *) |
|||
implement |
|||
test_equiv$reindex_i<tk_index> {i, j} {n} (i, j, n) = pred n - j |
|||
implement |
|||
test_equiv$reindex_j<tk_index> {i, j} {n} (i, j, n) = pred n - i |
|||
in |
|||
test_equiv<tk_index, tk_color> (a, b, n) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
board_equiv {n : int | 0 <= n; n <= SIDE_MAX} |
|||
(a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
b : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n), |
|||
rotation_equiv_classes : bool) : |
|||
bool = |
|||
let |
|||
(* Leave the colors unchanged. *) |
|||
implement test_equiv$recolor<tk_color> (c) = c |
|||
(* Test without rotations or reflections. *) |
|||
val equiv = test_equiv_rotate0<tk_index, tk_color> (a, b, n) |
|||
in |
|||
if ~rotation_equiv_classes then |
|||
equiv |
|||
else |
|||
let |
|||
(* Leave the colors unchanged. *) |
|||
implement test_equiv$recolor<tk_color> (c) = c |
|||
val equiv = |
|||
(equiv || |
|||
test_equiv_rotate90<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_rotate180<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_rotate270<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_reflecti<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_reflectj<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_reflect_diag_down<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_reflect_diag_up<tk_index, tk_color> (a, b, n)) |
|||
(* Reverse the colors of b in each test. *) |
|||
implement test_equiv$recolor<tk_color> (c) = reverse_color c |
|||
val equiv = |
|||
(equiv || |
|||
test_equiv_rotate0<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_rotate90<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_rotate180<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_rotate270<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_reflecti<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_reflectj<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_reflect_diag_down<tk_index, tk_color> (a, b, n) || |
|||
test_equiv_reflect_diag_up<tk_index, tk_color> (a, b, n)) |
|||
in |
|||
equiv |
|||
end |
|||
end |
|||
(********************************************************************) |
|||
fn {tk_index : tkind} |
|||
fprint_rule {n : int | 0 <= n; n <= SIDE_MAX} |
|||
(f : FILEref, |
|||
n : g1int (tk_index, n)) : |
|||
void = |
|||
let |
|||
fun |
|||
loop {j : int | 0 <= j; j <= n} .<n - j>. |
|||
(j : g1int (tk_index, j)) : |
|||
void = |
|||
if j <> n then |
|||
begin |
|||
fileref_puts (f, "----+"); |
|||
loop (succ j) |
|||
end |
|||
in |
|||
fileref_puts (f, "+"); |
|||
loop (g1i2i 0) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
fprint_board {n : int | 0 <= n; n <= SIDE_MAX} |
|||
(f : FILEref, |
|||
a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n)) : |
|||
void = |
|||
if n <> 0 then |
|||
let |
|||
fun |
|||
loopi {i : int | ~1 <= i; i < n} .<i + 1>. |
|||
(f : FILEref, |
|||
a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n), |
|||
i : g1int (tk_index, i)) : |
|||
void = |
|||
if i <> ~1 then |
|||
let |
|||
fun |
|||
loopj {j : int | 0 <= j; j <= n} .<n - j>. |
|||
(f : FILEref, |
|||
a : &(@[color_t tk_color][BOARD_SIZE]), |
|||
n : g1int (tk_index, n), |
|||
i : g1int (tk_index, i), |
|||
j : g1int (tk_index, j)) : |
|||
void = |
|||
if j <> n then |
|||
let |
|||
val k = storage_index<tk_index> (i, j) |
|||
val color = a[k] |
|||
val representation = |
|||
if color = g1i2i BLACK then |
|||
"| B " |
|||
else if color = g1i2i WHITE then |
|||
"| W " |
|||
else |
|||
"| " |
|||
in |
|||
fileref_puts (f, representation); |
|||
loopj (f, a, n, i, succ j) |
|||
end |
|||
in |
|||
fileref_puts (f, "\n"); |
|||
loopj (f, a, n, i, g1i2i 0); |
|||
fileref_puts (f, "|\n"); |
|||
fprint_rule (f, n); |
|||
loopi (f, a, n, pred i) |
|||
end |
|||
in |
|||
fprint_rule (f, n); |
|||
loopi (f, a, n, pred n) |
|||
end |
|||
(********************************************************************) |
|||
(* M2_MAX equals the maximum number of queens of either color. |
|||
Thus it is the maximum of 2*m, where m is the number of queens |
|||
in an army. *) |
|||
#define M2_MAX BOARD_SIZE |
|||
(* The even-index queens are BLACK, the odd-index queens are WHITE. *) |
|||
vtypedef board_record_vt (tk_color : tkind, |
|||
p : addr) = |
|||
@{ |
|||
pf = @[color_t tk_color][BOARD_SIZE] @ p, |
|||
pfgc = mfree_gc_v p | |
|||
p = ptr p |
|||
} |
|||
vtypedef board_record_vt (tk_color : tkind) = |
|||
[p : addr | null < p] |
|||
board_record_vt (tk_color, p) |
|||
vtypedef board_record_list_vt (tk_color : tkind, |
|||
n : int) = |
|||
list_vt (board_record_vt tk_color, n) |
|||
vtypedef board_record_list_vt (tk_color : tkind) = |
|||
[n : int] |
|||
board_record_list_vt (tk_color, n) |
|||
fn |
|||
board_record_vt_free |
|||
{tk_color : tkind} |
|||
{p : addr} |
|||
(record : board_record_vt (tk_color, p)) : |
|||
void = |
|||
let |
|||
val @{ |
|||
pf = pf, |
|||
pfgc = pfgc | |
|||
p = p |
|||
} = record |
|||
in |
|||
array_ptr_free (pf, pfgc | p) |
|||
end |
|||
overload free with board_record_vt_free |
|||
fn |
|||
board_record_list_vt_free |
|||
{tk_color : tkind} |
|||
{n : int} |
|||
(lst : board_record_list_vt (tk_color, n)) : |
|||
void = |
|||
let |
|||
fun |
|||
loop {n : int | 0 <= n} .<n>. |
|||
(lst : board_record_list_vt (tk_color, n)) : |
|||
void = |
|||
case+ lst of |
|||
| ~ NIL => () |
|||
| ~ head :: tail => |
|||
begin |
|||
free head; |
|||
loop tail |
|||
end |
|||
prval _ = lemma_list_vt_param lst |
|||
in |
|||
loop lst |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
any_board_equiv {n : int | 0 <= n; n <= SIDE_MAX} |
|||
(board : &(@[color_t tk_color][BOARD_SIZE]), |
|||
lst : !board_record_list_vt tk_color, |
|||
n : g1int (tk_index, n), |
|||
rotation_equiv_classes : bool) : |
|||
bool = |
|||
let |
|||
macdef board_equiv = board_equiv<tk_index, tk_color> |
|||
fun |
|||
loop {k : int | 0 <= k} .<k>. |
|||
(board : &(@[color_t tk_color][BOARD_SIZE]), |
|||
lst : !board_record_list_vt (tk_color, k), |
|||
n : g1int (tk_index, n)) : |
|||
bool = |
|||
case+ lst of |
|||
| NIL => false |
|||
| head :: tail => |
|||
if board_equiv (!(head.p), board, n, |
|||
rotation_equiv_classes) then |
|||
true |
|||
else |
|||
loop (board, tail, n) |
|||
prval _ = lemma_list_vt_param lst |
|||
in |
|||
loop (board, lst, n) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
queens_to_board |
|||
{count : int | 0 <= count; count <= M2_MAX} |
|||
(queens : &(@[g1int tk_index][M2_MAX]), |
|||
count : int count) : |
|||
[p : addr | null < p] |
|||
board_record_vt (tk_color, p) = |
|||
let |
|||
typedef color_t = color_t tk_color |
|||
fun |
|||
loop {k : int | ~1 <= k; k < count} .<k + 1>. |
|||
(queens : &(@[g1int tk_index][M2_MAX]), |
|||
board : &(@[color_t tk_color][BOARD_SIZE]), |
|||
k : int k) : |
|||
void = |
|||
if 0 <= k then |
|||
let |
|||
val [coords : int] coords = queens[k] |
|||
#if NDEBUG <> 0 #then |
|||
prval _ = $UN.prop_assert {0 <= coords} () |
|||
prval _ = $UN.prop_assert {coords < BOARD_SIZE} () |
|||
#else |
|||
val _ = assertloc (g1i2i 0 <= coords) |
|||
val _ = assertloc (coords < g1i2i BOARD_SIZE) |
|||
#endif |
|||
in |
|||
if g1int_nmod (k, 2) = 0 then |
|||
board[coords] := g1i2i BLACK |
|||
else |
|||
board[coords] := g1i2i WHITE; |
|||
loop (queens, board, pred k) |
|||
end |
|||
val @(pf, pfgc | p) = array_ptr_alloc<color_t> (i2sz BOARD_SIZE) |
|||
val _ = array_initize_elt<color_t> (!p, i2sz BOARD_SIZE, |
|||
g1i2i EMPTY) |
|||
val _ = loop (queens, !p, pred count) |
|||
in |
|||
@{ |
|||
pf = pf, |
|||
pfgc = pfgc | |
|||
p = p |
|||
} |
|||
end |
|||
fn {tk : tkind} |
|||
queen_would_fit_in |
|||
{count : int | 0 <= count; count <= M2_MAX} |
|||
{i, j : int | 0 <= i; i < SIDE_MAX; |
|||
0 <= j; j < SIDE_MAX} |
|||
(queens : &(@[g1int tk][M2_MAX]), |
|||
count : int count, |
|||
i : g1int (tk, i), |
|||
j : g1int (tk, j)) : |
|||
bool = |
|||
(* Would a new queen at (i,j) be feasible? *) |
|||
if count = 0 then |
|||
true |
|||
else |
|||
let |
|||
fun |
|||
loop {k : int | ~1 <= k; k < count} |
|||
(queens : &(@[g1int tk][M2_MAX]), |
|||
k : int k) : |
|||
bool = |
|||
if k < 0 then |
|||
true |
|||
else |
|||
let |
|||
val [coords : int] coords = queens[k] |
|||
#if NDEBUG <> 0 #then |
|||
prval _ = $UN.prop_assert {0 <= coords} () |
|||
prval _ = $UN.prop_assert {coords < BOARD_SIZE} () |
|||
#else |
|||
val _ = assertloc (g1i2i 0 <= coords) |
|||
val _ = assertloc (coords < g1i2i BOARD_SIZE) |
|||
#endif |
|||
val i1 = row_index<tk> coords |
|||
val j1 = column_index<tk> coords |
|||
in |
|||
if g1int_nmod (k, 2) = g1int_nmod (count, 2) then |
|||
(* The two queens are of the same color. They may not |
|||
share the same square. *) |
|||
begin |
|||
if i <> i1 || j <> j1 then |
|||
loop (queens, pred k) |
|||
else |
|||
false |
|||
end |
|||
else |
|||
(* The two queens are of different colors. They may not |
|||
share the same square nor attack each other. *) |
|||
begin |
|||
if (i <> i1 && |
|||
j <> j1 && |
|||
i + j <> i1 + j1 && |
|||
i - j <> i1 - j1) then |
|||
loop (queens, pred k) |
|||
else |
|||
false |
|||
end |
|||
end |
|||
in |
|||
loop (queens, pred count) |
|||
end |
|||
fn {tk : tkind} |
|||
latest_queen_fits_in |
|||
{count : int | 1 <= count; count <= M2_MAX} |
|||
(queens : &(@[g1int tk][M2_MAX]), |
|||
count : int count) : |
|||
bool = |
|||
let |
|||
val [coords : int] coords = queens[pred count] |
|||
#if NDEBUG <> 0 #then |
|||
prval _ = $UN.prop_assert {0 <= coords} () |
|||
prval _ = $UN.prop_assert {coords < BOARD_SIZE} () |
|||
#else |
|||
val _ = assertloc (g1i2i 0 <= coords) |
|||
val _ = assertloc (coords < g1i2i BOARD_SIZE) |
|||
#endif |
|||
val i = row_index<tk> coords |
|||
val j = column_index<tk> coords |
|||
in |
|||
queen_would_fit_in<tk> (queens, pred count, i, j) |
|||
end |
|||
fn {tk_index, tk_color : tkind} |
|||
find_solutions |
|||
{m : int | 0 <= m; 2 * m <= M2_MAX} |
|||
{n : int | 0 <= n; n <= SIDE_MAX} |
|||
{max_solutions : int | 0 <= max_solutions} |
|||
(f : FILEref, |
|||
m : int m, |
|||
n : g1int (tk_index, n), |
|||
rotation_equiv_classes : bool, |
|||
max_solutions : int max_solutions) : |
|||
[num_solutions : int | 0 <= num_solutions; |
|||
num_solutions <= max_solutions] |
|||
@(int num_solutions, |
|||
board_record_list_vt (tk_color, num_solutions)) = |
|||
(* This template function both prints the solutions and returns |
|||
them as a linked list. *) |
|||
if m = 0 then |
|||
@(0, NIL) |
|||
else if max_solutions = 0 then |
|||
@(0, NIL) |
|||
else |
|||
let |
|||
macdef latest_queen_fits_in = latest_queen_fits_in<tk_index> |
|||
macdef queens_to_board = queens_to_board<tk_index, tk_color> |
|||
macdef fprint_board = fprint_board<tk_index, tk_color> |
|||
macdef any_board_equiv = any_board_equiv<tk_index, tk_color> |
|||
macdef row_index = row_index<tk_index> |
|||
macdef column_index = column_index<tk_index> |
|||
macdef storage_index = storage_index<tk_index> |
|||
fnx |
|||
loop {num_solutions : int | 0 <= num_solutions; |
|||
num_solutions <= max_solutions} |
|||
{num_queens : int | 0 <= num_queens; |
|||
num_queens <= 2 * m} |
|||
(solutions : board_record_list_vt (tk_color, |
|||
num_solutions), |
|||
num_solutions : int num_solutions, |
|||
queens : &(@[g1int tk_index][M2_MAX]), |
|||
num_queens : int num_queens) : |
|||
[num_solutions1 : int | 0 <= num_solutions1; |
|||
num_solutions1 <= max_solutions] |
|||
@(int num_solutions1, |
|||
board_record_list_vt (tk_color, num_solutions1)) = |
|||
if num_queens = 0 then |
|||
@(num_solutions, solutions) |
|||
else if num_solutions = max_solutions then |
|||
@(num_solutions, solutions) |
|||
else if latest_queen_fits_in (queens, num_queens) then |
|||
begin |
|||
if num_queens = 2 * m then |
|||
let |
|||
val board = queens_to_board (queens, num_queens) |
|||
val equiv_solution = |
|||
any_board_equiv (!(board.p), solutions, n, |
|||
rotation_equiv_classes) |
|||
in |
|||
if ~equiv_solution then |
|||
begin |
|||
fprintln! (f, "Solution ", |
|||
succ num_solutions); |
|||
fprint_board (f, !(board.p), n); |
|||
fileref_puts (f, "\n\n"); |
|||
move_a_queen (board :: solutions, |
|||
succ num_solutions, |
|||
queens, num_queens) |
|||
end |
|||
else |
|||
begin |
|||
free board; |
|||
move_a_queen (solutions, num_solutions, |
|||
queens, num_queens) |
|||
end |
|||
end |
|||
else |
|||
add_another_queen (solutions, num_solutions, |
|||
queens, num_queens) |
|||
end |
|||
else |
|||
move_a_queen (solutions, num_solutions, |
|||
queens, num_queens) |
|||
and |
|||
add_another_queen |
|||
{num_solutions : int | |
|||
0 <= num_solutions; |
|||
num_solutions <= max_solutions} |
|||
{num_queens : int | 0 <= num_queens; |
|||
num_queens + 1 <= 2 * m} |
|||
(solutions : board_record_list_vt |
|||
(tk_color, num_solutions), |
|||
num_solutions : int num_solutions, |
|||
queens : &(@[g1int tk_index][M2_MAX]), |
|||
num_queens : int num_queens) : |
|||
[num_solutions1 : int | 0 <= num_solutions1; |
|||
num_solutions1 <= max_solutions] |
|||
@(int num_solutions1, |
|||
board_record_list_vt (tk_color, num_solutions1)) = |
|||
let |
|||
val coords = storage_index (g1i2i 0, g1i2i 0) |
|||
in |
|||
queens[num_queens] := coords; |
|||
loop (solutions, num_solutions, queens, succ num_queens) |
|||
end |
|||
and |
|||
move_a_queen {num_solutions : int | |
|||
0 <= num_solutions; |
|||
num_solutions <= max_solutions} |
|||
{num_queens : int | 0 <= num_queens; |
|||
num_queens <= 2 * m} |
|||
(solutions : board_record_list_vt |
|||
(tk_color, num_solutions), |
|||
num_solutions : int num_solutions, |
|||
queens : &(@[g1int tk_index][M2_MAX]), |
|||
num_queens : int num_queens) : |
|||
[num_solutions1 : int | 0 <= num_solutions1; |
|||
num_solutions1 <= max_solutions] |
|||
@(int num_solutions1, |
|||
board_record_list_vt (tk_color, num_solutions1)) = |
|||
if num_queens = 0 then |
|||
loop (solutions, num_solutions, queens, num_queens) |
|||
else |
|||
let |
|||
val [coords : int] coords = queens[pred num_queens] |
|||
#if NDEBUG <> 0 #then |
|||
prval _ = $UN.prop_assert {0 <= coords} () |
|||
prval _ = $UN.prop_assert {coords < BOARD_SIZE} () |
|||
#else |
|||
val _ = assertloc (g1i2i 0 <= coords) |
|||
val _ = assertloc (coords < g1i2i BOARD_SIZE) |
|||
#endif |
|||
val [i : int] i = row_index coords |
|||
val [j : int] j = column_index coords |
|||
prval _ = prop_verify {0 <= i} () |
|||
prval _ = prop_verify {i < SIDE_MAX} () |
|||
prval _ = prop_verify {0 <= j} () |
|||
prval _ = prop_verify {j < SIDE_MAX} () |
|||
#if NDEBUG <> 0 #then |
|||
prval _ = $UN.prop_assert {i < n} () |
|||
prval _ = $UN.prop_assert {j < n} () |
|||
#else |
|||
val _ = $effmask_exn assertloc (i < n) |
|||
val _ = $effmask_exn assertloc (j < n) |
|||
#endif |
|||
in |
|||
if j = pred n then |
|||
begin |
|||
if i = pred n then |
|||
(* Backtrack. *) |
|||
move_a_queen (solutions, num_solutions, |
|||
queens, pred num_queens) |
|||
else |
|||
let |
|||
val coords = storage_index (succ i, j) |
|||
in |
|||
queens[pred num_queens] := coords; |
|||
loop (solutions, num_solutions, |
|||
queens, num_queens) |
|||
end |
|||
end |
|||
else |
|||
let |
|||
#if NDEBUG <> 0 #then |
|||
prval _ = $UN.prop_assert {j < n - 1} () |
|||
#else |
|||
val _ = $effmask_exn assertloc (j < pred n) |
|||
#endif |
|||
in |
|||
if i = pred n then |
|||
let |
|||
val coords = storage_index (g1i2i 0, succ j) |
|||
in |
|||
queens[pred num_queens] := coords; |
|||
loop (solutions, num_solutions, |
|||
queens, num_queens) |
|||
end |
|||
else |
|||
let |
|||
val coords = storage_index (succ i, j) |
|||
in |
|||
queens[pred num_queens] := coords; |
|||
loop (solutions, num_solutions, |
|||
queens, num_queens) |
|||
end |
|||
end |
|||
end |
|||
var queens = @[g1int tk_index][M2_MAX] (g1i2i 0) |
|||
in |
|||
queens[0] := storage_index (g1i2i 0, g1i2i 0); |
|||
loop (NIL, 0, queens, 1) |
|||
end |
|||
(********************************************************************) |
|||
%{^ |
|||
#include <stdlib.h> |
|||
#include <limits.h> |
|||
%} |
|||
implement |
|||
main0 (argc, argv) = |
|||
let |
|||
stadef tk_index = int_kind |
|||
stadef tk_color = int_kind |
|||
macdef usage_error (status) = |
|||
begin |
|||
println! ("Usage: ", argv[0], |
|||
" M N IGNORE_EQUIVALENTS [MAX_SOLUTIONS]"); |
|||
exit (,(status)) |
|||
end |
|||
val max_max_solutions = |
|||
$extval ([i : int | 0 <= i] int i, "INT_MAX") |
|||
in |
|||
if 4 <= argc then |
|||
let |
|||
val m = $extfcall (int, "atoi", argv[1]) |
|||
val m = g1ofg0 m |
|||
val _ = if m < 0 then usage_error (2) |
|||
val _ = assertloc (0 <= m) |
|||
val _ = |
|||
if M2_MAX < 2 * m then |
|||
begin |
|||
println! (argv[0], ": M cannot be larger than ", |
|||
M2_MAX / 2); |
|||
usage_error (2) |
|||
end |
|||
val _ = assertloc (2 * m <= M2_MAX) |
|||
val n = $extfcall (int, "atoi", argv[2]) |
|||
val n = g1ofg0 n |
|||
val _ = if n < 0 then usage_error (2) |
|||
val _ = assertloc (0 <= n) |
|||
val _ = |
|||
if SIDE_MAX < n then |
|||
begin |
|||
println! (argv[0], ": N cannot be larger than ", |
|||
SIDE_MAX); |
|||
usage_error (2) |
|||
end |
|||
val _ = assertloc (n <= SIDE_MAX) |
|||
val ignore_equivalents = |
|||
if argv[3] = "T" || argv[3] = "t" || argv[3] = "1" then |
|||
true |
|||
else if argv[3] = "F" || argv[3] = "f" || argv[3] = "0" then |
|||
false |
|||
else |
|||
begin |
|||
println! (argv[0], |
|||
": select T=t=1 or F=f=0 ", |
|||
"for IGNORE_EQUIVALENTS"); |
|||
usage_error (2); |
|||
false |
|||
end |
|||
in |
|||
if argc = 5 then |
|||
let |
|||
val max_solutions = $extfcall (int, "atoi", argv[4]) |
|||
val max_solutions = g1ofg0 max_solutions |
|||
val max_solutions = max (0, max_solutions) |
|||
val @(num_solutions, solutions) = |
|||
find_solutions<tk_index, tk_color> |
|||
(stdout_ref, m, n, ignore_equivalents, |
|||
max_solutions) |
|||
in |
|||
board_record_list_vt_free solutions |
|||
end |
|||
else |
|||
let |
|||
val @(num_solutions, solutions) = |
|||
find_solutions<tk_index, tk_color> |
|||
(stdout_ref, m, n, ignore_equivalents, |
|||
max_max_solutions) |
|||
in |
|||
board_record_list_vt_free solutions |
|||
end |
|||
end |
|||
else |
|||
usage_error (1) |
|||
end |
|||
(********************************************************************)</lang> |
|||
{{out}} |
|||
$ patscc -DATS NDEBUG=1 -O3 -fno-stack-protector -march=native -DATS_MEMALLOC_LIBC -o peaceful_queens peaceful_queens.dats && ./peaceful_queens 4 5 T |
|||
<pre>Solution 1 |
|||
+----+----+----+----+----+ |
|||
| B | | | | B | |
|||
+----+----+----+----+----+ |
|||
| | | W | | | |
|||
+----+----+----+----+----+ |
|||
| | W | | W | | |
|||
+----+----+----+----+----+ |
|||
| | | W | | | |
|||
+----+----+----+----+----+ |
|||
| B | | | | B | |
|||
+----+----+----+----+----+ |
|||
Solution 2 |
|||
+----+----+----+----+----+ |
|||
| B | | B | | | |
|||
+----+----+----+----+----+ |
|||
| | | | | W | |
|||
+----+----+----+----+----+ |
|||
| | W | | W | | |
|||
+----+----+----+----+----+ |
|||
| | | | | W | |
|||
+----+----+----+----+----+ |
|||
| B | | B | | | |
|||
+----+----+----+----+----+ |
|||
Solution 3 |
|||
+----+----+----+----+----+ |
|||
| | W | | W | | |
|||
+----+----+----+----+----+ |
|||
| | | | | W | |
|||
+----+----+----+----+----+ |
|||
| B | | B | | | |
|||
+----+----+----+----+----+ |
|||
| | | | | W | |
|||
+----+----+----+----+----+ |
|||
| B | | B | | | |
|||
+----+----+----+----+----+ |
|||
</pre> |
|||
=={{header|C}}== |
=={{header|C}}== |