コード例 #1
0
def region_solve():
    """Hex slitherlink solver example using regions."""

    lattice = get_lattice()
    sym = grilops.SymbolSet(["I", "O"])
    sg = grilops.SymbolGrid(lattice, sym)
    rc = grilops.regions.RegionConstrainer(lattice,
                                           solver=sg.solver,
                                           complete=True)

    # There must be exactly two connected regions:  the inside and the outside.
    # The outside region ID will be 0 because the top-left-most element will
    # always be outside.

    inside_region_id = Int("inside_region_id")
    sg.solver.add(inside_region_id != 0)

    for p in lattice.points:
        # A cell should have symbol I if and only if it's in the inside region.
        sg.solver.add((sg.grid[p] == sym.I) == (
            rc.region_id_grid[p] == inside_region_id))

        # If this cell isn't in the givens array, it must be outside the loop.

        givens_addr = point_to_givens_row_col(p)
        if givens_addr is None:
            sg.solver.add(sg.grid[p] == sym.O)
            continue

        # Find the given corresponding to this cell.  If it's None, we don't
        # know anything about it.

        r, c = givens_addr
        given = GIVENS[r][c]
        if given is None:
            continue

        # The given number must equal the number of adjacent cells on the
        # opposite side of the loop line.

        num_different_neighbors_terms = [(n.symbol != sg.grid[p], 1)
                                         for n in sg.edge_sharing_neighbors(p)]
        sg.solver.add(PbEq(num_different_neighbors_terms, given))

    def hook_function(p, _):
        addr = point_to_givens_row_col(p)
        return " " if addr is None else None

    if sg.solve():
        sg.print(hook_function)
        print_loop(sg.grid, sg.solver.model())
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print(hook_function)
            print_loop(sg.grid, sg.solver.model())
    else:
        print("No solution")
コード例 #2
0
ファイル: nurikabe.py プロジェクト: jaylorch/grilops
def main():
    """Nurikabe solver example."""
    sym = grilops.SymbolSet([("B", chr(0x2588)), ("W", " ")])
    lattice = grilops.get_rectangle_lattice(HEIGHT, WIDTH)
    sg = grilops.SymbolGrid(lattice, sym)
    rc = grilops.regions.RegionConstrainer(lattice, solver=sg.solver)

    constrain_sea(sym, sg, rc)
    constrain_islands(sym, sg, rc)
    constrain_adjacent_cells(sg, rc)

    def print_grid():
        sg.print(lambda p, _: str(GIVENS[(p.y, p.x)])
                 if (p.y, p.x) in GIVENS else None)

    if sg.solve():
        print_grid()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            print_grid()
    else:
        print("No solution")
コード例 #3
0
def main():
    """Gokigen Naname solver example."""
    sym = grilops.SymbolSet([("F", chr(0x2571)), ("B", chr(0x2572))])
    lattice = grilops.get_rectangle_lattice(HEIGHT, WIDTH)
    sg = grilops.SymbolGrid(lattice, sym)

    # Ensure the given number of line segment constraints are met.
    for (y, x), v in GIVENS.items():
        terms = []
        if y > 0:
            if x > 0:
                terms.append(sg.cell_is(Point(y - 1, x - 1), sym.B))
            if x < WIDTH:
                terms.append(sg.cell_is(Point(y - 1, x), sym.F))
        if y < HEIGHT:
            if x > 0:
                terms.append(sg.cell_is(Point(y, x - 1), sym.F))
            if x < WIDTH:
                terms.append(sg.cell_is(Point(y, x), sym.B))
        sg.solver.add(PbEq([(term, 1) for term in terms], v))

    add_loop_constraints(sym, sg)

    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
