[ create a new paste ] login | about

Link: http://codepad.org/ACkQahvu    [ raw code | fork ]

k4st - Python, pasted on Jun 26:
from itertools import product
from copy import deepcopy

class Contradiction(Exception):
    pass

def irange(start, stop, step=1):
    """Custom range type for allowing zero step."""
    if 0 == step:
        stop, step = start + 1, 1
    return xrange(start, stop, step)

def get_seq(start_x, start_y, inc_x):
    """Get a row or column that a particular cell is constrained by"""
    nums = set(range(1, 10))
    cells = set()
    for x, y in product(irange(start_x, 9, inc_x), irange(start_y, 9, 1 - inc_x)):
        cells.add((x, y))
    return cells

def get_box(x, y):
    """Get all of the cells within a box that a specific cell is 
    constrained by."""
    left = (x // 3) * 3
    top = (y // 3) * 3
    cells = set(product(xrange(0 + left, 3 + left), xrange(0 + top, 3 + top)))
    return cells

# build up the constraints matrix
constraints = { }
for x, y in product(xrange(0, 9), xrange(0, 9)):
    constraints[x,y] = get_seq(0, y, 1)
    constraints[x,y].update(get_seq(x, 0, 0))
    constraints[x,y].update(get_box(x, y))
    constraints[x,y].remove((x,y))

def initialize(initial_board):
    """Create the board to reflect the initial assignments and to have all
    non-assigned cells have all possible values."""
    board = { }
    for (x, y) in product(xrange(0, 9), xrange(0, 9)):
        if (x, y) in initial_board:
            board[x,y] = set()
            board[x,y].add(initial_board[x,y])
        else:
            board[x,y] = set(range(1, 10))
    return board

def eliminate(board):
    """Propagate the constraints in the style of a breadth-first 
    search."""
    wave, next_wave, seen = set(), set(), set()
    for coord, cs in board.items():
        if 1 == len(cs):
            next_wave.add(coord)
    
    while 0 < len(next_wave):
        seen.update(wave)
        wave.clear()
        wave.update(next_wave)
        next_wave.clear()

        # propogate
        for (x, y) in wave:
            for (xi, yi) in constraints[x, y]:
                board[xi, yi].difference_update(board[x,y])
                if 0 == len(board[xi, yi]):
                    raise Contradiction
        
        # collect, after constraints have been propagated
        for xi, yi in product(xrange(0, 9), xrange(0, 9)):
            if 1 == len(board[xi, yi]) and (xi, yi) not in seen:
                next_wave.add((xi, yi))

def parse(line):
    """Parse a line into the initial board conditions"""
    initial = { }
    i = 0
    for (x, y) in product(xrange(0, 9), xrange(0, 9)):
        if "." != line[i]:
            initial[x, y] = int(line[i])
        i += 1
    return initial

def search(board):
    """Does a depth-first search of the solution space using the minimum
    remaining values heuristic."""
    min_elms = 10
    min_coord = None
    
    # go find the cell with the minimum number of remaining possibilities
    for (x, y) in product(xrange(0, 9), xrange(0, 9)):
        if 1 < len(board[x, y]) < min_elms:
            min_coord = x, y
            min_elms = len(board[x, y])
    
    # we have solved!
    if None is min_coord:
        return board
    
    # do the search
    choices = board[min_coord]
    for choice in choices:
        try:
            board[min_coord] = set([choice])
            temp_board = deepcopy(board)
            eliminate(temp_board)
            return search(temp_board)
        except Contradiction:
            pass    
    raise Contradiction

def solve(line):
    """Solve a sudoku puzzle"""
    board = initialize(parse(line))
    eliminate(board)
    return search(board)
    
def print_board(board):
    print "Solved Puzzle:",
    i = 0
    for x in range(0, 9):
        if 0 == (i % 3):
            print "\n", "-" * 95
        else:
            print
        for y in range(0, 9):
            if 0 == (y % 3):
                print "|",
            print "%9s" % "".join(map(str, board[x,y])),
        i += 1

print_board(solve("3...8.......7....51..............36...2..4....7...........6.13..452...........8.."))


Create a new paste based on this one


Comments: