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
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:])])
def consecutive(value1, value2): 'The values are in consecutive houses: green1 & white2 | green2 & white3 ...' return from_dnf([(comb(value1, i), comb(value2, j)) for i, j in zip(houses, houses[1:])])
def same_house(value1, value2): 'The two values occur in the same house: brit1 & red1 | brit2 & red2 ...' return from_dnf([(comb(value1, i), comb(value2, i)) for i in houses])
def as_cnf(self) -> List[Tuple[str]]: return sat_utils.from_dnf( [(comb(self.value1, i), comb(self.value2, j)) for i, j in zip(self.houses, self.houses[3:])] + [(comb(self.value2, i), comb(self.value1, j)) for i, j in zip(self.houses, self.houses[3:])])
def as_cnf(self) -> List[Tuple[str]]: return sat_utils.from_dnf((comb(self.value1, i), comb(self.value2, j)) for i, j in product(self.houses, self.houses) if i > j)
def as_cnf(self) -> List[Tuple[str]]: return sat_utils.from_dnf( (comb(self.value1, i), comb(self.value2, i)) for i in self.houses)