Example #1
0
def solve_nurikabe(height, width, problem, unknown_low=None):
    solver = Solver()
    clues = []
    for y in range(height):
        for x in range(width):
            if problem[y][x] >= 1 or problem[y][x] == -1:
                clues.append((y, x, problem[y][x]))
    division = solver.int_array((height, width), 0, len(clues))

    roots = [None] + list(map(lambda x: (x[0], x[1]), clues))
    graph.division_connected(solver, division, len(clues) + 1, roots=roots)
    is_white = solver.bool_array((height, width))
    solver.ensure(is_white == (division != 0))
    solver.add_answer_key(is_white)

    solver.ensure(
        (is_white[:-1, :]
         & is_white[1:, :]).then(division[:-1, :] == division[1:, :]))
    solver.ensure((is_white[:, :-1]
                   & is_white[:, 1:]).then(division[:, :-1] == division[:,
                                                                        1:]))
    solver.ensure(is_white[:-1, :-1] | is_white[:-1, 1:] | is_white[1:, :-1]
                  | is_white[1:, 1:])
    for i, (y, x, n) in enumerate(clues):
        if n > 0:
            solver.ensure(count_true(division == (i + 1)) == n)
        elif n == -1 and unknown_low is not None:
            solver.ensure(count_true(division == (i + 1)) >= unknown_low)

    is_sat = solver.solve()

    return is_sat, is_white
Example #2
0
def solve_putteria(height, width, blocks):
    solver = Solver()
    has_number = solver.bool_array((height, width))
    solver.add_answer_key(has_number)

    solver.ensure((~has_number[:, :-1]) | (~has_number[:, 1:]))
    solver.ensure((~has_number[:-1, :]) | (~has_number[1:, :]))
    for block in blocks:
        solver.ensure(count_true([has_number[y, x] for y, x in block]) == 1)

    block_size = [[0 for _ in range(width)] for _ in range(height)]
    for block in blocks:
        for y, x in block:
            block_size[y][x] = len(block)
    for y in range(height):
        for x1 in range(width):
            for x2 in range(x1 + 1, width):
                if block_size[y][x1] == block_size[y][x2]:
                    solver.ensure(~(has_number[y, x1] & has_number[y, x2]))
    for x in range(width):
        for y1 in range(height):
            for y2 in range(y1 + 1, height):
                if block_size[y1][x] == block_size[y2][x]:
                    solver.ensure(~(has_number[y1, x] & has_number[y2, x]))

    is_sat = solver.solve()
    return is_sat, has_number
Example #3
0
def solve_nurimaze(height, width, wall_vertical, wall_horizontal, mark, start,
                   goal):
    solver = Solver()
    is_white = solver.bool_array((height, width))
    graph.active_vertices_connected(solver, is_white, acyclic=True)
    solver.add_answer_key(is_white)

    solver.ensure(is_white[:-1, :-1] | is_white[:-1, 1:] | is_white[1:, :-1]
                  | is_white[1:, 1:])
    solver.ensure(~(is_white[:-1, :-1] & is_white[:-1, 1:] & is_white[1:, :-1]
                    & is_white[1:, 1:]))
    path = solver.bool_array((height, width))
    solver.ensure(path.then(is_white))
    for y in range(height):
        for x in range(width):
            if x < width - 1 and not wall_vertical[y][x]:
                solver.ensure(is_white[y, x] == is_white[y, x + 1])
            if y < height - 1 and not wall_horizontal[y][x]:
                solver.ensure(is_white[y, x] == is_white[y + 1, x])
            if (y, x) == start or (y, x) == goal:
                solver.ensure(path[y, x])
                solver.ensure(count_true(path.four_neighbors(y, x)) == 1)
            else:
                solver.ensure(
                    path[y,
                         x].then(count_true(path.four_neighbors(y, x)) == 2))
            if mark[y][x] != 0:
                solver.ensure(is_white[y, x])
            if mark[y][x] == 1:  # pass
                solver.ensure(path[y, x])
            elif mark[y][x] == 2:
                solver.ensure(~path[y, x])

    is_sat = solver.solve()
    return is_sat, is_white
Example #4
0
def solve_ripple(height, width, problem):
    solver = Solver()
    numbers = solver.int_array((height, width), 1, height * width + 1)
    solver.add_answer_key(numbers)

    block_num = max(sum(problem[0:height], [])) + 1
    blocks = [[] for _ in range(block_num)]
    for y in range(height):
        for x in range(width):
            blocks[problem[y][x]].append([y, x])
            if problem[y + height][x] > 0:
                solver.ensure(numbers[y, x] == problem[y + height][x])

    for block in blocks:
        solver.ensure(alldifferent([numbers[y, x] for y, x in block]))
        for y, x in block:
            solver.ensure(numbers[y, x] <= len(block))

    for y in range(height):
        for x in range(width):
            for i in range(1, width - x):
                solver.ensure(
                    (numbers[y, x] == numbers[y,
                                              x + i]).then(numbers[y, x] < i))
            for i in range(1, height - y):
                solver.ensure(
                    (numbers[y, x] == numbers[y + i,
                                              x]).then(numbers[y, x] < i))

    is_sat = solver.solve()
    return is_sat, numbers