def main():
    """SLICY solver example."""
    sym = grilops.SymbolSet(["S", "L", "I", "C", "Y", ("W", " ")])
    lattice = PointyToppedHexagonalLattice([
        areas_row_col_to_point(r, c) for r in range(len(AREAS))
        for c in range(len(AREAS[r]))
    ])
    sg = grilops.SymbolGrid(lattice, sym)
    rc = grilops.regions.RegionConstrainer(lattice,
                                           solver=sg.solver,
                                           complete=True)
    sc = ShapeConstrainer(
        lattice,
        [
            # Note that the example shapes are shown as flat-topped hexagons, so
            # you need to turn the page sideways to see them as pointy-topped ones.
            Shape([Vector(0, 0),
                   Vector(1, 1),
                   Vector(1, 3),
                   Vector(2, 4)]),  # S
            Shape([Vector(0, 0),
                   Vector(0, 2),
                   Vector(0, 4),
                   Vector(-1, 5)]),  # L
            Shape([Vector(0, 0),
                   Vector(0, 2),
                   Vector(0, 4),
                   Vector(0, 6)]),  # I
            Shape([Vector(0, 0),
                   Vector(1, 1),
                   Vector(1, 3),
                   Vector(0, 4)]),  # C
            Shape([Vector(0, 0),
                   Vector(2, 0),
                   Vector(1, 1),
                   Vector(1, 3)]),  # Y
        ],
        solver=sg.solver,
        allow_rotations=True,
        allow_reflections=True,
        allow_copies=True)

    link_symbols_to_shapes(sym, sg, sc)
    add_area_constraints(lattice, sc)
    add_sea_constraints(sym, sg, rc)
    add_adjacent_tetrahex_constraints(lattice, sc)

    if sg.solve():
        sg.print()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
            print()
    else:
        print("No solution")
コード例 #5
0
def main():
    """Kuromasu solver example."""
    sym = grilops.SymbolSet([("B", chr(0x2588) * 2), ("W", "  ")])
    lattice = grilops.get_rectangle_lattice(HEIGHT, WIDTH)
    sg = grilops.SymbolGrid(lattice, sym)
    rc = grilops.regions.RegionConstrainer(lattice,
                                           solver=sg.solver,
                                           complete=False)

    for p, c in GIVENS.items():
        # Numbered cells may not be black.
        sg.solver.add(sg.cell_is(p, sym.W))

        # Each number on the board represents the number of white cells that can be
        # seen from that cell, including itself. A cell can be seen from another
        # cell if they are in the same row or column, and there are no black cells
        # between them in that row or column.
        visible_cell_count = 1 + sum(
            grilops.sightlines.count_cells(
                sg, n.location, n.direction, stop=lambda c: c == sym.B)
            for n in sg.edge_sharing_neighbors(p))
        sg.solver.add(visible_cell_count == c)

    # All the white cells must be connected horizontally or vertically. Enforce
    # this by requiring all white cells to have the same region ID. Force the
    # root of this region to be the first given, to reduce the space of
    # possibilities.
    white_root = min(GIVENS.keys())
    white_region_id = lattice.point_to_index(white_root)

    for p in lattice.points:
        # No two black cells may be horizontally or vertically adjacent.
        sg.solver.add(
            Implies(
                sg.cell_is(p, sym.B),
                And(*[n.symbol == sym.W
                      for n in sg.edge_sharing_neighbors(p)])))

        # All white cells must have the same region ID. All black cells must not
        # be part of a region.
        sg.solver.add(
            If(sg.cell_is(p, sym.W), rc.region_id_grid[p] == white_region_id,
               rc.region_id_grid[p] == -1))

    def print_grid():
        sg.print(lambda p, _: f"{GIVENS[(p.y, p.x)]:02}"
                 if (p.y, p.x) in GIVENS else None)

    if sg.solve():
        print_grid()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            print_grid()
    else:
        print("No solution")
コード例 #6
0
ファイル: lits.py プロジェクト: space-egret/grilops
def main():
    """LITS solver example."""
    sym = grilops.SymbolSet(["L", "I", "T", "S", ("W", " ")])
    lattice = grilops.get_rectangle_lattice(HEIGHT, WIDTH)
    sg = grilops.SymbolGrid(lattice, sym)
    rc = grilops.regions.RegionConstrainer(lattice, solver=sg.solver)
    sc = grilops.shapes.ShapeConstrainer(
        lattice,
        [
            [Vector(0, 0),
             Vector(1, 0),
             Vector(2, 0),
             Vector(2, 1)],  # L
            [Vector(0, 0),
             Vector(1, 0),
             Vector(2, 0),
             Vector(3, 0)],  # I
            [Vector(0, 0),
             Vector(0, 1),
             Vector(0, 2),
             Vector(1, 1)],  # T
            [Vector(0, 0),
             Vector(1, 0),
             Vector(1, 1),
             Vector(2, 1)],  # S
        ],
        solver=sg.solver,
        allow_rotations=True,
        allow_reflections=True,
        allow_copies=True)

    link_symbols_to_shapes(sym, sg, sc)
    add_area_constraints(lattice, sc)
    add_nurikabe_constraints(sym, sg, rc)
    add_adjacent_tetronimo_constraints(lattice, sc)

    if sg.solve():
        sg.print()
        print()
        sc.print_shape_types()
        print()
        sc.print_shape_instances()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
            print()
            sc.print_shape_types()
            print()
            sc.print_shape_instances()
            print()
    else:
        print("No solution")
