Алгоритм для решения Судоку

Используя понимание списка, вы можете сделать что-то вроде этого:

def getUrl(keyword):
    return [dict[key] for key in dict.keys() if keyword in key]

, если я вызову это с помощью ключевого слова «= черный», он вернёт:

['https://kith.com/products/hoka-one-tor-ultra-high-2-wp-black', 'https://kith.com/products/adidas-originals-yung-1-core-black-white']

. URL-адреса, соответствующие ключам, содержащим keyword.

Если у вас более одного keyword, это должно сработать:

def getUrl(keywords):
    return [dict[key] for key in dict.keys() if len([keyword for keyword in keywords if keyword in key])>0]

, если я вызову это с помощью keywords = ['black','ultra'], это вернет:

['https://kith.com/products/hoka-one-tor-ultra-high-2-wp-black', 'https://kith.com/products/adidas-originals-yung-1-core-black-white']

вернуть [], если ключи не найдены.

13
задан genesis 22 September 2011 в 15:52
поделиться

4 ответа

Привет я вел блог о записи решателя судоку с нуля в Python и в настоящее время записи целого ряда о записи решателя программирования с использованием ограничительного языка в Julia (другой, но более быстрый язык высокого уровня), можно считать проблему судоку из файла, который, кажется, легче более удобный, чем gui или cli путь. Общее представление I использования это программирование с использованием ограничительного языка и использование всех, отличающихся / ограничение на уникальность данных, но я кодировал его сам вместо того, чтобы использовать решатель программирования с использованием ограничительного языка.

, Если кому-то интересно:

0
ответ дан 1 December 2019 в 18:06
поделиться

Существует четыре шага для решения судоку:

  1. Определяют все возможности для каждой ячейки (получение от строки, столбца и поля) и пытаются разработать возможную матрицу. 2. Проверьте на двойную пару, если она существует, тогда удаляют эти два значения из всех ячеек в той строке/столбце/поле, везде, где пара существует, Если какая-либо ячейка имеет единственную возможность, тогда присваивают тот шаг 1 выполнения снова
  2. Проверка на каждую ячейку с каждой строкой, столбец и поле. Если ячейка имеет одно значение, которое не принадлежит других возможных значений, тогда присваивают то значение той ячейке. выполненный шаг 1 снова
  3. , Если судоку все еще не решено, то мы должны запустить следующее предположение, Предположить первое возможное значение и присвоиться. Тогда выполненный шаг 1†“3, Если все еще не решено тогда делает это для следующего возможного значения и выполняет его в рекурсии.
  4. , Если судоку все еще не решено, то мы должны запустить следующее предположение, Предположить первое возможное значение и присвоиться. Тогда выполненный шаг 1†“3

, Если все еще не решено тогда делает это для следующего возможного значения и выполняет его в рекурсии.

import math
import sys


def is_solved(l):
    for x, i in enumerate(l):
        for y, j in enumerate(i):
            if j == 0:
                # Incomplete
                return None
            for p in range(9):
                if p != x and j == l[p][y]:
                    # Error
                    print('horizontal issue detected!', (x, y))
                    return False
                if p != y and j == l[x][p]:
                    # Error
                    print('vertical issue detected!', (x, y))
                    return False
            i_n, j_n = get_box_start_coordinate(x, y)
            for (i, j) in [(i, j) for p in range(i_n, i_n + 3) for q in range(j_n, j_n + 3)
                           if (p, q) != (x, y) and j == l[p][q]]:
                    # Error
                print('box issue detected!', (x, y))
                return False
    # Solved
    return True


def is_valid(l):
    for x, i in enumerate(l):
        for y, j in enumerate(i):
            if j != 0:
                for p in range(9):
                    if p != x and j == l[p][y]:
                        # Error
                        print('horizontal issue detected!', (x, y))
                        return False
                    if p != y and j == l[x][p]:
                        # Error
                        print('vertical issue detected!', (x, y))
                        return False
                i_n, j_n = get_box_start_coordinate(x, y)
                for (i, j) in [(i, j) for p in range(i_n, i_n + 3) for q in range(j_n, j_n + 3)
                               if (p, q) != (x, y) and j == l[p][q]]:
                        # Error
                    print('box issue detected!', (x, y))
                    return False
    # Solved
    return True


