Beispiel #1
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
Beispiel #2
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
Beispiel #3
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
Beispiel #4
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
Beispiel #5
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
Beispiel #6
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
Beispiel #7
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
Beispiel #8
0
def solve_lits(height, width, blocks):
    solver = Solver()
    is_black = solver.bool_array((height, width))
    solver.add_answer_key(is_black)

    # black cells are connected
    graph.active_vertices_connected(solver, is_black)

    # no 2x2 black cells
    solver.ensure(~(is_black[1:, 1:] & is_black[1:, :-1] & is_black[:-1, 1:] & is_black[:-1, :-1]))

    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

    num_straight = solver.int_array(len(blocks), 0, 2)
    has_t = solver.bool_array(len(blocks))

    for i in range(len(blocks)):
        solver.ensure(count_true([is_black[p] for p in blocks[i]]) == 4)
        adjacent_pairs = []
        is_straight = []
        is_t = []
        for y, x in blocks[i]:
            neighbor_same_block = []
            for y2, x2 in is_black.four_neighbor_indices(y, x):
                if block_id[y2][x2] == i:
                    neighbor_same_block.append((y2, x2))
                    if (y, x) < (y2, x2):
                        adjacent_pairs.append(is_black[y, x] & is_black[y2, x2])
            solver.ensure(is_black[y, x].then(fold_or([is_black[p] for p in neighbor_same_block])))

            tmp = []
            if 0 < y < height - 1 and block_id[y - 1][x] == i and block_id[y + 1][x] == i:
                tmp.append(fold_and(is_black[y-1:y+2, x]))
            if 0 < x < width - 1 and block_id[y][x - 1] == i and block_id[y][x + 1] == i:
                tmp.append(fold_and(is_black[y, x-1:x+2]))
            if len(tmp) >= 1:
                is_straight.append(fold_or(tmp))

            if len(neighbor_same_block) >= 3:
                is_t.append(count_true([is_black[p] for p in neighbor_same_block]) >= 3)
        solver.ensure(count_true(adjacent_pairs) == 3)

        solver.ensure(num_straight[i] == count_true(is_straight))
        solver.ensure(has_t[i] == fold_or(is_t))

    for y in range(height):
        for x in range(width):
            if y < height - 1 and block_id[y][x] != block_id[y + 1][x]:
                i = block_id[y][x]
                j = block_id[y + 1][x]
                solver.ensure((is_black[y, x] & is_black[y + 1, x]).then(
                    (num_straight[i] != num_straight[j]) | (has_t[i] != has_t[j])
                ))
            if x < width - 1 and block_id[y][x] != block_id[y][x + 1]:
                i = block_id[y][x]
                j = block_id[y][x + 1]
                solver.ensure((is_black[y, x] & is_black[y, x + 1]).then(
                    (num_straight[i] != num_straight[j]) | (has_t[i] != has_t[j])
                ))
    is_sat = solver.solve()
    return is_sat, is_black