コード例 #7
0
ファイル: shape.py プロジェクト: obijywk/grilops
def main():
    """Shape solver example."""
    points = []
    for y, row in enumerate(GRID):
        for x, c in enumerate(row):
            if c == "O":
                points.append(Point(y, x))
    lattice = RectangularLattice(points)

    shapes = [
        Shape([Vector(0, 0),
               Vector(1, 0),
               Vector(2, 0),
               Vector(3, 0)]),  # I
        Shape([Vector(0, 0),
               Vector(1, 0),
               Vector(2, 0),
               Vector(2, 1)]),  # L
        Shape([Vector(0, 1),
               Vector(0, 2),
               Vector(1, 0),
               Vector(1, 1)]),  # S
    ]

    sym = grilops.SymbolSet([("B", chr(0x2588) * 2), ("W", "  ")])
    sg = grilops.SymbolGrid(lattice, sym)
    sc = ShapeConstrainer(lattice,
                          shapes,
                          sg.solver,
                          complete=False,
                          allow_rotations=True,
                          allow_reflections=True,
                          allow_copies=False)
    for p in points:
        sg.solver.add(sg.cell_is(p, sym.W) == (sc.shape_type_grid[p] == -1))
        for n in sg.vertex_sharing_neighbors(p):
            np = n.location
            sg.solver.add(
                Implies(
                    And(sc.shape_type_grid[p] != -1,
                        sc.shape_type_grid[np] != -1),
                    sc.shape_type_grid[p] == sc.shape_type_grid[np]))

    if sg.solve():
        sg.print()
        print()
        sc.print_shape_types()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
    else:
        print("No solution")
コード例 #8
0
def main():
    """Star Battle solver example."""
    sym = grilops.SymbolSet([("EMPTY", " "), ("STAR", "*")])
    lattice = grilops.get_rectangle_lattice(HEIGHT, WIDTH)
    sg = grilops.SymbolGrid(lattice, sym)

    # There must be exactly two stars per column.
    for y in range(HEIGHT):
        sg.solver.add(
            Sum(*[
                If(sg.cell_is(Point(y, x), sym.STAR), 1, 0)
                for x in range(WIDTH)
            ]) == 2)

    # There must be exactly two stars per row.
    for x in range(WIDTH):
        sg.solver.add(
            Sum(*[
                If(sg.cell_is(Point(y, x), sym.STAR), 1, 0)
                for y in range(HEIGHT)
            ]) == 2)

    # There must be exactly two stars per area.
    area_cells = defaultdict(list)
    for y in range(HEIGHT):
        for x in range(WIDTH):
            area_cells[AREAS[y][x]].append(sg.grid[Point(y, x)])
    for cells in area_cells.values():
        sg.solver.add(Sum(*[If(c == sym.STAR, 1, 0) for c in cells]) == 2)

    # Stars may not touch each other, not even diagonally.
    for y in range(HEIGHT):
        for x in range(WIDTH):
            p = Point(y, x)
            sg.solver.add(
                Implies(
                    sg.cell_is(p, sym.STAR),
                    And(*[
                        n.symbol == sym.EMPTY
                        for n in sg.vertex_sharing_neighbors(p)
                    ])))

    if sg.solve():
        sg.print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
    else:
        print("No solution")