def get_box_start_coordinate(x, y):
    return 3 * int(math.floor(x/3)), 3 * int(math.floor(y/3))


def get_horizontal(x, y, l):
    return [l[x][i] for i in range(9) if l[x][i] > 0]


def get_vertical(x, y, l):
    return [l[i][y] for i in range(9) if l[i][y] > 0]


def get_box(x, y, l):
    existing = []
    i_n, j_n = get_box_start_coordinate(x, y)
    for (i, j) in [(i, j) for i in range(i_n, i_n + 3) for j in range(j_n, j_n + 3)]:
        existing.append(l[i][j]) if l[i][j] > 0 else None
    return existing


def detect_and_simplify_double_pairs(l, pl):
    for (i, j) in [(i, j) for i in range(9) for j in range(9) if len(pl[i][j]) == 2]:
        temp_pair = pl[i][j]
        for p in (p for p in range(j+1, 9) if len(pl[i][p]) == 2 and len(set(pl[i][p]) & set(temp_pair)) == 2):
            for q in (q for q in range(9) if q != j and q != p):
                pl[i][q] = list(set(pl[i][q]) - set(temp_pair))
                if len(pl[i][q]) == 1:
                    l[i][q] = pl[i][q].pop()
                    return True
        for p in (p for p in range(i+1, 9) if len(pl[p][j]) == 2 and len(set(pl[p][j]) & set(temp_pair)) == 2):
            for q in (q for q in range(9) if q != i and p != q):
                pl[q][j] = list(set(pl[q][j]) - set(temp_pair))
                if len(pl[q][j]) == 1:
                    l[q][j] = pl[q][j].pop()
                    return True
        i_n, j_n = get_box_start_coordinate(i, j)
        for (a, b) in [(a, b) for a in range(i_n, i_n+3) for b in range(j_n, j_n+3)
                       if (a, b) != (i, j) and len(pl[a][b]) == 2 and len(set(pl[a][b]) & set(temp_pair)) == 2]:
            for (c, d) in [(c, d) for c in range(i_n, i_n+3) for d in range(j_n, j_n+3)
                           if (c, d) != (a, b) and (c, d) != (i, j)]:
                pl[c][d] = list(set(pl[c][d]) - set(temp_pair))
                if len(pl[c][d]) == 1:
                    l[c][d] = pl[c][d].pop()
                    return True
    return False


def update_unique_horizontal(x, y, l, pl):
    tl = pl[x][y]
    for i in (i for i in range(9) if i != y):
        tl = list(set(tl) - set(pl[x][i]))
    if len(tl) == 1:
        l[x][y] = tl.pop()
        return True
    return False


def update_unique_vertical(x, y, l, pl):
    tl = pl[x][y]
    for i in (i for i in range(9) if i != x):
        tl = list(set(tl) - set(pl[i][y]))
    if len(tl) == 1:
        l[x][y] = tl.pop()
        return True
    return False


def update_unique_box(x, y, l, pl):
    tl = pl[x][y]
    i_n, j_n = get_box_start_coordinate(x, y)
    for (i, j) in [(i, j) for i in range(i_n, i_n+3) for j in range(j_n, j_n+3) if (i, j) != (x, y)]:
        tl = list(set(tl) - set(pl[i][j]))
    if len(tl) == 1:
        l[x][y] = tl.pop()
        return True
    return False


def find_and_place_possibles(l):
    while True:
        pl = populate_possibles(l)
        if pl != False:
            return pl


