Pastebin
Paste #1287: sudoku.py
< previous paste - next paste>
Pasted by tdn
import math
import sys
import time
from random import random
from collections import defaultdict
from logger import *
start_time = time.time()
def usage():
print """Usage: %s <file> <size> [reverse]
Examples:
%s puzzle-tiny.txt 4
%s puzzle-small.txt 9
%s puzzle.txt 16 reverse
""" % (sys.argv[0], sys.argv[0], sys.argv[0], sys.argv[0])
def cputime():
import resource
return (resource.getrusage(resource.RUSAGE_SELF).ru_utime +
resource.getrusage(resource.RUSAGE_SELF).ru_stime)
class Row:
def __init__(self, pos, cells=[]):
self.pos = pos
self.cells = cells
def __str__(self):
return "Row(p:%s, %s)" % (self.pos, self.cells)
def __repr__(self):
return str(self)
class Cell:
def __init__(self, pos, value, square, row):
self.pos = pos
self.value = value
self.square = square
self.row = row
def __str__(self):
return str(self.value)
def __repr__(self):
return "C(p:%s,val:%s,sq:%s)" % (self.pos, self.value, self.square)
class Node:
#def __init__(self, pos, queue, value, depth):
def __init__(self, queue, value, depth):
#self.pos = pos
self.queue = queue
self.value = value
self.depth = depth
def __str__(self):
return repr(self)
def __repr__(self):
return "N(p:%s, val:%s, d:%s)" % (self.pos, self.value, self.depth)
def load(filename, size):
"""Global function to load a sudoku puzzle from a file"""
row_num, cell_num = 1, 1
rows = []
row_vals = defaultdict(dict)
col_vals = defaultdict(dict)
square_vals = defaultdict(dict)
square_size = int(math.sqrt(size))
# Load rows
for line in open(filename).readlines():
line = line.strip()
debug("line: %s row_num: %s" % (line, row_num))
cells = []
row = Row(row_num)
pos = 0
rd = math.ceil(float(row_num)/float(square_size))
# Load the cells in each row
for cell in line.strip().split(","):
debug("cell: %s, cell_num: %s, pos: %s" % (cell, cell_num, pos))
cd = math.ceil(float(pos+1)/float(square_size))
square_num = int((rd-1)*square_size+cd)
debug("square_num: %s" % square_num)
cell_value = int(cell)
cells.append(Cell(pos, cell_value, square_num, row))
# remember which cells that have already been given a value
if cell_value:
row_vals[row_num][cell_value] = 1
col_vals[pos][cell_value] = 1
square_vals[square_num][cell_value] = 1
pos += 1
cell_num += 1
row.cells = cells
rows.append(row)
row_num += 1
return (rows, row_vals, cells, col_vals, square_vals)
stat_depth = 0
def expand(parent):
"""Returns true if problem is solved, expands the given node otherwise"""
global queue, num_blanks, cur_node_pos, SIZE
# Statistics begin
global stat_depth, rows, num_expanded
num_expanded += 1
if parent.depth + 1 > stat_depth:
stat_depth = parent.depth + 1
info("stat_depth: %s, num_blanks: %s, num_expanded: %s" % (stat_depth, num_blanks, num_expanded))
pp(rows, SIZE)
# Statistics end
if not parent.depth + 1 > num_blanks - 1:
children = []
for i in range(SIZE):
cur_node_pos += 1
#children.append(Node(cur_node_pos, queue, i + 1, parent.depth + 1))
children.append(Node(queue, i + 1, parent.depth + 1))
if do_reverse:
children.reverse()
for child in children:
queue.append(child)
else:
return True
try:
import psyco
psyco.full()
print "Using psyco specializing compiler"
except ImportError:
print "Psyco not available"
pass
if len(sys.argv) < 3:
error("Not enough parameters")
usage()
sys.exit(1)
if len(sys.argv) > 3:
do_reverse = True
info("reverse: on")
else:
do_reverse = False
info("reverse: off")
puzzle_file = sys.argv[1]
SIZE = int(sys.argv[2])
## INITIALIZATION
# Current node's position
cur_node_pos = 0
# Current depth starts on zero
cur_depth = 0
# Number of expanded nodes so far
num_expanded = 0
# Load rows from file
(rows, row_vals, cells, col_vals, square_vals) = load(puzzle_file, SIZE)
# Show the loaded puzzle
pp(rows, SIZE)
# list of empty cells
blanks = []
for row in rows:
for cell in row.cells:
if not cell.value:
blanks.append(cell)
num_blanks = len(blanks)
#queue = Queue()
queue = []
# Create root node and expand it
root = Node(queue, 0, -1)
expand(root)
while queue:
# Get next node from the queue
cur_node = queue.pop()
# Set value to current node's value
value = cur_node.value
# Set depth to the current node's depth
node_depth = cur_node.depth
cell = blanks[node_depth]
cell_row = cell.row.pos
cell_col = cell.pos
cell_square = cell.square
for i in range(node_depth, cur_depth + 1):
cur = blanks[i]
cur_row = cur.row.pos
cur_col = cur.pos
cur_square = cur.square
if cur.value:
del row_vals[cur_row][cur.value]
del col_vals[cur_col][cur.value]
del square_vals[cur_square][cur.value]
cur.value = 0
cur_depth = node_depth
if not (row_vals[cell_row].has_key(value) or
col_vals[cell_col].has_key(value) or
square_vals[cell_square].has_key(value)):
cell.value = value
finished = expand(cur_node)
if finished:
info("FINISHED")
pp(rows, SIZE)
break
row_vals[cell_row][value] = 1
col_vals[cell_col][value] = 1
square_vals[cell_square][value] = 1
else:
debug("Value: %s is already used" % value)
#for r in cur_node.queue:
# print map(repr, [r.value, r.pos, r.depth])
del cur_node
pp(rows, SIZE)
info("Expanded nodes: %s" % num_expanded)
info("CPU time used: %s" % cputime())
log("Time used: %s" % (time.time() - start_time), INFO)
New Paste
Go to most recent paste.