Advent of Code

Gute Links und Tutorials könnt ihr hier posten.
Benutzeravatar
__blackjack__
User
Beiträge: 13998
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Kebap: Muss ich gleich mal prüfen ob "\d+" tatsächlich funktioniert mit meinen Eingabedaten. Die Aufgabe war da ein bisschen spezifischer → "\d{1,3}". Das heisst "mul(42,4711)" wäre illegal, würde von "\d+" aber erfasst.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Benutzeravatar
Kebap
User
Beiträge: 772
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

@__blackjack__: Stimmt, das hatte ich wohl überlesen oder wieder vergessen. Jedenfalls hat es mein Ergebnis nicht beeinflusst.

Ich war hingegen an zwei anderen Stellen gestolpert:
- Der Status muss am Ende nicht "aktiviert" sein, also müssen ggf. mul-Befehle am Ende ignoriert werden. OK, leicht zu beheben. Randfälle sind ja Klassiker.
- Der Regex sucht nicht über Zeilenenden (also im gewissen Sinne auch "über einen Rand") hinweg. Also sowas wie hier hatte ich zuerst falsch behandelt:
don't()_blablabla
jippie_don't()_foobar_do()
Bei mir wurde zunächst nur foobar ignoriert. Wobei tatsächlich die kompletten zwei Zeilen ignoriert gehören! Der Workaround war zuerst \n zu löschen.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Benutzeravatar
Dennis89
User
Beiträge: 1517
Registriert: Freitag 11. Dezember 2020, 15:13

Danke für euren Input für Tag 2.

Bis jetzt habe ich noch kein Code geschrieben, der mir gefällt 🫣
Heute wurde es auch nicht besser, dafür war ich sehr schnell fertig. (Was gut war, weil ich leider nicht viel Zeit dazu hatte)

Code: Alles auswählen

#!/usr/bin/env python
import re
from pathlib import Path

INPUT_FILE = Path(__file__).parent / "input03.txt"

PUZZLE_INPUT = """\
xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))
""".splitlines()


EXPRESSION = re.compile(r"mul\(\d*,\d*\)|don't\(\)|do\(\)")


def parse_input(lines):
    expressions = []
    for line in lines:
        expressions.extend(re.findall(EXPRESSION, line))
    return expressions


def decode_expression(expression):
    if expression.startswith("mul"):
        return map(int, re.findall(r"\d*,\d*", expression)[0].split(","))
    return 0, 0


def get_mul(mul):
    x, y = decode_expression(mul)
    return x * y


def run_mul_expressions(expressions):
    return sum(get_mul(expression) for expression in expressions)


def run_and_enable_mul_expressions(expressions):
    run = True
    multiples = []
    for expression in expressions:
        if expression == "don't()":
            run = False
        elif expression == "do()":
            run = True
        elif run:
            multiples.append(get_mul(expression))
    return sum(multiples)


def main():
    puzzle_input = PUZZLE_INPUT
    puzzle_input = INPUT_FILE.read_text(encoding="UTF-8").splitlines()
    expressions = parse_input(puzzle_input)
    print(run_mul_expressions(expressions))
    print(run_and_enable_mul_expressions(expressions))


if __name__ == "__main__":
    main()
Ach und Tag 2 noch (fand das vorgeschlagene `skip_index`) schöner wie mein slicing:

Code: Alles auswählen

#!/usr/bin/env python
from itertools import pairwise
from pathlib import Path


INPUT_FILE = Path(__file__).parent / "input02.txt"
PUZZLE_INPUT = """\
7 6 4 2 1
1 2 7 8 9
9 7 6 2 1
1 3 2 4 5
8 6 4 4 1
1 3 6 7 9
""".splitlines()


def is_safe(report):
    return (
        all(1 <= x - y <= 3 for x, y in pairwise(report))
        or all(1 <= y - x <= 3 for x, y in pairwise(report))
    )


def get_safe_reports(reports):
    return sum(is_safe(report) for report in reports)


def skip_index(iterable, index):
    for i, value in enumerate(iterable):
        if i != index:
            yield value


def get_tolerated_safe_reports(reports):
    safe_reports = 0
    for report in reports:
        if is_safe(report):
            safe_reports += 1
        else:
            for index in range(len(report)):
                if is_safe(list(skip_index(report, index))):
                    safe_reports += 1
                    break
    return safe_reports


def main():
    # puzzle_input = PUZZLE_INPUT
    puzzle_input = INPUT_FILE.read_text(encoding="UTF-8").splitlines()
    reports = list(map(lambda x: list(map(int, x.split())), puzzle_input))
    print(get_safe_reports(reports))
    print(get_tolerated_safe_reports(reports))


if __name__ == "__main__":
    main()
Grüße
Dennis
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13998
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Hm, ich denke die lassen langsam nach. Früher hätten sie sichergestellt das weder "\d+" und schon gar nicht "\d*" funktioniert hätte. 😈
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
narpfel
User
Beiträge: 690
Registriert: Freitag 20. Oktober 2017, 16:10

