コード例 #1
0
def part_2(ingredients: list['Ingredient'], calories: int = 500) -> int:
    """
    Your cookie recipe becomes wildly popular! Someone asks if you can make another recipe that has
    exactly `500` calories per cookie (so they can use it as a meal replacement). Keep the rest of
    your award-winning process the same (`100` teaspoons, same ingredients, same scoring system).

    For example, given the ingredients above, if you had instead selected `40` teaspoons of
    butterscotch and `60` teaspoons of cinnamon (which still adds to `100`), the total calorie count
    would be `40*8 + 60*3 = 500`. The total score would go down, though: only `57600000`, the best
    you can do in such trying circumstances.

        >>> butterscotch, cinnamon = ingredients_from_file('data/15-example.txt')
        >>> recipe_score({butterscotch: 40, cinnamon: 60}, required_calories=500)
        57600000
        >>> recipe_score({butterscotch: 44, cinnamon: 56}, required_calories=500)
        -1

    Given the ingredients in your kitchen and their properties, what is the **total score** of the
    highest-scoring cookie you can make with a calorie total of `500`?

        >>> part_2([butterscotch, cinnamon])
        part 2: best recipe with 500 calories (40 Butterscotch, 60 Cinnamon) has score 57600000
        57600000
    """

    best_recipe, score = maxk(
        generate_recipes(ingredients, 100),
        key=lambda r: recipe_score(r, required_calories=calories))
    print(
        f"part 2: best recipe with {calories} calories ({recipe_str(best_recipe)}) "
        f"has score {score}")
    return score
コード例 #2
0
    def most_distant_scanners(self) -> tuple[tuple[Scanner, Scanner], int]:
        assert len(self.fixed_readings) >= 2

        def manhattan_distance(scanner_pair: tuple[Scanner, Scanner]) -> int:
            return sum(abs(v) for v in (scanner_pair[0].pos - scanner_pair[1].pos))

        scanner_pairs = ((s1, s2) for s1, s2 in itertools.combinations(self.scanners, 2))
        return maxk(scanner_pairs, key=manhattan_distance)
コード例 #3
0
ファイル: day11_hex.py プロジェクト: cathackk/advent-of-code
def part_2(directions: Iterable[str]) -> int:
    """
    **How many steps away** is the **furthest** he ever got from his starting position?

        >>> part_2(['n', 'ne', 'n', 'ne', 'se', 's', 'nw', 'sw', 'sw'])
        part 2: max distance was 4
        4
    """

    origin = (0, 0)
    _, max_distance = maxk(steps(origin, directions), lambda pos: distance(origin, pos))
    print(f"part 2: max distance was {max_distance}")
    return max_distance
コード例 #4
0
ファイル: day21_rpg.py プロジェクト: cathackk/advent-of-code
def part_2(boss: 'Character', player_hp: int, shop: 'Shop') -> int:
    """
    Turns out the shopkeeper is working with the boss, and can persuade you to buy whatever items he
    wants. The other rules still apply, and he still only has one of each item.

        >>> (example_boss := Character.from_file("boss", 'data/21-example-boss.txt'))
        Character('boss', hit_points=12, damage=7, armor=2)
        >>> the_shop = Shop.from_file('data/21-shop.txt')
        >>> expensive_equipment = the_shop.get_items('Dagger', 'Damage +3', 'Defense +3')
        >>> expensive_equipment  # doctest: +NORMALIZE_WHITESPACE
        [Item('Dagger', cost=8, damage=4),
         Item('Damage +3', cost=100, damage=3),
         Item('Defense +3', cost=80, armor=3)]
        >>> (player := Character('player', hit_points=8).with_equipment(expensive_equipment))
        Character('player', hit_points=8, damage=7, armor=3)
        >>> winner = battle(player, example_boss, log=True)
        The player deals 7-2 = 5 damage; the boss goes down to 7 hit points.
        The boss deals 7-3 = 4 damage; the player goes down to 4 hit points.
        The player deals 7-2 = 5 damage; the boss goes down to 2 hit points.
        The boss deals 7-3 = 4 damage; the player goes down to 0 hit points.
        >>> winner.name
        'boss'

    What is the **most** amount of gold you can spend and still lose the fight?

        >>> part_2(example_boss, player_hp=8, shop=the_shop)
        part 2: you can spend 188 gold and still lose the fight: Dagger, Damage +3, Defense +3
        188
    """

    losing_builds = (build for build in shop.generate_builds()
                     if not is_beating_boss(build, boss, player_hp))
    most_expensive_build, cost = maxk(losing_builds, key=total_cost)

    build_str = ", ".join(item.name for item in most_expensive_build)
    print(
        f"part 2: you can spend {cost} gold and still lose the fight: {build_str}"
    )
    return cost
