def parsed(data): grid = {} lines = data.splitlines() h = len(lines) [w] = {len(x) for x in lines} grid["y-axis"] = range(h) grid["x-axis"] = range(w) uid = 0 units = [] for y, line in enumerate(lines): for x, char in enumerate(line): pos = complex(x, y) if char in "#.": grid[pos] = char elif char == "G": g = Goblin(id=uid, pos=pos) units.append(g) grid[pos] = "." uid += 1 elif char == "E": e = Elf(id=uid, pos=pos) units.append(e) grid[pos] = "." uid += 1 grid["units"] = units return grid
def compute(data): result = {} def getval(v): return result[v] if v in result else uint16(v) lines = data.splitlines() lines = [line.partition(" -> ")[::2] for line in lines] def process_line(line): left, right = line left = left.split() len_left = len(left) if len_left == 1: # store result[right] = getval(left[0]) elif len_left == 2: # negation op, val = left if op != "NOT": raise Exception result[right] = ~getval(val) elif len_left == 3: a, op, b = left op = opmap[op] result[right] = op(getval(a), getval(b)) while lines: line = lines.pop() try: process_line(line) except (KeyError, ValueError): lines = [line] + lines return result
def scramble(data, original): list_ = list(original) for line in data.splitlines(): line = line.replace(" ", "_", 1) func_name, *words = line.split() globals()[func_name](list_, words) return "".join(list_)
def run_b(data, p, q): snd = None lines = data.splitlines() d = {line[4:5]: 0 for line in lines if not line[4:5].isdigit()} d['p'] = p i = 0 while True: line = lines[i] if line.startswith('snd'): _snd, n = line.split() n = d[n] if n in d else int(n) yield n elif line.startswith('rcv'): _rcv, k = line.split() try: d[k] = q.popleft() except IndexError: i -= 1 yield else: op, k, n = line.split() n = d[n] if n in d else int(n) if op == 'set': d[k] = n elif op == 'add': d[k] += n elif op == 'mul': d[k] *= n elif op == 'mod': d[k] %= n elif op == 'jgz': k = d[k] if k in d else int(k) i += n - 1 if k > 0 else 0 i += 1
def parsed(data): initial, _, *rest = data.splitlines() s0 = initial.split()[-1] p0 = s0.index("#") s0 = s0.strip(".") rules = dict(r.split(" => ") for r in rest) return s0, p0, rules
def work(data, n_workers=4, delay=60): template = "Step {} must be finished before step {} can begin." pairs = [parse(template, s).fixed for s in data.splitlines()] remaining = {x for pair in pairs for x in pair} in_progress = set() done = set() text = "" t = -1 workers = [Worker() for i in range(n_workers)] while remaining or in_progress: for w in workers: x = w.tick() if x is not None: text += x pairs = [pair for pair in pairs if x not in pair] in_progress.remove(x) done.add(x) avail = remaining - {two for one, two in pairs} - in_progress log.debug("candidates %d: %s", t, avail) for w in workers: if w.has == "." and avail: w.has = x = min(avail) avail.remove(x) remaining.remove(x) in_progress.add(x) if n_workers == 1: w.t = 1 else: w.t = ord(x) - ord("A") + 1 + delay t += 1 log.debug("%4d: %s %s", t, " ".join(w.has for w in workers), text) result = SimpleNamespace(text=text, n_iterations=t) return result
def run_a(data): snd = None lines = data.splitlines() d = {line[4:5]: 0 for line in lines if not line[4:5].isdigit()} i = 0 while True: line = lines[i] if line.startswith('snd'): _snd, k = line.split() snd = d[k] elif line.startswith('rcv'): _rcv, k = line.split() if d[k]: return snd else: op, k, n = line.split() n = d[n] if n in d else int(n) if op == 'set': d[k] = n elif op == 'add': d[k] += n elif op == 'mul': d[k] *= n elif op == 'mod': d[k] %= n elif op == 'jgz': k = d[k] if k in d else int(k) i += n - 1 if k > 0 else 0 i += 1
def parsed(data): """ state vector structure: 3-tuple of (int, tuple, tuple) ( elevator_floor, (chip1_floor, chip2_floor, ... chipN_floor), (genr1_floor, genr2_floor, ... genrN_floor), ) """ chips = {} generators = {} for line_no, line in enumerate(data.splitlines(), 1): words = line.split() for i, word in enumerate(words, -1): if word.startswith("generator"): generator = words[i] generators[generator] = line_no elif word.startswith("microchip"): chip, compatible = words[i].split("-") chips[chip] = line_no chip_names = sorted(chips) if chip_names != sorted(generators): raise Exception("chip and generators mismatched") state0 = ( 1, tuple(chips[k] for k in chip_names), tuple(generators[k] for k in chip_names), ) target = 4, tuple(4 for chip in chip_names), tuple( 4 for generator in generators) if not is_valid(state0) or not is_valid(target): raise Exception("parsed state vector is invalid") return state0, target
def parse_data(data): ingredients = {} for line in data.splitlines(): name, stats = line.split(': ') stats = stats.split()[1::2] ingredients[name] = np.array([int(s.rstrip(',')) for s in stats]) return ingredients
def parsed(data): template = "{name}: capacity {:d}, durability {:d}, flavor {:d}, texture {:d}, calories {:d}" ingredients = [] for line in data.splitlines(): nums = parse(template, line).fixed ingredients.append(nums) return ingredients
def risk_levels(data): arys = [N.fromiter(map(int,line), int) for line in data.splitlines()] start_ary = N.stack(arys) # pad starting array with a row of 10's around the edge, then use local_minima to find minima. minima = local_minima(start_ary) return sum(N.extract(minima, start_ary) + 1)
def parsed(data): template = "pos=<{:d},{:d},{:d}>, r={:d}" nums = [parse(template, s).fixed for s in data.splitlines()] A = np.array(nums) xs = A[:, :-1] rs = A[:, -1] return xs, rs
def count_flashes(data, steps = 100): ary = np.stack([np.fromiter(map(int,line), int) for line in data.splitlines()]) count = 0 for step in range(0,steps): ary += 1 flashed_coords = set() while True: locs = np.where(ary > 9) flashable_locs = list(zip(locs[0], locs[1])) flash_occurred = False for loc in flashable_locs: if loc not in flashed_coords: flash_occurred = True count += 1 flashed_coords.add(loc) for x in range(0 if loc[0] < 1 else loc[0] - 1, 10 if loc[0] > 8 else loc[0] + 2): for y in range(0 if loc[1] < 1 else loc[1] - 1, 10 if loc[1] > 8 else loc[1] + 2): if x != loc[0] or y != loc[1]: ary[x,y] += 1 if not flash_occurred: break if len(flashed_coords) == 100: raise AllOctopusesFlashed(step + 1) ary[ary > 9] = 0 return count
def part1(data): def step(map): changed = False def get(pos): nonlocal changed occ = sum(1 for d in (1, -1, 1j, -1j, 1 + 1j, 1 - 1j, -1 + 1j, -1 - 1j) if map.get((pos + d), '') == '#') if occ == 0 and map[pos] == 'L': changed = True return '#' elif occ >= 4 and map[pos] == '#': changed = True return 'L' return map[pos] new = {pos: get(pos) for pos in map} return changed, new map = {(r + c * 1j): x for r, row in enumerate(data.splitlines()) for c, x in enumerate(row) if x != '.'} while (res := step(map))[0]: map = res[1]
def parsed(data): d = { k.lower(): int(v) for k, v in (line.split(": ") for line in data.splitlines()) } d["hp"] = d.pop("hit points") return Player(name="boss", **d)
def run_b(data, p, q): lines = data.splitlines() d = {line[4:5]: 0 for line in lines if not line[4:5].isdigit()} d["p"] = p i = 0 while True: line = lines[i] if line.startswith("snd"): _snd, n = line.split() n = d[n] if n in d else int(n) yield n elif line.startswith("rcv"): _rcv, k = line.split() try: d[k] = q.popleft() except IndexError: i -= 1 yield else: op, k, n = line.split() n = d[n] if n in d else int(n) if op == "set": d[k] = n elif op == "add": d[k] += n elif op == "mul": d[k] *= n elif op == "mod": d[k] %= n elif op == "jgz": k = d[k] if k in d else int(k) i += n - 1 if k > 0 else 0 i += 1
def run_a(data): snd = None lines = data.splitlines() d = {line[4:5]: 0 for line in lines if not line[4:5].isdigit()} i = 0 while True: line = lines[i] if line.startswith("snd"): _snd, k = line.split() try: snd = d[k] except KeyError: return elif line.startswith("rcv"): _rcv, k = line.split() if d[k]: return snd else: op, k, n = line.split() n = d[n] if n in d else int(n) if op == "set": d[k] = n elif op == "add": d[k] += n elif op == "mul": d[k] *= n elif op == "mod": d[k] %= n elif op == "jgz": k = d[k] if k in d else int(k) i += n - 1 if k > 0 else 0 i += 1
def part_a(data): nodes = [tuple(int(n) for n in s.split(",")) for s in data.splitlines()] graph = nx.Graph() graph.add_nodes_from(nodes) for node1, node2 in combinations(nodes, 2): if sum(abs(x - y) for x, y in zip(node1, node2)) <= 3: graph.add_edge(node1, node2) return nx.number_connected_components(graph)
def parsed(data): lines = data.splitlines() s = len(lines) // 2 grid = {} for row, line in enumerate(lines, -s): for col, char in enumerate(line, -s): grid[col - row * 1j] = char return grid
def run(data): b = 0 d = defaultdict(int) for line in data.splitlines(): r = SimpleNamespace(**parse(template, line, {'op': ops.get}).named) d[r.x] = r.i(d[r.x], r.cmp(d[r.y], r.n) and r.m) b = max(b, d[r.x]) return max(d.values()), b
def part_ab(data): area = 0 length = 0 for line in data.splitlines(): w, h, l = [int(d) for d in line.split("x")] area += box_area(w, h, l) + smallest_side(w, h, l) length += shortest_perimeter(w, h, l) + box_volume(w, h, l) return area, length
def basin_sizes(data): arys = [N.fromiter(map(int,line), int) for line in data.splitlines()] start_ary = N.stack(arys) features = N.vectorize(lambda x: 0 if x == 9 else 1)(start_ary) labeled_ary, num_features = label(features) basin_sizes = sorted([N.count_nonzero(labeled_ary == x) for x in range(1, num_features + 1)]) return reduce(lambda a, b: a * b, list(basin_sizes)[-3:])
def parse_data(data): distances = {} cities = set() for line in data.splitlines(): a, to, b, equals, n = line.split() cities |= {a, b} distances[(a, b)] = distances[(b, a)] = int(n) return cities, distances
def parse_data(data): particles = [] for particle in data.splitlines(): match = re.match(r".*<(.*)>.*<(.*)>.*<(.*)>.*", particle) particle = list( np.array(tuple(to_int(x.replace(" ", "").split(",")))) for x in match.groups()) particles.append(particle) return particles
def parsed(data): asteroids = [] rows = data.splitlines() for y, row in enumerate(rows): for x, val in enumerate(row): if val == "#": asteroids.append((x, y)) assert len(asteroids) == data.count("#") return asteroids
def parsed(data): digraph = nx.DiGraph() for line in data.splitlines(): sources, sep, dest = line.partition(" => ") n0, elem0 = dest.split() for source in sources.split(", "): n1, elem1 = source.split() digraph.add_edge(elem0, elem1, ratio=(int(n0), int(n1))) return digraph
def parsed(data): rules = {} for line in data.splitlines(): a, b = line.split(" => ") a, b = s2a(a), s2a(b) for i in range(4): rules[a2s(a)] = rules[a2s(np.flipud(a))] = rules[a2s(np.fliplr(a))] = b a = np.rot90(a) return rules
def decode(keypad, data, pos0): pos = pos0 code = "" for line in data.splitlines(): for step in line: step = directions[step] if pos + step in keypad: pos += step code += keypad[pos] return code
def exe(data): b = 0 d = defaultdict(int) template = "{x} {i:op} {m:d} if {y} {cmp:op} {n:d}" for line in data.splitlines(): parsed = parse(template, line, {"op": ops.get}) r = SimpleNamespace(**parsed.named) d[r.x] = r.i(d[r.x], r.cmp(d[r.y], r.n) and r.m) b = max(b, d[r.x]) return max(d.values()), b
def race(data, max_t, measure): deers = [Reindeer(line) for line in data.splitlines()] for t in range(max_t): for deer in deers: deer.step() max_distance = max([deer.distance for deer in deers]) for deer in deers: if deer.distance == max_distance: deer.points += 1 return max([getattr(deer, measure) for deer in deers])