>>> checksum(['5928', '9473', '3865']) (18, 9) """ spreadsheet = [parse_and_sort(row) for row in spreadsheet] return ( sum(row[-1] - row[0] for row in spreadsheet), # part 1 sum(quotient(row) for row in spreadsheet) # part 2 ) def quotient(row): """Find the quotient of the first pair to divide evenly in a sorted row.""" for a, b in combinations(row, 2): if not b % a: return b // a return 0 def parse_and_sort(row): """Cast the values in a row to `int`s and then sort.""" return sorted(int(n) for n in row) if __name__ == '__main__': import doctest doctest.testmod() with puzzle_input(2) as f: sheet = csv.reader(f, delimiter='\t') print(checksum(sheet))
player1.append(p2) else: player2.append(p2) player2.append(p1) if len(player1) == 0 or len(player2) == 0: winning_player = 1 if len(player2) == 0 else 2 winning_hand = player1 if len(player2) == 0 else player2 score = sum( (i + 1) * c for i, c in enumerate(reversed(winning_hand))) return turn, winning_player, winning_hand, score print() with puzzle_input(21, example, False) as f: player1 = deque([ 31, 33, 27, 43, 29, 25, 36, 11, 15, 5, 14, 34, 7, 18,
"4", "2", "34", "10", "3", ]) def pairwise(iterable): "s -> (s0,s1), (s1,s2), (s2, s3), ..." a, b = tee(iterable) next(b, None) return zip(a, b) with puzzle_input(10, example2, False) as f: data = [int(e) for e in f.read().split()] full = deque([0]) # start from dead battery builtin = max(data) + 3 # built in jotlage adapter full.extend(sorted(data)) # sorted? simplest way they can all be arranged builtin = max(data) + 3 # built in jotlage adapter full.append(builtin) jumps = [b - a for a, b in pairwise(full)] jolt_jumps = Counter(jumps) print(jolt_jumps[1] * jolt_jumps[3]) # Part 1 # Part 2 # DFS works for examples, and gives the paths... but for real inputs... # build adjacency, n^2? beurk but makes implementing the loop next much simpler
from utils import puzzle_input def is_valid(passphrase: str, version: int = 1) -> bool: """Is a given `passphrase` valid? >>> is_valid('aa bb cc dd aa') False >>> is_valid('abcde xyz ecdab') True >>> is_valid('abcde xyz ecdab', version=2) False """ passphrase = passphrase.split() if version == 2: passphrase = [''.join(sorted(word)) for word in passphrase] return len(passphrase) == len(set(passphrase)) if __name__ == '__main__': import doctest doctest.testmod() with puzzle_input(4) as f: passphrase_list = f.read().splitlines() for version in (1, 2): print(sum(is_valid(p, version) for p in passphrase_list))
"""Associate each item with its `n`th neighbor to the right (wrapping). >>> list(chunk('123', n=1)) [('1', '2'), ('2', '3'), ('3', '1')] """ c = len(l) return ((l[i], l[(i + n) % c]) for i in range(c)) def solve(digits: Iterable, places: int = 1) -> int: """Solve the CAPTCHA. >>> solve('1122') 3 >>> solve('1234') 0 >>> solve('123425', places=3) 4 """ return sum(int(a) for a, b in chunk(digits, places) if a == b) if __name__ == '__main__': import doctest doctest.testmod() with puzzle_input(1) as f: digits = f.read().strip() print(solve(digits)) # part 1 print(solve(digits, len(digits) // 2)) # part 2
return abs(x - a) + abs(y - b) def spiral(): """Generate the points of an infinite spiral. >>> s = spiral() >>> [next(s) for _ in range(5)] [(0, 0), (1, 0), (1, 1), (0, 1), (-1, 1)] """ position = (0, 0) yield position for length, half in enumerate(cycle(HALVES), 1): for step in half: for _ in range(length): position = addv(position, step) yield position if __name__ == '__main__': import doctest doctest.testmod() with puzzle_input(3) as f: N = int(f.read()) print(carry_distance(N)) # part 1 print(stress_test(N)) # part 2
range_ = seq(number, match_item("-") >> number).map(lambda x: range(x[0], x[1] + 1)) range_pair = seq(range_, whitespace >> string("or") >> whitespace >> range_) rule = seq(rule_name, match_item(":") >> whitespace >> range_pair) rules = rule.sep_by(match_item("\n")).map(dict) fields = number.sep_by(match_item(","), min=1) your_ticket = string("your ticket:\n") >> fields nearby_tickets = string("nearby tickets:\n") >> fields.sep_by(match_item("\n")) all_of_it = ( seq(rules, string("\n\n") >> your_ticket, string("\n\n") >> nearby_tickets) << match_item("\n").optional() ) with puzzle_input(16, example2, False) as field_values: data, remain = all_of_it.parse_partial(field_values.read()) # print(data, repr(remain)) print(repr(remain)) all_ranges = list(chain.from_iterable(data[0].values())) # print(all_ranges) my_ticket = data[1] other_tickets = data[2] valid_tickets = [] s = 0 for ticket in other_tickets: valid = True for v in ticket:
"""Count the number of steps required to reach the exit. >>> count_steps([0, 3, 0, 1, -3]) 5 """ index, steps = 0, 0 instructions = array('i', instructions[:]) while True: try: index = jump(instructions, index, update) steps += 1 except IndexError: return steps def jump(instructions: list, index: int, update: Callable) -> int: """Execute and update a jump instruction.""" next_index = index + instructions[index] instructions[index] = update(instructions[index]) return next_index if __name__ == '__main__': import doctest doctest.testmod() with puzzle_input(5) as f: instructions = [int(n) for n in f] print(count_steps(instructions)) print(count_steps(instructions, update=lambda n: n + (n < 3 or -1)))
"..##.......", "#...#...#..", ".#....#..#.", "..#.#...#.#", ".#...##..#.", "..#.##.....", ".#.#.#....#", ".#........#", "#.##...#...", "#...##....#", ".#..#...#.#", ] ) with puzzle_input(3, example) as f: data = [list(l.strip()) for l in f.readlines()] def slide(slope, direction, pos=(0, 0)): width = len(slope[0]) trees = 0 r, c = pos r_step, c_step = direction while r < len(slope): if slope[r][c] == "#": trees += 1 r += r_step c = (c + c_step) % width