Example #5
0
def solve_fillomino(height,
                    width,
                    problem,
                    checkered=False,
                    is_non_con=False,
                    is_anti_knight=False):
    solver = Solver()
    size = solver.int_array((height, width), 1, height * width)
    solver.add_answer_key(size)
    group_id = graph.division_connected_variable_groups(solver,
                                                        group_size=size)
    solver.ensure(
        (group_id[:, :-1] == group_id[:, 1:]) == (size[:, :-1] == size[:, 1:]))
    solver.ensure(
        (group_id[:-1, :] == group_id[1:, :]) == (size[:-1, :] == size[1:, :]))
    for y in range(height):
        for x in range(width):
            if problem[y][x] >= 1:
                solver.ensure(size[y, x] == problem[y][x])
    if checkered:
        color = solver.bool_array((height, width))
        solver.ensure(
            (group_id[:, :-1] == group_id[:,
                                          1:]) == (color[:, :-1] == color[:,
                                                                          1:]))
        solver.ensure((group_id[:-1, :] == group_id[1:, :]) == (
            color[:-1, :] == color[1:, :]))
    if is_non_con:
        graph.numbers_non_consecutive(solver, size)
    if is_anti_knight:
        graph.numbers_anti_knight(solver, size)
    is_sat = solver.solve()
    return is_sat, size
Example #6
0
def solve_building(n, u, d, l, r):
    solver = Solver()
    answer = solver.int_array((n, n), 1, n)
    solver.add_answer_key(answer)

    for i in range(n):
        solver.ensure(alldifferent(answer[i, :]))
        solver.ensure(alldifferent(answer[:, i]))

    def num_visible_buildings(cells):
        cells = list(cells)
        res = 1
        for i in range(1, len(cells)):
            res += fold_and([cells[j] < cells[i] for j in range(i)]).cond(1, 0)
        return res

    for i in range(n):
        if u[i] >= 1:
            solver.ensure(num_visible_buildings(answer[:, i]) == u[i])
        if d[i] >= 1:
            solver.ensure(
                num_visible_buildings(reversed(list(answer[:, i]))) == d[i])
        if l[i] >= 1:
            solver.ensure(num_visible_buildings(answer[i, :]) == l[i])
        if r[i] >= 1:
            solver.ensure(
                num_visible_buildings(reversed(list(answer[i, :]))) == r[i])

    is_sat = solver.solve()
    return is_sat, answer
Example #7
0
def solve_gokigen(height, width, problem):
    solver = Solver()
    edge_type = solver.bool_array((height, width))  # false: /, true: \
    solver.add_answer_key(edge_type)

    g = graph.Graph((height + 1) * (width + 1))
    edge_list = []
    for y in range(height):
        for x in range(width):
            g.add_edge(y * (width + 1) + x, (y + 1) * (width + 1) + (x + 1))
            edge_list.append(edge_type[y, x])
            g.add_edge(y * (width + 1) + (x + 1), (y + 1) * (width + 1) + x)
            edge_list.append(~edge_type[y, x])
    graph.active_edges_acyclic(solver, Array(edge_list), g)

    for y in range(height + 1):
        for x in range(width + 1):
            if problem[y][x] >= 0:
                related = []
                if 0 < y and 0 < x:
                    related.append(edge_type[y - 1, x - 1])
                if 0 < y and x < width:
                    related.append(~edge_type[y - 1, x])
                if y < height and 0 < x:
                    related.append(~edge_type[y, x - 1])
                if y < height and x < width:
                    related.append(edge_type[y, x])
                solver.ensure(count_true(related) == problem[y][x])

    is_sat = solver.solve()
    return is_sat, edge_type
Example #8
0
def solve_geradeweg(height, width, problem):
    def line_length(edges):
        edges = list(edges)
        if len(edges) == 0:
            return 0
        ret = edges[-1].cond(1, 0)
        for i in range(len(edges) - 2, -1, -1):
            ret = edges[i].cond(1 + ret, 0)
        return ret

    solver = Solver()
    grid_frame = BoolGridFrame(solver, height - 1, width - 1)
    solver.add_answer_key(grid_frame)
    is_passed = graph.active_edges_single_cycle(solver, grid_frame)

    for y in range(height):
        for x in range(width):
            if problem[y][x] >= 1:
                solver.ensure(is_passed[y, x])
                solver.ensure(fold_or(([grid_frame.horizontal[y, x - 1]] if x > 0 else []) + ([grid_frame.horizontal[y, x]] if x < width - 1 else [])).then(
                    line_length(reversed(list(grid_frame.horizontal[y, :x]))) + line_length(grid_frame.horizontal[y, x:]) == problem[y][x]
                ))
                solver.ensure(fold_or(([grid_frame.vertical[y - 1, x]] if y > 0 else []) + ([grid_frame.vertical[y, x]] if y < height - 1 else [])).then(
                    line_length(reversed(list(grid_frame.vertical[:y, x]))) + line_length(grid_frame.vertical[y:, x]) == problem[y][x]
                ))

    is_sat = solver.solve()
    return is_sat, grid_frame
