Advent of Code

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

Aaah, hatte ich noch gar nicht nachgeschaut. Weiss gar nicht mit welchem Rechner/System ich das dieses Jahr angehen will. Bin halbwegs sattelfest in CP/M auf Intel 8080, aber PDP-11 ist auch irgendwie interessant. Da aber noch kein Betriebssystem angeschaut. Vielleicht am Wochenende mal Unix installieren und dann vielleicht einen nativen C-Compiler in den Fingern haben‽
“All tribal myths are true, for a given value of 'true'.” — Terry Pratchett, The Last Continent
nezzcarth
User
Beiträge: 1788
Registriert: Samstag 16. April 2011, 12:47

Emulierst du diese Systeme mit SIMH oder wie ist da die Herangehensweise?
Benutzeravatar
__blackjack__
User
Beiträge: 14240
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

CP/M mit z80pack, weil man den Altair/IMSAI da so schön grafisch hat. PDP würde ich mit simh machen.
“All tribal myths are true, for a given value of 'true'.” — Terry Pratchett, The Last Continent
Benutzeravatar
Kebap
User
Beiträge: 785
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Traditionellerweise löse ich die ersten 2-3 Tage per Excel, einfach weils am schnellsten geht, die Daten manuell herum zu schubsen, statt eine sattelfeste automatische Lösung zu programmieren.

Diesmal hab ich Tag 1 pflichtgemäßg per Python versucht, und immerhin den ersten Teil auch geschafft, nur beim zweiten bekomme ich die Info, dass meine Antwort zu hoch gegriffen sei. Ich fand noch nicht alle Gründe. Einen Schnitzer hatte ich schon ausgebaut, dass die Position 100 fälschlich doppelt berechnet wurde. Bin jetzt schon ein paar Dutzend Zeilen manuell durchgegangen, aber die Logik scheint soweit erstmal stichfest. Was habe ich noch übersehen?

Code: Alles auswählen

import os
from dataclasses import dataclass

@dataclass
class Instruction:
  direction: str
  length: int
  text: str


def parse_data_01(data):
  instructions = []
  for line in data.split("\n"):
    first_char = line[0]
    if first_char == "R":
      direction = +1
    elif first_char == "L":
      direction = -1
    else:
      raise ValueError("Direction must be coded as L or R, but found: {first_char}.")

    other_chars = line[1:]
    length = int(other_chars)
    instructions.append(Instruction(direction, length, line))

  return instructions


def solve_01(data):
  zeroes_hit = 0
  zeroes_passed = 0
  position = 50

  print(f"- The dial starts by pointing at {position}.")

  instructions = parse_data_01(data)
  for i in instructions:
    position = (position + (i.direction * i.length))

    while position < 0:
      zeroes_passed += 1
      position += + 100

    while position > 100:
      zeroes_passed += 1
      position -= 100

    if position in (0, 100):
      position = 0
      zeroes_hit += 1
      zeroes_passed += 1

    print(f"- The dial is rotated {i.text} to point at {position}.")

  print(f"- Hit position 0 a total of {zeroes_hit} times.")
  print(f"- Passed position 0 a total of {zeroes_passed} times.")

if __name__ == "__main__":
  folder = "C:/data/py/26-aoc2025"
  number = "01"
  file_path = os.path.join(folder, f"{number}.txt")

  with open(file_path) as f:
    data = f.read().strip()

  solve_01(data)

Das i hab ich extra so unerwartet abgekürzt benannt, um die Stammuser hier zu grüßen. :mrgreen:
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.
Manul
User
Beiträge: 55
Registriert: Samstag 13. Februar 2021, 16:00

Kebap hat geschrieben: Montag 1. Dezember 2025, 14:48 Einen Schnitzer hatte ich schon ausgebaut, dass die Position 100 fälschlich doppelt berechnet wurde. Bin jetzt schon ein paar Dutzend Zeilen manuell durchgegangen, aber die Logik scheint soweit erstmal stichfest. Was habe ich noch übersehen?
Es gibt noch eine weitere Position, die in Deinem Code manchmal (etwa in der Hälfte der Fälle) doppelt gezählt wird.

Ich hatte erst den gleichen Fehler beim 2. Teil gemacht, daher hab ich das schnell gefunden.
Benutzeravatar
__blackjack__
User
Beiträge: 14240
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Kebap: Das ``position > 100`` ist komisch. Sollte das nicht >99 sein und den Fall ``if position == 100`` kann man sich dann sparen‽
“All tribal myths are true, for a given value of 'true'.” — Terry Pratchett, The Last Continent
narpfel
User
Beiträge: 705
Registriert: Freitag 20. Oktober 2017, 16:10

Teil 1 in ging in Bash noch relativ einfach als Einzeiler:

Code: Alles auswählen

n=50; < input tr LR -+ | while read line; do ((n = (n $line + 100) % 100)); echo $n; done | grep -c '^0$'
Oder gegolft sogar unter 80 Zeichen:

Code: Alles auswählen

n=50;tr LR -+<i|while read l;do((n=(n$l+100)%100));echo $n;done|grep -c '^0$'
Aber für Teil 2 hab’ ich mehrere Zeilen gebraucht:

Code: Alles auswählen

n=50
part_2=0
while read line; do
    ((step = line < 0 ? -1 : 1))
    ((step_count = line < 0 ? -line : line))
    for ((i = 0; i < step_count; ++i)); do
        ((n = (n + step + 100) % 100, n == 0 && ++part_2))
    done
