예제 #1
0
def main():
    """Skyscraper solver example."""
    lattice = grilops.get_square_lattice(SIZE)
    directions = {d.name: d for d in lattice.edge_sharing_directions()}
    sg = grilops.SymbolGrid(lattice, SYM)

    # Each row and each column contains each building height exactly once.
    for y in range(SIZE):
        sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for x in range(SIZE)]))
    for x in range(SIZE):
        sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for y in range(SIZE)]))

    # We'll use the sightlines accumulator to keep track of a tuple storing:
    #   the tallest building we've seen so far
    #   the number of visible buildings we've encountered
    Acc = Datatype("Acc")  # pylint: disable=C0103
    Acc.declare("acc", ("tallest", IntSort()), ("num_visible", IntSort()))
    Acc = Acc.create()  # pylint: disable=C0103

    def accumulate(a, height):
        return Acc.acc(
            If(height > Acc.tallest(a), height, Acc.tallest(a)),
            If(height > Acc.tallest(a),
               Acc.num_visible(a) + 1, Acc.num_visible(a)))

    for x, c in enumerate(GIVEN_TOP):
        sg.solver.add(c == Acc.num_visible(
            grilops.sightlines.reduce_cells(sg, Point(0, x), directions["S"],
                                            Acc.acc(0, 0), accumulate)))
    for y, c in enumerate(GIVEN_LEFT):
        sg.solver.add(c == Acc.num_visible(
            grilops.sightlines.reduce_cells(sg, Point(y, 0), directions["E"],
                                            Acc.acc(0, 0), accumulate)))
    for y, c in enumerate(GIVEN_RIGHT):
        sg.solver.add(c == Acc.num_visible(
            grilops.sightlines.reduce_cells(sg, Point(
                y, SIZE - 1), directions["W"], Acc.acc(0, 0), accumulate)))
    for x, c in enumerate(GIVEN_BOTTOM):
        sg.solver.add(c == Acc.num_visible(
            grilops.sightlines.reduce_cells(sg, Point(
                SIZE - 1, x), directions["N"], Acc.acc(0, 0), accumulate)))

    if sg.solve():
        sg.print()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
    else:
        print("No solution")
