Advent of Code

Gute Links und Tutorials könnt ihr hier posten.
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

__blackjack__ hat geschrieben: Samstag 5. Dezember 2020, 14:48 So furchtbar einfach heute…
Es wird vmtl. wieder schnell genug komplizierter ;) Ich weiß nicht, ob das eine Besonderheit meines Inputs war (es gibt ja verschiedene), aber der "Catch", der in Teil 2 beschriebene wurde, tauchte bei mir gar nicht auf. Es gab einfach nur ein fehlendes Element im aufgespannten ID-Bereich ("set(range(min(ids), max(ids))) - set(ids)"). Könnte auch sein, dass es einfach nur das war, worauf die Aufgabe hinaus wollte. Keine Ahnung.
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Mein Input war ebenfalls eindeutig für die Lösung von Teil 2.
narpfel
User
Beiträge: 645
Registriert: Freitag 20. Oktober 2017, 16:10

@nezzcarth: Ich verstehe den Catch so, dass man nicht einfach `set(range(2 ** 10)) - set(ids)` rechnen kann.
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Tag 5 in 3 Zeilen

Code: Alles auswählen

seatID = lambda s : int(s.replace('F','0').replace('B','1').replace('L','0').replace('R','1'), 2)
ids = set(map(seatID, open('input.txt').read().splitlines()))
print(max(ids), (set(range(min(ids), max(ids))) - ids).pop())
meine erste Lösung war da noch etwas umfangreicher

Code: Alles auswählen

with open('input.txt') as file:
    data = [line.strip() for line in file]

def partition(cmds, letter, end, start=0):
    for char in cmds:
        mid = (end - start) // 2
        if char == letter:
            end = mid + start
        else:
            start = start + mid + 1
    return end
    
def seatid(line):
    row = partition(line[:-3], 'F', 127)
    col = partition(line[-3:], 'L', 7)
    idd = row * 8 + col
    return idd

# Part 1
maxid = max(seatid(line) for line in data)
print(maxid)

# Part 2
ids = {seatid(line) for line in data}
for i in range(maxid):
    if not i in ids and (i + 1) in ids and (i - 1) in ids:
        print(i)
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
narpfel
User
Beiträge: 645
Registriert: Freitag 20. Oktober 2017, 16:10

Gegolfte Lösung für Tag 5 in Zsh (107 Zeichen):

Code: Alles auswählen

n=`sed 'y/FLBR/0011/;s/^/ibase=2;/'<f|sort|bc`;tail -n1<<<$n;comm -23 <(seq `sed -n '1p;$p'<<<$n`) <(<<<$n)
Die Eingabedaten müssen dabei in der Datei `f` liegen.

Für Bash wird es drei Zeichen länger, anscheinend unterstützt Bash keinen Here-String alleine in einer Process-Substitution:

Code: Alles auswählen

n=`sed 'y/FLBR/0011/;s/^/ibase=2;/'<f|sort|bc`;tail -n1<<<$n;comm -23 <(seq `sed -n '1p;$p'<<<$n`) <(cat<<<$n)
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ThomasL: Das ``.read().splitlines()`` kannst Du einfach weglassen. Das Dateiobjekt ist doch schon ein Iterator über die Zeilen. Und den ``lambda``-Ausdruck bekommt man mit der `translate()`-Methode kürzer. Dann kann man den auch direkt einsetzen und kommt mit einer Zeile weniger aus. Wobei ein Generator-Ausdruck kürzer ist als ``map(lambda s:``. Dann noch alle Namen auf einen Buchstaben begrenzen und überflüssige Leerzeichen weg, ich denke das hier ist dann ganz gut eingedampft:

Code: Alles auswählen

S=set(int(s.translate({70:48,66:49,76:48,82:49}),2)for s in open("input.txt"))
print(max(S),(set(range(min(S),max(S)))-S).pop())
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Noch mal ein Byte eingespart:

Code: Alles auswählen

S=set(int(s.translate({70:48,66:49,76:48,82:49}),2)for s in open("input.txt"))
m=max(S);print(m,(set(range(min(S),m))-S).pop())
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
ThomasL
User
Beiträge: 1366
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Cool, ich bin auch nach fast 3 Jahren immer wieder aufs neue begeistert von Python. Danke dir.
Ich bin Pazifist und greife niemanden an, auch nicht mit Worten.
Für alle meine Code Beispiele gilt: "There is always a better way."
https://projecteuler.net/profile/Brotherluii.png
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

@ThomasL, 3 Jahre nur? Wenn ich deinen Code lese, denke ich immer du bist ein Urgestein :)

