def set_constraints(self) -> Puzzle: # each house gets exactly one value from each set of literals for house in self.houses: for element_type in self.element_classes: literals_of_that_type = [l for l in self.literals if isinstance(l, element_type)] self._add_constraint( sat_utils.one_of(comb(value, house) for value in literals_of_that_type) ) # each value gets assigned to exactly one house for literal in self.literals: self._add_constraint(sat_utils.one_of(comb(literal, house) for house in self.houses)) return self
def solve_range(self): def comb(point, value): """Format how a value is shown at a given coordinate""" return intern(f'{point} {value}') values = ['W', 'B'] all_coords = list(product(range(self.height), range(self.width))) for coord in all_coords: # Assign a "White" or "Black Box" value to each cell self.cnf += one_of(comb(coord, value) for value in values) # Rule: No two black squares are orthogonally adjacent. neighbor_coord = self.find_adjacency(coord) neighbor_dnf = [comb(coord, 'B')] for p in neighbor_coord: neighbor_dnf.append(comb(p, 'W')) self.cnf += from_dnf([neighbor_dnf, [comb(coord, 'W')]]) for clue in self.clues: # for each clue (numbered cell), assign a valid permutation of black boxes permutation_len = len(clue.permutation_box) p_dnf = [] for i in range(permutation_len): # different possible permutations for each clue temp = [] for direction in clue.permutation_box[i].keys(): if clue.permutation_box[i][direction]: temp.append( comb(clue.permutation_box[i][direction], 'B')) for direction in clue.permutation_white[i].keys(): for cell in clue.permutation_white[i][direction]: temp.append(comb(cell, 'W')) p_dnf.append(temp) # TODO: This from_dnf is so slow, maybe need some optimization self.cnf += from_dnf(p_dnf) possible_solution = solve_all(self.cnf) res = [] for solution_facts in possible_solution: ans = deepcopy(self.board) box_list = [] for fact_str in solution_facts: if fact_str[-1] == 'B': row, col = eval(fact_str[:-2]) box_list.append((row, col)) ans[row][col] = 'B' if self.check_connectivity(box_list): # Rule: Verify the connectivity of all of the white cells res.append(deepcopy(ans)) return res
' 9 7 4 1 6 2 8 1 43 6 59 1 3 97 8 52 7 6 8 4 7 5 8 2 ', '67 38 921 85 736 1 8 4 7 5 1 8 4 2 6 8 5 175 24 321 61 84', '27 15 8 3 7 4 7 5 1 7 9 2 6 2 5 8 6 5 4 8 59 41', '8 64 3 5 7 2 32 8 5 8 5 4 1 7 93 4 9 4 6 72 8', ' 1 2 7 5 9 4 8 5 9 6 2 2 6 5 9 83', # sudoku of 9 with only 17 digits http://www2.ic-net.or.jp/~takaken/auto/guest/bbs46.html '1 3 7428 3 5 6 8 84537 6 4 5 482 6 5 7 612 9 3 ', '8 36 7 9 2 5 7 457 1 3 1 68 85 1 9 4 ', # (was) hardest (35s) '1 2 9 4 5 6 7 5 9 3 7 85 4 7 6 3 9 8 2 1', # (was) hard (28s) "easter monster" ' 6 59 82 8 45 3 6 3 54 325 6 ', # hardest norvig (188 sec, but not a sudoku) ]: cnf = [] # each point assigned exactly one value for point in points: cnf += one_of(comb(point, value) for value in values) # each value gets assigned to exactly one point in each group for group in groups: for value in values: cnf += one_of(comb(point, value) for point in group) # add facts for known values in a specific puzzle for known in str_to_facts(given): cnf += basic_fact(known) # solve it and display the results result = facts_to_str(solve_one(cnf)) show(given) print() show(result)
def beside(value1, value2): 'The values occur side-by-side: blends1 & cat2 | blends2 & cat1 ...' return from_dnf([(comb(value1, i), comb(value2, j)) for i, j in zip(houses, houses[1:])] + [(comb(value2, i), comb(value1, j)) for i, j in zip(houses, houses[1:])]) cnf = [] # each house gets exactly one value from each attribute group for house in houses: for group in groups: cnf += one_of(comb(value, house) for value in group) # each value gets assigned to exactly one house for value in values: cnf += one_of(comb(value, house) for house in houses) cnf += same_house('brit', 'red') cnf += same_house('swede', 'dog') cnf += same_house('dane', 'tea') cnf += consecutive('green', 'white') cnf += same_house('green', 'coffee') cnf += same_house('pall mall', 'bird') cnf += same_house('yellow', 'dunhill') cnf += found_at('milk', 3) cnf += found_at('norwegian', 1) cnf += beside('blends', 'cat')