예제 #2
0
def main():
  """Sudoku solver example."""
  givens = [
      [5, 3, 0, 0, 7, 0, 0, 0, 0],
      [6, 0, 0, 1, 9, 5, 0, 0, 0],
      [0, 9, 8, 0, 0, 0, 0, 6, 0],
      [8, 0, 0, 0, 6, 0, 0, 0, 3],
      [4, 0, 0, 8, 0, 3, 0, 0, 1],
      [7, 0, 0, 0, 2, 0, 0, 0, 6],
      [0, 6, 0, 0, 0, 0, 2, 8, 0],
      [0, 0, 0, 4, 1, 9, 0, 0, 5],
      [0, 0, 0, 0, 8, 0, 0, 7, 9],
  ]

  sym = grilops.make_number_range_symbol_set(1, 9)
  sg = grilops.SymbolGrid(grilops.get_square_lattice(9), sym)

  for y, given_row in enumerate(givens):
    for x, given in enumerate(given_row):
      if given != 0:
        sg.solver.add(sg.cell_is(Point(y, x), sym[given]))

  for y in range(9):
    sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for x in range(9)]))

  for x in range(9):
    sg.solver.add(Distinct(*[sg.grid[Point(y, x)] for y in range(9)]))

  for z in range(9):
    top = (z // 3) * 3
    left = (z % 3) * 3
    cells = [sg.grid[Point(y, x)] for y in range(top, top + 3) for x in range(left, left + 3)]
    sg.solver.add(Distinct(*cells))

  if sg.solve():
    sg.print()
    print()
    if sg.is_unique():
      print("Unique solution")
    else:
      print("Alternate solution")
      sg.print()
  else:
    print("No solution")
예제 #3
0
def main():
    """Heteromino solver example."""
    lattice = grilops.get_square_lattice(SIZE)
    sg = grilops.SymbolGrid(lattice, SYM)
    rc = grilops.regions.RegionConstrainer(lattice,
                                           solver=sg.solver,
                                           complete=False)

    def constrain_neighbor(p, np, is_root, shape, has_neighbor):
        sg.solver.add(Implies(And(is_root, has_neighbor),
                              sg.grid[np] == shape))
        sg.solver.add(
            Implies(rc.region_id_grid[p] != rc.region_id_grid[np],
                    sg.grid[np] != shape))

    for p in lattice.points:
        if p in BLACK_CELLS:
            sg.solver.add(sg.cell_is(p, SYM.BL))
            sg.solver.add(rc.region_id_grid[p] == -1)
            continue

        sg.solver.add(Not(sg.cell_is(p, SYM.BL)))

        # All regions have size 3.
        sg.solver.add(rc.region_size_grid[p] == 3)

        # Force the root of each region subtree to be in the middle of the
        # region, by not allowing non-root cells to have children.
        sg.solver.add(
            Implies(rc.parent_grid[p] != grilops.regions.R,
                    rc.subtree_size_grid[p] == 1))

        # All cells in the same region must have the same shape symbol. Cells in
        # different regions must not have the same shape symbol.

        shape = sg.grid[p]
        is_root = rc.parent_grid[p] == grilops.regions.R

        has_north = False
        if p.y > 0:
            np = Point(p.y - 1, p.x)
            has_north = rc.parent_grid[np] == rc.parent_type_to_index("S")
            constrain_neighbor(p, np, is_root, shape, has_north)

        has_south = False
        if p.y < SIZE - 1:
            np = Point(p.y + 1, p.x)
            has_south = rc.parent_grid[np] == rc.parent_type_to_index("N")
            constrain_neighbor(p, np, is_root, shape, has_south)

        has_west = False
        if p.x > 0:
            np = Point(p.y, p.x - 1)
            has_west = rc.parent_grid[np] == rc.parent_type_to_index("E")
            constrain_neighbor(p, np, is_root, shape, has_west)

        has_east = False
        if p.x < SIZE - 1:
            np = Point(p.y, p.x + 1)
            has_east = rc.parent_grid[np] == rc.parent_type_to_index("W")
            constrain_neighbor(p, np, is_root, shape, has_east)

        # Constrain the shape symbol based on adjacent cell relationships.
        for shape_symbol, region_presence in [
            (SYM.NS, (has_north, has_south)),
            (SYM.EW, (has_east, has_west)),
            (SYM.NE, (has_north, has_east)),
            (SYM.SE, (has_south, has_east)),
            (SYM.SW, (has_south, has_west)),
            (SYM.NW, (has_north, has_west)),
        ]:
            sg.solver.add(Implies(And(*region_presence),
                                  shape == shape_symbol))

    if sg.solve():
        sg.print()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
    else:
        print("No solution")
예제 #4
0
import grilops
import grilops.loops
from grilops.geometry import Point

ANSWERS = [
    "HATAMOTO",
    "IONESKYE",
    "JARGONIC",
    "KLONDIKE",
    "LUCHADOR",
    "MOCKTAIL",
    "NURSEJOY",
    "OMOPLATE",
]
LATTICE = grilops.get_square_lattice(8)
SYM = grilops.loops.LoopSymbolSet(LATTICE)
TURN_SYMBOLS = [SYM.NE, SYM.SE, SYM.SW, SYM.NW]


def extract_answer(sg, loop_order_grid):
    """Extract the metapuzzle answer from the grids."""
    model = sg.solver.model()
    loop_order_to_point = {
        model.eval(loop_order_grid[p]).as_long(): p
        for p in sg.lattice.points
    }
    ordered_points = sorted(list(loop_order_to_point.items()))
    solved_grid = sg.solved_grid()
    answer = ""
    for _, p in ordered_points:
예제 #5
0
def main():
    """Greater Than Killer Sudoku solver example."""

    cages = [
        "AABCCDDEE",
        "FFBGGHIJK",
        "FLMNHHIJK",
        "LLMNNOIPP",
        "QQRNSOTTU",
        "VWRSSXTUU",
        "VWYYSXZaa",
        "bccddXZee",
        "bbbdffZgg",
    ]

    cage_sums = {
        "B": 6,
        "D": 16,
        "F": 14,
        "H": 17,
        "I": 9,
        "J": 12,
        "K": 9,
        "L": 20,
        "M": 13,
        "N": 29,
        "O": 4,
        "R": 8,
        "S": 12,
        "V": 8,
        "W": 14,
        "Y": 17,
        "b": 11,
        "d": 11,
        "e": 8,
    }

    sym = grilops.make_number_range_symbol_set(1, 9)
    lattice = grilops.get_square_lattice(9)
    sg = grilops.SymbolGrid(lattice, sym)

    add_sudoku_constraints(sg)

    # Build a map from each cage label to the cells within that cage.
    cage_cells = defaultdict(list)
    for p in lattice.points:
        cage_cells[cages[p.y][p.x]].append(sg.grid[p])

    # The digits used in each cage must be unique.
    for cells_in_cage in cage_cells.values():
        sg.solver.add(Distinct(*cells_in_cage))

    # Add constraints for cages with given sums.
    for cage_label, cage_sum in cage_sums.items():
        sg.solver.add(Sum(*cage_cells[cage_label]) == cage_sum)

    # Add constraints between cage sums.
    def cage_sum_greater(a, b):
        sg.solver.add(Sum(*cage_cells[a]) > Sum(*cage_cells[b]))

    def cage_sum_equal(a, b):
        sg.solver.add(Sum(*cage_cells[a]) == Sum(*cage_cells[b]))

    cage_sum_equal("C", "G")
    cage_sum_greater("J", "E")
    cage_sum_greater("E", "K")
    cage_sum_greater("W", "c")
    cage_sum_greater("c", "b")
    cage_sum_greater("f", "d")
    cage_sum_greater("X", "f")

    if sg.solve():
        sg.print()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
    else:
        print("No solution")
예제 #6
0
def main():
    """Akari solver example."""
    size = 10
    lattice = grilops.get_square_lattice(size)

    black_cells = {
        (0, 0): None,
        (0, 3): None,
        (0, 9): None,
        (1, 7): None,
        (2, 1): 3,
        (2, 6): 0,
        (3, 2): 2,
        (3, 5): None,
        (3, 9): 1,
        (4, 3): 1,
        (4, 4): 0,
        (4, 5): None,
        (5, 4): 1,
        (5, 5): None,
        (5, 6): None,
        (6, 0): None,
        (6, 4): 2,
        (6, 7): 2,
        (7, 3): None,
        (7, 8): None,
        (8, 2): 1,
        (9, 0): 0,
        (9, 6): 1,
        (9, 9): 0,
    }

    def print_given(point):
        if point in black_cells:
            v = black_cells.get(point)
            if v is None:
                return chr(0x2588)
            return str(v)
        return None

    lattice.print(print_given)
    print()

    sym = grilops.SymbolSet([
        ("BLACK", chr(0x2588)),
        ("EMPTY", " "),
        ("LIGHT", "*"),
    ])
    sg = grilops.SymbolGrid(lattice, sym)

    for point in lattice.points:
        if point in black_cells:
            sg.solver.add(sg.cell_is(point, sym.BLACK))
            light_count = black_cells[point]
            if light_count is not None:
                sg.solver.add(
                    PbEq([(n.symbol == sym.LIGHT, 1)
                          for n in sg.edge_sharing_neighbors(point)],
                         light_count))
        else:
            # All black cells are given; don't allow this cell to be black.
            sg.solver.add(sg.cell_is_one_of(point, [sym.EMPTY, sym.LIGHT]))

    def is_black(c):
        return c == sym.BLACK

    def count_light(c):
        return If(c == sym.LIGHT, 1, 0)

    for point in lattice.points:
        if point in black_cells:
            continue
        visible_light_count = sum(
            grilops.sightlines.count_cells(
                sg, n.location, n.direction, count=count_light, stop=is_black)
            for n in sg.edge_sharing_neighbors(point))
        # Ensure that each light cannot see any other lights, and that each cell
        # is lit by at least one light.
        sg.solver.add(
            If(sg.cell_is(point, sym.LIGHT), visible_light_count == 0,
               visible_light_count > 0))

    if sg.solve():
        sg.print()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
    else:
        print("No solution")
예제 #7
0
def main():
    """Outflight Entertainment sudoku solver example."""

    cages = [
        "AABCCD",
        "EFBCGD",
        "EFFHGI",
        "EJJHGI",
        "EKJHGL",
        "KKJLLL",
    ]

    peaks = [
        (0, 1),
        (0, 2),
        (1, 3),
        (1, 4),
        (1, 5),
        (2, 1),
        (2, 3),
        (3, 0),
        (3, 5),
        (4, 2),
        (5, 1),
        (5, 4),
    ]

    extract = {
        "A": (5, 2),
        "B": (0, 3),
        "C": (3, 2),
        "D": (1, 4),
        "E": (0, 1),
        "F": (1, 5),
        "G": (4, 2),
        "H": (3, 5),
        "I": (1, 0),
        "J": (5, 5),
        "K": (3, 4),
        "L": (5, 1),
        "M": (0, 5),
        "N": (4, 4),
    }

    def answer(sg):
        solved_grid = sg.solved_grid()
        s = ""
        s += chr(64 + solved_grid[extract["A"]] + solved_grid[extract["B"]])
        s += chr(64 + solved_grid[extract["C"]] + solved_grid[extract["D"]])
        s += chr(64 + solved_grid[extract["E"]] + solved_grid[extract["F"]] +
                 solved_grid[extract["G"]])
        s += chr(64 + solved_grid[extract["H"]] + solved_grid[extract["I"]])
        s += chr(64 + solved_grid[extract["J"]] + solved_grid[extract["K"]] +
                 solved_grid[extract["L"]])
        s += chr(64 + solved_grid[extract["M"]] + solved_grid[extract["N"]])
        return s

    sym = grilops.make_number_range_symbol_set(1, 6)
    lattice = grilops.get_square_lattice(6)
    sg = grilops.SymbolGrid(lattice, sym)

    add_sudoku_constraints(sg)

    # Constrain regions to match the cages and be rooted at the peaks.
    cage_label_to_region_id = {}
    for py, px in peaks:
        cage_label_to_region_id[cages[py][px]] = lattice.point_to_index(
            (py, px))

    rc = grilops.regions.RegionConstrainer(lattice, sg.solver)
    for y, x in lattice.points:
        sg.solver.add(
            rc.region_id_grid[(y, x)] == cage_label_to_region_id[cages[y][x]])

    # Within each region, a parent cell must have a greater value than a child
    # cell, so that the values increase as you approach the root cell (the peak).
    for p in lattice.points:
        for n in sg.edge_sharing_neighbors(p):
            sg.solver.add(
                Implies(
                    rc.edge_sharing_direction_to_index(
                        n.direction) == rc.parent_grid[p],
                    n.symbol > sg.grid[p]))

    if sg.solve():
        sg.print()
        print()
        print(answer(sg))
        while not sg.is_unique():
            print()
            print("Alternate solution")
            sg.print()
            print()
            print(answer(sg))
    else:
        print("No solution")