Day 6: check - Schönen Nikolaustag Euch allen!
Bild

Die Lösung zu Teil 2 ist bei mir arg kompliziert. Das braucht ein Refactoring. Mal sehen, ob ich bis morgen in einer Form habe, die ich hier posten mag. :?
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Meine Lösung zu Tag 5 halte ich für ganz okay. Euer Feedback wirkt. :)
(und doch habe ich ein wenig Angst, __blackjack__ zu enttäuschen ;))

Code: Alles auswählen

# Tag 5
# https://adventofcode.com/2020/day/5

def main():
    def decode_seat(seatcode):
        row = int(seatcode[:7].replace('F', '0').replace('B', '1'), 2)
        column = int(seatcode[-3:].replace('L', '0').replace('R', '1'), 2)
        seat_id = row * 8 + column
        return (row, column, seat_id)

    # Tests
    seats = [
        'FBFBBFFRLR', # row 44, column 5, seat ID 357.
        'BFFFBBFRRR', # row 70, column 7, seat ID 567.
        'FFFBBBFRRR', # row 14, column 7, seat ID 119.
        'BBFFBBFRLL'  # row 102, column 4, seat ID 820.
    ]
    print('tests: ', [decode_seat(seat) for seat in seats])

    # Part 1
    with open('input_day5.txt', 'r') as lines:
        seat_codes = [x.strip('\n') for x in lines]

    seat_ids = set(decode_seat(x)[2] for x in seat_codes)
    print('Solution Part 1: ', max(seat_ids))

    # Part 2
    print('Solution Part 1: ', set(range(min(seat_ids), max(seat_ids)))-seat_ids)


if __name__ == "__main__":
    main()
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

@Bolitho:
'decode_seats' kann ruhig eine globale Funktion sein. Mir fallen gerade nur zwei Gründe für Funktionen innerhalb von Funktionen ein: Entweder man braucht die speziellen Eigenschaften von Closures (z. B. für Dekoratoren), oder (sehr, sehr seltener Fall) man braucht eine Teilfunktion, die so spezifisch ist, dass sie aus keinem anderen Kontext heraus Sinn ergibt, meistens wegen ganz spezifischer Parameter/Rückgabewerte o.ä. Hier trifft keines von beiden zu.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Bolitho: Ein Lerneffekt könnte vielleicht noch sein, wenn Du überlegst warum man `row` und `column` eigentlich gar nicht braucht. Also was ``a * 8 + b`` auf Bitebene bedeutet, wenn man das ganze in Binärdarstellung betrachtet. Dann wird `decode_seat()` einfacher.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Danke, euch beiden!

Code: Alles auswählen

# Tag 5
# https://adventofcode.com/2020/day/5


def decode_seat(seatcode):
    seatcode = (
        seatcode.replace("F", "0").replace("B", "1").replace("L", "0").replace("R", "1")
    )
    return (int(seatcode[:7], 2), int(seatcode[-3:], 2), int(seatcode, 2))


def main():
    # Tests
    seats = [
        "FBFBBFFRLR",  # row 44, column 5, seat ID 357.
        "BFFFBBFRRR",  # row 70, column 7, seat ID 567.
        "FFFBBBFRRR",  # row 14, column 7, seat ID 119.
        "BBFFBBFRLL",  # row 102, column 4, seat ID 820.
    ]
    print("tests: ", [decode_seat(seat) for seat in seats])

    # Part 1
    with open("input_day5.txt", "r") as lines:
        seat_codes = [x.strip("\n") for x in lines]

    seat_ids = set(decode_seat(x)[2] for x in seat_codes)
    print("Solution Part 1: ", max(seat_ids))

    # Part 2
    print("Solution Part 2: ", set(range(min(seat_ids), max(seat_ids))) - seat_ids)


if __name__ == "__main__":
    main()
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Tag 6 in BASIC für den C64:

