示例#1
0
def _pointing_pairs_test(s, region, verbose=0):
    """
    :type s: Sudoku
    :type region: set
    :type verbose: int
    """
    changes = 0
    freq = collections.defaultdict(set)
    taken_poss = set()
    for loc in region:
        for poss in s.fields[loc]:
            if len(s.fields[loc]) == 1:
                taken_poss = taken_poss | s.fields[loc]
                continue
            freq[poss].add(loc)
    for poss in taken_poss:
        try:
            freq.pop(poss)
        except KeyError:
            pass
    for poss, locs in freq.items():
        for _, area in s.areas.items():
            if not locs.issubset(area):
                continue
            for loc in region - locs:
                old_possibles = s.fields[loc]
                new_possibles = old_possibles - {poss}
                change = len(old_possibles - new_possibles)
                assert len(new_possibles) != 0
                if change:
                    changes += change
                    if verbose:
                        Colors.yellow(REMOVE.format(old_possibles, poss, loc))
                    s.fields[loc] = new_possibles
    return changes
示例#2
0
def run(sudoku, verbose=0):
    changes = 0
    if verbose:
        Colors.blue("[*] Technique: SimpleColouring".format(changes))
        # sudoku.print()
    all_doubles = _get_doubles(sudoku, verbose)
    for poss, doubles in all_doubles.items():
        changes += _colouring(sudoku, poss, doubles, verbose)
    return changes
示例#3
0
 def check_sudoku(sudoku, verbose=0):
     """
     :type sudoku: Sudoku
     """
     # verbose = True
     solved_fields = len([None for _, poss in sudoku.fields.items() if len(poss) == 1])
     if solved_fields == 81:
         if verbose >= 2:
             Colors.green("[+] Sudoku solved!".format())
         return True
     if verbose >= 2:
         Colors.red("[-] Solved fields: {}".format(solved_fields))
     return False
示例#4
0
def run(sudoku, verbose=0):
    """
    :type sudoku: Sudoku
    :type verbose: int
    """
    changes = 0
    if verbose:
        Colors.blue("[*] Technique: PointingPairs".format(changes))
        sudoku.print()
    for _, row in sudoku.rows.items():
        changes += _pointing_pairs_test(sudoku, row, verbose)
        if changes:
            if verbose:
                Colors.green("[+] PointingPairs (Row) > Changes: {}".format(changes))
                # sudoku.print()
            return changes
    for _, col in sudoku.cols.items():
        changes += _pointing_pairs_test(sudoku, col, verbose)
        if changes:
            if verbose:
                Colors.green("[+] PointingPairs (Col) > Changes: {}".format(changes))
                # sudoku.print()
            return changes
    if verbose:
        Colors.red("[+] PointingPairs > No changes".format(changes))
        # sudoku.print()
    return changes
示例#5
0
def _hidden_singles(s, region, verbose=0):
    changes = 0
    freq = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    locations = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    for loc in region:
        for poss in s.fields[loc]:
            freq[poss] += 1
            locations[poss] = loc
    for poss in range(1, 10):
        if freq[poss] == 1:
            loc = locations[poss]
            changes += len(s.fields[loc]) - 1
            if verbose >= 3:
                Colors.yellow(REMOVE.format(loc, s.fields[loc], poss))
            s.fields[loc] = {poss}
    return changes
示例#6
0
def _eliminate_from_regions(s, source_loc, poss, verbose=0):
    """
    :type s: Sudoku
    :type source_loc: int
    :type poss: set
    :type verbose: int
    :return:
    """
    changes = 0
    target_locs = s.matching_regions_single(s, source_loc)
    for loc in target_locs:
        if poss.issubset(s.fields[loc]):
            changes += 1
            if verbose >= 3:
                Colors.yellow(REMOVE.format(source_loc, poss, loc, s.fields[loc]))
            s.fields[loc] = s.fields[loc] - poss
    return changes
