Пример #1
0
 def box(self, row, col):
     """Get the values of the box pertaining to the specified row and column of the Sudoku"""
     box = []
     box_i = (row // self.order) * self.order
     box_j = (col // self.order) * self.order
     for i in utils.range_(box_i, box_i + self.order):
         for j in utils.range_(box_j, box_j + self.order):
             box.append(self[i][j])
     return box
Пример #2
0
 def __eq__(self, other):
     if isinstance(other, Sudoku):
         if self.order != other.order:
             return False
         for i in utils.range_(self.side):
             for j in utils.range_(self.side):
                 if self[i][j] != other[i][j]:
                     return False
         return True
     return False
Пример #3
0
    def _parse_from_string(string_input):
        """Parses a Sudoku instance from string input.

        :param string_input: A string containing the Sudoku to parse.
        :type string_input: str
        :return: The parsed Sudoku.
        :rtype: :py:class:`dlxsudoku.sudoku.Sudoku`

        """
        # Check if comment line is present.
        read_lines = list(filter(None, string_input.split('\n')))
        if read_lines[0].startswith('#'):
            comment = read_lines.pop(0)
        else:
            comment = ''

        if len(read_lines) > 1:
            # Assume that Sudoku is defined over several rows.
            order = int(math.sqrt(len(read_lines)))
        else:
            # Sudoku is defined on one line.
            order = int(math.sqrt(math.sqrt(len(read_lines[0]))))
            read_lines = filter(lambda x: len(x) == (order ** 2), [read_lines[0][i:(i + order ** 2)] for
                                i in utils.range_(len(read_lines[0])) if i % (order ** 2) == 0])
        matrix = utils.get_list_of_lists(
            order ** 2, order ** 2, fill_with=0)

        for i, line in enumerate(read_lines):
            line = line.strip()
            for j, value in enumerate(line):
                if value.isdigit() and int(value):
                    matrix[i][j] = int(value)
                else:
                    matrix[i][j] = 0
        return order, comment, matrix
Пример #4
0
def project_euler_sudokus():
    try:
        r = urlrequest.urlopen("https://projecteuler.net/project/resources/p096_sudoku.txt")
        sudokus = r.readlines()
        sudokus = [sudokus[k:k+10] for k in range_(0, len(sudokus), 10)]
    except:
        sudokus = []
    return sudokus
Пример #5
0
    def _update(self):
        """Calculate remaining values for each row, column, box and finally cell."""
        # Update possible values in each row, column and box.
        for i, (row, col, box) in enumerate(zip(self.row_iter(), self.col_iter(), self.box_iter())):
            self._poss_rows[i] = set(self._values).difference(set(row))
            self._poss_cols[i] = set(self._values).difference(set(col))
            self._poss_box[i] = set(self._values).difference(set(box))

        # Iterate over the entire Sudoku and combine information about possible values
        # from rows, columns and boxes to get a set of possible values for each cell.
        for i in utils.range_(self.side):
            self._possibles[i] = {}
            for j in utils.range_(self.side):
                self._possibles[i][j] = set()
                if self[i][j] > 0:
                    continue
                this_box_index = ((i // self.order) * self.order) + (j // self.order)
                self._possibles[i][j] = self._poss_rows[i].intersection(
                    self._poss_cols[j]).intersection(self._poss_box[this_box_index])
Пример #6
0
    def _fill_naked_singles(self):
        """Look for naked singles, i.e. cells with ony one possible value.

        :return: If any Naked Single has been found.
        :rtype: bool

        """
        simple_found = False
        for i in utils.range_(self.side):
            for j in utils.range_(self.side):
                if self[i][j] > 0:
                    continue
                p = self._possibles[i][j]
                if len(p) == 1:
                    self.set_cell(i, j, list(p)[0])
                    self.solution_steps.append(self._format_step("NAKED", (i, j), self[i][j]))
                    simple_found = True
                elif len(p) == 0:
                    raise SudokuHasNoSolutionError("Error made! No possible value for ({0},{1})!".format(i + 1, j + 1))

        return simple_found
Пример #7
0
    def __init__(self, string_input):

        self.order, self.comment, self._matrix = \
            self._parse_from_string(string_input)

        self.side = self.order ** 2
        self.solution_steps = []

        self._values = tuple(utils.range_(0, (self.order ** 2) + 1))
        self._poss_rows = {}
        self._poss_cols = {}
        self._poss_box = {}
        self._possibles = {}

        self._check_sudoku_validity()
Пример #8
0
    def _fill_hidden_singles(self):
        """Look for hidden singles, i.e. cells with only one unique possible value in row, column or box.

        :return: If any Hidden Single has been found.
        :rtype: bool

        """
        for i in utils.range_(self.side):
            box_i = (i // self.order) * self.order
            for j in utils.range_(self.side):
                box_j = (j // self.order) * self.order
                # Skip if this cell is determined already.
                if self[i][j] > 0:
                    continue

                # Look for hidden single in rows.
                p = self._possibles[i][j]
                for k in utils.range_(self.side):
                    if k == j:
                        continue
                    p = p.difference(self._possibles[i][k])
                if len(p) == 1:
                    # Found a hidden single in a row!
                    self.set_cell(i, j, p.pop())
                    self.solution_steps.append(self._format_step("HIDDEN-ROW", (i, j), self[i][j]))
                    return True

                # Look for hidden single in columns
                p = self._possibles[i][j]
                for k in utils.range_(self.side):
                    if k == i:
                        continue
                    p = p.difference(self._possibles[k][j])
                if len(p) == 1:
                    # Found a hidden single in a column!
                    self.set_cell(i, j, p.pop())
                    self.solution_steps.append(self._format_step("HIDDEN-COL", (i, j), self[i][j]))
                    return True

                # Look for hidden single in box
                p = self._possibles[i][j]
                for k in utils.range_(box_i, box_i + self.order):
                    for kk in utils.range_(box_j, box_j + self.order):
                        if k == i and kk == j:
                            continue
                        p = p.difference(self._possibles[k][kk])
                if len(p) == 1:
                    # Found a hidden single in a box!
                    self.set_cell(i, j, p.pop())
                    self.solution_steps.append(self._format_step("HIDDEN-BOX", (i, j), self[i][j]))
                    return True

        return False
Пример #9
0
 def box_iter(self):
     """Get an iterator over all boxes in the Sudoku"""
     for i in utils.range_(self.order):
         for j in utils.range_(self.order):
             yield self.box(i * 3, j * 3)
Пример #10
0
 def col_iter(self):
     """Get an iterator over all columns in the Sudoku"""
     for k in utils.range_(self.side):
         yield self.col(k)
Пример #11
0
 def row_iter(self):
     """Get an iterator over all rows in the Sudoku"""
     for k in utils.range_(self.side):
         yield self.row(k)