コード例 #5
0
def max_square(serial: int,
               square_size: int | range = 3,
               grid_size: int = 300) -> tuple[tuple[int, int, int], int]:

    if isinstance(square_size, range):
        square_size_range = square_size
    elif isinstance(square_size, int):
        square_size_range = range(square_size, square_size + 1)
    else:
        raise TypeError(type(square_size))

    squares = ((x, y, size) for size in square_size_range
               for x in range(1, grid_size - size + 2)
               for y in range(1, grid_size - size + 2))
    squares_progress = tqdm(squares,
                            desc="finding square",
                            total=sum((grid_size - size + 1)**2
                                      for size in square_size_range),
                            unit=" squares",
                            unit_scale=True,
                            delay=0.5)

    return maxk(squares_progress,
                key=lambda square: square_sum(*square, serial))
コード例 #6
0
def points_race_winner(reindeer: list[Reindeer],
                       seconds: int) -> tuple[str, int]:
    race_results = points_race(reindeer, seconds)
    return maxk(race_results, key=lambda r: race_results[r])
コード例 #7
0
def part_1(ingredients: list['Ingredient']) -> int:
    """
    Today, you set out on the task of perfecting your milk-dunking cookie recipe. All you have to
    do is find the right balance of ingredients.

    Your recipe leaves room for exactly `100` teaspoons of ingredients. You make a list of the
    **remaining ingredients you could use to finish the recipe** (your puzzle input) and their
    **properties per teaspoon**:

      - `capacity` (how well it helps the cookie absorb milk)
      - `durability` (how well it keeps the cookie intact when full of milk)
      - `flavor` (how tasty it makes the cookie)
      - `texture` (how it improves the feel of the cookie)
      - `calories` (how many calories it adds to the cookie)

    You can only measure ingredients in whole-teaspoon amounts accurately, and you have to be
    accurate so you can reproduce your results in the future. The **total score** of a cookie can be
    found by adding up each of the properties (negative totals become `0`) and then multiplying
    together everything except calories.

    For instance, suppose you have these two ingredients:

        >>> butterscotch, cinnamon = ingredients_from_text('''
        ...     Butterscotch: capacity -1, durability -2, flavor 6, texture 3, calories 8
        ...     Cinnamon: capacity 2, durability 3, flavor -2, texture -1, calories 3
        ... ''')
        >>> butterscotch
        Ingredient('Butterscotch', capacity=-1, durability=-2, flavor=6, texture=3, calories=8)
        >>> cinnamon
        Ingredient('Cinnamon', capacity=2, durability=3, flavor=-2, texture=-1, calories=3)

    Then, choosing to use `44` teaspoons of butterscotch and `56` teaspoons of cinnamon (because the
    amounts of each ingredient must add up to `100`) would result in a cookie with the following
    properties:

      - A `capacity`   of `44*-1 + 56* 2 =  68`
      - A `durability` of `44*-2 + 56* 3 =  80`
      - A `flavor`     of `44* 6 + 56*-2 = 152`
      - A `texture`    of `44* 3 + 56*-1 =  76`

    Multiplying these together (`68 * 80 * 152 * 76`, ignoring `calories` for now) results in
    a total score of `62842880`, which happens to be the best score possible given these
    ingredients.

        >>> recipe_score({butterscotch: 44, cinnamon: 56})
        62842880

    If any properties had produced a negative total, it would have instead become zero,
    causing the whole score to multiply to zero.

        >>> recipe_score({butterscotch: 66, cinnamon: 34})
        0

    Given the ingredients in your kitchen and their properties, what is the **total score** of the
    highest-scoring cookie you can make?

        >>> part_1([butterscotch, cinnamon])
        part 1: best recipe (44 Butterscotch, 56 Cinnamon) has score 62842880
        62842880
    """

    best_recipe, score = maxk(generate_recipes(ingredients, 100),
                              key=recipe_score)
    print(f"part 1: best recipe ({recipe_str(best_recipe)}) has score {score}")
    return score
