def a(): groups = data.split("\n\n") criteria, ticket, nearby = [l.split("\n") for l in groups] rules = {} for c in criteria: k, vs = c.split(":") rs = u.lmap(tuple, u.chunks(u.ints(vs.replace("-", " to ")), 2)) rules[k] = rs def valid(val): for ruleset in rules.values(): for a, b in ruleset: if a <= val <= b: return True return False s = 0 for ticket in nearby[1:]: t = u.ints(ticket) for v in t: if not valid(v): s += v return s
def parse_segments(prog): segments = [seg.splitlines() for seg in prog.split('inp w\n')[1:]] out = [] for segment in segments: param1 = u.ints(segment[4]).pop() param2 = u.ints(segment[14]).pop() out.append((param1, param2)) return out
def b(): groups = data.split("\n\n") criteria, my_ticket, nearby = [g.split("\n") for g in groups] my_ticket = u.ints(my_ticket[1]) rules = {} for c in criteria: k, vs = c.split(":") rs = u.lmap(tuple, u.chunks(u.ints(vs.replace("-", " ")), 2)) rules[k] = rs def valid_for_field(v, field): return any(a <= v <= b for a, b in rules[field]) def valid(val): return any(valid_for_field(val, field) for field in rules) valid_nearby = [] for ticket in nearby[1:]: t = u.ints(ticket) if all(valid(v) for v in t): valid_nearby.append(t) possible = [] for _ in range(len(my_ticket)): possible.append(set(rules.keys())) for ticket in valid_nearby: for i, v in enumerate(ticket): pl = list(possible[i]) for field in pl: if not valid_for_field(v, field): possible[i].remove(field) mapping = {} allocated = set() for i, p in sorted(enumerate(possible), key=lambda x: x[1]): field = (p - allocated).pop() mapping[i] = field allocated.add(field) s = functools.reduce( operator.mul, (my_ticket[i] for i in mapping if mapping[i].startswith("departure")), 1, ) return s
def b(): def min_perim(l, w, h): return min(2 * sum(s) for s in sides(l, w, h)) return sum( math.prod((l, w, h)) + min_perim(l, w, h) for l, w, h in u.chunks(u.ints(data), 3))
def b(): players, last = u.ints(data) last *= 100 scores = Counter() marbles = u.Linked(0) st = marbles player = 0 for marble in range(1, last + 1): if marble % 23 == 0: scores[player] += marble other = marbles.move(-7) scores[player] += other.item marbles = other.move(1) other.remove() else: cur = u.Linked(marble) marbles.move(1).add(cur) marbles = cur player = (player + 1) % players return max(scores.values()) pass
def a(): pvs = [] for line in lines: pvs.append(list(u.ints(line))) i = 0 pa = math.inf grid = None while True: for pv in pvs: pv[0] += pv[2] pv[1] += pv[3] lt = min(pv[0] for pv in pvs) rt = max(pv[0] for pv in pvs) up = min(pv[1] for pv in pvs) dn = max(pv[1] for pv in pvs) a = (rt - lt) * (dn - up) if pa < a: for y in range(up, dn): row = [] for x in range(lt, rt): row.append(grid[x, y]) print("".join(row)) print(i) break else: grid = defaultdict(lambda: ".") for pv in pvs: grid[pv[0], pv[1]] = "#" pa = a i += 1 pass
def b(): reindeer = {} for line in lines: name = line.split(" ")[0] reindeer[name] = tuple(u.ints(line)) def dist(name, sec): s, mi, ri = reindeer[name] full, rem = divmod(sec, mi + ri) return full * s * mi + min(mi, rem) * s points = Counter() for sec in range(2503): md = -math.inf mw = [] for name in reindeer: d = dist(name, sec + 1) if d > md: mw = [name] md = d elif d == md: mw.append(name) points.update(mw) return max(points.values())
def a(): sizes = u.ints(data) out = 0 for s in u.powerset(sizes): if sum(s) == 150: out += 1 return out
def a(): grid = defaultdict(bool) for line in lines: nums = u.ints(line) if line.startswith("rect"): a, b = nums for x in range(a): for y in range(b): grid[x, y] = True elif "row" in line: y, b = nums row = [grid[x, y] for x in range(width)] for x, val in enumerate(row): grid[(x + b) % width, y] = val else: x, b = nums col = [grid[x, y] for y in range(height)] for y, val in enumerate(col): grid[x, (y + b) % height] = val for y in range(height): o = [] for x in range(width): o.append("#" if grid[x, y] else ".") print("".join(o)) return sum(grid.values())
def a(): s = 0 for line in lines: xs = u.ints(line) d = max(xs) - min(xs) s += d return s
def b(): nums = [u.ints(line) for line in lines] cs = zip(*nums) s = 0 for tri in u.chunks(itertools.chain.from_iterable(cs), 3): s += possible(tri) return s
def a(): packages = list(reversed(sorted(u.ints(data)))) target = sum(packages) // 3 for k in range(4, len(packages)): for subset in itertools.combinations(packages, k): if sum(subset) == target: return math.prod(subset)
def b(): s = 0 for line in lines: for p in itertools.combinations(u.ints(line), 2): y, x = min(p), max(p) d, r = divmod(x, y) if r == 0: s += d return s
def a(): def area(l, w, h): return sum(2 * math.prod(s) for s in sides(l, w, h)) def slack(l, w, h): return min(math.prod(s) for s in sides(l, w, h)) return sum( area(l, w, h) + slack(l, w, h) for l, w, h in u.chunks(u.ints(data), 3))
def a(): insns = u.ints(data) ptr = 0 s = 0 while 0 <= ptr < len(insns): s += 1 offs = insns[ptr] insns[ptr] += 1 ptr += offs return s
def b(): adapters = u.ints(data) adapters.sort() adapters.append(adapters[-1] + 3) outputs = [] ways = Counter({0: 1}) for jolt in adapters: ways[jolt] = ways[jolt - 1] + ways[jolt - 2] + ways[jolt - 3] return ways[adapters[-1]]
def play(turns): spoken = [None] * turns d = u.ints(data) for i, k in enumerate(d[:-1]): spoken[k] = i + 1 last = d[-1] for i in range(len(d), turns): s = spoken[last] or i spoken[last] = i last = i - s return last
def b(): insns = u.ints(data) ptr = 0 s = 0 while 0 <= ptr < len(insns): s += 1 offs = insns[ptr] d = 1 if offs < 3 else -1 insns[ptr] += d ptr += offs return s
def b(): mask = 0 mem = defaultdict(int) for line in lines: if line.startswith("mask"): mask = line.split("=")[1].strip() else: m, v = u.ints(line) for addr in addrs(mask, m): mem[addr] = v return sum(mem.values())
def fight_cost(items, player_hp=100): boss_hp, boss_damage, boss_armor = u.ints(data) cost = sum(item[1] for item in items) damage = sum(item[2] for item in items) armor = sum(item[3] for item in items) necessary_hits = boss_hp // max(damage - boss_armor, 1) my_damage = (necessary_hits - 1) * max(boss_damage - armor, 1) if my_damage < player_hp: return -math.inf else: return cost
def a(): reindeer = {} for line in lines: name = line.split(" ")[0] reindeer[name] = tuple(u.ints(line)) def dist(name, sec): s, mi, ri = reindeer[name] full, rem = divmod(sec, mi + ri) return full * s * mi + min(mi, rem) * s return max(dist(name, 2503) for name in reindeer)
def a(): boss_hp, boss_dmg = u.ints(data) state = State( player_hp=50, player_armor=0, player_mana=500, shield_effect=0, poison_effect=0, recharge_effect=0, boss_hp=boss_hp, boss_dmg=boss_dmg, ) return search(state, 0, False)
def a(): mask = 0 mem = defaultdict(int) for line in lines: if line.startswith("mask"): mask = line.split("=")[1].strip() ors = int(mask.replace("X", "0"), 2) ands = int(mask.replace("X", "1"), 2) else: m, v = u.ints(line) mem[m] = (v | ors) & ands return sum(mem.values()) pass
def b(): sizes = u.ints(data) bestln = math.inf out = 0 for s in u.powerset(sizes): if sum(s) != 150: continue l = len(s) if l < bestln: bestln = l best = 0 if l == bestln: best += 1 return best
def b(): grid = defaultdict(int) ops = { "turn on": lambda pos: grid[pos] + 1, "turn of": lambda pos: max(grid[pos] - 1, 0), "toggle ": lambda pos: grid[pos] + 2, } for line in lines: l, t, r, b = u.ints(line) op = line[:len("turn on")] for pos in itertools.product(range(l, r + 1), range(t, b + 1)): grid[pos] = ops[op](pos) return sum(grid.values()) pass
def decompress(s): out = [] i = 0 while i < len(s): c = s[i] if c == "(": end = s.find(")", i) marker = s[i:end] l, rpt = u.ints(marker) val = s[end + 1:end + 1 + l] out.append(val * rpt) i = end + l else: out.append(c) i += 1 return "".join(out)
def a(): ts = int(lines[0]) ids = u.ints(lines[1]) best = math.inf bi = None for b in ids: earliest = math.ceil(ts / b) * b l = earliest - ts if l < best: best = l bi = b return bi * best pass
def a(): length = 0 i = 0 s = data while i < len(s): c = s[i] if c == "(": end = s.find(")", i) marker = s[i:end] l, rpt = u.ints(marker) val = s[end + 1:end + 1 + l] length += len(val) * rpt i = end + l else: length += 1 i += 1 return length
def find_length(s): length = 0 i = 0 while i < len(s): c = s[i] if c == "(": end = s.find(")", i) marker = s[i:end] l, rpt = u.ints(marker) val = s[end + 1:end + 1 + l] tot = find_length(val) length += tot * rpt i = end + l else: length += 1 i += 1 return length
def a(): cpos = 0 skip = 0 l = list(range(256)) for length in u.ints(data): left = cpos right = cpos + length - 1 while left < right: lt = left % len(l) rt = right % len(l) tmp = l[lt] l[lt] = l[rt] l[rt] = tmp left += 1 right -= 1 cpos += length cpos += skip skip += 1 return l[0] * l[1]