Example #9
0
def solve_doppelblock(n, clue_row, clue_column):
    solver = Solver()
    answer = solver.int_array((n, n), 0, n - 2)
    solver.add_answer_key(answer)

    def sequence_constraint(cells, v):
        s = 0
        for i in range(n):
            s += (fold_or(cells[:i] == 0) & fold_or(cells[i+1:] == 0)).cond(cells[i], 0)
        return s == v

    def occurrence_constraint(cells):
        solver.ensure(count_true(cells == 0) == 2)
        for i in range(1, n - 1):
            solver.ensure(count_true(cells == i) == 1)

    for i in range(n):
        occurrence_constraint(answer[i, :])
        occurrence_constraint(answer[:, i])
        if clue_row[i] >= 0:
            solver.ensure(sequence_constraint(answer[i, :], clue_row[i]))
        if clue_column[i] >= 0:
            solver.ensure(sequence_constraint(answer[:, i], clue_column[i]))

    is_sat = solver.solve()
    return is_sat, answer
Example #10
0
def solve_magnets(height, width, to_right, to_down, cond_row, cond_col):
    solver = Solver()
    plus = solver.bool_array((height, width))
    minus = solver.bool_array((height, width))
    solver.add_answer_key(plus)
    solver.add_answer_key(minus)
    solver.ensure(~(plus & minus))
    solver.ensure(
        Array(to_right)[:, :-1].then((plus[:, :-1] == minus[:, 1:])
                                     & (minus[:, :-1] == plus[:, 1:])))
    solver.ensure(
        Array(to_down)[:-1, :].then((plus[:-1, :] == minus[1:, :])
                                    & (minus[:-1, :] == plus[1:, :])))
    solver.ensure(~(plus[:-1, :] & plus[1:, :]))
    solver.ensure(~(minus[:-1, :] & minus[1:, :]))
    solver.ensure(~(plus[:, :-1] & plus[:, 1:]))
    solver.ensure(~(minus[:, :-1] & minus[:, 1:]))
    for y in range(height):
        if cond_row[y][0] >= 0:
            solver.ensure(count_true(plus[y, :]) == cond_row[y][0])
        if cond_row[y][1] >= 0:
            solver.ensure(count_true(minus[y, :]) == cond_row[y][1])
    for x in range(width):
        if cond_col[x][0] >= 0:
            solver.ensure(count_true(plus[:, x]) == cond_col[x][0])
        if cond_col[x][1] >= 0:
            solver.ensure(count_true(minus[:, x]) == cond_col[x][1])
    is_sat = solver.solve()
    return is_sat, plus, minus
Example #11
0
def solve_fivecells(height, width, problem):
    vertex_id = [[-1 for _ in range(width)] for _ in range(height)]
    id_last = 0
    for y in range(height):
        for x in range(width):
            if problem[y][x] >= -1:
                vertex_id[y][x] = id_last
                id_last += 1
    g = graph.Graph(id_last)
    for y in range(height):
        for x in range(width):
            if problem[y][x] >= -1:
                if y < height - 1 and problem[y + 1][x] >= -1:
                    g.add_edge(vertex_id[y][x], vertex_id[y + 1][x])
                if x < width - 1 and problem[y][x + 1] >= -1:
                    g.add_edge(vertex_id[y][x], vertex_id[y][x + 1])
    solver = Solver()
    group_id = graph.division_connected_variable_groups(solver,
                                                        graph=g,
                                                        group_size=5)
    is_invalid = False
    for y in range(height):
        for x in range(width):
            if problem[y][x] >= 0:
                borders = []
                if y > 0 and problem[y - 1][x] >= -1:
                    borders.append(
                        group_id[vertex_id[y][x]] != group_id[vertex_id[y -
                                                                        1][x]])
                if y < height - 1 and problem[y + 1][x] >= -1:
                    borders.append(
                        group_id[vertex_id[y][x]] != group_id[vertex_id[y +
                                                                        1][x]])
                if x > 0 and problem[y][x - 1] >= -1:
                    borders.append(
                        group_id[vertex_id[y][x]] != group_id[vertex_id[y][x -
                                                                           1]])
                if x < width - 1 and problem[y][x + 1] >= -1:
                    borders.append(
                        group_id[vertex_id[y][x]] != group_id[vertex_id[y][x +
                                                                           1]])
                always_border = 4 - len(borders)
                solver.ensure(
                    count_true(borders) == problem[y][x] - always_border)
                if problem[y][x] - always_border < 0:
                    is_invalid = True

    is_border = solver.bool_array(len(g))
    for i, (u, v) in enumerate(g):
        solver.ensure(is_border[i] == (group_id[u] != group_id[v]))
    solver.add_answer_key(is_border)

    if is_invalid:
        is_sat = False
    else:
        is_sat = solver.solve()
    return is_sat, is_border
