Kirjautuminen

Haku

Tehtävät

Keskustelu: Koodit: 8th: Sudokun ratkaisija

jalski [26.12.2022 17:39:29]

#

Sain vanhasta Sudokun ratkaisijastani melkein puolet nopeamman kuin mitä se aiemmin oli. Vieläkin on toki mahdollisuuksia nopeuttaa...

\
\  Simple backtracking Sudoku solver for the 8th programming language
\

\ Sub-board window for the given board index
[ 00, 00, 00, 01, 01, 01, 02, 02, 02,
  00, 00, 00, 01, 01, 01, 02, 02, 02,
  00, 00, 00, 01, 01, 01, 02, 02, 02,
  03, 03, 03, 04, 04, 04, 05, 05, 05,
  03, 03, 03, 04, 04, 04, 05, 05, 05,
  03, 03, 03, 04, 04, 04, 05, 05, 05,
  06, 06, 06, 07, 07, 07, 08, 08, 08,
  06, 06, 06, 07, 07, 07, 08, 08, 08,
  06, 06, 06, 07, 07, 07, 08, 08, 08
] ( swap a:_@ ) curry: window?  \ n -- n

\ Sub-board indices for the given window
[
  [00,01,02,09,10,11,18,19,20],
  [03,04,05,12,13,14,21,22,23],
  [06,07,08,15,16,17,24,25,26],
  [27,28,29,36,37,38,45,46,47],
  [30,31,32,39,40,41,48,49,50],
  [33,34,35,42,43,44,51,52,53],
  [54,55,56,63,64,65,72,73,74],
  [57,58,59,66,67,68,75,76,77],
  [60,61,62,69,70,71,78,79,80]
] ( swap a:_@ a:_@ ) curry: sub?  \ a n -- a

[
  [0,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]
] ( swap a:_@ a:_@ ) curry: row?  \ a n -- a

[
  [0,9,18,27,36,45,54,63],
  [1,10,19,28,37,46,55,64,73],
  [2,11,20,29,38,47,56,65,74],
  [3,12,21,30,39,48,57,66,75],
  [4,13,22,31,40,49,58,67,76],
  [5,14,23,32,41,50,59,68,77],
  [6,15,24,33,42,51,60,69,78],
  [7,16,25,34,43,52,61,70,79],
  [8,17,26,35,44,53,62,71,80]
] ( swap a:_@ a:_@ ) curry: col?  \ a n -- a

: trailing-zero-bits  \ n -- n
  32 >r
  dup n:neg n:band
  dup if -1 n:r+ then
  dup x0000ffff n:band if -16 n:r+ then
  dup x00ff00ff n:band if -8 n:r+ then
  dup x0f0f0f0f n:band if -4 n:r+ then
  dup x33333333 n:band if -2 n:r+ then
  x55555555 n:band if -1 n:r+ then
  r> ;

\ Bit number presentations
a:new 0 a:push ( 1 swap n:shl a:push ) 0 8 loop
( swap a:_@ ) curry: posbit?

: search  \ n -- n n | n null
  dup trailing-zero-bits dup 8 n:> if
    drop null
  then ;

: bxor  \ n n -- n
  n:bxor 511 n:band ;

: bnot  \ n n -- n
  n:bnot 511 n:band ;

: b-any  \ a -- n
  ' n:bor 0 posbit? a:reduce ;

a:new 0 args "Give Sudoku text file as param" thrownull
f:slurp "Cannot read file" thrownull >s "\n" "" s:replace "" s:/
' >n a:map ( posbit? "Bad data" thrownull a:push ) a:each! drop constant board

: display-board
  board ( search nip -1 ?: n:1+ ) a:map
  "+-----+-----+-----+\n"
  "|%d %d %d|%d %d %d|%d %d %d|\n" s:+
  "|%d %d %d|%d %d %d|%d %d %d|\n" s:+
  "|%d %d %d|%d %d %d|%d %d %d|\n" s:+
  "+-----+-----+-----+\n" s:+
  "|%d %d %d|%d %d %d|%d %d %d|\n" s:+
  "|%d %d %d|%d %d %d|%d %d %d|\n" s:+
  "|%d %d %d|%d %d %d|%d %d %d|\n" s:+
  "+-----+-----+-----+\n" s:+
  "|%d %d %d|%d %d %d|%d %d %d|\n" s:+
  "|%d %d %d|%d %d %d|%d %d %d|\n" s:+
  "|%d %d %d|%d %d %d|%d %d %d|\n" s:+
  "+-----+-----+-----+\n" s:+
  s:strfmt . ;

\ Store move history
a:new constant history

\ Possible numbers for a cell
: candidates?  \ n -- n
  dup dup 9 n:/ n:int swap 9 n:mod \ row col
  board swap col? b-any
  board rot row? b-any
  n:bor
  board rot window? sub? b-any
  n:bor
  bnot ;

\ If found:     -- n T
\ If not found: -- F
: find-free-cell
  false board
  ( 0 posbit? n:= if
      nip true break
    else
      drop
    then ) a:each drop ;

: validate
  true
  board
  ( dup -rot a:@ swap 2 pick 0 posbit? a:! 2 pick candidates? 2 pick n:= if
      -rot a:!
    else
      3drop
      false swap
      break
    then ) 0 80 loop drop ;

: solve
  repeat
    find-free-cell if
    dup candidates?
      repeat
        search null? if
          drop board -rot a:! drop
          history a:len !if
            drop false ;;
          then
          a:pop nip
          a:open
        else
          n:1+ posbit? dup
          board 4 pick rot a:! drop
          bxor
          2 a:close
          history swap a:push drop
          break
        then
      again
    else
      validate break
    then
  again ;

: app:main
  "Sudoku puzzle:\n" .
  display-board cr
  solve if
    "Sudoku solved:\n" .
    display-board
  else
    "No solution!\n" .
  then ;

Ohjelmaa voi kokeilla vaikka tallentamalla seuraava Sudoku tekstitiedostoon ja antamalla se ohjelmalle parametriksi:

000590000230004001000800003002000000050002006416700080807000000009067034000000079
C:\temp>8th sudoku.8th puzzle.txt
Sudoku puzzle:
+-----+-----+-----+
|0 0 0|5 9 0|0 0 0|
|2 3 0|0 0 4|0 0 1|
|0 0 0|8 0 0|0 0 3|
+-----+-----+-----+
|0 0 2|0 0 0|0 0 0|
|0 5 0|0 0 2|0 0 6|
|4 1 6|7 0 0|0 8 0|
+-----+-----+-----+
|8 0 7|0 0 0|0 0 0|
|0 0 9|0 6 7|0 3 4|
|0 0 0|0 0 0|0 7 9|
+-----+-----+-----+

Sudoku solved:
+-----+-----+-----+
|1 7 4|5 9 3|2 6 8|
|2 3 8|6 7 4|5 9 1|
|6 9 5|8 2 1|7 4 3|
+-----+-----+-----+
|9 8 2|4 1 6|3 5 7|
|7 5 3|9 8 2|4 1 6|
|4 1 6|7 3 5|9 8 2|
+-----+-----+-----+
|8 6 7|3 4 9|1 2 5|
|5 2 9|1 6 7|8 3 4|
|3 4 1|2 5 8|6 7 9|
+-----+-----+-----+

C:\temp>

Vastaus

Muista lukea kirjoitusohjeet.
Tietoa sivustosta