示例#7
0
def run(sudoku, verbose=0):
    changes = 0
    if verbose >= 2:
        Colors.blue("[*] Technique: HiddenPairs".format(changes))
        # s.print()
    for tag, row in sudoku.rows.items():
        changes = _find_hidden_pairs(sudoku, row, verbose=verbose)
    for tag, col in sudoku.cols.items():
        changes = _find_hidden_pairs(sudoku, col, verbose=verbose)
    for tag, area in sudoku.areas.items():
        changes = _find_hidden_pairs(sudoku, area, verbose=verbose)
    if changes:
        if verbose >= 2:
            Colors.green("[+] HiddenPairs > Changes: {}".format(changes))
        if verbose >= 4:
            sudoku.print()
    return changes
示例#8
0
 def solve_sudoku(self, sudoku, verbose=0):
     """
     :type sudoku: Sudoku
     """
     total_changes = 0
     changes = 0
     while True:
         total_changes += changes
         changes = 0
         if self.check_sudoku(sudoku):
             if verbose >= 2:
                 Colors.green("[+] Solved: {}".format(sudoku.line))
             break
         sudoku.print()
         changes += technique.naked_singles(sudoku, verbose)
         if changes:
             continue
         sudoku.print()
         changes += technique.hidden_singles(sudoku, verbose)
         if changes:
             continue
         sudoku.print()
         changes += technique.hidden_pairs(sudoku, verbose)
         if changes:
             continue
         sudoku.print()
         changes += technique.pointing_pairs(sudoku, verbose)
         if changes:
             continue
         # changes += technique.fish(sudoku, verbose)
         # if changes:
         #     continue
         # changes += technique.simple_colouring(sudoku, verbose)
         if verbose >= 2:
             Colors.red("[-] Not solved: {}".format(sudoku.line))
         if verbose >= 4:
             sudoku.print()
         break
     # if total_changes:
     #     print("Aaahh!")
     return total_changes
示例#9
0
def _pointing_pairs(s, locs, verbose=0):
    """
    :type s: Sudoku
    :type locs: set
    :type verbose: int
    """
    changes = 0
    freq = collections.defaultdict(list)
    for loc in locs:
        for poss in s.fields[loc]:
            freq[poss].append(loc)
    for poss, pair_locs in {p: set(ls) for p, ls in freq.items() if len(ls) in (2, 3)}.items():
        target_locs = s.matching_regions(s, pair_locs)
        for loc in target_locs:
            if poss in s.fields[loc]:
                changes += 1
                s.fields[loc].remove(poss)
                if verbose:
                    Colors.yellow(REMOVE.format(pair_locs, poss, loc))
                assert len(s.fields[loc]) > 0
    return changes
示例#10
0
def _hidden_singles_test(s, region, verbose=0):
    changes = 0
    freq = collections.defaultdict(list)
    for loc in region:
        for poss in s.fields[loc]:
            freq[poss].append(loc)
    for poss, locs in freq.items():
        if len(locs) > 1:
            continue
        for loc in region:
            if loc in locs:
                continue
            old_possibles = s.fields[loc]
            new_possibles = old_possibles - {poss}
            change = len(old_possibles - new_possibles)
            if change:
                changes += change
                if verbose >= 3:
                    Colors.yellow(REMOVE.format(loc, s.fields[loc], poss))
                s.fields[loc] = new_possibles
    return changes
示例#11
0
 def solve_current_puzzle_file(self, verbose=0, chucksize=42):
     changes = 0
     count = 0
     solved = 0
     start = time()
     middle_time = time()
     try:
         Colors.yellow(self.update.format(0, 0, 0, 0, 0), end="\r")
         while True:
             su = self.next_sudoku()
             count += 1
             if verbose >= 2:
                 Colors.blue("[*] Puzzle #{}".format(count))
             if verbose >= 4:
                 su.print()
             changes += self.solve_current_sudoku(verbose)
             if verbose >= 4:
                 su.print()
             if self.check_sudoku(su, verbose):
                 solved += 1
             if verbose == 1 and count % chucksize == 0:
                 total_duration = time() - start
                 duration = time() - middle_time
                 middle_time = time()
                 Colors.yellow(self.update.format(count,
                                                  changes,
                                                  (solved / count) * 100,
                                                  total_duration,
                                                  chucksize / duration),
                               end="\r")
             # input("Press Enter to continue...")
     except StopIteration:
         if verbose >= 2:
             Colors.blue("[*] End of puzzle file.")
         pass
     end = time()
     total_time = end - start
     status_message = self.status.format(self.current_puzzles,
                                         changes,
                                         solved,
                                         count,
                                         (solved / count) * 100,
                                         total_time,
                                         count / total_time)
     if verbose >= 2:
         print(status_message)
     return changes, solved, count, status_message
