1+ import random
2+
3+ from Cell import Cell
4+
5+
6+ class Board :
7+
8+ # intializing a board
9+ def __init__ (self , numbers = None ):
10+
11+ # we keep list of cells and dictionaries to point to each cell
12+ # by various locations
13+ self .rows = {}
14+ self .columns = {}
15+ self .boxes = {}
16+ self .cells = []
17+
18+ # looping rows
19+ for row in xrange (0 , 9 ):
20+ # looping columns
21+ for col in xrange (0 , 9 ):
22+ # calculating box
23+ box = 3 * (row / 3 ) + (col / 3 )
24+
25+ # creating cell instance
26+ cell = Cell (row , col , box )
27+
28+ # if initial set is given, set cell value
29+ if not numbers is None :
30+ cell .value = numbers .pop (0 )
31+ else :
32+ cell .value = 0
33+
34+ # initializing dictionary keys and corresponding lists
35+ # if they are not initialized
36+ if not row in self .rows :
37+ self .rows [row ] = []
38+ if not col in self .columns :
39+ self .columns [col ] = []
40+ if not box in self .boxes :
41+ self .boxes [box ] = []
42+
43+ # adding cells to each list
44+ self .rows [row ].append (cell )
45+ self .columns [col ].append (cell )
46+ self .boxes [box ].append (cell )
47+ self .cells .append (cell )
48+
49+
50+ # returning cells in puzzle that are not set to zero
51+ def get_used_cells (self ):
52+ return [x for x in self .cells if x .value != 0 ]
53+
54+ # returning cells in puzzle that are set to zero
55+ def get_unused_cells (self ):
56+ return [x for x in self .cells if x .value == 0 ]
57+
58+ # returning all possible values that could be assigned to the
59+ # cell provided as argument
60+ def get_possibles (self , cell ):
61+ all = self .rows [cell .row ] + self .columns [cell .col ] + self .boxes [cell .box ]
62+ excluded = set ([x .value for x in all if x .value != 0 and x .value != cell .value ])
63+ results = [x for x in range (1 , 10 ) if x not in excluded ]
64+ return results
65+
66+ # calculates the density of a specific cell's context
67+ def get_density (self ,cell ):
68+ all = self .rows [cell .row ] + self .columns [cell .col ] + self .boxes [cell .box ]
69+ if cell .value != 0 : all .remove (cell )
70+ return len ([x for x in set (all ) if x .value != 0 ])/ 20.0
71+
72+ # gets complement of possibles, values that cell cannot be
73+ def get_excluded (self ,cell ):
74+ all = self .rows [cell .row ] + self .columns [cell .col ] + self .boxes [cell .box ]
75+ excluded = set ([x .value for x in all if x .value != 0 and x .value != cell .value ])
76+
77+
78+ # swaps two rows
79+ def swap_row (self , row_index1 , row_index2 , allow = False ):
80+ if allow or row_index1 / 3 == row_index2 / 3 :
81+ for x in range (0 , len (self .rows [row_index2 ])):
82+ temp = self .rows [row_index1 ][x ].value
83+ self .rows [row_index1 ][x ].value = self .rows [row_index2 ][x ].value
84+ self .rows [row_index2 ][x ].value = temp
85+ else :
86+ raise Exception ('Tried to swap non-familial rows.' )
87+
88+ # swaps two columns
89+ def swap_column (self , col_index1 , col_index2 , allow = False ):
90+ if allow or col_index1 / 3 == col_index2 / 3 :
91+ for x in range (0 , len (self .columns [col_index2 ])):
92+ temp = self .columns [col_index1 ][x ].value
93+ self .columns [col_index1 ][x ].value = self .columns [col_index2 ][x ].value
94+ self .columns [col_index2 ][x ].value = temp
95+ else :
96+ raise Exception ('Tried to swap non-familial columns.' )
97+
98+ # swaps two stacks
99+ def swap_stack (self , stack_index1 , stack_index2 ):
100+ for x in range (0 , 3 ):
101+ self .swap_column (stack_index1 * 3 + x , stack_index2 * 3 + x , True )
102+
103+ # swaps two bands
104+ def swap_band (self , band_index1 , band_index2 ):
105+ for x in range (0 , 3 ):
106+ self .swap_row (band_index1 * 3 + x , band_index2 * 3 + x , True )
107+
108+ # copies the board
109+ def copy (self ):
110+ b = Board ()
111+ for row in xrange (0 ,len (self .rows )):
112+ for col in xrange (0 ,len (self .columns )):
113+ b .rows [row ][col ].value = self .rows [row ][col ].value
114+ return b
115+
116+ # returns string representation
117+ def __str__ (self ):
118+ output = []
119+ for index , row in self .rows .iteritems ():
120+ my_set = map (str , [x .value for x in row ])
121+ new_set = []
122+ for x in my_set :
123+ if x == '0' : new_set .append ("_" )
124+ else : new_set .append (x )
125+ output .append ('|' .join (new_set ))
126+ return '\r \n ' .join (output )
127+
128+
129+ # exporting puzzle to a html table for prettier visualization
130+ def html (self ):
131+ html = "<table>"
132+ for index , row in self .rows .iteritems ():
133+ values = []
134+ row_string = "<tr>"
135+ for x in row :
136+ if x .value == 0 :
137+ values .append (" " )
138+ row_string += "<td>%s</td>"
139+ else :
140+ values .append (x .value )
141+ row_string += "<td>%d</td>"
142+ row_string += "</tr>"
143+ html += row_string % tuple (values )
144+ html += "</table>"
145+ return html
0 commit comments