-
Notifications
You must be signed in to change notification settings - Fork 29
/
n-queens.ml
94 lines (91 loc) · 2.53 KB
/
n-queens.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
(*
* Solve N-Queens puzzle with back-tracking
* https://en.wikipedia.org/wiki/Eight_queens_puzzle
*)
let rec make_board size =
let ret = Array.make size (Array.make 0 0) in
let rec set idx =
if idx < 0 then () else
(ret.(idx) <- Array.make size 0;
set (idx - 1))
in
set (size - 1);
ret
in
let rec n_queens n =
let SOLVED = true in
let FAILED = false in
let QUEEN = -1 in
let board = make_board n in
let rec in_board x y = x >= 0 && y >= 0 && n > x && n > y in
let rec update x y delta =
let rec f x y dx dy =
let x = x + dx in
let y = y + dy in
if not (in_board x y) then () else
(board.(x).(y) <- board.(x).(y) + delta; f x y dx dy)
in
f x y 1 0;
f x y 1 1;
f x y 0 1;
f x y (-1) 1;
f x y (-1) 0;
f x y (-1) (-1);
f x y 0 (-1);
f x y 1 (-1);
board.(x).(y) <- board.(x).(y) + delta
in
let rec put_queen x y = update x y 1 in
let rec remove_queen x y = update x y (-1) in
let rec solve nth x y =
if not in_board x y then FAILED else
let rec go_next _ =
if x < n then
solve nth (x+1) y
else
solve nth 0 (y+1)
in
if board.(x).(y) > 0 then
go_next ()
else (
put_queen x y;
let nth = nth + 1 in
if nth >= n || solve nth 0 (y+1) then
board.(x).(y) <- QUEEN;
SOLVED
else
(remove_queen x y; go_next ())
)
in
if solve 0 0 0 then
(* When answer was found, show fancy output. *)
let rec show _ =
let rec show_cell v = print_str (if v = QUEEN then "x" else "."); print_str " " in
let rec show_y y =
if y >= n then () else
let rec show_x x =
if x >= n then () else (show_cell board.(x).(y); show_x (x+1))
in
(show_x 0; print_str "\n"; show_y (y+1))
in
show_y 0
in
show ()
else
println_str "No answer"
in
let rec usage _ = print_str "Usage: "; print_str argv.(0); println_str " NUMBER" in
if Array.length argv = 1 then usage () else
let n = str_to_int (argv.(1)) in
if n = 0 then usage () else
n_queens n
(* Output of `./n-queens 8`:
x . . . . . . .
. . . . x . . .
. . . . . . . x
. . . . . x . .
. . x . . . . .
. . . . . . x .
. x . . . . . .
. . . x . . . .
*)