コード例 #9
0
def main():
    """Aquarium solver example."""
    sym = grilops.SymbolSet([("B", chr(0x2588)), ("W", " ")])
    lattice = grilops.get_rectangle_lattice(HEIGHT, WIDTH)
    sg = grilops.SymbolGrid(lattice, sym)

    # Number of shaded cells per row / column must match clues.
    for y in range(HEIGHT):
        sg.solver.add(
            PbEq([(sg.grid[(y, x)] == sym.B, 1) for x in range(WIDTH)],
                 ROW_CLUES[y]))
    for x in range(WIDTH):
        sg.solver.add(
            PbEq([(sg.grid[(y, x)] == sym.B, 1) for y in range(HEIGHT)],
                 COL_CLUES[x]))

    # The water level in each aquarium is the same across its full width.
    for y in range(HEIGHT):
        for al in set(REGIONS[y]):
            # If any aquarium cell is filled within a row, then all cells of that
            # aquarium within that row must be filled.
            cells = [
                sg.grid[(y, x)] for x in range(WIDTH) if REGIONS[y][x] == al
            ]
            for cell in cells[1:]:
                sg.solver.add(cell == cells[0])

            # If an aquarium is filled within a row, and that aquarium also has
            # cells in the row below that row, then that same aquarium's cells below
            # must be filled as well.
            if y < HEIGHT - 1:
                cells_below = [
                    sg.grid[(y + 1, x)] for x in range(WIDTH)
                    if REGIONS[y + 1][x] == al
                ]
                if cells_below:
                    sg.solver.add(
                        Implies(cells[0] == sym.B, cells_below[0] == sym.B))

    if sg.solve():
        sg.print()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
    else:
        print("No solution")
コード例 #10
0
ファイル: heyawake.py プロジェクト: obijywk/grilops
def main():
  """Heyawake solver example."""
  sym = grilops.SymbolSet([("B", chr(0x2588)), ("W", " ")])
  lattice = grilops.get_rectangle_lattice(HEIGHT, WIDTH)
  sg = grilops.SymbolGrid(lattice, sym)

  # Rule 1: Painted cells may never be orthogonally connected (they may not
  # share a side, although they can touch diagonally).
  for p in lattice.points:
    sg.solver.add(
        Implies(
            sg.cell_is(p, sym.B),
            And(*[n.symbol != sym.B for n in sg.edge_sharing_neighbors(p)])
        )
    )

  # Rule 2: All white cells must be interconnected (form a single polyomino).
  rc = grilops.regions.RegionConstrainer(
      lattice,
      sg.solver,
      complete=False)
  white_region_id = Int("white_region_id")
  sg.solver.add(white_region_id >= 0)
  sg.solver.add(white_region_id < HEIGHT * WIDTH)
  for p in lattice.points:
    sg.solver.add(
        If(
            sg.cell_is(p, sym.W),
            rc.region_id_grid[p] == white_region_id,
            rc.region_id_grid[p] == -1
        )
    )

  # Rule 3: A number indicates exactly how many painted cells there must be in
  # that particular room.
  region_cells = defaultdict(list)
  for p in lattice.points:
    region_cells[REGIONS[p.y][p.x]].append(sg.grid[p])
  for region, count in REGION_COUNTS.items():
    sg.solver.add(PbEq([(c == sym.B, 1) for c in region_cells[region]], count))

  # Rule 4: A room which has no number may contain any number of painted cells,
  # or none.

  # Rule 5: Where a straight (orthogonal) line of connected white cells is
  # formed, it must not contain cells from more than two rooms—in other words,
  # any such line of white cells which connects three or more rooms is
  # forbidden.
  region_names = sorted(list(set(c for row in REGIONS for c in row)))
  bits = len(region_names)

  def set_region_bit(bv, p):
    i = region_names.index(REGIONS[p.y][p.x])
    chunks = []
    if i < bits - 1:
      chunks.append(Extract(bits - 1, i + 1, bv))
    chunks.append(BitVecVal(1, 1))
    if i > 0:
      chunks.append(Extract(i - 1, 0, bv))
    return Concat(*chunks)

  for p in lattice.points:
    for n in sg.edge_sharing_neighbors(p):
      bv = reduce_cells(
          sg,
          p,
          n.direction,
          set_region_bit(BitVecVal(0, bits), p),
          lambda acc, c, ap: set_region_bit(acc, ap),
          lambda acc, c, sp: c == sym.B
      )
      popcnt = Sum(*[BV2Int(Extract(i, i, bv)) for i in range(bits)])
      sg.solver.add(Implies(sg.cell_is(p, sym.W), popcnt <= 2))

  if sg.solve():
    sg.print()
    print()
    if sg.is_unique():
      print("Unique solution")
    else:
      print("Alternate solution")
      sg.print()
  else:
    print("No solution")
