def check_for_poss_to_eliminate_easily(self): user_input_map = {(x, y): self.board[x][y] for x, y in product(SudokuBoard.INDEX_RANGE, SudokuBoard.INDEX_RANGE)} offending_coord_pairs = [] for index in SudokuBoard.INDEX_RANGE: sub_area_solved_numbers = [ { coord: val for coord, val in user_input_map.items() if coord[0] == index and type(val) is int }, { coord: val for coord, val in user_input_map.items() if coord[1] == index and type(val) is int }, { coord: val for coord, val in user_input_map.items() if SudokuBoard.sector_lookup(coord[0], coord[1]) == index and type(val) is int } ] sub_area_poss = [ { coord: val for coord, val in user_input_map.items() if coord[0] == index and type(val) is list }, { coord: val for coord, val in user_input_map.items() if coord[1] == index and type(val) is list }, { coord: val for coord, val in user_input_map.items() if SudokuBoard.sector_lookup(coord[0], coord[1]) == index and type(val) is list } ] for sub_area_index in range(len(sub_area_solved_numbers)): for coord_solved, value in sub_area_solved_numbers[ sub_area_index].items(): for coord_poss, sublist in sub_area_poss[ sub_area_index].items(): if value in sublist: offending_coord_pairs.append(coord_poss) offending_coord_pairs.append(coord_solved) offending_coord_pairs.append(value) return offending_coord_pairs
def code_set(self, x, y, value): moves = [] self.board[x][y] = value indices = product(SudokuBoard.INDEX_RANGE, SudokuBoard.INDEX_RANGE) for x_index, y_index in indices: if not (x_index == x and y_index == y) and \ (x_index == x or y_index == y or SudokuBoard.sector_lookup(x_index, y_index) == SudokuBoard.sector_lookup(x, y)) and \ type(self.board[x_index][y_index]) is list and \ value in self.board[x_index][y_index]: moves.append( Move( REMOVE_POSS, value, (x_index, y_index), f'The value {value} was eliminated from the possibilities at {x_index, y_index} because we determined {x, y} to be {value}' )) return moves
def hint(self): # TODO # check for any blank cells coords = self.user_board.check_for_blank_cells() if coords: for coord in coords: self.draw_error_cell_highlight(coord, ERROR_CURSOR_COLOR) self.write_to_console(f'HINT: fill in the possible values that could be in {coord}') return # check the user model to see if any direct contradictions have been made accidentally and highglight them... coords = self.user_board.check_for_simple_contradiction() if coords and SudokuBoard.sector_lookup(coords[0][0], coords[0][1]) != SudokuBoard.sector_lookup(coords[1][0], coords[1][1]): self.draw_error_line_highlight(coords[0], coords[1], ERROR_CURSOR_COLOR) self.write_to_console(f'HINT: {coords[0]} and {coords[1]} contradict') return elif coords: self.draw_error_sector(coords[0], coords[1], SudokuBoard.sector_lookup(coords[0][0], coords[0][1]), ERROR_CURSOR_COLOR) self.write_to_console(f'HINT: {coords[0]} and {coords[1]} contradict') return # check and see if any cells are incorrect, possibilities or solutions; if so highlight them and say so. for x, y in product(SudokuBoard.INDEX_RANGE, SudokuBoard.INDEX_RANGE): if type(self.user_board.get(x, y)) is int and self.solve_model.get(x, y) != self.user_board.get(x, y): self.draw_error_cell_highlight((x, y), ERROR_CURSOR_COLOR) self.write_to_console(f'HINT: {(x, y)} is incorrect, reevaluate your method you used to find it') return # check if any possibilities can be easily removed. coords = self.user_board.check_for_poss_to_eliminate_easily() if coords and SudokuBoard.sector_lookup(coords[0][0], coords[0][1]) != SudokuBoard.sector_lookup(coords[1][0], coords[1][1]): self.draw_error_line_highlight(coords[0], coords[1], ERROR_CURSOR_COLOR, value=coords[2]) self.write_to_console(f'HINT: the {coords[2]} in {coords[0]} can be removed because of the {coords[2]} in {coords[1]}') return elif coords: self.draw_error_sector(coords[0], coords[1], SudokuBoard.sector_lookup(coords[0][0], coords[0][1]), ERROR_CURSOR_COLOR, value=coords[2]) self.write_to_console(f'HINT: the {coords[2]} in {coords[0]} can be removed because of the {coords[2]} in {coords[1]}') return self.moves = self.user_board.get_sudoku_object().solve()[::-1] move = self.moves.pop() # TODO improve reason object to make graphics clearer if move.get_operation() == NUMBER_SOLVE: self.draw_error_cell_highlight(move.get_pos(), ERROR_CURSOR_COLOR) self.write_to_console('HINT: ' + move.get_reason()) else: self.draw_error_number_highlight(move.get_pos(), ERROR_CURSOR_COLOR, move.get_number()) self.write_to_console('HINT: ' + move.get_reason())
def check_for_simple_contradiction(self): user_input_map = { (x, y): self.board[x][y] if type(self.board[x][y]) is int else 0 for x, y in product(SudokuBoard.INDEX_RANGE, SudokuBoard.INDEX_RANGE) } counts = {number: 0 for number in SudokuBoard.VALUE_RANGE} offending_coord_pairs = [] for index in SudokuBoard.INDEX_RANGE: sub_area_solved_numbers = [ { coord: val for coord, val in user_input_map.items() if coord[0] == index and type(val) is int and val != 0 }, { coord: val for coord, val in user_input_map.items() if coord[1] == index and type(val) is int and val != 0 }, { coord: val for coord, val in user_input_map.items() if SudokuBoard.sector_lookup(coord[0], coord[1]) == index and type(val) is int and val != 0 } ] for sub_area in sub_area_solved_numbers: for value in SudokuBoard.VALUE_RANGE: for coord, number in sub_area.items(): if number == value: counts[number] += 1 offending_coord_pairs.append(coord) if counts[number] > 1: if len(offending_coord_pairs) == 2: print(offending_coord_pairs) return offending_coord_pairs offending_coord_pairs.clear() counts = {number: 0 for number in SudokuBoard.VALUE_RANGE}