rendered paste body#! /usr/bin/env gforth
( ============================================================================ )
( = Sudoku input = )
( ============================================================================ )
0 constant _
defer |
: <+---------+---------+---------+> ;
: [+---------+---------+---------+] ;
: |> ( char1 char2 char3 -- )
rot c, swap c, c, ;
: |] ( board char1 char2 char3 -- board+3 )
>r >r over c! 1+ r> over c! 1+ r> over c! 1+ ;
: <| ( -- )
['] |> is | ;
: [| ( -- )
['] |] is | ;
: >board ( 81*fields board -- )
dup 80 + DO
i c!
-1 +LOOP ;
: row>board ( row board+row-index -- )
dup 8 + DO
10 /mod swap i c!
-1 +LOOP drop ;
: rows>board ( 9*row board -- )
dup 72 + DO
i row>board
-9 +LOOP ;
: delete ( board -- )
81 erase ;
( ============================================================================ )
( = Create sudoku = )
( ============================================================================ )
create board
<+---------+---------+---------+>
<| 2 _ _ | 6 7 _ | _ _ _ |>
<| _ _ 6 | _ _ _ | 2 _ 1 |>
<| 4 _ _ | _ _ _ | 8 _ _ |>
<+---------+---------+---------+>
<| 5 _ _ | _ _ 9 | 3 _ _ |>
<| _ 3 _ | _ _ _ | _ 5 _ |>
<| _ _ 2 | 8 _ _ | _ _ 7 |>
<+---------+---------+---------+>
<| _ _ 1 | _ _ _ | _ _ 4 |>
<| 7 _ 8 | _ _ _ | 6 _ _ |>
<| _ _ _ | _ 5 3 | _ _ 8 |>
<+---------+---------+---------+>
( ============================================================================ )
( = Show sudoku = )
( ============================================================================ )
: digit>char ( digit -- char )
[char] 0 + ;
char | constant v-bar
: .v-bar ( -- )
v-bar emit ;
s" +---------+---------+---------+" 2constant h-bar
: .h-bar ( -- )
h-bar type cr ;
: .digit>0 ( char -- )
dup 9 u> IF
drop [char] ? emit
ELSE
digit>char emit
THEN space ;
: .digit ( char -- )
dup 0= IF
drop space space
ELSE
.digit>0
THEN ;
: .1/3row ( board -- board+3 )
3 0 DO
space dup c@ .digit 1+
LOOP .v-bar ;
: .row ( board -- board+9 )
.v-bar 3 0 DO
.1/3row
LOOP ;
: .3rows ( board -- board+27 )
3 0 DO
.row cr
LOOP ;
: .board ( board -- )
.h-bar 3 0 DO
.3rows .h-bar
LOOP drop ;
( ============================================================================ )
( = Now solve it. = )
( ============================================================================ )
: >row ( index -- row-index )
9 / 9 * ;
: >column ( index -- column-index )
9 mod ;
: >box ( index -- box-index )
27 /mod 27 * swap 9 mod 3 / 3 * + ;
: row? ( board+index digit -- found? )
swap 9 0 DO
2dup i + c@ = IF
2drop true
UNLOOP EXIT
THEN
LOOP 2drop false ;
: column? ( board+index digit -- found? )
swap 81 0 DO
2dup i + c@ = IF
2drop true
UNLOOP EXIT
THEN
9 +LOOP 2drop false ;
: field?
2dup i + c@ = IF
2drop true
rdrop UNLOOP EXIT
THEN ;
: box? ( board+index digit -- found? )
swap 03 00 DO 2dup i + c@ = IF 2drop true UNLOOP EXIT THEN LOOP
12 09 DO 2dup i + c@ = IF 2drop true UNLOOP EXIT THEN LOOP
21 18 DO 2dup i + c@ = IF 2drop true UNLOOP EXIT THEN LOOP
2drop false ;
: fits? ( board index digit -- unused? )
>r 2dup >row + r@ row? IF 2drop rdrop false ELSE
2dup >column + r@ column? IF 2drop rdrop false ELSE
>box + r> box? IF false ELSE
true THEN THEN THEN ;
: guess ( board index -- solved? )
dup 81 = IF
2drop true
ELSE
2dup + c@ IF
1+ RECURSE
ELSE
10 1 DO
2dup i fits? IF
2dup + i swap c!
2dup 1+ RECURSE IF
2drop true
UNLOOP EXIT
THEN
THEN
LOOP
+ 0 swap c!
false
THEN
THEN ;
: solve ( board -- )
." Unsolved:" cr
dup .board cr cr
dup 0 guess IF
." Solved:" cr
.board
ELSE
drop ." No solution found."
THEN cr ;
: (ok) ." ok" ; latestxt is bootmessage