コード例 #11
0
"""Battleship solver example."""

from z3 import And, Not, Implies, Or, PbEq

import grilops
import grilops.shapes
from grilops.geometry import Point, Vector


SYM = grilops.SymbolSet([
    ("X", " "),
    ("N", chr(0x25B4)),
    ("E", chr(0x25B8)),
    ("S", chr(0x25BE)),
    ("W", chr(0x25C2)),
    ("B", chr(0x25AA)),
    ("O", chr(0x2022)),
])
DIR_TO_OPPOSITE_SYM = {
    Vector(-1, 0): SYM.S,
    Vector(0, 1): SYM.W,
    Vector(1, 0): SYM.N,
    Vector(0, -1): SYM.E,
}
HEIGHT, WIDTH = 8, 8
LATTICE = grilops.get_rectangle_lattice(HEIGHT, WIDTH)
GIVENS_Y = [1, 5, 1, 5, 0, 3, 2, 2]
GIVENS_X = [2, 4, 2, 3, 0, 4, 1, 3]
GIVENS = {
    Point(2, 5): SYM.S,
    Point(6, 1): SYM.S,
コード例 #12
0
ファイル: tapa.py プロジェクト: space-egret/grilops
    (1, 6): [2, 2],
    (1, 9): [2],
    (3, 3): [1],
    (4, 2): [1, 1],
    (4, 5): [2],
    (4, 7): [2, 2],
    (5, 2): [4],
    (5, 4): [4],
    (5, 7): [3],
    (6, 6): [3],
    (8, 0): [4],
    (8, 3): [4],
    (8, 9): [3],
    (9, 6): [3],
}
SYM = grilops.SymbolSet([("B", chr(0x2588)), ("W", " ")])


def make_neighbor_locations(y, x):
    """Returns a list of neighboring locations, without gaps between them."""
    ds = [(-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1), (-1, -1)]
    ns = []
    start = 0
    for dy, dx in ds:
        ny, nx = y + dy, x + dx
        if 0 <= ny < HEIGHT and 0 <= nx < WIDTH:
            ns.append((ny, nx))
        else:
            start = len(ns)
    return ns[start:] + ns[:start]
コード例 #13
0
def region_solve():
    """Slitherlink solver example using regions."""
    sym = grilops.SymbolSet([("I", chr(0x2588)), ("O", " ")])
    lattice = grilops.get_rectangle_lattice(HEIGHT, WIDTH)
    sg = grilops.SymbolGrid(lattice, sym)
    rc = grilops.regions.RegionConstrainer(lattice,
                                           solver=sg.solver,
                                           complete=False)

    def constrain_no_inside_diagonal(y, x):
        """Add constraints for diagonally touching cells.

    "Inside" cells may not diagonally touch each other unless they also share
    an adjacent cell.
    """
        nw = sg.grid[Point(y, x)]
        ne = sg.grid[Point(y, x + 1)]
        sw = sg.grid[Point(y + 1, x)]
        se = sg.grid[Point(y + 1, x + 1)]
        sg.solver.add(
            Implies(And(nw == sym.I, se == sym.I), Or(ne == sym.I,
                                                      sw == sym.I)))
        sg.solver.add(
            Implies(And(ne == sym.I, sw == sym.I), Or(nw == sym.I,
                                                      se == sym.I)))

    region_id = Int("region_id")
    for p in lattice.points:
        # Each cell must be either "inside" (part of a single region) or
        # "outside" (not part of any region).
        sg.solver.add(
            Or(rc.region_id_grid[p] == region_id, rc.region_id_grid[p] == -1))
        sg.solver.add(
            (sg.grid[p] == sym.I) == (rc.region_id_grid[p] == region_id))

        if p not in GIVENS:
            continue
        given = GIVENS[p]
        neighbors = sg.edge_sharing_neighbors(p)
        # The number of grid edge border segments adjacent to this cell.
        num_grid_borders = 4 - len(neighbors)
        # The number of adjacent cells on the opposite side of the loop line.
        num_different_neighbors_terms = [(n.symbol != sg.grid[p], 1)
                                         for n in neighbors]
        # If this is an "inside" cell, we should count grid edge borders as loop
        # segments, but if this is an "outside" cell, we should not.
        sg.solver.add(
            If(sg.grid[p] == sym.I,
               PbEq(num_different_neighbors_terms, given - num_grid_borders),
               PbEq(num_different_neighbors_terms, given)))

    # "Inside" cells may not diagonally touch each other unless they also share
    # an adjacent cell.
    for y in range(HEIGHT - 1):
        for x in range(WIDTH - 1):
            constrain_no_inside_diagonal(y, x)

    if sg.solve():
        sg.print()
        print()
        if sg.is_unique():
            print("Unique solution")
        else:
            print("Alternate solution")
            sg.print()
    else:
        print("No solution")