Code: Alles auswählen

   10 TI$="000000":DIM A(25):R1=0:R2=0:GN=1:OPEN 2,8,2,"INPUT06,S,R"
   20 PRINT"ASK GROUPS..."
  100 IF ST<>0 THEN CLOSE 2:GOTO 9999
  110 PRINT GN:PRINT"{UP}";:GN=GN+1:FOR I=0 TO 25:A(I)=0:NEXT:PC=0
  200 REM ASK PERSON
  210 INPUT#2,A$:IF ST<>0 OR A$="" THEN 300
  220 PC=PC+1:FOR I=1 TO LEN(A$):J=ASC(MID$(A$,I,1))-65:A(J)=A(J)+1:NEXT:GOTO 200
  300 REM EVALUATE GROUPS ANSWERS
  310 FOR I=0 TO 25:N=A(I):IF N>0 THEN R1=R1+1
  320 IF N=PC THEN R2=R2+1
  330 NEXT:GOTO 100
 9999 PRINT"PART 1:"R1:PRINT"PART 2:"R2:PRINT"TIME: "TI$
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
narpfel
User
Beiträge: 645
Registriert: Freitag 20. Oktober 2017, 16:10

Tag 5 noch ein wenig weiter gegolft (Zsh, 96 Zeichen):

Code: Alles auswählen

n(){sed 'y/FLBR/0011/;s/^/ibase=2;/'<f|sort|bc};n|tail -1;n|comm -23 <(seq `n|sed -n '1p;$p'`) -
Bolitho
User
Beiträge: 219
Registriert: Donnerstag 21. Juli 2011, 07:01
Wohnort: Stade / Hamburg
Kontaktdaten:

Viel Spaß bei Tag 7!

Bei mir sieht es wieder wie Kraut und Rüben aus. Das Refactoring wird intensiv werden.
Bild
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bei mir ging's. Habe den ersten Teil über ne Queue gelöst, wo immer die neuen "Super Bags" rein kamen und parallel dazu ein Set für die Ergebnisse. Darüber lief eine while-Schleife, die fertig ist, sobald die Queue vollständig geleert wurde - eben das Prinzip einer Warteschlange. Als Datenstruktur hab ich dafür ebenfalls ein Set genommen, um doppelte Einträge zu vermeiden.

Und Teil zwei konnte man rekursiv lösen, wenn man sich vorher eine geeignete Datenstruktur (Bags <-> Anzahl) angelegt hat. Aufpassen musste man, weil halt neben den enthaltenen Bags ja auch die Tasche an sich (quasi das jeweilige Super Bag) mitgezählt werden musste - außer auf der obersten Ebene.

Wer schon fertig ist oder sich gerne selbst betrügen möchte, kann ja mal hier in meine Lösung schauen... :)

https://gist.github.com/seblin/52b63d94 ... 245902ed0b
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Hier nochmal deutlich kompakter, wobei ich mir den rekursiven Ansatz für Schritt 1 ehrlich gesagt abgeguckt hab und nur leicht angepasst habe.

Trigger-Warnung: Nicht PEP8-konform, da Code auf Modulebene steht. Mache ich normalerweise nicht, tat ich für diese Version aber dennoch. :)

Code: Alles auswählen

import re

parse_bag = re.compile("[a-z]+ [a-z]+").match
parse_contents = re.compile("(\d+) ([a-z]+ [a-z]+)").findall
with open("day7/input.txt") as stream:
    rules = {
        parse_bag(line).group(): {
            name: int(amount) for amount, name in parse_contents(line)
        } for line in stream
    }

def count_super_bags(needle):
    return needle == "shiny gold" or any(map(count_super_bags, rules[needle]))

def count(needle):
    return 1 + sum(amount * count(bag) for bag, amount in rules[needle].items())

print(sum(map(count_super_bags, rules)) - 1)
print(count("shiny gold") - 1)
Zuletzt geändert von snafu am Montag 7. Dezember 2020, 20:47, insgesamt 1-mal geändert.
Benutzeravatar
__blackjack__
User
Beiträge: 13077
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@snafu: Ich habe es mir im ersten Teil einfacher gemacht. Auch per rekursiven Aufrufen und die haben auch eiskalt Knoten mehrfach geliefert und am Ende erst alles ein ein `set` gekippt. Laufzeit ist auf dem Desktoprechner nicht merkbar.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Gibt es auch schon eine C64-Lösung in BASIC oder ist die Aufgabe zu komplex dafür?
Antworten