( * * Sudokiller.gf - A Sudoku solver in Forth * * Two versions: * - the simple one includes board in code * - the longer one reads the board from a text file (and is HEX sudo !) * * Download sources * ) ( * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * at your option any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ) ( written by David Stevenson March 2006 david at avoncliff dot com ) ( Based on Daniele Mazzocchio's sudokiller.asm ) ( for gforth - although should work in others. Note rdrop may need to be r>drop ) ." Sudoka in Forth " create board ( enter your own board here ) 2 c, 0 c, 0 c, 6 c, 7 c, 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, 6 c, 0 c, 0 c, 0 c, 2 c, 0 c, 1 c, 4 c, 0 c, 0 c, 0 c, 0 c, 0 c, 8 c, 0 c, 0 c, 5 c, 0 c, 0 c, 0 c, 0 c, 9 c, 3 c, 0 c, 0 c, 0 c, 3 c, 0 c, 0 c, 0 c, 0 c, 0 c, 5 c, 0 c, 0 c, 0 c, 2 c, 8 c, 0 c, 0 c, 0 c, 0 c, 7 c, 0 c, 0 c, 1 c, 0 c, 0 c, 0 c, 0 c, 0 c, 4 c, 7 c, 0 c, 8 c, 0 c, 0 c, 0 c, 6 c, 0 c, 0 c, 0 c, 0 c, 0 c, 0 c, 5 c, 3 c, 0 c, 0 c, 8 c, ( display board ) : print_val ( addr -- ) c@ dup 0= if ." - " drop else . then ; : print_line ( addr -- ) 9 0 do dup i + print_val loop cr drop ; : print_board ( -- ) cr 9 0 do board 9 i * + print_line loop ; ( now solve it ) : check_row ( addr num -- f) ( 0 = num found ) swap 9 0 do 2dup i + c@ = if unloop 2drop 0 exit then loop 2drop 1 ; : check_col ( addr num -- f) swap 9 0 do 2dup 9 i * + c@ = if unloop 2drop 0 exit then loop 2drop 1 ; : check_box ( addr num -- f ) swap 3 0 do 2dup i + c@ = if unloop 2drop 0 exit then loop 12 9 do 2dup i + c@ = if unloop 2drop 0 exit then loop 21 18 do 2dup i + c@ = if unloop 2drop 0 exit then loop 2drop 1 ; : box_calc ( cell -- box ) 27 /mod 27 * swap 9 mod 3 / 3 * + ; : check_cell ( cell num -- f ) >r dup 9 / 9 * board + r@ check_row 0= if rdrop drop 0 exit then dup 9 mod board + r@ check_col 0= if rdrop drop 0 exit then box_calc board + r@ check_box 0= if rdrop 0 exit then rdrop 1 ; : guess ( cell -- f ) recursive dup 81 = if drop 1 exit then dup board + c@ if 1 + guess exit then 10 1 do dup i check_cell if dup board + i swap c! dup 1+ guess if drop 1 unloop exit then then loop board + 0 swap c! 0 ; : sudokiller 0 guess if print_board else ." No solution found " then ; sudokiller

( * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * at your option any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ) ( written by David Stevenson March 2006 david at avoncliff dot com ) ( Based on Daniele Mazzocchio's sudokiller.asm ) ( for gforth - although should work in others. Note rdrop may need to be r>drop ) ." Sudoka in Forth " ( version 4 - reads from file 16x16 puzzle ) 16 constant width 256 constant size 255 constant empty variable board size allot board size empty fill ( read file into buffer ) variable buff 1000 allot s" sud_puzzle1" r/o open-file throw Value fh buff 1000 fh read-file throw drop fh close-file throw ( parse buffer and put values in array ) : test-char ( c -- f ) dup 44 < swap 70 > or ; variable pos-buf 0 pos-buf ! : get-next-val ( -- n ) begin buff pos-buf @ + c@ dup test-char while ( false will exit with -- n ) drop pos-buf 1 swap +! repeat ; : load_square ( addr -- ) get-next-val dup 47 > if 48 - dup 9 > if 7 - then swap c! else drop drop then ; : load_line ( addr -- ) width 0 do dup i + load_square pos-buf 1 swap +! loop drop ; : load_board ( -- ) width 0 do board width i * + load_line loop ; ( display board ) : print_val ( addr -- ) c@ dup empty = if ." - " drop else hex . decimal then ; : print_line ( addr -- ) width 0 do dup i + print_val loop cr drop ; : print_board ( -- ) cr width 0 do board width i * + print_line loop ; ( now solve it ) : check_row ( addr num -- f) ( 0 = num found ) swap width 0 do 2dup i + c@ = if unloop 2drop 0 exit then loop 2drop 1 ; : check_col ( addr num -- f) swap width 0 do 2dup width i * + c@ = if unloop 2drop 0 exit then loop 2drop 1 ; : check_box ( addr num -- f ) swap 4 0 do 2dup i + c@ = if unloop 2drop 0 exit then loop 20 16 do 2dup i + c@ = if unloop 2drop 0 exit then loop 36 32 do 2dup i + c@ = if unloop 2drop 0 exit then loop 52 48 do 2dup i + c@ = if unloop 2drop 0 exit then loop 2drop 1 ; : box_calc ( cell -- box ) 64 /mod 64 * swap 16 mod 4 / 4 * + ; : check_cell ( cell num -- f ) >r dup width / width * board + r@ check_row 0= if rdrop drop 0 exit then dup width mod board + r@ check_col 0= if rdrop drop 0 exit then box_calc board + r@ check_box 0= if rdrop 0 exit then rdrop 1 ; : guess ( cell -- f ) recursive dup size = if drop 1 exit then dup board + c@ 255 <> if 1 + guess exit then 16 0 do dup i check_cell if dup board + i swap c! dup 1+ guess if drop 1 unloop exit then then loop board + empty swap c! 0 ; : sudo4 load_board 0 guess if print_board else ." No solution found " then ; sudo4