コード例 #14
0
ファイル: heteromino.py プロジェクト: space-egret/grilops
import grilops
import grilops.regions
from grilops.geometry import Point

SIZE = 4
BLACK_CELLS = set([
    Point(0, 0),
    Point(1, 0),
    Point(3, 1),
    Point(3, 2),
])
SYM = grilops.SymbolSet([
    ("BL", chr(0x2588)),
    ("NS", chr(0x25AF)),
    ("EW", chr(0x25AD)),
    ("NE", chr(0x25F9)),
    ("SE", chr(0x25FF)),
    ("SW", chr(0x25FA)),
    ("NW", chr(0x25F8)),
])


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):
コード例 #15
0
def slitherlink(givens):
    """Solver for Slitherlink minipuzzles."""
    sym = grilops.SymbolSet([("I", chr(0x2588)), ("O", " ")])
    sg = grilops.SymbolGrid(LATTICE, sym)
    rc = grilops.regions.RegionConstrainer(LATTICE,
                                           solver=sg.solver,
                                           complete=False)
    shifter = Shifter(sg.solver)

    region_id = Int("region_id")
    for p in LATTICE.points:
        # Each cell must be either "inside" (part of a single region) or
        # "outside" (not part of any region).
        sg.solver.add(
            Or(rc.region_id_grid[p] == region_id, rc.region_id_grid[p] == -1))
        sg.solver.add(
            (sg.grid[p] == sym.I) == (rc.region_id_grid[p] == region_id))

        given = givens[p.y][p.x]
        if given == 9:
            continue
        given = shifter.given(p, given)

        neighbors = sg.edge_sharing_neighbors(p)
        # The number of grid edge border segments adjacent to this cell.
        num_grid_borders = 4 - len(neighbors)
        # The number of adjacent cells on the opposite side of the loop line.
        num_different_neighbors = Sum(
            [If(n.symbol != sg.grid[p], 1, 0) for n in neighbors])
        # If this is an "inside" cell, we should count grid edge borders as loop
        # segments, but if this is an "outside" cell, we should not.
        sg.solver.add(
            If(sg.grid[p] == sym.I,
               num_different_neighbors == given - num_grid_borders,
               num_different_neighbors == given))

    def constrain_no_inside_diagonal(y, x):
        """Add constraints for diagonally touching cells.

    "Inside" cells may not diagonally touch each other unless they also share
    an adjacent cell.
    """
        nw = sg.grid[Point(y, x)]
        ne = sg.grid[Point(y, x + 1)]
        sw = sg.grid[Point(y + 1, x)]
        se = sg.grid[Point(y + 1, x + 1)]
        sg.solver.add(
            Implies(And(nw == sym.I, se == sym.I), Or(ne == sym.I,
                                                      sw == sym.I)))
        sg.solver.add(
            Implies(And(ne == sym.I, sw == sym.I), Or(nw == sym.I,
                                                      se == sym.I)))

    for y in range(SIZE - 1):
        for x in range(SIZE - 1):
            constrain_no_inside_diagonal(y, x)

    assert sg.solve()
    sg.print()
    print()
    shifter.print_shifts()
    print()
    return shifter.eval_binary()
コード例 #16
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")