examples/nqueens/
Count the ways to place eight queens on a chessboard so none can attack another.
- 101 lines
- threads
Each thread, a task that can run alongside the others, starts with a different position for the first queen and explores the remaining choices. Some starting positions take much longer to explore, but adding the counts still gives the exact total.
Run it
ways to place 8 queens: 92
exit 0 · 1 line
The program
# How many ways eight queens fit on a chessboard, one thread per opening move —
# the member of this family whose work is a SEARCH TREE rather than a range.
#
# Every other program here divides a straight line of numbers. This one divides
# a tree: thread `c` places the first queen in column `c` and explores only what
# follows from that. The eight subtrees are different sizes and none of them
# knows what the others found, which is the same shape as `collatz/`'s uneven
# bands one level up — and the answer is still one `i64` per thread.
#
# WHY THE BOARD NEVER CROSSES. The partial board is a `[i64]` built and grown
# inside the thread as the search descends. It could not be handed to a thread
# even if this program wanted to: a container in a callback signature is
# `error[ffi_type]` on the line that writes it. So the only thing that can
# start a thread's work is the number that describes it, which here is the
# column of the first queen — and that turns out to be all a search needs.
extern "hero_os.h"
function hero_thread_spawn(body: (function(i64) -> i64), arg: i64) -> i64
function hero_thread_join(handle: i64) -> i64
constant SIZE: i64
8
# May a queen stand in `col` of the next row, given the rows already placed?
# `placed[r]` is the column of the queen in row `r`.
function fits(placed: [i64], col: i64) -> bool
row: i64 @= 0
while row < len(placed)
other = placed[row]
if other == col
return false
down = len(placed) - row
if other - down == col || other + down == col
return false
row @ row + 1
return true
# Every completed board that starts with the rows already placed.
function solutions_from(placed: [i64]) -> i64
if len(placed) == SIZE
return 1
found: i64 @= 0
col: i64 @= 0
while col < SIZE
if fits(placed: placed, col: col)
deeper: [i64] @= placed
deeper @ deeper.push(col)
found @ found + solutions_from(placed: deeper)
col @ col + 1
return found
# One thread's whole job: the first queen goes in this column.
function from_column(col: i64) -> i64
start: [i64] = [col]
return solutions_from(placed: start)
function together() -> i64
handles: [i64] @= []
c: i64 @= 0
while c < SIZE
handles @ handles.push(hero_thread_spawn(body: from_column, arg: c))
c @ c + 1
found: i64 @= 0
for h in handles
found @ found + hero_thread_join(handle: h)
return found
function alone() -> i64
empty: [i64] = []
return solutions_from(placed: empty)
function main()
print("ways to place ", SIZE, " queens: ", together())
test "the threads count what one thread counts"
assert together() == alone()
test "the published answer for eight queens is 92"
assert together() == 92
test "the board is symmetric, so the first column and the last agree"
assert from_column(col: 0) == from_column(col: SIZE - 1)
test "a queen cannot share a column"
one: [i64] = [3]
assert !fits(placed: one, col: 3)
test "nor a diagonal, one row down"
one: [i64] = [3]
assert !fits(placed: one, col: 4)
assert fits(placed: one, col: 5)
fingerprint sha256 47a0e498d7c7 · 2 files · index.json
Next: collatz. All the examples. ← Previous: montecarlo
Run one yourself: the four commands. Learn the language, or read the full specification in one file.