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
Пример #3
0
    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}