--UFHRwCdBEJvubb2X
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Here is a functional sodoku solver that uses continuations. Note that
it works because all the functions called within the chooser are
purely functional -- they do not alter their arguments, and their
value does not depend on any saved state.
# Size of board
SIZE
# Size of individual boxes
BOX
input ""+-------+-------+-------+
| _ 6 _ | 1 _ 4 | _ 5 _ |
| _ _ 8 | 3 _ 5 | 6 _ _ |
| 2 _ _ | _ _ _ | _ _ 1 |
+-------+-------+-------+
| 8 _ _ | 4 _ 7 | _ _ 6 |
| _ _ 6 | _ _ _ | 3 _ _ |
| 7 _ _ | 9 _ 1 | _ _ 4 |
+-------+-------+-------+
| 5 _ _ | _ _ _ | _ _ 2 |
| _ _ 7 | 2 _ 6 | 9 _ _ |
| _ 4 _ | 5 _ 8 | _ 7 _ |
+-------+-------+-------+"""
# ---- Continuation-based Choooser -----------------
$paths ]
def choose(possibilities)
catch(:the_choice){
possibilities.each do |p|
throw :the_choice, p if callcc {|cc| $paths << cc;}
end
failure
}
end
def failure
raise "No solution" if $paths.empty?
$paths.pop.call
end
# ----------------------------------------------------
# Returns board as a flat array
def parse(board)
board.scan( /[1-9_]/ ).map {|x| x '_' ? nil : x.to_i}
end
# all existing numbers on the same horizontal row as elt
def horiz(board, elt)
board[ elt - elt%SIZE , SIZE ].select {|x| x}
end
# all existing numbers in same vertical column as elt
def vert(board, elt)
result ]
(elt % SIZE).step(SIZE*SIZE, SIZE) {|i|
result << board[i] if board[i]
}
result
end
# all existing numbers in same box as elt
def box(board, elt)
result ]
start elt / SIZE / BOX * BOX) * SIZE + (elt % SIZE / BOX * BOX)
BOX.times {|i| result + oard[start + i*SIZE,BOX] }
result.select {|x| x}
end
# numbers that can legally fill elt
def available(board, elt)
(1..9).to_a - horiz(board,elt) - vert(board,elt) - box(board,elt)
end
# Recursive solution
def solve(board)
elt oard.index(nil)
return board unless elt
newboard oard.dup
newboard[elt] hoose(available(board,elt))
solve(newboard)
end
def output(board)
SIZE.times {|i|
puts "#{board[i*SIZE,SIZE].join(' ')}\n"
}
:done
end
# Go!
output(solve(parse(input)))
regards,
Ed
--UFHRwCdBEJvubb2X
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
iD8DBQFDhLBtnhUz11p9MSARAn8SAKCVO1T6GgBQ0km7zOfTqNLzVFJjBQCg0QaT
JKEdQoBOOqdaxwE2RMNU3gI
k5
-----END PGP SIGNATURE-----
--UFHRwCdBEJvubb2X--