예제 #1
0
def gen_contiguous_constraints_single(index_, count_, *, width, height, board, puzzle):
    at_ = lambda l, c : board[l][c]
    at_puzzle = lambda l, c : puzzle[l][c]
    def is_valid_cell(ind, current_index=index_, height=height, width=width):
        if ind == current_index: # redundant check at_puzzle(ind) == count_
            return True
        if not inside_board(ind, height=height, width=width):
            return False
        # a cell is considered valid neighbour (to spawn) if it is empty
        # or it has the same count_
        return at_puzzle(*ind) == 0 or at_puzzle(*ind) == count_
    possibs = [] # possible configurations given the count_ of contiguous cells in the block
    blocks = get_block(index_, nb_cells=count_, is_valid_cell=is_valid_cell)
    for block in blocks:
        block_vars = [ at_(*ind) for ind in block ]
        # fence can be thought of as completely encircling the block
        fence = get_fence(enclosure=block)
        geom = { 'width': width, 'height': height }
        fence_inside_board = [ ind for ind in fence
                if inside_board(ind, **geom) ]
        fence_var = [ at_(*ind) for ind in fence_inside_board ]
        fenced_enclosure = And(
                coerce_eq(block_vars, [count_] * len(block_vars)),
                And([var != count_ for var in fence_var]))
        possibs.append(simplify(fenced_enclosure))
    return Exactly(*possibs, 1) #only one configuration would prevail
예제 #2
0
 def is_valid_cell(ind, current_index=index_, height=height, width=width):
     if ind == current_index: # redundant check at_puzzle(ind) == count_
         return True
     if not inside_board(ind, height=height, width=width):
         return False
     # a cell is considered valid neighbour (to spawn) if it is empty
     # or it has the same count_
     return at_puzzle(*ind) == 0 or at_puzzle(*ind) == count_
 def gen_consecutive_nums_constraint(l, c):
     val_neighs = [ neigh for neigh in neighbours(l, c)
             if inside_board(neigh, height=order, width=order) ]
     neighs = get_vars_at(val_neighs)
     occupied_neighs = set(neighs).intersection(occupied_cells)
     var = at_(l, c) #content of current cell
     one_adj_cell_is_consec_c = Exactly(*[ adj == var + 1 for adj in occupied_neighs ], 1)
     current_cell_is_max_c = var == maximum
     return Or(current_cell_is_max_c, one_adj_cell_is_consec_c)
예제 #4
0
 def gen_coupling_constraints(l, c):
     val_neighs = [
         neigh for neigh in neighbours((l, c))
         if inside_board(neigh, height=height, width=width)
     ]
     couplings = [X[l][c] == -at_(*cell) for cell in val_neighs]
     # we don't add constraint that it is unoccupied by a tree
     # it's taken care by another set of constraints
     # return Exactly(*couplings, 1)
     return Exactly(*couplings, 1)
예제 #5
0
 def gen_proximity_constraints(l, c):
     square = [
         (l, c),
         (l, c + 1),  # towards right
         (l + 1, c),
         (l + 1, c + 1)
     ]  # towards bottom and right
     val_cells_in_square = [
         cell for cell in square
         if inside_board(cell, height=height, width=width)
     ]
     # cell < 0 : we have encoded as tent
     tents_in_a_square = [at_(*cell) < 0 for cell in val_cells_in_square]
     return AtMost(*tents_in_a_square, 1)
def gen_contiguous_constraints_single(index_, count_, *, width, height, board):
    at_ = lambda l, c: board[l][c]
    # count_ - 1 because the current square is always counted
    possibs = []  #possible configurations given the count_ of white squares
    for distrib in distribute_in_4_directions(count_ - 1):
        strict_boundaries = boundaries(index_, spawn_direction=distrib)
        geom = {'width': width, 'height': height}
        can_spawn = all(
            (inside_board(ind, **geom) for ind in strict_boundaries))
        if can_spawn:
            enclosure = get_enclosed_space(index_, spawn_direction=distrib)
            encloure_vars = [at_(*ind) for ind in enclosure]
            direction_plus_one = tuple(d + 1 for d in distrib)
            # walls can be thought of as surrounding boundaries
            walls = boundaries(index_, spawn_direction=direction_plus_one)
            walls_within_board = [
                ind for ind in walls if inside_board(ind, **geom)
            ]
            walls_var = [at_(*ind) for ind in walls_within_board]
            walled_enclosure = And(
                coerce_eq(encloure_vars, [WHITE] * len(encloure_vars)),
                coerce_eq(walls_var, [BLACK] * len(walls_var)))
            possibs.append(simplify(walled_enclosure))
    return Exactly(*possibs, 1)  #only one configuration would prevail
    def gen_consecutive_nums_constraint(l, c):
        geom = {'height': height, 'width': width}
        val_neighs = [
            neigh for neigh in neighbours((l, c))
            if inside_board(neigh, **geom)
        ]
        neighs = get_vars_at(val_neighs)

        var = at_(l, c)  #content of current cell
        one_adj_cell_is_consec_c = Exactly(*[adj == var + 1 for adj in neighs],
                                           1)
        current_cell_is_max_c = var == MAX
        unoccupied_c = var == 0
        return Or(unoccupied_c, current_cell_is_max_c,
                  one_adj_cell_is_consec_c)
 def valid_neighbours(l, c):
     return [
         neigh for neigh in neighbours((l, c))
         if inside_board(neigh, **geom)
     ]
예제 #9
0
 def valid_cells_in_disk(l, c):
     geom = {'height': height, 'width': width}
     cells = cells_in_disk((l, c), radius=1)
     return [cell for cell in cells if inside_board(cell, **geom)]