Example #12
0
def solve_slitherlink(height, width, problem):
    solver = Solver()
    grid_frame = BoolGridFrame(solver, height, width)
    solver.add_answer_key(grid_frame)
    graph.active_edges_single_cycle(solver, grid_frame)
    for y in range(height):
        for x in range(width):
            if problem[y][x] >= 0:
                solver.ensure(
                    count_true(grid_frame.cell_neighbors(y, x)) == problem[y]
                    [x])
    is_sat = solver.solve()
    return is_sat, grid_frame
Example #13
0
def solve_nurimisaki(height, width, problem):
    solver = Solver()
    is_white = solver.bool_array((height, width))
    solver.add_answer_key(is_white)

    graph.active_vertices_connected(solver, is_white)

    solver.ensure(is_white[:-1, :-1] | is_white[1:, :-1] | is_white[:-1, 1:]
                  | is_white[1:, 1:])
    solver.ensure(~(is_white[:-1, :-1] & is_white[1:, :-1] & is_white[:-1, 1:]
                    & is_white[1:, 1:]))

    for y in range(height):
        for x in range(width):
            if problem[y][x] == -1:
                solver.ensure(is_white[y, x].then(
                    count_true(is_white.four_neighbors(y, x)) != 1))
            else:
                solver.ensure(is_white[y, x])
                solver.ensure(count_true(is_white.four_neighbors(y, x)) == 1)
                if problem[y][x] != 0:
                    n = problem[y][x]
                    cand = []
                    if y == n - 1:
                        cand.append(fold_and(is_white[(y - n + 1):y, x]))
                    elif y > n - 1:
                        cand.append(
                            fold_and(is_white[(y - n + 1):y, x],
                                     ~is_white[y - n, x]))
                    if y == height - n:
                        cand.append(fold_and(is_white[(y + 1):(y + n), x]))
                    elif y < height - n:
                        cand.append(
                            fold_and(is_white[(y + 1):(y + n), x],
                                     ~is_white[y + n, x]))
                    if x == n - 1:
                        cand.append(fold_and(is_white[y, (x - n + 1):x]))
                    elif x > n - 1:
                        cand.append(
                            fold_and(is_white[y, (x - n + 1):x],
                                     ~is_white[y, x - n]))
                    if x == width - n:
                        cand.append(fold_and(is_white[y, (x + 1):(x + n)]))
                    elif x < width - n:
                        cand.append(
                            fold_and(is_white[y, (x + 1):(x + n)],
                                     ~is_white[y, x + n]))
                    solver.ensure(fold_or(cand))

    is_sat = solver.solve()
    return is_sat, is_white
Example #14
0
def solve_creek(height, width, problem):
    solver = Solver()
    is_white = solver.bool_array((height, width))
    solver.add_answer_key(is_white)
    graph.active_vertices_connected(solver, is_white)
    for y in range(0, height + 1):
        for x in range(0, width + 1):
            if problem[y][x] >= 0:
                solver.ensure(
                    count_true(~is_white[max(y - 1, 0):min(y + 1, height),
                                         max(x - 1, 0):min(x + 1, width)]) ==
                    problem[y][x])
    is_sat = solver.solve()
    return is_sat, is_white
Example #15
0
def solve_norinori(height, width, blocks):
    solver = Solver()
    is_black = solver.bool_array((height, width))
    solver.add_answer_key(is_black)

    for y in range(height):
        for x in range(width):
            solver.ensure(is_black[y, x].then(
                count_true(is_black.four_neighbors(y, x)) == 1))

    for block in blocks:
        solver.ensure(count_true(map(lambda p: is_black[p], block)) == 2)

    is_sat = solver.solve()
    return is_sat, is_black