done < <(tr LR -+ < input)
echo $part_2
Dass in der `for`-Schleife alles in einer arithmetic expansion gemacht wird, ist eine Performanceoptimierung. Bash ist sehr geeignet für sowas, nur 100x langsamer als der selbe Algorithmus in Python umgesetzt.
narpfel
User
Beiträge: 705
Registriert: Freitag 20. Oktober 2017, 16:10

Heute gingen beide Teile sehr schön als Basheinzeiler. :mrgreen:
Benutzeravatar
Kebap
User
Beiträge: 785
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Manul hat geschrieben: Montag 1. Dezember 2025, 17:29
Kebap hat geschrieben: Montag 1. Dezember 2025, 14:48 Einen Schnitzer hatte ich schon ausgebaut, dass die Position 100 fälschlich doppelt berechnet wurde. Bin jetzt schon ein paar Dutzend Zeilen manuell durchgegangen, aber die Logik scheint soweit erstmal stichfest. Was habe ich noch übersehen?
Es gibt noch eine weitere Position, die in Deinem Code manchmal (etwa in der Hälfte der Fälle) doppelt gezählt wird.

Ich hatte erst den gleichen Fehler beim 2. Teil gemacht, daher hab ich das schnell gefunden.
Hmm, ich habe nun ein Beispiel isolieren können, das fälschlich doppelt gezählt wird.
Tatsächlich an derselben Position, die ich bereits repariert wähnte:

Code: Alles auswählen

- The dial starts by pointing at 50.
- The dial is rotated R50 to point at 0.
- Passed zero: 2 times. 
- Hit zero: 1 time.
Irgendwie hab ich gerade einen Knoten im Kopf, wie ich das am besten löse, ohne zu viel zu verlieren.
Habe den Vorschlag von __blackjack__ umgesetzt, aber das brachte keine Besserung.


edit: Habe jetzt meinen letzten Entwurf mit den While-Schleifen weggeworfen, die jede Drehung einzeln summieren.
Statt dessen benutze ich nun die Kraft der Division, um direkt die richtige Anzahl der Hunderterübergänge zu errechnen:

Code: Alles auswählen

    zeroes_passed += abs(position // 100)
    position = position % 100
    zeroes_hit += (position == 0)
Damit konnte ich meine Antwort erneut deutlich reduzieren, doch oh je, sie ist immer noch zu hoch..

edit: Sie ist zu HOCH, obwohl mir jetzt wieder Fälle aufgefallen sind, die ich gar nicht richtig mitzähle:

Code: Alles auswählen

- The dial starts by pointing at 1.
- The dial is rotated L1  to point at 0.        Passed 0: 0 times. Hit 0: 1 times.
Sollte doch auch 1x passed sein. Hmrgl.
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.
Manul
User
Beiträge: 55
Registriert: Samstag 13. Februar 2021, 16:00

Kebap hat geschrieben: Mittwoch 3. Dezember 2025, 12:03 Hmm, ich habe nun ein Beispiel isolieren können, das fälschlich doppelt gezählt wird.
Tatsächlich an derselben Position, die ich bereits repariert wähnte:

Code: Alles auswählen

- The dial starts by pointing at 50.
- The dial is rotated R50 to point at 0.
- Passed zero: 2 times. 
- Hit zero: 1 time.
Die war auch schon repariert. Zumindest tritt das mit Deinem oben geposteten Code nicht auf.
Kebap hat geschrieben: Mittwoch 3. Dezember 2025, 12:03 Irgendwie hab ich gerade einen Knoten im Kopf, wie ich das am besten löse, ohne zu viel zu verlieren.
Habe den Vorschlag von __blackjack__ umgesetzt, aber das brachte keine Besserung.
Das hat im Gegenteil wahrscheinlich den Fehler eingeführt. Ich mag was übersehen, aber ich halte den Vorschlag mit ">99" ausnahmsweise für nicht hilfreich.
Kebap hat geschrieben: Mittwoch 3. Dezember 2025, 12:03

Code: Alles auswählen

    zeroes_passed += abs(position // 100)
    position = position % 100
    zeroes_hit += (position == 0)
[...]

Code: Alles auswählen

- The dial starts by pointing at 1.
- The dial is rotated L1  to point at 0.        Passed 0: 0 times. Hit 0: 1 times.
[...]
Sollte doch auch 1x passed sein. Hmrgl.
Warum sollte es das? Wenn Du die drei Zeilen oben im Kopf mit der Endposition durchgehst, sollte klar werden, dass "zeroes_passed" hier nicht hochgezählt wird.
Benutzeravatar
snafu
User
Beiträge: 6903
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Tag 1 in Rust, aber erstmal nur für die Beispiele aus Part 1:

Code: Alles auswählen

fn parse_steps(instruction: &str) -> i32 {
    instruction.trim_start_matches("R")
               .replace("L", "-")
               .parse()
               .unwrap()
}

fn find_path(start: i32, instructions: Vec<&str>) -> impl Iterator<Item = i32> {
    instructions.into_iter().map(parse_steps)
                .scan(start, |position, steps| {
                    *position = (*position + steps).rem_euclid(100);
                    dbg!(&position);
                    Some(*position)
                })
}

fn main() {
    let instructions = vec!["L68", "L30", "R48", "L5", "R60", "L55", "L1", "L99", "R14", "L82"];
    let zeros = find_path(50, instructions).filter(|n| *n == 0);
    dbg!(zeros.count());
}
Das Lesen aus dem Dateianhang baue ich noch ein. Bin gespannt, ob mir da mein Parser zum Verhängnis wird. :D

Jedenfalls ist das ein schönes Anwendungsbeispiel für die scan()-Methode, finde ich. :)
Antworten