def find_portals(maze): """Find each inner and outer portal.""" # inner_portals[inner_location] = label inner_portals = {} # outer_portals[outer_location] = label outer_portals = {} # Look at every point in the maze for pos, tile in maze.items(): # If it's traversable look at everything adjacent to it if tile == ".": for offset in ((1, 0), (0, 1), (-1, 0), (0, -1)): adj = tuple_add(pos, offset) adj_tile = maze[adj] # If it's the start of a label find the whole label if adj_tile.isupper(): next_pos = tuple_add(adj, offset) next_tile = maze[next_pos] assert next_tile.isupper(), "ill-formed label found" after_pos = tuple_add(next_pos, offset) label = label_for(adj_tile, next_tile, offset) if after_pos in maze: inner_portals[pos] = label else: outer_portals[pos] = label return inner_portals, outer_portals
def get_tiles_in_aoe(self, user, map, target_loc): if target_loc[0] > user.location[0]: aoe = [ target_loc, tuple_add(target_loc, (1, 0)), tuple_add(target_loc, (2, 0)) ] elif target_loc[0] < user.location[0]: aoe = [ target_loc, tuple_add(target_loc, (-1, 0)), tuple_add(target_loc, (-2, 0)) ] elif target_loc[1] > user.location[1]: aoe = [ target_loc, tuple_add(target_loc, (0, 1)), tuple_add(target_loc, (0, 2)) ] elif target_loc[1] < user.location[1]: aoe = [ target_loc, tuple_add(target_loc, (0, -1)), tuple_add(target_loc, (0, -2)) ] else: aoe = [] return [map.get_tile(loc) for loc in aoe if map.on_map(loc)]
def optimize_polynomial(pol): r""" Optimization polynomial by representing it as an SDP in the appropriate basis TODO: Support constraints \min_y c^\top y subject to M(y) \succeq 0 y_1 = 1 @param poly - polynomial to optimize @param basis - basis for the polynomial (can be 'power', 'symmetric', 'symmetric_irreducible') @returns (p*, y*) - the optimal value of the polynomial and y* = E_\mu[b(x)]. """ # basis in sorted order from 1 to largest # Get the largest monomial term max_degree = get_max_degree(pol) half_degree = map(lambda deg: int(np.ceil(deg / 2.)), max_degree) # Generate basis basis = list(it.product(*[range(deg + 1) for deg in max_degree])) half_basis = list(it.product(*[range(deg + 1) for deg in half_degree])) N, M = len(basis), len(half_basis) # The coefficient term c = np.matrix([float(pol.nth(*elem)) for elem in basis]).T # The inequality term, enforcing sos-ness G = np.zeros((M**2, N)) for i, j in it.product(xrange(M), xrange(M)): e1, e2 = half_basis[i], half_basis[j] monom = tuple_add(e1, e2) k = basis.index(monom) if k != -1: G[M * i + j, k] = 1 h = np.zeros((M, M)) # Finally, y_1 = 1 A = np.zeros((1, N)) A[0, 0] = 1 b = np.zeros(1) b[0] = 1 sol = solvers.sdp( c=matrix(c), Gs=[matrix(-G)], hs=[matrix(h)], A=matrix(A), b=matrix(b), ) assert sol['status'] == 'optimal' return dict([(get_monom(pol, coeff), val) for coeff, val in zip(basis, list(sol['x']))])
def get_tiles_in_aoe(self, user, map, target_loc): if target_loc[0] > user.location[0]: aoe = [target_loc, tuple_add(target_loc, (1,0)), tuple_add(target_loc, (2,0))] elif target_loc[0] < user.location[0]: aoe = [target_loc, tuple_add(target_loc, (-1,0)), tuple_add(target_loc, (-2,0))] elif target_loc[1] > user.location[1]: aoe = [target_loc, tuple_add(target_loc, (0,1)), tuple_add(target_loc, (0,2))] elif target_loc[1] < user.location[1]: aoe = [target_loc, tuple_add(target_loc, (0,-1)), tuple_add(target_loc, (0,-2))] else: aoe = [] return [map.get_tile(loc) for loc in aoe if map.on_map(loc)]
def describe_moment_polynomial(syms, moments_x, moment_y, alpha, b): """ Computes the moment polynomial for E[x^alpha, y^b] """ D = len(syms) expr = -moment_y coeffs = sp.ntheory.multinomial_coefficients(D, b) for beta in partitions(D, b): expr += coeffs[beta] * monomial(syms, beta) * moments_x[tuple_add(alpha, beta)] return expr
def optimize_polynomial(pol): r""" Optimization polynomial by representing it as an SDP in the appropriate basis TODO: Support constraints \min_y c^\top y subject to M(y) \succeq 0 y_1 = 1 @param poly - polynomial to optimize @param basis - basis for the polynomial (can be 'power', 'symmetric', 'symmetric_irreducible') @returns (p*, y*) - the optimal value of the polynomial and y* = E_\mu[b(x)]. """ # basis in sorted order from 1 to largest # Get the largest monomial term max_degree = get_max_degree(pol) half_degree = map( lambda deg: int(np.ceil(deg/2.)), max_degree) # Generate basis basis = list(it.product( *[range(deg + 1) for deg in max_degree] ) ) half_basis = list(it.product( *[range(deg + 1) for deg in half_degree] ) ) N, M = len(basis), len(half_basis) # The coefficient term c = np.matrix([float(pol.nth(*elem)) for elem in basis]).T # The inequality term, enforcing sos-ness G = np.zeros( ( M**2, N ) ) for i, j in it.product(xrange(M), xrange(M)): e1, e2 = half_basis[i], half_basis[j] monom = tuple_add(e1,e2) k = basis.index(monom) if k != -1: G[ M * i + j, k ] = 1 h = np.zeros((M, M)) # Finally, y_1 = 1 A = np.zeros((1, N)) A[0,0] = 1 b = np.zeros(1) b[0] = 1 sol = solvers.sdp( c = matrix(c), Gs = [matrix(-G)], hs = [matrix(h)], A = matrix(A), b = matrix(b), ) assert sol['status'] == 'optimal' return dict([ (get_monom(pol,coeff), val) for coeff, val in zip(basis, list(sol['x'])) ] )
def describe_moment_polynomial(syms, moments_x, moment_y, alpha, b): """ Computes the moment polynomial for E[x^alpha, y^b] """ D = len(syms) expr = -moment_y coeffs = sp.ntheory.multinomial_coefficients(D, b) for beta in partitions(D, b): expr += coeffs[beta] * monomial(syms, beta) * moments_x[tuple_add( alpha, beta)] return expr
def compute_exact_y_moments(ws, pis, moments_x, alpha, b): """ Compute the exact moments E[x^a y^b] using coefficients ws, pis and moments_x. """ D, _ = ws.shape coeffs = sp.ntheory.multinomial_coefficients(D, b) ret = 0. for beta in partitions(D, b): ret += coeffs[beta] * evaluate_mixture(ws, pis, beta) * moments_x[tuple_add(alpha, beta)] return ret
def compute_exact_y_moments(ws, pis, moments_x, alpha, b): """ Compute the exact moments E[x^a y^b] using coefficients ws, pis and moments_x. """ D, _ = ws.shape coeffs = sp.ntheory.multinomial_coefficients(D, b) ret = 0. for beta in partitions(D, b): ret += coeffs[beta] * evaluate_mixture( ws, pis, beta) * moments_x[tuple_add(alpha, beta)] return ret
def part2(maze, state): """Solve for the answer to part 2.""" # Section the maze and add the robots replacement = ["@#@", "###", "@#@"] start = state["start"] for x_offset, y_offset in itertools.product((-1, 0, 1), repeat=2): maze_idx = tuple_add(start, (x_offset, y_offset)) maze[maze_idx] = replacement[y_offset + 1][x_offset + 1] # The strategy here is basically the same as part 1, only slight change in the DFS # Get some data out of the maze robots = frozenset(pos for pos, tile in maze.items() if tile == "@") keys = state["keys"] doors = state["doors"] key_for = state["key_for"] # Mark the shortest paths similar to part 1, but including all 4 start positions now paths = {} for robot in robots: mark_paths(maze, robot, keys, doors, paths) for key in keys: mark_paths(maze, key, keys, doors, paths) @functools.lru_cache(maxsize=None) def shortest_tour(robots, unlocked=frozenset()): """Find the shortest number of steps to get all keys.""" # Use DFS remaining = keys - unlocked if not remaining: return 0 # Brute force all the places each robot could go next, thank you lru_cache return min( path.dist + shortest_tour( robots - {mover} | {path.end}, unlocked | path.keys | {path.end}, ) for mover in robots for path in [paths[mover, key] for key in remaining if (mover, key) in paths] if all(key_for[door] in unlocked for door in path.doors)) return shortest_tour(robots)
def process(input): instrs = input.strip().splitlines() loc = (0, 0) way = (10, 1) dir = 'E' for instr in instrs: cmd, val = instr[0], int(instr[1:]) if cmd == 'F': move = tuple([val * x for x in way]) loc = util.tuple_add(loc, move) elif cmd in ['L', 'R']: repeat = int(val / 90) for _ in range(repeat): way = way[1], way[0] if cmd == 'L': way = (way[0] * -1, way[1]) else: way = (way[0], way[1] * -1) else: way = util.coord_move(way, cmd, val) print(cmd, val, '->', loc, way) return util.taxi_distance(loc)
def count_trees(input, dir): input = input.strip() grid = util.text_to_grid(input) y_size = len(grid) x_size = len(grid[0]) num_trees = 0 loc = (0, 0) while True: loc = util.tuple_add(loc, dir) # Stop after reaching the bottom if loc[1] >= y_size: break # Loop around at the horizontal edge if loc[0] >= x_size: loc = (loc[0] - x_size, loc[1]) is_tree = grid[loc[1]][loc[0]] == '#' print('loc', loc, ':', is_tree) if is_tree: num_trees += 1 return num_trees
def calc_move(self, direction): """Calculate the resulting position of moving in a direction.""" return tuple_add(self.pos, DIRECTION_TO_OFFSET[direction])