#! /usr/bin/env gforth ( ============================================================================ ) ( = Sudoku input = ) ( ============================================================================ ) 0 constant _ defer | : <+---------+---------+---------+> ; : [+---------+---------+---------+] ; : |> ( char1 char2 char3 -- ) rot c, swap c, c, ; : |] ( char1 char2 char3 -- ) >r >r over c! 1+ r> over c! 1+ r> over c! 1+ ; : <| ( -- ) ['] |> is | ; : [| ( -- ) ['] |] is | ; ( ============================================================================ ) ( = 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 ( addr -- ) 3 0 DO space dup c@ .digit 1+ LOOP drop .v-bar ; : .row ( addr -- ) .v-bar 3 0 DO dup .1/3row 3 + LOOP drop ; : .3rows ( addr -- ) 3 0 DO dup .row cr 9 + LOOP drop ; : .board ( addr -- ) .h-bar 3 0 DO dup .3rows .h-bar 27 + 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 9 0 DO 2dup 9 i * + c@ = IF 2drop true UNLOOP EXIT THEN LOOP 2drop false ; : 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 EXIT THEN 2dup + c@ IF 1+ RECURSE EXIT THEN 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 ; : solve ( board -- ) ." Unsolved:" cr board .board cr cr 0 guess IF ." Solved:" cr board .board ELSE ." No solution found." THEN cr ; board solve