示例#12
0
def run(sudoku, verbose=0):
    changes = 0
    if verbose >= 2:
        Colors.blue("[*] Technique: Hidden Singles".format(changes))
        # sudoku.print()
    for _, region in sudoku.regions.items():
        changes += _hidden_singles_test(sudoku, region, verbose)
        if changes:
            if verbose >= 2:
                Colors.green("[+] Hidden Singles > Changes: {}".format(changes))
                # sudoku.print()
            return changes
    if verbose >= 2:
        Colors.red("[-] Hidden Singles > No change".format(changes))
        # sudoku.print()
    return changes
示例#13
0
def run(s, verbose=0):
    changes = 0
    if verbose >= 2:
        Colors.blue("[*] Technique: NakedSingles".format(changes))
    if verbose >= 4:
        s.print()
    for loc, poss in s.fields.items():
        if len(poss) == 1:
            changes += _eliminate_from_regions(s, loc, poss, verbose)
    if changes:
        if verbose >= 2:
            Colors.green("[+] NakedSingles > Changes: {}".format(changes))
        if verbose >= 4:
            s.print()
        return changes
    if verbose >= 2:
        Colors.red("[-] NakedSingles > No change".format(changes))
    if verbose >= 4:
        s.print()
    return changes
示例#14
0
def _find_hidden_pairs(s, region, verbose=0):
    changes = 0
    freq = collections.defaultdict(set)
    already_set = 0
    for loc in region:
        length = len(s.fields[loc])
        if length == 1:
            already_set += 1
            continue
        for poss in s.fields[loc]:
            freq[poss].add(loc)
    pairs = []
    taken_poss = set()
    max_length = 9 - already_set
    for length in reversed(range(2, max_length + 1)):
        try:
            for candidates in itertools.combinations(freq, length):
                all_locs = set()
                all_poss = set()
                for p in candidates:
                    all_locs = all_locs | freq[p]
                    all_poss = all_poss | {p}
                if len(all_locs) == max_length:
                    raise StopIteration
                for (poss, locs) in pairs:
                    if all_poss.issubset(poss):
                        raise StopIteration
                if len(all_poss) == len(all_locs):
                    # Leaves a pair that is not a pair
                    # So...
                    # There are false hits, or freq should be redone for each iteration (meaning, return changes)
                    changes += _remove_pairs(s, all_poss, all_locs, verbose)
                    pairs.append((all_poss, all_locs))
                    taken_poss = taken_poss | all_poss
        except StopIteration:
            continue
    if len(pairs) == 0:
        return changes
    for poss, locs in pairs:
        for loc in region:
            old_possibles = s.fields[loc]
            if loc in locs:
                new_possibles = old_possibles & poss
                change = len(old_possibles - new_possibles)
                if change:
                    if verbose >= 3:
                        Colors.yellow(REMOVE.format(locs, old_possibles - poss, loc, old_possibles))
                    s.fields[loc] = new_possibles
                    changes += change
            else:
                new_possibles = old_possibles - poss
                change = len(old_possibles - new_possibles)
                if change:
                    if verbose >= 3:
                        Colors.yellow(REMOVE.format(locs, poss, loc, old_possibles))
                    s.fields[loc] = new_possibles
                    changes += change
            # change = len(old_possibles - new_possibles)
            # if change:
            #     if verbose >= 3:
            #         Colors.yellow(REMOVE.format(locs, poss, loc, old_possibles))
            #     s.fields[loc] = new_possibles
            #     changes += change
    # if changes:
    #     print("Boo!")
    return changes