--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--