def naive_step_inner(curr): @cache def alter_pair(pair): return pair[0] + rules[pair] + pair[1] pairs = tuple(lmap("".join, sliding_window(2, curr))) return do_merge(tuple(lmap(alter_pair, pairs)))
def process_two(data): oxy_lines = data[:] colnum = 0 while len(oxy_lines) > 1: cols = parse_lines_into_cols(oxy_lines) most_common, mc_count = lmap(str, Counter(cols[colnum]).most_common()[0]) least_common, lc_count = lmap(str, Counter(cols[colnum]).most_common()[-1]) if mc_count == lc_count: most_common = "1" oxy_lines = lfilter(lambda x: x[colnum] == most_common, oxy_lines) colnum = colnum + 1 oxy_rating = int(oxy_lines[0], 2) co_lines = data[:] colnum = 0 while len(co_lines) > 1: cols = parse_lines_into_cols(co_lines) most_common, mc_count = lmap(str, Counter(cols[colnum]).most_common()[0]) least_common, lc_count = lmap(str, Counter(cols[colnum]).most_common()[-1]) if mc_count == lc_count: least_common = "0" co_lines = lfilter(lambda x: x[colnum] == least_common, co_lines) colnum = colnum + 1 co_rating = int(co_lines[0], 2) return oxy_rating * co_rating
def parse_input(data: str): sections = data.split("\n\n") numbers = sections[0].split(",") boards = sections[1:] lboards = lmap(splitstriplines, boards) dboards = lmap(lambda b: lmap(str.split, b), lboards) return (numbers, dboards)
def rearrange_data(data): # We want to have an ordered bunch of rows, corresponding to each puzzle, # and each row should have the puzzle id and the list of people's times in # the same order as the intiial entries. # We can think about sorting it differently another time. entries = [data["members"][k] for k in data["members"]] ordered = sorted(entries, key=lambda x: -x["local_score"]) names = lmap(lambda n: NAMES.get(n, n), lpluck("name", ordered)) days = lmap(methodcaller("keys"), lpluck("completion_day_level", ordered)) latest_day = max(map(int, lconcat(days))) puzzle_rows = [] def get_timestamp(day, part, entry): times = entry["completion_day_level"] timestamp = (times.get(str(day), {}).get(str(part), {}).get("get_star_ts", 0)) return timestamp for i in range(1, 1 + latest_day): p1_info = [] p2_info = [] for entry in ordered: part_one_ts = get_timestamp(i, 1, entry) p1_info.append(part_one_ts) part_two_ts = get_timestamp(i, 2, entry) p2_info.append(part_two_ts) puzzle_rows.append(p1_info) puzzle_rows.append(p2_info) def check(idx_item): return sum([x[idx_item[0]] for x in puzzle_rows]) > 0 filtered = lfilter(check, enumerate(names)) filtered_cols = lpluck(0, filtered) filtered_names = lpluck(1, filtered) def filter_row(row): cols = lfilter(lambda i_r: i_r[0] in filtered_cols, enumerate(row)) return lpluck(1, cols) filtered_rows = lmap(filter_row, puzzle_rows) def mark_winner(row): winner = min(filter(lambda x: x != 0, row)) return [(item, item == winner) for item in row] with_winners = lmap(mark_winner, filtered_rows) return (filtered_names, with_winners)
def process_data(data): names, rows = rearrange_data(data) longest_name = max([*map(len, names)] + [11]) # print_names = [name.rjust(longest_name) for name in names] print_names = rjust_row(longest_name, names) headers = " ".join(["Puzzle"] + print_names) hr = "".join(["-" * len(headers)]) times = lmap(lambda _: fmt_timestamps(*_), enumerate(rows)) # pdb.set_trace() print_times = [rjust_row(longest_name, row) for row in times] def add_puzzle(day, times): base_day = str(day // 2 + 1) puzzle = "1" if day % 2 == 0 else "2" return [f"{base_day}.{puzzle}".rjust(6)] + times print_rows = [add_puzzle(i, row) for i, row in enumerate(print_times)] print(headers) print(hr) for i, row in enumerate(print_rows): if i != 0 and i % 10 == 0: print(hr) print(headers) print(hr) print(" ".join(row))
def rjust_row(width, row): justify = methodcaller("rjust", width) brighten = lambda s: f"{Fore.CYAN}{s}{Style.RESET_ALL}" make_cell = lambda c: brighten(justify(c[0])) if c[1] else justify(c[0]) if len(row[0]) == 2 and row[0][1] in (True, False): return lmap(make_cell, row) return [justify(str(col)) for col in row]
def get_lows(data): grid = [] gridd = {} for y, row in enumerate(data): for x, char in enumerate(row): grid.append(aoc.Point(x=x, y=y)) gridd[aoc.Point(x=x, y=y)] = (char, None) for pt in gridd: above = gridd.get(aoc.Point(x=pt.x, y=pt.y - 1)) below = gridd.get(aoc.Point(x=pt.x, y=pt.y + 1)) left = gridd.get(aoc.Point(x=pt.x - 1, y=pt.y)) right = gridd.get(aoc.Point(x=pt.x + 1, y=pt.y)) adjs = lcompact([above, below, left, right]) curr = int(gridd[pt][0]) low = True for adj in adjs: if curr >= int(adj[0]): low = False if low: gridd[pt] = (gridd[pt][0], curr + 1) lows = lmap(lambda x: x, lfilter(lambda x: x[1][1] is not None, gridd.items())) return lows
def process_one(data): numbers, boards = data called_numbers, rest = numbers[:4], numbers[4:] # Can't win without 5 nums for number in rest: called_numbers.append(number) check = partial(is_winner, called_numbers) if winning_totals := lcompact(lmap(check, boards)): return winning_totals[0]
def coords_to_lines(coords: set[Point]) -> list[str]: getx, gety = attrgetter("x"), attrgetter("y") xmax, ymax = max(map(getx, coords)), max(map(gety, coords)) def get_line(idx): vals = (Point(x=xval, y=idx) for xval in range(xmax + 1)) return "".join("█" if pt in coords else " " for pt in vals) return lmap(get_line, range(ymax + 1))
def xdo_steps(curr, rules, num): pairs = lmap("".join, sliding_window(2, curr)) couplets = {p: 1 for p in pairs} for i in range(num): print(i, couplets, sum(couplets.values())) new_couplets = {} for couplet in couplets: triplet = couplet[0] + rules[couplet] + couplet[1] newpairs = lmap("".join, sliding_window(2, triplet)) for np in newpairs: if np in new_couplets: new_couplets[np] = new_couplets[np] + 1 else: new_couplets[np] = 1 for k in couplets: if k in new_couplets: new_couplets[k] = new_couplets[k] * couplets[k] couplets = new_couplets return couplets
def incr_neighbors(grid, center, flashed): neighbors = lmap(lambda x: center + Point(*x), adjacent_transforms(2)) points = lfilter(lambda x: x in grid, neighbors) for pt in points: grid[pt] = grid[pt] + 1 for pt in points: if pt not in flashed and grid[pt] > 9: flashed = flashed + [pt] grid, flashed = incr_neighbors(grid, pt, flashed) return grid, flashed
def better_step(curr): print(len(sequences)) if curr in sequences: return sequences[curr] elif len(curr) > 7: quads = make_quads(curr) altered_quads = map(alter_quad, quads) stuff = "" for q in altered_quads: stuff = stuff[:-1] + q if curr not in sequences: sequences[curr] = stuff return stuff else: pairs = lmap("".join, sliding_window(2, curr)) return merge(lmap(alter_pair, pairs))
def process_step(curr, rules): pairs = lmap("".join, sliding_window(2, curr)) def alter_pair(pair): if pair in rules: pair = pair[0] + rules[pair] + pair[1] return pair def merge(couplets): st = "" for i, couplet in enumerate(couplets): if not st: st = couplet else: st = st[: 2 * (i)] + couplet return st xx = merge(lmap(alter_pair, pairs)) xx2 = merge(xx[0]) return xx2, rules
def process_two(data): grid = {} for y, row in enumerate(data): for x, char in enumerate(row): grid[aoc.Point(x=x, y=y)] = (char, None) lows = get_lows(data) basins = lmap(lambda x: explore(grid, x[0], [], [x[0]]), lows) sbasins = sorted(basins, key=len) threebasins = sbasins[-3:] return prod(map(len, threebasins)) return data
def parse_line(line): coords = splitstrip(line, "->") raw_points = [lmap(int, splitstrip(coord, ",")) for coord in coords] points = lmap(lambda x: aoc.Point(*x), raw_points) return points
def process_two(data): lines = lcompact(lmap(make_line_diag, data)) count = detect_overlap(lines) return count
def process_one(data): lines = lcompact(lmap(make_line, data)) count = detect_overlap(lines) return count
def parse_lines_into_cols(data): ints = lmap(partial(lmap, int), data) crosswise = list(zip(*ints)) return crosswise
def parse_line(line): return lmap(aoc.Point.from_string, splitstrip(line, sep="->"))
def parse_data(data): start, raw_rules = data.split("\n\n") rules = lmap(lambda x: splitstrip(x, sep="->"), splitstriplines(raw_rules)) rules = dict(rules) return start, rules
def parse_input(data: str): sections = data.split("\n\n") numbers, raw_boards = sections[0].split(","), sections[1:] boards_as_rows = lmap(splitstriplines, raw_boards) boards = lmap(lambda b: lmap(str.split, b), boards_as_rows) return (numbers, boards)
def detect_overlap(lines): llines = lmap(list, lines) counted = Counter(lconcat(llines)) overone = {k: v for k, v in counted.items() if v >= 2} return len(overone)
def parse_line(line): raw_signals, raw_value = splitstrip(line, sep=" | ") sortjoin = compose_left(sorted, "".join) signals = lmap(sortjoin, raw_signals.split()) value = lmap(sortjoin, raw_value.split()) return signals, value
def parse_data(data: str) -> tuple[set[Point], list[dict]]: raw_coords, raw_instructions = map(splitstriplines, data.split("\n\n")) coords = set(map(Point.from_string, raw_coords)) instructions = lmap(parse_instruction, raw_instructions) return (coords, instructions)
from toolz import keyfilter from tadhg_utils import ( lcompact, lconcat, lfilter, lmap, splitstrip, splitstriplines, ) INPUT, TEST = aoc.get_inputs(__file__) TA1, TA2, A1, A2 = 26397, 288957, 399153, 2995077699 pairs = ("()", "[]", r"{}", "<>") openers = dict(lmap(tuple, pairs)) closers = {k: v for v, k in openers.items()} """ openers = [pair[0] for pair in pairs] closers = [pair[1] for pair in pairs] get_c_for_o = dict(zip(openers, closers)) get_o_for_c = dict(zip(closers, openers)) """ def find_errors(line) -> int: error_vals = { ")": 3, "]": 57, "}": 1197, ">": 25137,
def process_two(data): incomplete = lfilter(lambda x: find_errors(x) == 0, data) scores = lmap(complete_line, incomplete) return sorted(scores)[len(scores) // 2]
def parse_lines(lines): return lmap(parse_line, lines)
def alter_quad(quad): pairs = lmap("".join, sliding_window(2, quad)) return merge(lmap(alter_pair, pairs))