def promote(cur): for ((i, j, s2), nxt) in cur.down.items(): rule[i][j] = s2 promote(nxt) rule[i][j] = None add = {} for ((i, j, s2), nxt) in cur.down.items(): rule[i][j] = s cur_mn = sum( 0 if rule[x][y] is None else rule[x][y].min_length(settings.sinput.permutations) for x in range(n) for y in range(m) ) if cur_mn <= settings.mn_at_most and s2 in above and (i, j, s) not in cur.down and (i, j, s) not in add: if all((i, j, a) in cur.down for a in above): ok = True if ok: # make sure the current type is an allowed neighbor of all (not necessarily immediate) neighbors for ci in range(i, n): for cj in range(m): if (ci, cj) > (i, j): di = signum(ci - i) dj = signum(cj - j) if s not in allowed_neighbors_cpp[(rule[ci][cj], -di, -dj)]: ok = False break if not ok: break if ok: # check if any of my immediate neighbors are neither empty nor a point # in that case, we can only put a point in the current box for di in range(-1, 2): for dj in range(-1, 2): ci, cj = i + di, j + dj if (ci, cj) > (i, j) and 0 <= ci < n and 0 <= cj < m: if rule[ci][cj] is not None and type(rule[ci][cj]) is not PointPermutationSet: ok = False break if not ok: break if ok: add[(i, j, s)] = intersect([cur.down[(i, j, a)] for a in above], (i, j)) rule[i][j] = None for (k, v) in add.items(): if v is not None: cur.down[k] = v
def intersect(cur, pos): if settings.filter_rule_incrementally and not generates_subset(GeneratingRule(rule)): return None here = TrieNode() here.end = all(c.end for c in cur) if here.end: si = pos[0] sj = None for y in range(m): found = False for x in range(si, n): if rule[x][y] is not None: found = True break if found: sj = y break assert sj is not None g = GeneratingRule({(x - si, y - sj): rule[x][y] for x in range(si, n) for y in range(sj, m)}) ok = True if (si, sj) == (n - 1, m - 1) and not rule[si][sj].can_be_alone(): ok = False if ok: res = rule_set.add_rule(g) if res == RuleDeath.PERM_PROP: return None elif res != RuleDeath.ALIVE: here.end = False found = False for (i, j, s2) in reduce(lambda x, y: x & y, [set(c.down.keys()) for c in cur]): rule[i][j] = s2 ok = True if ok: # make sure the current type is an allowed neighbor of all (not necessarily immediate) neighbors for ci in range(i, n): for cj in range(m): if (ci, cj) > (i, j): di = signum(ci - i) dj = signum(cj - j) if s2 not in allowed_neighbors_cpp[(rule[ci][cj], -di, -dj)]: ok = False break if not ok: break if ok and type(s2) is not PointPermutationSet: # check if any of my immediate neighbors are neither empty nor a point # in that case, we can only put a point in the current box for di in range(-1, 2): for dj in range(-1, 2): ci, cj = i + di, j + dj if (ci, cj) > (i, j) and 0 <= ci < n and 0 <= cj < m: if rule[ci][cj] is not None and type(rule[ci][cj]) is not PointPermutationSet: ok = False break if not ok: break if ok: rest = intersect([c.down[(i, j, s2)] for c in cur], (i, j)) if rest is not None: found = True here.down[(i, j, s2)] = rest rule[i][j] = None if not found and not here.end: return None return here