Чекер для судоку. 🔢
Мы хотим научить модель решать Судоку и применить для этого 
                                  метод Tree of Thoughts. Для этого нам необходимо написать класс-проверщик
                                  (Checker), который будет проверять в правильном направлении модель строит
                                  рассуждения или нет.
Для начала посмотрим на промпт для судоку 4 х 4:
sudoku_puzzle = "3,*,*,2|1,*,3,*|*,1,*,3|4,*,*,1"
sudoku_solution = "3,4,1,2|1,2,3,4|2,1,4,3|4,3,2,1"
problem_description = f"""
{sudoku_puzzle}
- Это головоломка Судоку размером 4x4.
- Символ * обозначает ячейку, которую тебе нужно заполнить.
- Символ | разделяет строки.
- На каждом шаге замени одну или несколько * цифрами от 1 до 4.
- Напиши текущее состояние пазла с добавленными цифрами
- Ни в одной строке, столбце или 2x2 подсетке не должно быть одинаковых цифр.
- Сохраняй полученные цифры из предыдущих успешных мыслей на своих местах.
- Каждая мысль может быть промежуточным или окончательным решением.
""".strip()
print(problem_description)Как можно понять из промпта, мы хотим, чтобы на каждом шаге заменялась одна или несколько звездочек . Но при этом модели нужно понимать в верную ли сторону произошла замена. Может быть предыдущий шаг был неверный, и стоит вернуться с этой ветки размышлений на шаг назад и попробовать заменить другой пропуск или заменить пропуск на другое число. На помощь придут ToTChecker и ThoughtValidity.
Немного пояснений:
Нам нужно взять поледнее рассуждение (мысль), они хранятся в переменной thoughts.
Далее мы проверим соответствует ли предложенная мысль верному ответу. Т.е. если мысль
                                  равна переменной sudoku_solution, значит мы нашли верное решение.  В таком случае
                                  чекер должен вернуть ThoughtValidity.VALID_FINAL.
Если наше решение не содержит ошибок, но при этом в нем есть незаполненные клетки, мы
                                  вернем ThoughtValidity.VALID_INTERMEDIATE. Проверим, является ли наше
                                  решение частичным с помощью регулярных выражений.
Символы "*" и "|" являются специальными. "*" нам нужно будет заменить на специальный символ в регулярных выражениях, обозначающий любой одиночный символ, а "|" должен восприниматься в регулярном выражении не как специальный символ, а как элемент в нашей строке. Т.е. если мы оставили клетки незаполненными, при этом все значения в заполненных нами клетках совпадают с правильным решением, то наше решение будет матчится регуляркой с правильным решением.
Если в какой-то клетке содержится неверная цифра - мы возвращаем
                                  ThoughtValidity.INVALID. Мы можем считать, что решение неверное, если оно
                                  не является верным или частичным решением.
Ноутбук с тестами для проверки работы чекера ссылка.
Выберете одну или несколько верных реализаций нашего класса.
A.
class MyChecker(ToTChecker):
    def evaluate(
        self, problem_description: str, thoughts: Tuple[str, ...] = ()
    ) -> ThoughtValidity:
        if eval(thoughts) == 10:
            return ThoughtValidity.VALID_FINAL
        elif eval(thoughts) in [9,8,7,6]:
            return ThoughtValidity.VALID_INTERMEDIATE
        else:
            return ThoughtValidity.INVALIDB.
import re
class MyChecker(ToTChecker):
    def evaluate(
        self, problem_description: str, thoughts: Tuple[str, ...] = ()
    ) -> ThoughtValidity:
        last_thought = thoughts[-1]
        clean_solution = last_thought.replace(" ", "").replace('"', "")
        regex_solution = clean_solution.replace("*", ".").replace("|", "\\|")
        if sudoku_solution in clean_solution:
            return ThoughtValidity.VALID_FINAL
        elif re.search(regex_solution, sudoku_solution):
            return ThoughtValidity.VALID_INTERMEDIATE
        else:
            return ThoughtValidity.INVALIDC.
import re
class MyChecker(ToTChecker):
    def evaluate(
        self, problem_description: str, thoughts: Tuple[str, ...] = ()
    ) -> ThoughtValidity:
        solution = thoughts[-1].replace(" ", "").replace('"', "")
        if sudoku_solution in solution:
            return ThoughtValidity.VALID_FINAL
        elif re.search(solution, sudoku_solution):
            return ThoughtValidity.VALID_INTERMEDIATE
        else:
            return ThoughtValidity.INVALID
D.
import re
class MyChecker(ToTChecker):
    def evaluate(
        self, problem_description: str, thoughts: Tuple[str, ...] = ()
    ) -> ThoughtValidity:
        last_thought = thoughts[-1]
        clean_solution = last_thought.replace(" ", "").replace('"', "")
        regex_solution = clean_solution.replace("*", ".")
        if sudoku_solution in clean_solution:
            return ThoughtValidity.VALID_FINAL
        elif re.search(regex_solution, sudoku_solution):
            return ThoughtValidity.VALID_INTERMEDIATE
        else:
            return ThoughtValidity.INVALID