コード例 #8
0
def part_1(seat_codes: Iterable[str]) -> int:
    """
    This airline uses binary space partitioning to seat people. A seat might be specified like
    `FBFBBFFRLR`, where `F` means "front", `B` means "back", `L` means "left", and `R` means
    "right".

    The first 7 characters will either be `F` or `B`; these specify exactly one of the *128 rows*
    on the plane (numbered 0 through 127). Each letter tells you which half of a region the given
    seat is in. Start with the whole list of rows; the first letter indicates whether the seat is
    in the *front* (0 through 63) or the *back* (64 through 127). The next letter indicates which
    half of that region the seat is in, and so on until you're left with exactly one row.

    For example, consider just the first seven characters of `FBFBBFFRLR`:

        - Start by considering the whole range, rows `0` through `127`.
        - `F` means to take the lower half, keeping rows `0` through `63`.
        - `B` means to take the upper half, keeping rows `32` through `63`.
        - `F` means to take the lower half, keeping rows `32` through `47`.
        - `B` means to take the upper half, keeping rows `40` through `47`.
        - `B` keeps rows `44` through `47`.
        - `F` keeps rows `44` through `45`.
        - The final `F` keeps the lower of the two, row `44`.

        >>> row_number('FBFBBFF')
        44

    The last three characters will be either `L` or `R`; these specify exactly one of the 8 columns
    of seats on the plane (numbered `0` through `7`). The same process as above proceeds again,
    this time with only three steps. `L` means to keep the *lower half*, while `R` means to keep
    the *upper half*.

    For example, consider just the last 3 characters of `FBFBBFFRLR`:

        - Start by considering the whole range, columns `0` through `7`.
        - `R` means to take the upper half, keeping columns `4` through `7`.
        - `L` means to take the lower half, keeping columns `4` through `5`.
        - The final `R` keeps the upper of the two, column `5`.

        >>> column_number('RLR')
        5

    So, decoding `FBFBBFFRLR` reveals that it is the seat at *row `44`, column `5`*.

        >>> seat_coordinates('FBFBBFFRLR')
        (44, 5)

    Every seat also has a unique *seat ID*: multiply the row by 8, then add the column. In this
    example, the seat has ID `44 * 8 + 5 = 357`.

        >>> seat_id('FBFBBFFRLR')
        357

    Here are some other boarding passes:

        >>> passes = ['BFFFBBFRRR', 'FFFBBBFRRR', 'BBFFBBFRLL']
        >>> seat_coordinates(passes[0]), seat_id(passes[0])
        ((70, 7), 567)
        >>> seat_coordinates(passes[1]), seat_id(passes[1])
        ((14, 7), 119)
        >>> seat_coordinates(passes[2]), seat_id(passes[2])
        ((102, 4), 820)

    As a sanity check, look through your list of boarding passes. *What is the highest seat ID on
    a boarding pass?*

        >>> part_1(passes)
        part 1: boarding pass 'BBFFBBFRLL' has the highest seat ID: 820
        820
    """

    max_seat_code, max_seat_id = maxk(seat_codes, key=seat_id)

    print(
        f"part 1: boarding pass {max_seat_code!r} has the highest seat ID: {max_seat_id}"
    )
    return max_seat_id