<commit_before># Copyright (C) 2015 <NAME> <<EMAIL>>
#
# This script is published under the terms of the MIT license.
# See http://opensource.org/licenses/mit-license.php

# Python 3 is required

import itertools

from sudoku import Clue


class _Data:
    pass


class _Ceil:
    def __init__(self, data):
        self.data = data
        self.ghost = self.value = [-i - 1 for i in range(data.size)]
        self.groups = []

    def __repr__(self):
        return "<Ceil value:%s>" % self.value

    def set(self, value):
        self.ghost = self.value
        self.value = [value]
        # Notify the groups.
        for i in self.groups:
            i.on_ceil_value_set_pre(self, value)
        # Notify the groups.
        for i in self.groups:
            i.on_ceil_value_set(self, value)

    def abandon(self, value):
        for i, j in enumerate(self.value):
            if j == value:
                # Notify the groups.
                for k in self.groups:
                    k.on_ceil_value_abandoned_pre(self, value)
                del self.value[i]
                break
        else:
            return False
        # Notify the groups.
        for i in self.groups:
            i.on_ceil_value_abandoned(self, value)
        return True


class _Group:
    def __init__(self, cells, data):
        self.data = data
        self.cells = cells
        # Link this group to the cells.
        for ceil in cells:
            ceil.groups.append(self)
        # Create depth map.
        self.depth = [1] * data.size
        # Create pairs dict.
        self.pairs = {}

    def on_ceil_value_set_pre(self, ceil, value):
        # Remove the ceil from list.
        self.cells.remove(ceil)

        # Hidden singles
        self.depth[value - 1] = -self.data.size
        for i in ceil.ghost:
            self.depth[-i - 1] += 1

    def on_ceil_value_set(self, ceil, value):
        # Naked singles
        for i in self.cells:
            i.abandon(-value)

    def on_ceil_value_abandoned_pre(self, ceil, value):
        key = frozenset(ceil.value)
        try:
            self.pairs[key] -= 1
        except KeyError:
            self.pairs[key] = self.data.size - 1

    def on_ceil_value_abandoned(self, ceil, value):
        size = self.data.size

        # Hidden singles
        self.depth[-value - 1] += 1

        # Naked pairs/triples/etc
        has_open_pairs = False
        key = frozenset(ceil.value)
        try:
            self.pairs[key] += 1
            if self.pairs[key] == len(ceil.value) > 1:
                has_open_pairs = True
        except KeyError:
            self.pairs[key] = 1

        # Pointing pairs/triples
        pointing_cells = []
        possibly_pointing = size > self.depth[-value - 1] > size - size ** 0.5

        for i in self.cells:
            if i is ceil:
                continue
            # Hidden singles
            if self.depth[-value - 1] == size and value in i.value:
                # Simplify the superposition.
                for k in i.value:
                    if k != value:
                        i.abandon(k)
            # Naked pairs/triples/etc
            if has_open_pairs and ceil.value in i.value:
                # Simplify the superposition.
                for k in ceil.value:
                    if k not in i.value:
                        i.abandon(k)
            # Pointing pairs/triples
            if possibly_pointing and value in i.value:
                pointing_cells.append(i)
            continue

        # Pointing pairs/triples
        if pointing_cells:
            groups = list(pointing_cells[0].groups)
            groups.remove(self)
            for i in pointing_cells:
                groups[:] = [j for j in groups if j in i.groups]
                if not groups:
                    break
            else:
                for i in groups:
                    for j in i.cells:
                        if j not in pointing_cells:
                            j.abandon(value)


class Sudoku:
    def __init__(self, sudoku):
        # Parse the source of a sudoku.<commit_msg>sudoku_i.py: Filter pointing groups while searching cells<commit_after># Copyright (C) 2015 <NAME> <<EMAIL>>
#
# This script is published under the terms of the MIT license.
# See http://opensource.org/licenses/mit-license.php

# Python 3 is required

import itertools

from sudoku import Clue


class _Data:
    pass


class _Ceil:
    def __init__(self, data):
        self.data = data
        self.ghost = self.value = [-i - 1 for i in range(data.size)]
        self.groups = []

    def __repr__(self):
        return "<Ceil value:%s>" % self.value

    def set(self, value):
        self.ghost = self.value
        self.value = [value]
        # Notify the groups.
        for i in self.groups:
            i.on_ceil_value_set_pre(self, value)
        # Notify the groups.
        for i in self.groups:
            i.on_ceil_value_set(self, value)

    def abandon(self, value):
        for i, j in enumerate(self.value):
            if j == value:
                # Notify the groups.
                for k in self.groups:
                    k.on_ceil_value_abandoned_pre(self, value)
                del self.value[i]
                break
        else:
            return False
        # Notify the groups.
        for i in self.groups:
            i.on_ceil_value_abandoned(self, value)
        return True


class _Group:
    def __init__(self, cells, data):
        self.data = data
        self.cells = cells
        # Link this group to the cells.
        for ceil in cells:
            ceil.groups.append(self)
        # Create depth map.
        self.depth = [1] * data.size
        # Create pairs dict.
        self.pairs = {}

    def on_ceil_value_set_pre(self, ceil, value):
        # Remove the ceil from list.
        self.cells.remove(ceil)

        # Hidden singles
        self.depth[value - 1] = -self.data.size
        for i in ceil.ghost:
            self.depth[-i - 1] += 1

    def on_ceil_value_set(self, ceil, value):
        # Naked singles
        for i in self.cells:
            i.abandon(-value)

    def on_ceil_value_abandoned_pre(self, ceil, value):
        key = frozenset(ceil.value)
        try:
            self.pairs[key] -= 1
        except KeyError:
            self.pairs[key] = self.data.size - 1

    def on_ceil_value_abandoned(self, ceil, value):
        size = self.data.size

        # Hidden singles
        self.depth[-value - 1] += 1

        # Naked pairs/triples/etc
        has_open_pairs = False
        key = frozenset(ceil.value)
        try:
            self.pairs[key] += 1
            if self.pairs[key] == len(ceil.value) > 1:
                has_open_pairs = True
        except KeyError:
            self.pairs[key] = 1

        # Pointing pairs/triples
        pointing_cells = None
        pointing_groups = None
        possibly_pointing = size > self.depth[-value - 1] > size - size ** 0.5

        for i in self.cells:
            if i is ceil:
                continue
            # Hidden singles
            if self.depth[-value - 1] == size and value in i.value:
                # Simplify the superposition.
                for k in i.value:
                    if k != value:
                        i.abandon(k)
            # Naked pairs/triples/etc
            if has_open_pairs and ceil.value in i.value:
                # Simplify the superposition.
                for k in ceil.value:
                    if k not in i.value:
                        i.abandon(k)
            # Pointing pairs/triples
            if possibly_pointing and value in i.value:
                if pointing_cells is None:
                    pointing_cells = []
                    pointing_groups = list(i.groups)
                    pointing_groups.remove(self)
                else:
                    pointing_groups[:] = [j for j in pointing_groups if j in i.groups]
                    possibly_pointing = bool(pointing_groups)
                pointing_cells.append(i)
            continue

        # Pointing pairs/triples
        if pointing_groups:
            for i in pointing_groups:
                for j in i.cells:
                    if j not in pointing_cells:
                        j.abandon(value)


class Sudoku:
    def __init__(self, sudoku):
        # Parse the source of a sudoku.
{'fraction_non_alphanumeric': 0.08576206402293358, 'fraction_numerical': 0.005136168179646441, 'mean_word_length': 1.4347193951730155, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '855176', 'n_tokens_mistral': 2565, 'n_tokens_neox': 2398, 'n_words': 699}