def populate_possibles(l):
    pl = [[[]for j in i] for i in l]
    for (i, j) in [(i, j) for i in range(9) for j in range(9) if l[i][j] == 0]:
        p = list(set(range(1, 10)) - set(get_horizontal(i, j, l) +
                                         get_vertical(i, j, l) + get_box(i, j, l)))
        if len(p) == 1:
            l[i][j] = p.pop()
            return False
        else:
            pl[i][j] = p
    return pl


def find_and_remove_uniques(l, pl):
    for (i, j) in [(i, j) for i in range(9) for j in range(9) if l[i][j] == 0]:
        if update_unique_horizontal(i, j, l, pl) == True:
            return True
        if update_unique_vertical(i, j, l, pl) == True:
            return True
        if update_unique_box(i, j, l, pl) == True:
            return True
    return False


def try_with_possibilities(l):
    while True:
        improv = False
        pl = find_and_place_possibles(l)
        if detect_and_simplify_double_pairs(
                l, pl) == True:
            continue
        if find_and_remove_uniques(
                l, pl) == True:
            continue
        if improv == False:
            break
    return pl


def get_first_conflict(pl):
    for (x, y) in [(x, y) for x, i in enumerate(pl) for y, j in enumerate(i) if len(j) > 0]:
        return (x, y)


def get_deep_copy(l):
    new_list = [i[:] for i in l]
    return new_list


def run_assumption(l, pl):
    try:
        c = get_first_conflict(pl)
        fl = pl[c[0]
                ][c[1]]
        # print('Assumption Index : ', c)
        # print('Assumption List: ',  fl)
    except:
        return False
    for i in fl:
        new_list = get_deep_copy(l)
        new_list[c[0]][c[1]] = i
        new_pl = try_with_possibilities(new_list)
        is_done = is_solved(new_list)
        if is_done == True:
            l = new_list
            return new_list
        else:
            new_list = run_assumption(new_list, new_pl)
            if new_list != False and is_solved(new_list) == True:
                return new_list
    return False


if __name__ == "__main__":
    l = [
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 8, 0, 0, 0, 0, 4, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 6, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0],
        [2, 0, 0, 0, 0, 0, 0, 0, 0],
        [0, 0, 0, 0, 0, 0, 2, 0, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0]
    ]
    # This puzzle copied from Hacked rank test case
    if is_valid(l) == False:
        print("Sorry! Invalid.")
        sys.exit()
    pl = try_with_possibilities(l)
    is_done = is_solved(l)
    if is_done == True:
        for i in l:
            print(i)
        print("Solved!!!")
        sys.exit()

    print("Unable to solve by traditional ways")
    print("Starting assumption based solving")
    new_list = run_assumption(l, pl)
    if new_list != False:
        is_done = is_solved(new_list)
        print('is solved ? - ', is_done)
        for i in new_list:
            print(i)
        if is_done == True:
            print("Solved!!! with assumptions.")
        sys.exit()
    print(l)
    print("Sorry! No Solution. Need to fix the valid function :(")
    sys.exit()
1
ответ дан 1 December 2019 в 18:06
поделиться

Используя Google ortools - следующее или генерирует фиктивный массив судоку или решит кандидата. Код является, вероятно, более подробным, чем необходимый, любая обратная связь ценится.

идея состоит в том, чтобы решить проблему программирования с использованием ограничительного языка, которая включает

  1. Список 81 переменной с целочисленными границами между 1 и 9.
  2. Все другое ограничение для вектора - строки
  3. Все другое ограничение для вектора - столбца
  4. Все другое ограничение для подматриц

, Кроме того, при попытке решить существующее судоку, мы добавляем дополнительные ограничения на переменные, которые уже присвоили значение.

from ortools.constraint_solver import pywrapcp
import numpy as np