Example #16
0
def solve_amarune(height, width, problem):
    solver = Solver()
    numbers = solver.int_array((height, width), 1, height * width)
    solver.add_answer_key(numbers)

    solver.ensure(alldifferent(numbers))

    for y in range(height):
        for x in range(width - 1):
            solver.ensure(numbers[y, x] > numbers[y, x + 1])

    for y in range(height):
        for x in range(width):
            if problem[y][x] > 0:
                solver.ensure(numbers[y, x] == problem[y][x])

    for y in range(height):
        for x in range(width - 1):
            for i in range(height * width):
                if problem[y + height][x] in [0, 1, 2]:
                    solver.ensure((numbers[y, x + 1] == i).then(
                        numbers[y, x] % i == problem[y + height][x]))
                elif problem[y + height][x] == 3:
                    solver.ensure(
                        (numbers[y, x + 1] == i).then(numbers[y, x] % i >= 3))

    for y in range(height - 1):
        for x in range(width):
            for i in range(height * width):
                if problem[y + height * 2][x] in [0, 1, 2]:
                    solver.ensure(
                        ((numbers[y, x] > numbers[y + 1, x]) &
                         (numbers[y + 1, x] == i)).then(
                             numbers[y, x] % i == problem[y + height * 2][x]))
                    solver.ensure(((numbers[y + 1, x] > numbers[y, x]) &
                                   (numbers[y, x] == i)).then(
                                       numbers[y + 1, x] %
                                       i == problem[y + height * 2][x]))
                elif problem[y + height * 2][x] == 3:
                    solver.ensure(((numbers[y, x] > numbers[y + 1, x]) &
                                   (numbers[y + 1, x] == i)).then(
                                       numbers[y, x] % i >= 3))
                    solver.ensure(((numbers[y + 1, x] > numbers[y, x]) &
                                   (numbers[y, x] == i)).then(
                                       numbers[y + 1, x] % i >= 3))

    is_sat = solver.solve()
    return is_sat, numbers
Example #17
0
def solve_darts(target, darts, board):
    solver = Solver()
    is_dart = solver.bool_array(len(board))
    solver.add_answer_key(is_dart)

    solver.ensure(count_true(is_dart) == darts)

    def _sum(d, b):
        sums = 0
        for i in range(len(board)):
            sums += d[i].cond(b[i], 0)
        return sums

    solver.ensure(_sum(is_dart, board) == target)

    is_sat = solver.solve()
    return is_sat, is_dart
Example #18
0
def solve_koutano(height, width, problem):
    solver = Solver()
    col = solver.int_array(width, 0, width - 1)
    row = solver.int_array(height, 0, height - 1)

    solver.add_answer_key(col)
    solver.add_answer_key(row)

    solver.ensure(alldifferent(col))
    solver.ensure(alldifferent(row))

    for y in range(height):
        for x in range(width):
            if problem[y][x] >= 0:
                solver.ensure(col[x] + row[y] == problem[y][x])

    is_sat = solver.solve()
    return is_sat, col, row
Example #19
0
def solve_view(height, width, problem, is_non_con=False, is_anti_knight=False):
    solver = Solver()
    has_number = solver.bool_array((height, width))
    graph.active_vertices_connected(solver, has_number)
    nums = solver.int_array((height, width), 0, height + width)
    solver.add_answer_key(nums)
    solver.add_answer_key(has_number)

    to_up = solver.int_array((height, width), 0, height - 1)
    solver.ensure(to_up[0, :] == 0)
    solver.ensure(to_up[1:, :] == has_number[:-1, :].cond(0, to_up[:-1, :] + 1))

    to_down = solver.int_array((height, width), 0, height - 1)
    solver.ensure(to_down[-1, :] == 0)
    solver.ensure(to_down[:-1, :] == has_number[1:, :].cond(0, to_down[1:, :] + 1))

    to_left = solver.int_array((height, width), 0, width - 1)
    solver.ensure(to_left[:, 0] == 0)
    solver.ensure(to_left[:, 1:] == has_number[:, :-1].cond(0, to_left[:, :-1] + 1))

    to_right = solver.int_array((height, width), 0, width - 1)
    solver.ensure(to_right[:, -1] == 0)
    solver.ensure(to_right[:, :-1] == has_number[:, 1:].cond(0, to_right[:, 1:] + 1))

    solver.ensure(has_number.then(nums == to_up + to_left + to_down + to_right))
    solver.ensure((has_number[:-1, :] & has_number[1:, :]).then(nums[:-1, :] != nums[1:, :]))
    solver.ensure((has_number[:, :-1] & has_number[:, 1:]).then(nums[:, :-1] != nums[:, 1:]))
    solver.ensure((~has_number).then(nums == 0))
    for y in range(height):
        for x in range(width):
            if problem[y][x] >= 0:
                solver.ensure(nums[y, x] == problem[y][x])
                solver.ensure(has_number[y, x])

    if is_non_con:
        graph.numbers_non_consecutive(solver, nums, has_number)

    if is_anti_knight:
        graph.numbers_anti_knight(solver, nums, has_number)

    is_sat = solver.solve()

    return is_sat, nums, has_number
Example #20
0
def solve_compass(height, width, problem):
    solver = Solver()
    roots = map(lambda x: (x[0], x[1]), problem)
    division = solver.int_array((height, width), 0, len(problem) - 1)
    graph.division_connected(solver, division, len(problem), roots=roots)
    solver.add_answer_key(division)
    for i, (y, x, u, l, d, r) in enumerate(problem):
        solver.ensure(division[y, x] == i)
        if u >= 0:
            solver.ensure(count_true(division[:y, :] == i) == u)
        if d >= 0:
            solver.ensure(count_true(division[(y + 1):, :] == i) == d)
        if l >= 0:
            solver.ensure(count_true(division[:, :x] == i) == l)
        if r >= 0:
            solver.ensure(count_true(division[:, (x + 1):] == i) == r)
    is_sat = solver.solve()

    return is_sat, division
Example #21
0
def solve_castle_wall(height, width, arrow, inside):
    solver = Solver()
    grid_frame = BoolGridFrame(solver, height - 1, width - 1)
    solver.add_answer_key(grid_frame)
    passed = graph.active_edges_single_cycle(solver, grid_frame)

    # arrow constraints
    for y in range(height):
        for x in range(width):
            if arrow[y][x] == '..':
                continue
            solver.ensure(~passed[y, x])
            if arrow[y][x][0] == '^':
                related_edges = grid_frame.vertical[:y, x]
            elif arrow[y][x][0] == 'v':
                related_edges = grid_frame.vertical[y:, x]
            elif arrow[y][x][0] == '<':
                related_edges = grid_frame.horizontal[y, :x]
            elif arrow[y][x][0] == '>':
                related_edges = grid_frame.horizontal[y, x:]
            else:
                continue
            solver.ensure(count_true(related_edges) == int(arrow[y][x][1:]))

    # inout constraints
    is_inside = solver.bool_array((height - 1, width - 1))
    for y in range(height - 1):
        for x in range(width - 1):
            if y == 0:
                solver.ensure(is_inside[y, x] == grid_frame[0, x * 2 + 1])
            else:
                solver.ensure(is_inside[y, x] == (
                    is_inside[y - 1, x] != grid_frame[y * 2, x * 2 + 1]))
    for y in range(height):
        for x in range(width):
            if inside[y][x] is True:
                solver.ensure(is_inside[max(0, y - 1), max(0, x - 1)])
            elif inside[y][x] is False:
                solver.ensure(~is_inside[max(0, y - 1), max(0, x - 1)])
    is_sat = solver.solve()

    return is_sat, grid_frame
Example #22
0
def solve_star_battle(n, blocks, k, is_anti_knight=False):
    if not isinstance(blocks, Array):
        blocks = Array(blocks)
    solver = Solver()
    has_star = solver.bool_array((n, n))
    solver.add_answer_key(has_star)
    for i in range(n):
        solver.ensure(sum(has_star[i, :].cond(1, 0)) == k)
        solver.ensure(sum(has_star[:, i].cond(1, 0)) == k)
    solver.ensure(~(has_star[:-1, :] & has_star[1:, :]))
    solver.ensure(~(has_star[:, :-1] & has_star[:, 1:]))
    solver.ensure(~(has_star[:-1, :-1] & has_star[1:, 1:]))
    solver.ensure(~(has_star[:-1, 1:] & has_star[1:, :-1]))
    for i in range(n):
        solver.ensure(sum((has_star & (blocks == i)).cond(1, 0)) == k)

    if is_anti_knight:
        graph.active_vertices_anti_knight(solver, has_star)
    is_sat = solver.solve()
    return is_sat, has_star
Example #23
0
def solve_simpleloop(height, width, blocked, pivot):
    solver = Solver()
    grid_frame = BoolGridFrame(solver, height - 1, width - 1)
    solver.add_answer_key(grid_frame)
    is_passed = graph.active_edges_single_cycle(solver, grid_frame)

    for y in range(height):
        for x in range(width):
            if (y, x) != pivot:
                solver.ensure(is_passed[y, x] == (blocked[y][x] == 0))

    py, px = pivot
    n_pass = 0
    for y in range(height):
        for x in range(width):
            if (y, x) != pivot and blocked[y][x] == 0:
                n_pass += 1
    solver.ensure(is_passed[py, px] == (n_pass % 2 == 1))
    is_sat = solver.solve()
    return is_sat, grid_frame
Example #24
0
def solve_nanro(height, width, blocks, num):
    block_id = [[-1 for _ in range(width)] for _ in range(height)]
    for i, block in enumerate(blocks):
        for y, x in block:
            block_id[y][x] = i
    solver = Solver()
    answer = []
    has_num = solver.bool_array((height, width))
    for y in range(height):
        row = []
        for x in range(width):
            v = solver.int_var(0, len(blocks[block_id[y][x]]))
            solver.add_answer_key(v)
            solver.ensure(has_num[y, x] == (v != 0))
            row.append(v)
        answer.append(row)
    graph.active_vertices_connected(solver, has_num)

    for i, block in enumerate(blocks):
        nonempty = solver.int_var(1, len(block))
        solver.ensure(nonempty == count_true(answer[y][x] != 0
                                             for y, x in block))
        for y, x in block:
            solver.ensure((answer[y][x] == 0) | (answer[y][x] == nonempty))
    for y in range(height):
        for x in range(width):
            if num[y][x] > 0:
                solver.ensure(answer[y][x] == num[y][x])
            if y < height - 1 and x < width - 1:
                solver.ensure((answer[y][x] == 0) | (answer[y][x + 1] == 0)
                              | (answer[y + 1][x] == 0)
                              | (answer[y + 1][x + 1] == 0))
            if y < height - 1 and block_id[y][x] != block_id[y + 1][x]:
                solver.ensure((answer[y][x] == 0) | (answer[y + 1][x] == 0)
                              | (answer[y][x] != answer[y + 1][x]))
            if x < width - 1 and block_id[y][x] != block_id[y][x + 1]:
                solver.ensure((answer[y][x] == 0) | (answer[y][x + 1] == 0)
                              | (answer[y][x] != answer[y][x + 1]))

    is_sat = solver.solve()
    return is_sat, answer
Example #25
0
def solve_yinyang(height, width, problem):
    solver = Solver()
    is_black = solver.bool_array((height, width))
    solver.add_answer_key(is_black)

    graph.active_vertices_connected(solver, is_black)
    graph.active_vertices_connected(solver, ~is_black)
    solver.ensure(is_black[:-1, :-1] | is_black[:-1, 1:] | is_black[1:, :-1]
                  | is_black[1:, 1:])
    solver.ensure(~(is_black[:-1, :-1] & is_black[:-1, 1:] & is_black[1:, :-1]
                    & is_black[1:, 1:]))

    # auxiliary constraint
    solver.ensure(~(is_black[:-1, :-1] & is_black[1:, 1:] & ~is_black[1:, :-1]
                    & ~is_black[:-1, 1:]))
    solver.ensure(~(~is_black[:-1, :-1] & ~is_black[1:, 1:] & is_black[1:, :-1]
                    & is_black[:-1, 1:]))

    circ = []
    for y in range(height):
        circ.append(is_black[y, 0])
    for x in range(1, width):
        circ.append(is_black[-1, x])
    for y in reversed(range(0, height - 1)):
        circ.append(is_black[y, -1])
    for x in reversed(range(1, width - 1)):
        circ.append(is_black[0, x])
    circ_switching = []
    for i in range(len(circ)):
        circ_switching.append(circ[i] != circ[(i + 1) % len(circ)])
    solver.ensure(count_true(circ_switching) <= 2)

    for y in range(height):
        for x in range(width):
            if problem[y][x] == 1:
                solver.ensure(~is_black[y, x])
            elif problem[y][x] == 2:
                solver.ensure(is_black[y, x])

    is_sat = solver.solve()
    return is_sat, is_black