Wenn man was parsen muss, ist Prolog immer eine gute Wahl:

Code: Alles auswählen

#!/usr/bin/env -S swipl -g main -t halt

:- use_module(library(dcg/basics)).
:- use_module(library(pure_input)).

one_to_three_digit_integer(Int) --> integer(Int), { 0 =< Int, Int < 1000 }.

mul(Product) -->
    "mul(", one_to_three_digit_integer(Lhs), ",", one_to_three_digit_integer(Rhs), ")",
    { Product is Lhs * Rhs }.

conditional_mul(Value) --> mul(Value).
conditional_mul(0) --> "don't()", string(_), "do()".

multiplications(Mul, Result) -->
    string(_), call(Mul, Product), multiplications(Mul, Rest),
    { Result is Rest + Product }.
multiplications(_, 0) --> string(_), eos.

main :-
    phrase_from_file(multiplications(mul, Part1), input),
    write(Part1), nl,
    phrase_from_file(multiplications(conditional_mul, Part2), input),
    write(Part2), nl.
Interessanterweise brauche ich für meinen Input den Test auf höchstens drei Ziffern auch nicht. Scheint also gewollt zu sein, dass das keine „richtige“ Anforderung ist.
Benutzeravatar
__blackjack__
User
Beiträge: 13998
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Vielleicht weil es erst der dritte Tag ist. 😉
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Benutzeravatar
Dennis89
User
Beiträge: 1517
Registriert: Freitag 11. Dezember 2020, 15:13

Oh:
it specifies that the previous character can be matched zero or more times, instead of exactly once.
Eigentlich wollte ich `+`weil ich wohl die Aufgabenstellung nicht ordentlich gelesen habe 🙃
"When I got the music, I got a place to go" [Rancid, 1993]
Benutzeravatar
__blackjack__
User
Beiträge: 13998
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Kebap: Zeilenenden löschen ist aber auch gefährlich, denn das würde beispielsweise aus einem "d\no()" ein "do()" machen was es gar nicht geben sollte.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
nezzcarth
User
Beiträge: 1749
Registriert: Samstag 16. April 2011, 12:47

Keine Ahnung, ob ich etwas falsch gemacht habe, aber Teil 1 und Teil 2 kamen mir heute fast wie zwei separate Aufgaben vor und der zweiter leichter als der erste.
Benutzeravatar
__blackjack__
User
Beiträge: 13998
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Also ich habe eine Funktion die beide Teile benutzen, die die Koordinaten des jeweiligen Startbuchstabens liefert. 😎
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Benutzeravatar
__blackjack__
User
Beiträge: 13998
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@nezzcarth: Wenn ich so drüber nachdenke kann man da aber *eine* Funktion schreiben, die das Suchmuster als Datenstruktur bekommt.

@all: Heute war soweit ich das sehe, die erste schwierigere Aufgabe, also Aufgabenteil 2. Also zumindest sofern man nicht auf den Namen des Algorithmus kommt, den man da benutzen kann. Und es ist natürlich dann auch praktisch, dass es den Algorithmus schon fertig in der Standardbibliothek gibt. 😀
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Benutzeravatar
Kebap
User
Beiträge: 772
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

@__blackjack__: Da hast du tatsächlich auch wieder Recht..! :o
__blackjack__ hat geschrieben: Mittwoch 4. Dezember 2024, 09:58 @Kebap: Zeilenenden löschen ist aber auch gefährlich, denn das würde beispielsweise aus einem "d\no()" ein "do()" machen was es gar nicht geben sollte.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
Benutzeravatar
Dennis89
User
Beiträge: 1517
Registriert: Freitag 11. Dezember 2020, 15:13

Ich war gestern den ganzen Tag unterwegs und wie ich heute feststellen musste, habe ich nur ein dummes Rätsel verpasst. Ich will die Rätsel immer nutzen um an mir zu arbeiten, aber hier fällt mir nur ein, das ich mir merke wo in welcher Reihe und welcher Position ein "X" steht und dann muss ich gefühlt über 100 verschachtelte Schleifen den gefunden Index, wie auch die Reihe in alle Richtungen erhöhen und schauen ob irgendwie das Wort zusammen kommt.

Ich erinnere mich an letztes Jahr, da musste man Symbole suchen, aber wenigstens nur im Umkreis von einem Index-Wert und das war bei mir schon doof unleserlich. Ich wette, falls __blackjack__ das in Python gelöst hat, gibt es wieder "schlaue" Map-Objekte und dann geht das wie von alleine. Aber ich komm auf sowas einfach nicht.
"When I got the music, I got a place to go" [Rancid, 1993]
nezzcarth
User
Beiträge: 1749
Registriert: Samstag 16. April 2011, 12:47

__blackjack__ hat geschrieben: Donnerstag 5. Dezember 2024, 13:41 Und es ist natürlich dann auch praktisch, dass es den Algorithmus schon fertig in der Standardbibliothek gibt. 😀
Falls wir an dasselbe denken, war zumindest mein Input so aufgebaut, dass er mit dem Ding aus der Standardbibliothek problemlos durchlief, beim eigentlichen Input aber Probleme machte. :|
narpfel
User
Beiträge: 690
Registriert: Freitag 20. Oktober 2017, 16:10

