Sean McLemon | Advent of Code

Home | Czech | Blog | GitHub | Advent Of Code | Notes


2015-12-15 - Science for Hungry People

(original .ipynb)

Puzzle input is a list of ingredients and some properties about those. Part one involves finding the combination of these ingredients that maximises the product of all their properties (except calories). Part two involves finding the maximum scoring cookie that has exactly 500 calories.

from functools import reduce
from collections import defaultdict

puzzle_input_str = open("./puzzle_input/day15.txt").read()


#- TODO: move to 'advent' library --------------------
def quantity_combinations(components, limit):
    for n in range(limit):
        if len(components[1:]) > 0:
            for res in quantity_combinations(components[1:], limit-n):
                yield [(components[0], n)] + res
        else:
            yield [(components[0], limit)]


def prod(lst):
    return reduce(lambda x, y: x * y, lst)
#------------------------------------------------------


def cookie_score(quantities, properties):
    subtotals = defaultdict(lambda:0)
    for ingredient, quantity in quantities:
        for prop in properties[ingredient]:
            subtotals[prop] += quantity * properties[ingredient][prop]
    
    score = prod(list(
        0 if subtotals[prop] < 0 else subtotals[prop]
        for prop in subtotals
        if prop != "calories"
    ))
    
    calories = sum(subtotals[prop] for prop in subtotals if prop == "calories")
    
    return (score, calories)


def parse_property(prop_str):
    prop, score = prop_str.split(" ")
    return prop, int(score)
    

def parse_ingredient_properties(line):
    name, properties_str = line.split(":")
    properties = {
        p: score
        for p, score
        in [parse_property(prop) for prop in properties_str.lstrip(" ").split(", ")]
    }
    return name, properties
    

def parse_input(input_str):
    return {name: properties for name, properties in [parse_ingredient_properties(line) for line in input_str.split("\n")]}


def part_one(input_str):
    properties = parse_input(input_str)
    cookies = (cookie_score(cookie, properties) for cookie in quantity_combinations(list(properties.keys()), 100))
    
    return max(score for score, calories in cookies)
    
test_input_str = """Butterscotch: capacity -1, durability -2, flavor 6, texture 3, calories 8
Cinnamon: capacity 2, durability 3, flavor -2, texture -1, calories 3"""


assert 62842880 == part_one(test_input_str)

print("part one:", part_one(puzzle_input_str))
part one: 18965440
def part_two(input_str):
    properties = parse_input(input_str)
    cookies = (cookie_score(cookie, properties) for cookie in quantity_combinations(list(properties.keys()), 100))
    
    return max(score for score, calories in cookies if calories == 500)


assert 57600000 == part_two(test_input_str)

print("part two:", part_two(puzzle_input_str))
part two: 15862900