Example #26
0
def solve_masyu(height, width, problem):
    solver = Solver()
    grid_frame = BoolGridFrame(solver, height - 1, width - 1)
    solver.add_answer_key(grid_frame)
    graph.active_edges_single_cycle(solver, grid_frame)

    def get_edge(y, x, neg=False):
        if 0 <= y <= 2 * (height - 1) and 0 <= x <= 2 * (width - 1):
            if y % 2 == 0:
                r = grid_frame.horizontal[y // 2][x // 2]
            else:
                r = grid_frame.vertical[y // 2][x // 2]
            if neg:
                return ~r
            else:
                return r
        else:
            return neg

    for y in range(height):
        for x in range(width):
            if problem[y][x] == 1:
                solver.ensure(
                    (get_edge(y * 2, x * 2 - 1) & get_edge(y * 2, x * 2 + 1)
                     & (get_edge(y * 2, x * 2 - 3, True)
                        | get_edge(y * 2, x * 2 + 3, True)))
                    | (get_edge(y * 2 - 1, x * 2) & get_edge(y * 2 + 1, x * 2)
                       & (get_edge(y * 2 - 3, x * 2, True)
                          | get_edge(y * 2 + 3, x * 2, True))))
            elif problem[y][x] == 2:
                dirs = [
                    get_edge(y * 2, x * 2 - 1) & get_edge(y * 2, x * 2 - 3),
                    get_edge(y * 2 - 1, x * 2) & get_edge(y * 2 - 3, x * 2),
                    get_edge(y * 2, x * 2 + 1) & get_edge(y * 2, x * 2 + 3),
                    get_edge(y * 2 + 1, x * 2) & get_edge(y * 2 + 3, x * 2),
                ]
                solver.ensure((dirs[0] | dirs[2]) & (dirs[1] | dirs[3]))

    is_sat = solver.solve()
    return is_sat, grid_frame
Example #27
0
def solve_sukoro(height, width, problem, is_anti_knight=False):
    solver = Solver()

    has_number = solver.bool_array((height, width))
    graph.active_vertices_connected(solver, has_number)
    nums = solver.int_array((height, width), -1, 4)
    solver.add_answer_key(nums)
    solver.add_answer_key(has_number)

    for y in range(height):
        for x in range(width):
            neighbors = []
            if y > 0:
                neighbors.append(has_number[y-1, x])
                solver.ensure((has_number[y, x] & has_number[y-1, x]).then(nums[y, x] != nums[y-1, x]))
            if y < height - 1:
                neighbors.append(has_number[y+1, x])
                solver.ensure((has_number[y, x] & has_number[y+1, x]).then(nums[y, x] != nums[y+1, x]))
            if x > 0:
                neighbors.append(has_number[y, x-1])
                solver.ensure((has_number[y, x] & has_number[y, x-1]).then(nums[y, x] != nums[y, x-1]))
            if x < width - 1:
                neighbors.append(has_number[y, x+1])
                solver.ensure((has_number[y, x] & has_number[y, x+1]).then(nums[y, x] != nums[y, x+1]))
            solver.ensure(has_number[y, x].then(count_true(neighbors) == nums[y, x]))

    solver.ensure((~has_number).then(nums < 0))

    for y in range(height):
        for x in range(width):
            if problem[y][x] >= 0:
                solver.ensure(nums[y, x] == problem[y][x])
                solver.ensure(has_number[y, x])

    if is_anti_knight:
        graph.numbers_anti_knight(solver, nums, has_number)

    is_sat = solver.solve()

    return is_sat, nums, has_number
Example #28
0
def solve_yajilin(height, width, problem):
    solver = Solver()
    grid_frame = BoolGridFrame(solver, height - 1, width - 1)
    is_passed = graph.active_edges_single_cycle(solver, grid_frame)
    black_cell = solver.bool_array((height, width))
    graph.active_vertices_not_adjacent(solver, black_cell)
    solver.add_answer_key(grid_frame)
    solver.add_answer_key(black_cell)

    for y in range(height):
        for x in range(width):
            if problem[y][x] != '..':
                # clue
                solver.ensure(~is_passed[y, x])
                solver.ensure(~black_cell[y, x])

                if problem[y][x][0] == '^':
                    solver.ensure(
                        count_true(black_cell[0:y,
                                              x]) == int(problem[y][x][1:]))
                elif problem[y][x][0] == 'v':
                    solver.ensure(
                        count_true(black_cell[(y + 1):height,
                                              x]) == int(problem[y][x][1:]))
                elif problem[y][x][0] == '<':
                    solver.ensure(
                        count_true(black_cell[y,
                                              0:x]) == int(problem[y][x][1:]))
                elif problem[y][x][0] == '>':
                    solver.ensure(
                        count_true(black_cell[y, (
                            x + 1):width]) == int(problem[y][x][1:]))
            else:
                solver.ensure(is_passed[y, x] != black_cell[y, x])

    is_sat = solver.solve()
    return is_sat, grid_frame, black_cell
Example #29
0
def solve_sudoku(problem,
                 n=3,
                 is_non_con=False,
                 is_anti_knight=False,
                 is_non_dicon=False,
                 is_anti_alfil=False):
    size = n * n
    solver = Solver()
    answer = solver.int_array((size, size), 1, size)
    solver.add_answer_key(answer)
    for i in range(size):
        solver.ensure(alldifferent(answer[i, :]))
        solver.ensure(alldifferent(answer[:, i]))
    for y in range(n):
        for x in range(n):
            solver.ensure(
                alldifferent(answer[y * n:(y + 1) * n, x * n:(x + 1) * n]))
    for y in range(size):
        for x in range(size):
            if problem[y][x] >= 1:
                solver.ensure(answer[y, x] == problem[y][x])

    if is_non_con:
        graph.numbers_non_consecutive(solver, answer)

    if is_anti_knight:
        graph.numbers_anti_knight(solver, answer)

    if is_non_dicon:
        graph.numbers_non_diagonally_consecutive(solver, answer)

    if is_anti_alfil:
        graph.numbers_anti_alfil(solver, answer)

    is_sat = solver.solve()

    return is_sat, answer
Example #30
0
def solve_simplegako(height, width, problem):
    solver = Solver()
    numbers = solver.int_array((height, width), 1, height + width - 1)
    solver.add_answer_key(numbers)

    for y in range(height):
        for x in range(width):
            if problem[y][x] > 0:
                solver.ensure(numbers[y, x] == problem[y][x])

    def _count(y0, x0, n):
        sum = -1
        for y in range(height):
            sum += (numbers[y, x0] == n).cond(1, 0)
        for x in range(width):
            sum += (numbers[y0, x] == n).cond(1, 0)
        return sum

    for y in range(height):
        for x in range(width):
            solver.ensure(numbers[y, x] == _count(y, x, numbers[y, x]))

    is_sat = solver.solve()
    return is_sat, numbers