verbose = False def indices(lst, element): """ See . """ result = [] offset = -1 while True: try: offset = lst.index(element, offset+1) except ValueError: return result result.append(offset) def load_input(filename="input"): with open(filename, "r") as fp: lines = fp.read().splitlines() # Find the empty line/separator. sep = lines.index("") # Handle rules rule_lines = lines[:sep] rules = [tuple(map(int, l.split("|"))) for l in rule_lines] # Handle lines update_lines = lines[sep + 1:] updates = [list(map(int, l.split(","))) for l in update_lines] return rules, updates def is_update_legal(update, rules, print_offence=False) -> bool: for rule in rules: # Find indices of left hand side and right hand side lhs, rhs = rule if not lhs in update or not rhs in update: continue # This reminds me of limes inferior and limes superior. # Thanks, Mueger. if max(indices(update, lhs)) > min(indices(update, rhs)): if print_offence: print(f"Rule", rule, "offended by update", update) return False return True def middle_page_num(update) -> int: return update[len(update) // 2] if __name__ == "__main__": rules, updates = load_input() indices_legal = [] middle_sum = 0 for idx, update in enumerate(updates): if is_update_legal(update, rules): if verbose: print(update, " is legal") indices_legal.append(idx) middle_sum += middle_page_num(update) else: if verbose: print(update, " is illegal") if verbose: print(indices_legal) print(f"The sum of middle page numbers of legal updates is {middle_sum}.")