ruleExpression = ''.join(exprList) return ruleExpression def partOne(data): pattern = parseRules(data) startIndex = data.index('') + 1 validMessages = 0 for line in data[startIndex:]: if regex.match(pattern, line): validMessages += 1 return validMessages def partTwo(data): data[data.index('8: 42')] = '8: 42 | 42 8' data[data.index('11: 42 31')] = '11: 42 31 | 42 11 31' pattern = parseRules(data) startIndex = data.index('') + 1 validMessages = 0 for line in data[startIndex:]: if regex.match(pattern, line): validMessages += 1 return validMessages puzzleInput = util.fileToStringList('input') #print(f'Part one: Found {partOne(puzzleInput)} valid messages!') print(f'Part two: Found {partTwo(puzzleInput)} valid messages!')
unique.add(vals[0]) else: for uq in unique: if uq in vals: vals.remove(uq) return decipheredTicket def partOne(data): parsedNotes = parseNotes(data) return sum(findInvalidVals(parsedNotes)) def partTwo(data): parsedNotes = parseNotes(data) ticketInfo = decipherTicket(parsedNotes) departureIndexes = set() for key in ticketInfo.keys(): if key.startswith('departure'): departureIndexes.add(ticketInfo[key][0]) departureVals = [] for i in departureIndexes: departureVals.append(parsedNotes['your ticket'][i]) res = reduce((lambda x, y: x * y), departureVals) return res notes = util.fileToStringList('input') print(f'Part one: Ticket scanning error rate: {partOne(notes)}') print(f'Part two: Product of fields starting with departure: {partTwo(notes)}')
maskedAddrs = applyMask_v2(mask, addr) for a in maskedAddrs: mem[a] = val def runInit(mem, data, func): mask = '' for line in data: if line.startswith('mask = '): mask = line else: func(mem, mask, line) def partOne(data): mem = {} runInit(mem, data, execValInst) return sum(mem.values()) def partTwo(data): mem = {} runInit(mem, data, execAddrInst) return sum(mem.values()) initData = util.fileToStringList('input') print(f'Part one: Sum = {partOne(initData)}') print(f'Part two: Sum = {partTwo(initData)}')
def evalShuntingYard(output): stack = deque() for token in output: if re.match('\d', token): stack.append(int(token)) elif token == '+': stack.append(stack.pop() + stack.pop()) else: stack.append(stack.pop() * stack.pop()) return stack.pop() def partOne(data): res = 0 for line in data: res += solveLeftToRight(solveParentheses(line, solveLeftToRight)) return res def partTwo(data): res = 0 for line in data: res += evalShuntingYard(shuntingYard(line)) return res homework = util.fileToStringList('input') print(f'Part one: Sum of all expressions = {partOne(homework)}') print(f'Part two: Sum of all expressions = {partTwo(homework)}')
moveShip(currentState, eastWest, currentWaypoint[eastWest]) i += 1 elif op == 'L' or op == 'R': rotateWaypoint(currentWaypoint, op, amount) else: moveShip(currentWaypoint, op, amount) def partOne(actions): state = {'N': 0, 'E': 0, 'S': 0, 'W': 0} facing = 90 for action in actions: facing = executeAction(state, facing, action) return (max(state['N'], state['S']) + max(state['E'], state['W'])) def partTwo(actions): state = {'N': 0, 'E': 0, 'S': 0, 'W': 0} waypoint = {'N': 1, 'E': 10, 'S': 0, 'W': 0} for action in actions: executeWaypointAction(state, waypoint, action) return (max(state['N'], state['S']) + max(state['E'], state['W'])) directions = {0: 'N', 90: 'E', 180: 'S', 270: 'W'} actions = util.fileToStringList('input') print(f'Part one: Manhattan distance = {partOne(actions)}') print(f'Part two: Manhattan distance = {partTwo(actions)}')
for ing in ingredients: try: count[ing] += 1 except KeyError: pass return sum(list(count.values())) def getCanonicalList(allergens): keys = list(allergens.keys()) keys.sort() ingredients = [allergens[key] for key in keys] return reduce((lambda x, y: x + ',' + y), ingredients) def partOne(data): allergens, nonAllergens = separateIngredients(data) return countAppearances(nonAllergens, data) def partTwo(data): allergens, nonAllergens = separateIngredients(data) allergens = getAllergenPairs(allergens) return getCanonicalList(allergens) foods = util.fileToStringList('input') print(f'Part one: Non-allergens appear a total of {partOne(foods)} times!') print(f'Part two: Canonical list of allergens = {partTwo(foods)}')
return arr[0] def computeSeatId(codes): rows = [*range(0, 128)] cols = [*range(0, 8)] rowCodes = codes[:7] colCodes = codes[7:] row = findMatch(rowCodes, rows) col = findMatch(colCodes, cols) return row * 8 + col def partOne(codesList): return max([computeSeatId(code) for code in codesList]) def partTwo(codesList): seatIds = [computeSeatId(code) for code in codesList] missingSeatId = [ x for x in range(min(seatIds), max(seatIds) + 1, 1) if x not in seatIds ] return missingSeatId[0] seatCodes = util.fileToStringList('input') print('Part one: Highest seat ID = %d' % partOne(seatCodes)) print('Part two: Missing seat ID = %d' % partTwo(seatCodes))
bc += 1 if bc == 2: nextBlack.add(whiteTile) return nextBlack def partOne(data): flippedTiles = flipTiles(parseDirections(data)) blackTiles = [x for x in flippedTiles.values() if x % 2 != 0] return len(blackTiles) def partTwo(data): flippedTiles = flipTiles(parseDirections(data)) blackTiles = {x for x, y in flippedTiles.items() if y % 2 != 0} for i in range(1, 101): blackTiles = flip(blackTiles) if i % 10 == 0: print(f'({i}) - Black tiles: {len(blackTiles)}') return len(blackTiles) floorTiles = util.fileToStringList('input') print( f'Part one: Number of tiles left with black side up = {partOne(floorTiles)}' ) print( f'Part two: Number of tiles with black side facing up after 100 days: {partTwo(floorTiles)}' )
executed.append(nextInst) action, offset = parseInstruction(data[nextInst]) acc, nextInst = executeInstruction(action, offset, nextInst, acc) return acc def partTwo(data): executed = [] acc = prevAcc = nextInst = prevInst = 0 changed = False while nextInst < len(data): executed.append(nextInst) action, offset = parseInstruction(data[nextInst]) if action != 'acc' and changed == False: prevAcc, prevInst, changed = acc, nextInst, True action = 'nop' if action == 'jmp' else 'jmp' acc, nextInst = executeInstruction(action, offset, nextInst, acc) if nextInst in executed: changed = False executed = executed[0:executed.index(prevInst)] action, offset = parseInstruction(data[prevInst]) acc, nextInst = executeInstruction(action, offset, prevInst, prevAcc) return acc bootCode = util.fileToStringList('input') print('Part one: Acc = %d!' % partOne(bootCode)) print('Part two: Acc = %d!' % partTwo(bootCode))
pattern = [' # ', '# ## ## ###', ' # # # # # # '] totalHashes = 0 for row in grid: totalHashes += row.count('#') i = 0 matches = 0 while matches == 0 and i < 8: matches = scanGrid(grid, pattern) if matches == 0: grid, b = rotateImg(grid, None) if i == 3: grid, b = flipVertical(grid, None) i += 1 return totalHashes - (matches * 15) def partOne(data): return reduce((lambda x,y: x*y), findCornerTiles(findAdjacentTiles(parseInput(data)))) def partTwo(data): tiles = parseInput(data) grid, gridTiles = buildImage(tiles) return findSeaMonster(grid) imageData = util.fileToStringList('input') print(f'Part one: Product of corner tile IDs = {partOne(imageData)}') print(f'Part two: Water roughness = {partTwo(imageData)}')
class TestPuzzle(unittest.TestCase): data = util.fileToStringList('testinput') data2 = ['#..', '..#', '.##'] borders = {'top': 1, 'rgt': 2, 'btm': 3, 'lft': 4} def testFindAdjacentTiles(self): expected = {'top': '1427', 'lft': '1951', 'btm': None, 'rgt': '3079'} result = findAdjacentTiles(parseInput(self.data))['2311'] self.assertEqual(result, expected) def testFindCornerTiles(self): expected = [1951, 1171, 2971, 3079] result = findCornerTiles(findAdjacentTiles(parseInput(self.data))) self.assertEqual(result, expected) def testRotateImg(self): expectedTiles = ['..#', '#..', '##.'] expectedBorders = {'top': 4, 'rgt': 1, 'btm': 2, 'lft': 3} resTiles, resBorders = rotateImg(self.data2, self.borders) self.assertEqual(resTiles, expectedTiles) self.assertEqual(resBorders, expectedBorders) def testAddToGrid(self): expectedGrid = [ '.#.#..#.', '###....#', '##.##.##', '###.####', '##.#....', '...#####', '....#..#', '.####...' ] expectedGridTiles = {(0, 0): '1951'} grid = [] gridTiles = {} allTiles = parseInput(self.data) adjacents = findAdjacentTiles(allTiles) addToGrid('1951', 0, 0, allTiles, adjacents, grid, gridTiles) self.assertEqual(grid, expectedGrid) self.assertEqual(gridTiles, expectedGridTiles) def testAddToGrid_withExisting(self): expectedGrid = [ '.#.#..#.##...#.#', '###....#.#....#.', '##.##.###.#.#..#', '###.#####...#.##', '##.#....#.##.###', '...########.#...', '....#..#...##..#', '.####...#..#....' ] expectedGridTiles = {(0, 0): '1951', (1, 0): '2311'} grid = [ '.#.#..#.', '###....#', '##.##.##', '###.####', '##.#....', '...#####', '....#..#', '.####...' ] gridTiles = {(0, 0): '1951'} allTiles = parseInput(self.data) adjacents = findAdjacentTiles(allTiles) addToGrid('2311', 1, 0, allTiles, adjacents, grid, gridTiles) self.assertEqual(grid, expectedGrid) self.assertEqual(gridTiles, expectedGridTiles) def testBuildImage(self): expectedGrid = [ '.#.#..#.##...#.##..#####', '###....#.#....#..#......', '##.##.###.#.#..######...', '###.#####...#.#####.#..#', '##.#....#.##.####...#.##', '...########.#....#####.#', '....#..#...##..#.#.###..', '.####...#..#.....#......', '#..#.##..#..###.#.##....', '#.####..#.####.#.#.###..', '###.#.#...#.######.#..##', '#.####....##..########.#', '##..##.#...#...#.#.#.#..', '...#..#..#.#.##..###.###', '.#.#....#.##.#...###.##.', '###.#...#..#.##.######..', '.#.#.###.##.##.#..#.##..', '.####.###.#...###.#..#.#', '..#.#..#..#.#.#.####.###', '#..####...#.#.#.###.###.', '#####..#####...###....##', '#.##..#..#...#..####...#', '.#.###..##..##..####.##.', '...###...##...#...#..###' ] expectedGridTiles = { (0, 0): '1951', (1, 0): '2311', (2, 0): '3079', (0, 1): '2729', (1, 1): '1427', (2, 1): '2473', (0, 2): '2971', (1, 2): '1489', (2, 2): '1171' } resGrid, resGridTiles = buildImage(parseInput(self.data)) self.assertEqual(resGrid, expectedGrid) self.assertEqual(resGridTiles, expectedGridTiles) def testPartOne(self): expected = 20899048083289 result = partOne(self.data) self.assertEqual(result, expected) def testPartTwo(self): expected = 273 result = partTwo(self.data) self.assertEqual(result, expected)
bagSet.add(key) collectContainers(key, dictionary, bagSet) def countBags(search, dictionary): count = sum(dictionary[search].values()) for key in dictionary[search].keys(): amount = dictionary[search][key] count += amount * countBags(key, dictionary) return count def partOne(data): bagDict = parseToDict(data) bag = 'shiny gold' bagSet = set() collectContainers(bag, bagDict, bagSet) return len(bagSet) def partTwo(data): bagDict = parseToDict(data) bag = 'shiny gold' return countBags(bag, bagDict) bagRules = util.fileToStringList('input') print('Part one: %d possible outer bags!' % partOne(bagRules)) print('Part two: %d contained bags!' % partTwo(bagRules))