Пример #1
0
class Generator:

    # # constructor for generator, reads in a space delimited
    # def __init__(self, starting_file):

    #     # opening file
    #     f = open(starting_file)

    #     # reducing file to a list of numbers
    #     numbers = filter(lambda x: x in '123456789',list(reduce(lambda x,y:x+y,f.readlines())))
    #     print (numbers)
    #     numbers = map(int,numbers)
    #     ['1', '2', '3', '4', '5', '6', '7', '8', '9', '4', '5', '6', '7', '8', '9', '1', '2', '3', '7', '8', '9', '1', '2', '3', '4', '5', '6', '2', '1', '4', '3', '6', '5', '8', '9', '7', '3', '6', '5', '8', '9', '7', '2', '1', '4', '8', '9', '7', '2', '1', '4', '3', '6', '5', '5', '3', '1', '6', '4', '2', '9', '7', '8', '6', '4', '2', '9', '7', '8', '5', '3', '1', '9', '7', '8', '5', '3', '1', '6', '4', '2']

    #     # closing file
    #     f.close()

    #     # constructing board
    #     self.board = Board(numbers)

        # constructor for generator, reads in a space delimited
    def __init__(self):
        numbers = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '4', '5', '6', '7', '8', '9', '1', '2', '3', '7', '8', '9', '1', '2', '3', '4', '5', '6', '2', '1', '4', '3', '6', '5', '8', '9', '7', '3', '6', '5', '8', '9', '7', '2', '1', '4', '8', '9', '7', '2', '1', '4', '3', '6', '5', '5', '3', '1', '6', '4', '2', '9', '7', '8', '6', '4', '2', '9', '7', '8', '5', '3', '1', '9', '7', '8', '5', '3', '1', '6', '4', '2']
        numbers = map(int,numbers)
        self.board = Board(numbers)

    # function randomizes an existing complete puzzle
    def randomize(self, iterations):

        # not allowing transformations on a partial puzzle
        if len(self.board.get_used_cells())==81:

            # looping through iterations
            for x in range(0, iterations):

                # to get a random column/row
                case = random.randint(0, 3)

                # to get a random band/stack
                block = random.randint(0, 2) * 3

                # in order to select which row and column we shuffle an array of
                # indices and take both elements
                options = range(0,3)
                random.shuffle(options)
                piece1, piece2 = options[0],options[1]

                # pick case according to random to do transformation
                if case == 0:
                    self.board.swap_row(block + piece1, block + piece2)
                elif case == 1:
                    self.board.swap_column(block + piece1, block + piece2)
                elif case == 2:
                    self.board.swap_stack(piece1, piece2)
                elif case == 3:
                    self.board.swap_band(piece1, piece2)
        else:
            raise Exception('Rearranging partial board may compromise uniqueness.')

    # method gets all possible values for a particular cell, if there is only one
    # then we can remove that cell
    def reduce_via_logical(self, cutoff = 81):
        cells = self.board.get_used_cells()
        random.shuffle(cells)
        for cell in cells:
                if len(self.board.get_possibles(cell)) == 1:
                    cell.value = 0
                    cutoff -= 1
                if cutoff == 0:
                    break

    # method attempts to remove a cell and checks that solution is still unique
    def reduce_via_random(self, cutoff=81):
        temp = self.board
        existing = temp.get_used_cells()

        # sorting used cells by density heuristic, highest to lowest
        new_set = [(x,self.board.get_density(x)) for x in existing]
        elements= [x[0] for x in sorted(new_set, key=lambda x: x[1], reverse=True)]

        # for each cell in sorted list
        for cell in elements:
            original = cell.value

            # get list of other values to try in its place
            complement = [x for x in range(1,10) if x != original]
            ambiguous = False

            # check each value in list of other possibilities to try
            for x in complement:

                # set cell to value
                cell.value = x

                # create instance of solver
                s = Solver(temp)

                # if solver can fill every box and the solution is valid then
                # puzzle becomes ambiguous after removing particular cell, so we can break out
                if s.solve() and s.is_valid():
                    cell.value = original
                    ambiguous = True
                    break

            # if every value was checked and puzzle remains unique, we can remove it
            if not ambiguous:
                cell.value = 0
                cutoff -= 1

            # if we ever meet the cutoff limit we can break out
            if cutoff == 0:
                break


    # returns current state of generator including number of empty cells and a representation
    # of the puzzle
    def get_current_state(self):
        template = "There are currently %d starting cells.\n\rCurrent puzzle state:\n\r\n\r%s\n\r"
        return template % (len(self.board.get_used_cells()),self.board.__str__())