Advent of Code day 15
Verfasst: Sonntag 3. Januar 2016, 08:58
Hallo 
Weihnachten ist zwar schon vorbei, aber ich habe immer noch Spaß mit den Advent of Code Aufgaben. Für Tag 15 habe ich folgendes gebastelt:
(Python 3)
Ich versuche zwar keine Minimallösungen zu schreiben, wie vieles, was man so findet. Allerdings kommt mir das wieder an einigen Stellen trotzdem zu kompliziert vor. Insb. hatte ich Probleme, eine geschickte Repräsentationen für die vorgegebenen Daten zu finden. Ist die Cookie-Klasse so sinnvoll, oder ist das zu meta? (Objekt-orientiertes Programmieren ist ja leider nicht so meine Stärke
) Unschön finde ich beispielsweise die Behandlung der Kalorien oder das Erstellen der Dictionaries für die Mengenangaben. Ungünstig ist auch, dass die Attribute jedes Mal neu berechnet werden, obwohl sie sich selten ändern werden; da einen Caching/Update-Mechanismus einzubauen ist aber vielleicht etwas übertrieben?
Bzgl. der eigentlichen Lösung war ich unkreativ; das Verfahren ist ineffizient, aber liefert das Ergebnis in vertretbarer Zeit. Gibt es eigentlich auch einen effizienteren Algorithmus, um das zu bewältigen? Ich hatte zwischenzeitlich mal zufällige Kekse erstellt und mir den jeweils besten gemerkt; das gesuchte Optimum kommt spannenderweise meist in wenigen Sekunden und deutlich schneller, als per Brute-Force
An Kommentaren und Alternativvorschlägen wäre ich wie immer sehr interessiert.
Weihnachten ist zwar schon vorbei, aber ich habe immer noch Spaß mit den Advent of Code Aufgaben. Für Tag 15 habe ich folgendes gebastelt:
(Python 3)
Code: Alles auswählen
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import re
import fileinput
from itertools import tee, product
from functools import reduce
from operator import mul
ATTRIBUTES = ('capacity', 'durability', 'flavor', 'texture', 'calories')
EXCLUDED = ('calories')
SEPARATOR = re.compile(r'^(\w+)[^\d-]+(-?[\d]+)[^\d-]+(-?[\d]+)[^\d-]+(-?[\d]+)[^\d-]+(-?[\d]+)[^\d-]+(-?[\d]+)$')
SPOONS = 100
CALORIES = 500
class Cookie:
def __init__(self, amounts, stats, spoons=SPOONS):
self.amounts = amounts
self.stats = stats
if not sum(self.amounts.values()) == spoons:
raise ValueError
def __getattr__(self, name):
attribute = name
result = sum(
self.stats[ingredient][attribute]*amount
for ingredient, amount in self.amounts.items()
)
return result if result > 0 else 0
@property
def score(self):
return reduce(
mul,
[getattr(self, attribute) for attribute in ATTRIBUTES if not attribute in EXCLUDED]
)
def parse_file():
result = dict()
lines = [line.strip() for line in fileinput.input()]
for line in lines:
name, *stats = re.search(SEPARATOR, line).groups()
stats = map(int, stats)
result[name] = dict(zip(ATTRIBUTES, stats))
return result
def main():
stats = parse_file()
ingredients = stats.keys()
ingredients_n = len(ingredients)
upper_boundary = SPOONS - ingredients_n + 1
print("Part A")
result = max(
Cookie(dict(zip(ingredients, item)), stats).score
for item in filter(
lambda x:sum(x)==SPOONS,
product(*tee(range(1, upper_boundary), ingredients_n))
)
)
print(result)
print("Part B")
result = 0
for item in filter(
lambda x:sum(x)==SPOONS,
product(*tee(range(1, upper_boundary), ingredients_n))):
cookie = Cookie(dict(zip(ingredients, item)), stats)
if cookie.calories == CALORIES:
result = cookie.score if cookie.score > result else result
print(result)
if __name__ == '__main__':
main()Bzgl. der eigentlichen Lösung war ich unkreativ; das Verfahren ist ineffizient, aber liefert das Ergebnis in vertretbarer Zeit. Gibt es eigentlich auch einen effizienteren Algorithmus, um das zu bewältigen? Ich hatte zwischenzeitlich mal zufällige Kekse erstellt und mir den jeweils besten gemerkt; das gesuchte Optimum kommt spannenderweise meist in wenigen Sekunden und deutlich schneller, als per Brute-Force
An Kommentaren und Alternativvorschlägen wäre ich wie immer sehr interessiert.