Ich finde, die heutige Aufgabe war geradezu prädestiniert dazu, sie in einem Basheinzeiler zu lösen:

Code: Alles auswählen

for eq in "==" "!="; do grep , input | tr ',' '|' | xargs -I '{}' bash -c 'l=$(grep -E '"'"'({})\|({})'"'"' input | tr '"'"'|'"'"' '"'"' '"'"' | tsort | grep -E '"'"'{}'"'"'); n=$(echo "$l" | wc -l); if [[ $(echo '"'"'{}'"'"' | tr '"'"'|'"'"' '"'"','"'"'), '$eq' $(echo "$l" | tr '"'"'\n'"'"' '"'"','"'"') ]]; then echo "$l" | head -n $(($n / 2 + 1)) | tail -n1; fi' | sed -E 's/\s+/+/g' | paste -sd+ | bc; done
Das ist nur 100x langsamer als meine Python-Lösung.
__blackjack__ hat geschrieben: Donnerstag 5. Dezember 2024, 13:41 Und es ist natürlich dann auch praktisch, dass es den Algorithmus schon fertig in der Standardbibliothek gibt. 😀
Meinst du (Achtung, Spoiler!) das hier? Das habe ich nicht benutzt, meine Lösung ist einfacher und benutzt nur Builtins und eine wenig benutzte, aber bei AoC immer wieder erstaunlich hilfreiche Funktion aus `functools`. Das funktioniert, weil die Inputdaten eine totale Ordnung bilden und jedes Paar aus den einzelnen Updates immer in genau einer der beiden möglichen Reihenfolge vorkommt.
narpfel
User
Beiträge: 690
Registriert: Freitag 20. Oktober 2017, 16:10

Dennis89 hat geschrieben: Donnerstag 5. Dezember 2024, 18:09 Ich war gestern den ganzen Tag unterwegs und wie ich heute feststellen musste, habe ich nur ein dummes Rätsel verpasst. Ich will die Rätsel immer nutzen um an mir zu arbeiten, aber hier fällt mir nur ein, das ich mir merke wo in welcher Reihe und welcher Position ein "X" steht und dann muss ich gefühlt über 100 verschachtelte Schleifen den gefunden Index, wie auch die Reihe in alle Richtungen erhöhen und schauen ob irgendwie das Wort zusammen kommt.
Es gibt auch einen anderen Lösungsansatz, der nicht unbedingt einfacher, aber vielleicht interessanter ist: In einem String kann man `XMAS` einfach mit `str.count` zählen. Wenn man den String drehen könnte, würde man `XMAS` auch diagonal/senkrecht/rückwärts einfach mit `str.count` suchen können... :wink:
nezzcarth
User
Beiträge: 1749
Registriert: Samstag 16. April 2011, 12:47

narpfel hat geschrieben: Donnerstag 5. Dezember 2024, 18:27 Meinst du (Achtung, Spoiler!) das hier? Das habe ich nicht benutzt, meine Lösung ist einfacher
Der Input ist mutwillig so gestaltet, dass das im Spoiler Angesprochene explizit nicht so ohne Weiteres funktioniert.
narpfel
User
Beiträge: 690
Registriert: Freitag 20. Oktober 2017, 16:10

nezzcarth hat geschrieben: Donnerstag 5. Dezember 2024, 18:46 Der Input ist mutwillig so gestaltet, dass das im Spoiler Angesprochene explizit nicht so ohne Weiteres funktioniert.
Das „nicht ohne Weiteres“ ist dann aber ein relativ einfacher Schritt? Alle Paare ignorieren, bei denen nicht beide Zahlen in der betrachteten Update-Zeile vorkommen? So hab ich es zumindest in der gezeigten Bash-Lösung gemacht.
nezzcarth
User
Beiträge: 1749
Registriert: Samstag 16. April 2011, 12:47

Genau :)
Benutzeravatar
__blackjack__
User
Beiträge: 13998
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@nezzcarth: Wir denken an das selbe. Der Hinweis Regeln die sich auf Seitenzahlen beziehen, die nicht im jeweiligen Update vorkommen, zu ignorieren, steht soweit ich mich erinnere ja sogar in der Aufgabe. Ich bin da aber auch erst einmal in die Ausnahme wegen einem Kreis gerannt.

@Dennis89: Eine Schleife um die ganzen Koordinaten des Startbuchstabens "X" zu finden, und eine Schleife über die 8 möglichen Richtungen, und dann eine Schleife die diese Richtung absucht. Das sind doch bloss 3 Schleifen. Eine davon ist in einer Funktion ausgelagert und die kann man im zweiten Aufgabenteil benutzen um die ganzen Koordinaten des Startbuchstabens dort zu finden.
“The best book on programming for the layman is »Alice in Wonderland«; but that's because it's the best book on anything for the layman.” — Alan J. Perlis
Antworten