def sudoku_solver(candidate = None):
    solver = pywrapcp.Solver("Sudoku")

    variables = [solver.IntVar(1,9,f"x{i}") for i in range(81)]
    if len(candidate)>0:
        candidate = np.int64(candidate)
        for i in range(81):
            val = candidate[i]
            if val !=0:
                solver.Add(variables[i] == int(val))

    def set_constraints():
        for i in range(9):
            # All columns should be different
            q=[variables[j] for j in list(range(i,81,9))]
            solver.Add(solver.AllDifferent(q))

            #All rows should be different
            q2=[variables[j] for j in list(range(i*9,(i+1)*9))]
            solver.Add(solver.AllDifferent(q2))

            #All values in the sub-matrix should be different
            a = list(range(81))
            sub_blocks = a[3*i:3*(i+9):9] + a[3*i+1:3*(i+9)+1:9] + a[3*i+2:3*(i+9)+2:9]
            q3 = [variables[j] for j in sub_blocks]
            solver.Add(solver.AllDifferent(q3))

    set_constraints()
    db = solver.Phase(variables, solver.CHOOSE_FIRST_UNBOUND, solver.ASSIGN_MIN_VALUE)
    solver.NewSearch(db)    

    results_store =[]
    num_solutions =0
    total_solutions = 5
    while solver.NextSolution() and num_solutions<total_solutions:
        results = [j.Value() for j in variables]
        results_store.append(results)
        num_solutions +=1

    return results_store

Решают следующее судоку

candidate = np.array([0, 2, 0, 4, 5, 6, 0, 8, 0, 0, 5, 6, 7, 8, 9, 0, 0, 3, 7, 0, 9, 0,
       2, 0, 4, 5, 6, 2, 0, 1, 5, 0, 4, 8, 9, 7, 5, 0, 4, 8, 0, 0, 0, 0,
       0, 3, 1, 0, 6, 4, 5, 9, 7, 0, 0, 0, 5, 0, 7, 8, 3, 1, 2, 8, 0, 7,
       0, 1, 0, 5, 0, 4, 9, 7, 8, 0, 3, 0, 0, 0, 5])


results_store = sudoku_solver(candidate)  
0
ответ дан 1 December 2019 в 18:06
поделиться

Проблема с предупреждением в последней версии приведения имеет исторические корни. Вы знаете, что язык C (а также C ++) правильно запрещает преобразование T ** -> const T ** . Это правильно, поскольку разрешение этого преобразования откроет путь для некоторых тонких нарушений правил корректности констант (их можно найти в любом уважающем себя FAQ).

Однако язык C также запрещает преобразование T ** -> const T * const * . Это отличается от C ++, который позволяет это преобразование. (Это преобразование не нарушает константную корректность.) Это долгое время считалось «дефектом дизайна» в спецификации языка C. Этот дефект был «исправлен» в C ++, но продолжает сохраняться в C (даже в C99). Честно говоря, понятия не имею, почему это осталось без изменений в C99. Один из " Структура данных для ее решения представляла собой всего лишь матрицу битовой маски 9 на 9. Битовая маска будет указывать, какие числа все еще возможны в определенной позиции. Заполнение чисел из файла уменьшит числа во всех строках / столбцах рядом с каждым известным местоположением. Когда это будет сделано, вы продолжите итерацию по матрице и уменьшите возможные числа. Если в каждом месте остался только один вариант, все готово. Но есть судоку, над которыми нужно поработать. Для них вы можете просто использовать грубую силу: попробуйте все оставшиеся возможные комбинации, пока не найдете ту, которая работает.

Когда это будет сделано, вы продолжите итерацию по матрице и уменьшите возможные числа. Если в каждом месте остался только один вариант, все готово. Но есть судоку, над которыми нужно поработать. Для них вы можете просто использовать грубую силу: попробуйте все оставшиеся возможные комбинации, пока не найдете ту, которая работает.

Когда это будет сделано, вы продолжите итерацию по матрице и уменьшите возможные числа. Если в каждом месте остался только один вариант, все готово. Но есть судоку, над которыми нужно поработать. Для них вы можете просто использовать грубую силу: попробуйте все оставшиеся возможные комбинации, пока не найдете ту, которая работает.

4
ответ дан 1 December 2019 в 18:06
поделиться
Другие вопросы по тегам:

Похожие вопросы: