Advent of Code

Gute Links und Tutorials könnt ihr hier posten.
steveO_O
User
Beiträge: 19
Registriert: Montag 23. März 2020, 20:08

Das ist ziemlich cool. Danke!
nezzcarth
User
Beiträge: 1418
Registriert: Samstag 16. April 2011, 12:47

Und auch dieses Jahr gibt es wieder einen Advent of Code: :)
https://adventofcode.com/2021
Benutzeravatar
sls
User
Beiträge: 479
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

Ich hatte mir dieses Jahr vorgenommen, AoC zu nutzen um Bash-Scripting zu lernen. Ich glaube ich verwerfe das Vorhaben schnell wieder.

Part 1:

Code: Alles auswählen

#!/usr/bin/env bash

MEASUREMENTS=()
INCREASED=0

while read line
  do
    MEASUREMENTS+=($line)
  done < day1-input.txt

for (( i=2; i<=${#MEASUREMENTS[@]}; i++ ));
  do
    if [[ $MEASUREMENTS[$i] -gt $MEASUREMENTS[$i-1] ]]; then
      INCREASED=$((INCREASED + 1))
    fi
  done

echo $INCREASED
When we say computer, we mean the electronic computer.
Benutzeravatar
__blackjack__
User
Beiträge: 10537
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Jo, Tag 1 ist ja wie immer ziemlich einfach. Das liess sich problemlos mit BASIC auf dem C64 lösen. Wobei Teil 2 Potential hat optimiert zu werden:

Code: Alles auswählen

10 TI$="000000":PRINT"READING INPUT...":DIM A(2000):OPEN 1,8,0,"INPUT01,S":N=0
20 INPUT#1,A(N):N=N+1:IF ST=0 THEN 20
30 CLOSE 1:PRINT N;"VALUES IN ";TI$:PRINT"PART 1..."
40 C=0:FOR I=0 TO N-2:IF A(I)<A(I+1) THEN C=C+1
50 NEXT:PRINT C;TI$
60 PRINT"PART 2...":C=0:FOR I=0 TO N-4
70 X=0:Y=0:FOR J=0 TO 2:K=I+J:X=X+A(K):Y=Y+A(K+1):NEXT:IF X<Y THEN C=C+1
80 NEXT:PRINT C;TI$
“»So computers are tools of the devil?« thought Newt. He had no problem believing it. Computers had to be the tools of *somebody*, and all he knew for certain was that it definitely wasn't him.” — Neil Gaiman & Terry Pratchett, Good Omens
Benutzeravatar
__blackjack__
User
Beiträge: 10537
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@sls: Das läuft bei mir nicht solange ich die Indexzugriffe auf MEASUREMENTS nicht in geschweifte Klammern setze: ``${MEASUREMENTS[$i]}``. Meine Bash sagt da sonst Syntaxfehler.

Und dann kommt bei mir das falsche Ergebnis, weil die Schleife bei 2 statt bei 1 anfängt. Indizes fangen bei Bash-Arrays bei 0 an.

Dann hat die Bash den praktischen ``readarray``-Befehl.

Um 1 erhöhen geht ohne Zuweisung, mit ``++``.

Und Lesbarkeit wird IMHO überbewertet — weg mit dem ``if``, her mit dem ``&&``. 😜

Code: Alles auswählen

#!/usr/bin/env bash

readarray MEASUREMENTS < input.txt

INCREASED=0
for (( i=1; i<=${#MEASUREMENTS[@]}; i++ )); do
    [[ ${MEASUREMENTS[i]} -gt ${MEASUREMENTS[i-1]} ]] && (( INCREASED++ ))
done

echo $INCREASED
“»So computers are tools of the devil?« thought Newt. He had no problem believing it. Computers had to be the tools of *somebody*, and all he knew for certain was that it definitely wasn't him.” — Neil Gaiman & Terry Pratchett, Good Omens
Benutzeravatar
sls
User
Beiträge: 479
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

__blackjack__ hat geschrieben: Mittwoch 1. Dezember 2021, 17:56 @sls: Das läuft bei mir nicht solange ich die Indexzugriffe auf MEASUREMENTS nicht in geschweifte Klammern setze: ``${MEASUREMENTS[$i]}``. Meine Bash sagt da sonst Syntaxfehler.

Und dann kommt bei mir das falsche Ergebnis, weil die Schleife bei 2 statt bei 1 anfängt. Indizes fangen bei Bash-Arrays bei 0 an.
Oh man, ich hatte das Bash-Skript in PyCharm geschrieben und ausgeführt, dabei hat er das auf meiner Kiste mit zsh ausgeführt. Komischerweise zählt er dort noch das newline mit und das `INCREASED` ist dann um eins zu hoch, selbst wenn ich beim korrekten Index 1 starte. Der Rest ist mega praktisch, danke dir!

Update: readarray wird von zsh nicht mal gefunden... Ein grund mehr wieder bash zu verwenden.
Update2: Newline wurde ebenfalls von Pycharm hinzugefügt. Trotzdem will ich zsh nicht mehr verwenden.
Zuletzt geändert von sls am Mittwoch 1. Dezember 2021, 18:51, insgesamt 1-mal geändert.
When we say computer, we mean the electronic computer.
Benutzeravatar
__blackjack__
User
Beiträge: 10537
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Iiihk, ja das ``<=`` als Schleifenbedingung ist natürlich falsch, dass müsste nur ``<`` heissen. Sorry, das habe ich übersehen.
“»So computers are tools of the devil?« thought Newt. He had no problem believing it. Computers had to be the tools of *somebody*, and all he knew for certain was that it definitely wasn't him.” — Neil Gaiman & Terry Pratchett, Good Omens
nezzcarth
User
Beiträge: 1418
Registriert: Samstag 16. April 2011, 12:47

@sls:
Zu deinem Shell-Skript hier noch meine "One-Liner" (spätestens beim zweiten wird es etwas absurd, aber nun gut … :) ):

Code: Alles auswählen

#!/bin/bash
FILE="day01.txt"
paste <(head -n -1 "$FILE") <(tail -n +2 "$FILE" ) | awk '$2>$1{print}' | wc -l
paste -d + <(head -n -2 "$FILE") <(tail -n +2 "$FILE" | head -n -1) <(tail -n +3 "$FILE") | bc >_day01.tmp && paste <(head -n -1 _day01.tmp) <(tail -n +2 _day01.tmp) | awk '$2>$1{print}' | wc -l && rm -f _day01.tmp 
(AWK wollte ich so minimal wie möglich verwenden; ansonsten könnte man natürlich auch da viel mehr direkt machen)
Benutzeravatar
sls
User
Beiträge: 479
Registriert: Mittwoch 13. Mai 2015, 23:52
Wohnort: Country country = new Zealand();

__blackjack__ hat geschrieben: Mittwoch 1. Dezember 2021, 18:48 Iiihk, ja das ``<=`` als Schleifenbedingung ist natürlich falsch, dass müsste nur ``<`` heissen. Sorry, das habe ich übersehen.
Alles gut, das war ja ein Fehler von mir :-D

@nezzcarth:

Das beste was ich für Tag auf die Schnelle hinbekommen habe ist das (Part 2):

Code: Alles auswählen

#!/usr/bin/env bash

readarray MEASUREMENTS < day1.txt

for (( i=0; i+3<${#MEASUREMENTS[@]}; i++ )); do
  WINDOW1=$((${MEASUREMENTS[i]} + ${MEASUREMENTS[i+1]} + ${MEASUREMENTS[i+2]}))
  WINDOW2=$((${MEASUREMENTS[i+1]} + ${MEASUREMENTS[i+2]} + ${MEASUREMENTS[i+3]}))
  [[ ${WINDOW1} -lt ${WINDOW2} ]] && (( INCREASED++ ))
  done


echo $INCREASED
When we say computer, we mean the electronic computer.
Benutzeravatar
Kebap
User
Beiträge: 475
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Ich versuche mich derzeit auch am AoC 2021, weil ich das schöne Rätsel und Übung und Inspiration finde.
Zwar erwarte ich nicht, da innerhalb eines Monats fertig zu werden, aber darum geht es mir auch gar nicht.

Nur weiß ich noch nicht, wie ich dann hier Feedback zu meinen stümperhaften Ergebnissen erfragen kann.
Soll ich neue Threads pro Tag öffnen oder alles hier in den riesigen Thread einfügen, wo es ggf. untergeht?
Bis dato stelle ich alles bei Github online, weil ich die Versionierung mag und Zugriff von mehreren Orten:

https://github.com/Kebap/aoc2021
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
Kebap
User
Beiträge: 475
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

Tag 6 brachte exponentielles Wachstum mit sich.
Meine naive Lösung für die erste Teilaufgabe ließ sich nicht ohne weiteres für größere Listen fortsetzen, da die Berechnungen exponentiell immer länger dauerten.
Stattdessen habe ich (weil es nicht gefragt war) einen Teil der Informationen fallen gelassen, und die Gegenstände in Masse bearbeitet, statt jedes einzeln in Reihenfolge.
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
ThomasL
User
Beiträge: 1247
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

Bei den Aufgaben kommt es manchmal auf einzelne Worte in der Aufgabenstellung an, die einen Hinweis auf die Art und Weise einer Lösung geben.

Bei dieser Aufgabe war es die erste Zeile im gegebenen Beispiel: "Initial state: 3,4,3,1,2" und zwar das Wort state.

Danach wurde man zwar durch die Art und Weise der Erklärung des Beispiels auf eine falsche Fährte geschickt (erstellen einer immer längeren Liste).

Anstatt für jeden einzelnen Fisch den Status nachzuhalten, reicht es die Anzahl der Fische pro State (Lebenstage) nachzuhalten. Wenn man das mal mit Pen & Paper macht, kommt das heraus. Und dann erkennt man,
dass dies einfachst durch eine Verschiebung der Werte nach links zu erreichen ist.

Code: Alles auswählen

   0 1 2 3 4 5 6 7 8
0:   1 1 2 1
1: 1 1 2 1
2: 1 2 1       1   1
3: 2 1       1 1 1 1
Hatte die Verschiebung zuerst selbst gecodet und mich dann an collections deque erinnert. Das ist auch mit eine der wichtigen Helferbibliotheken bei AoC jedes Jahr. Meine Lösung:

Code: Alles auswählen

from collections import deque

data = list(map(int, open('input.txt').read().split(',')))

def life(n):
    counts = deque([data.count(i) for i in range(9)])
    for _ in range(n):
        counts.rotate(-1)
        counts[6] += counts[8]
    return sum(counts)

print('Part1:', life(80))
print('Part2:', life(256))
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
Benutzeravatar
__blackjack__
User
Beiträge: 10537
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich hatte gleich Abstand von der länger werdenden Liste genommen, weil ich ja immer als erstes CBM BASIC V2 im Kopf habe, und da wäre das selbst ohne exponentielles Wachstum ja keine gute Idee gewesen. Hier der erste Lösungsansatz von mir:

Code: Alles auswählen

   10 TI$="000000":SF=7:DIM P(SF+1)
   20 OPEN 1,8,0,"INPUT06,S":PRINT"READING FISH..."
   30 GET#1,A$:IF ST<>0 THEN PRINT"READ ERROR":CLOSE 1:END
   40 I=VAL(A$):P(I)=P(I)+1:GET#1,A$:REM SKIP ","
   50 IF ST=0 THEN 30
   60 CLOSE 1:PRINT "READING TIME ";TI$:PRINT
   70 FOR D=1 TO 256:PRINT"{UP}DAY";D
   80 C=P(0):FOR I=0 TO SF:P(I)=P(I+1):NEXT:P(SF+1)=C:P(SF-1)=P(SF-1)+C
   90 IF D=80 THEN GOSUB 200
  100 NEXT:GOSUB 200:PRINT"TOTAL TIME ";TI$:END
  200 S=0:FOR I=0 TO SF+1:S=S+P(I):NEXT:PRINT S:PRINT:RETURN
Funktioniert eigentlich auch, wenn der begrenzte Wertebereich der Gleitkommazahlen nicht wäre, denn die 80 Tage-Marke gibt das noch exakt aus, aber nach 256 Tagen fallen 36 Fische ”hinten runter”:

Code: Alles auswählen

RUN
READING FISH...
READING TIME 000008
DAY 80
 353079
DAY 256
 1.60540013E+12

TOTAL TIME 000037
37 Sekunden Laufzeit inklusive einlesen der Daten von Diskette ist aber okay für den alten Rechner.
“»So computers are tools of the devil?« thought Newt. He had no problem believing it. Computers had to be the tools of *somebody*, and all he knew for certain was that it definitely wasn't him.” — Neil Gaiman & Terry Pratchett, Good Omens
Benutzeravatar
ThomasL
User
Beiträge: 1247
Registriert: Montag 14. Mai 2018, 14:44
Wohnort: Kreis Unna NRW

ist aber okay für den alten Rechner.
Was ist denn das für eine Hardware?
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
Benutzeravatar
__blackjack__
User
Beiträge: 10537
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Commodore 64, interpretiertes BASIC auf einer etwas unter 1 Mhz getakteten 8-Bit-CPU. Plus grottenlangsame Disk-I/O. Einlesen der 600 einstelligen Werte hat alleine schon 8 Sekunden gedauert.

Ich habe das mal zu GW-BASIC für den PC portiert, da gibt es auch einen Gleitkommatyp mit höherer Genauigkeit:

Code: Alles auswählen

10 SPAWN.FREQ=7:REM In days.
20 DIM POPULATION#(SPAWN.FREQ+1):REM Index=days till spawn, Value=# of fish.
30 OPEN "INPUT06.TXT" FOR INPUT AS #1
40 WHILE NOT EOF(1):INPUT #1,I:POPULATION#(I)=POPULATION#(I)+1:WEND:CLOSE #1
100 FOR DAY=1 TO 256
110   N#=POPULATION#(0)
120   FOR I=0 TO SPAWN.FREQ:POPULATION#(I)=POPULATION#(I+1):NEXT
130   POPULATION#(SPAWN.FREQ+1)=N#
140   POPULATION#(SPAWN.FREQ-1)=POPULATION#(SPAWN.FREQ-1)+N#
150   IF DAY=80 THEN GOSUB 500
160 NEXT:GOSUB 500:END
500 SUM#=0:FOR I=0 TO SPAWN.FREQ+1:SUM#=SUM#+POPULATION#(I):NEXT
510 PRINT SUM#:RETURN
“»So computers are tools of the devil?« thought Newt. He had no problem believing it. Computers had to be the tools of *somebody*, and all he knew for certain was that it definitely wasn't him.” — Neil Gaiman & Terry Pratchett, Good Omens
Benutzeravatar
kbr
User
Beiträge: 1359
Registriert: Mittwoch 15. Oktober 2008, 09:27

__blackjack__ hat geschrieben: Freitag 10. Juni 2022, 19:36 Plus grottenlangsame Disk-I/O.
Da gab es doch den Fastloader – das meist raubkopierte Programm seiner Zeit.
Benutzeravatar
__blackjack__
User
Beiträge: 10537
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@kbr: Da gab es mehrere, aber die meisten Leute die ich kannte/kenne haben ein Steckmodul mit Fastloader (gehabt). In der Regel eine Final Cartridge 3 oder ein Action Replay 5 oder 6. Ich hatte damals ein Action Replay 6 und heute ein Retro Replay. Das Problem ist, dass die nur LOAD und SAVE beschleunigen, aber nicht was man so nach einem OPEN mit Dateien macht: GET#/INPUT#/PRINT#.

Da gibt es auch Lösungen für, für die man aber an die Hardware ran muss und im einfachsten Fall sowohl beim Rechner als auch im Laufwerk ROMs austauschen muss. Bei älteren Geräten waren die Bausteine nicht zwingend gesockelt und man musste mit dem Lötkolben ran. Bei einigen Lösungen kam dann noch Basteln und Löten von zusätzlichen Kabeln und RAM-Platinen für das Laufwerk dazu. Da wird das mit dem Raubkopieren zumindest mal aufwändiger.

Ich war dann jetzt doch mal motiviert auch auf dem C64 die exakte Lösung zu bekommen und habe die Zähler in zwei Teile aufgeteilt: alles über eine Million und alles unter einer Million:

Code: Alles auswählen

   10 TI$="000000":SF=7:DIM P(SF+1,1):OM=1E6
   20 OPEN 1,8,0,"INPUT06,S":PRINT"READING FISH..."
   30 GET#1,A$:IF ST<>0 THEN PRINT"READ ERROR":CLOSE 1:END
   40 I=VAL(A$):P(I,0)=P(I,0)+1:GET#1,A$:REM SKIP ","
   50 IF ST=0 THEN 30
   60 CLOSE 1:PRINT "READING TIME ";TI$:PRINT
   70 FOR D=1 TO 256:PRINT"{UP}DAY";D
   80 AL=P(0,0):AH=P(0,1):FOR I=0 TO SF:P(I,0)=P(I+1,0):P(I,1)=P(I+1,1):NEXT
   90 P(SF+1,0)=AL:P(SF+1,1)=AH
  100 BL=P(SF-1,0):BH=P(SF-1,1):GOSUB 300:P(SF-1,0)=AL:P(SF-1,1)=AH
  110 IF D=80 THEN GOSUB 200
  120 NEXT:GOSUB 200:PRINT"TOTAL TIME ";TI$:END
  200 AL=0:AH=0:FOR I=0 TO SF+1:BL=P(I,0):BH=P(I,1):GOSUB 300:NEXT
  210 PRINT AH;"MILLIONS +";AL:PRINT:RETURN
  300 AL=AL+BL:AH=AH+BH:IF AL>=OM THEN AL=AL-OM:AH=AH+1
  310 RETURN
Jetzt gehen keine Fische mehr verloren. Bei einer Laufzeit von rund 1½ Minuten:

Code: Alles auswählen

RUN
READING FISH...
READING TIME 000011
DAY 80
 0 MILLIONS + 353079
DAY 256
 1605400 MILLIONS + 130036

TOTAL TIME 000129

READY.
Und hier mal meine Python-Lösung:

Code: Alles auswählen

#!/usr/bin/env python3
from collections import Counter

import pytest
from more_itertools import iterate, nth

SPAWN_FREQUENCY = 7  # in days.

EXAMPLE_INPUT = "3,4,3,1,2"

EXAMPLE_DEVELOPMENT = """\
Initial state: 3,4,3,1,2
After  1 day:  2,3,2,0,1
After  2 days: 1,2,1,6,0,8
After  3 days: 0,1,0,5,6,7,8
After  4 days: 6,0,6,4,5,6,7,8,8
After  5 days: 5,6,5,3,4,5,6,7,7,8
After  6 days: 4,5,4,2,3,4,5,6,6,7
After  7 days: 3,4,3,1,2,3,4,5,5,6
After  8 days: 2,3,2,0,1,2,3,4,4,5
After  9 days: 1,2,1,6,0,1,2,3,3,4,8
After 10 days: 0,1,0,5,6,0,1,2,2,3,7,8
After 11 days: 6,0,6,4,5,6,0,1,1,2,6,7,8,8,8
After 12 days: 5,6,5,3,4,5,6,0,0,1,5,6,7,7,7,8,8
After 13 days: 4,5,4,2,3,4,5,6,6,0,4,5,6,6,6,7,7,8,8
After 14 days: 3,4,3,1,2,3,4,5,5,6,3,4,5,5,5,6,6,7,7,8
After 15 days: 2,3,2,0,1,2,3,4,4,5,2,3,4,4,4,5,5,6,6,7
After 16 days: 1,2,1,6,0,1,2,3,3,4,1,2,3,3,3,4,4,5,5,6,8
After 17 days: 0,1,0,5,6,0,1,2,2,3,0,1,2,2,2,3,3,4,4,5,7,8
After 18 days: 6,0,6,4,5,6,0,1,1,2,6,0,1,1,1,2,2,3,3,4,6,7,8,8,8,8
""".splitlines()


def parse_population(string):
    """
    Parse given `string` into a histogram of the population.

    Each index in the result represents the number of fish that spawn in the
    number of days represented by that index.  This way the exponential growth
    is kept in a fixed size data structure.

    >>> p = parse_population("")
    >>> p
    [0, 0, 0, 0, 0, 0, 0, 0, 0]
    >>> len(p) == SPAWN_FREQUENCY + 2
    True
    >>> parse_population("4,2,4")
    [0, 0, 1, 0, 2, 0, 0, 0, 0]
    """
    histogram = Counter(map(int, string.split(",") if string.strip() else []))
    return [histogram[i] for i in range(SPAWN_FREQUENCY + 2)]


def do_one_day(population):
    creator_count = population[0]
    new_population = population[1:]
    new_population.append(creator_count)  # The new ones.
    new_population[SPAWN_FREQUENCY - 1] += creator_count  # The old ones.
    return new_population


def iter_days(population):
    return iterate(do_one_day, population)


def count_fish_after_period(population, day_count):
    return sum(nth(iter_days(population), day_count))


def main():
    population = parse_population(input())
    for day_count in [80, 256]:
        print(count_fish_after_period(population, day_count))


def _parse_example_development_line(line):
    description, colon, population_text = line.partition(":")
    assert colon == ":", line
    return description, parse_population(population_text)


def test_do_one_day():
    values = iter_days(parse_population(EXAMPLE_INPUT))
    expected_values = map(_parse_example_development_line, EXAMPLE_DEVELOPMENT)
    for value, (description, expected) in zip(values, expected_values):
        assert value == expected, description


@pytest.mark.parametrize(
    "day_count, expected", [(18, 26), (80, 5934), (256, 26_984_457_539)]
)
def test_count_fish_after_period(day_count, expected):
    assert (
        count_fish_after_period(parse_population(EXAMPLE_INPUT), day_count)
        == expected
    )


if __name__ == "__main__":
    main()
“»So computers are tools of the devil?« thought Newt. He had no problem believing it. Computers had to be the tools of *somebody*, and all he knew for certain was that it definitely wasn't him.” — Neil Gaiman & Terry Pratchett, Good Omens
Benutzeravatar
__blackjack__
User
Beiträge: 10537
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Noch mal eine Tag 6 Lösung für den C64. In COMAL. So eine Mischung zwischen BASIC und Pascal und eine recht angenehme Art lesbar auf solchen Systemen zu programmieren. Ist so ähnlich interpretiert wie BASIC, also bei der Eingabe werden die Zeilen kompakter im Speicher abgelegt als es reiner Text wäre. Im Gegensatz zum Microsoft BASIC werden nicht nur Schlüsselworte zu 1 Byte Tokens, sondern auch Zahlen werden nicht als Text gespeichert. Namen werden in einer Namenstabelle geführt und in den Zeilendaten landet nur der Index in diese Tabelle, so dass obwohl Namen bis zu 79 Zeichen lang sein dürfen, jeder Name nur einmal diesen vollen Speicherplatz im Programm belegt, und das nachschlagen des Namens nicht zur Laufzeit des Programms passiert, sondern schon bei der Eingabe.

Neben den ganzen strukturierten Kontrollstrukturen wie IF … THEN … ELIF … ELSE … ENDIF und FOR, WHILE, REPEAT … UNTIL, … Schleifen, gibt es benannte Funktionen und Prozeduren. Mit lokalen Namensräumen. Und sowohl „pass by value“ als auch „pass by reference“-Argumente.

Weil Zeichenketten in COMAL nicht auf 255 Zeichen beschränkt sind wie bei BASIC, kann man hier einfach die komplette Datei in eine Zeichenkette einlesen. Und weil das COMAL-Steckmodul keinen eigenen Schnelllader mitbringt, kommt auch beim OPEN/get$() JiffyDOS zum Zug und das ist noch mal schneller als das BASIC-Programm mit RetroReplay-Steckmodul.

Code: Alles auswählen

0010 TIME 0
0020 sf#:=7 // spawn frequency
0030 DIM pop(0:sf#+1,0:1)
0040 
0050 PRINT "Reading fish...";
0060 read'fish
0070 PRINT TIME/60;"s"
0080 
0090 FOR d#:=1 TO 256 DO
0100   PRINT AT 0,1: "Day";d#;
0110   
0120   // Rotate pop(,) left.
0130   nl:=pop(0,0); nh:=pop(0,1)
0140   FOR i#:=0 TO sf# DO
0150     pop(i#,0):=pop(i#+1,0)
0160     pop(i#,1):=pop(i#+1,1)
0170   ENDFOR i#
0180   pop(sf#+1,0):=nl; pop(sf#+1,1):=nh
0190   
0200   add(nl,nh,pop(sf#-1,0),pop(sf#-1,1))
0210   pop(sf#-1,0):=nl; pop(sf#-1,1):=nh
0220   
0230   IF d#=80 THEN print'result
0240 ENDFOR d#
0250 print'result
0260 PRINT "Total";TIME/60;"s"
0270 END 
0280 
0290 PROC read'fish CLOSED
0300   IMPORT pop(,)
0310   DIM buf$ OF 1000
0320   OPEN FILE 2,"input06",READ
0330   INPUT FILE 2: buf$
0340   FOR i#:=1 TO LEN(buf$) STEP 2 DO
0350     pop(VAL(buf$(i#:i#)),0):+1
0360   ENDFOR i#
0370   CLOSE FILE 2
0380 ENDPROC read'fish
0390 
0400 PROC print'result CLOSED
0410   IMPORT sf#,pop(,),add
0420   sum'l:=0; sum'h:=0
0430   FOR i#:=0 TO sf#+1 DO
0440     add(sum'l,sum'h,pop(i#,0),pop(i#,1))
0450   ENDFOR i#
0460   
0470   PRINT "=";
0480   IF sum'h=0 THEN
0490     PRINT sum'l;
0500   ELSE 
0510     PRINT sum'h,
0520     PRINT USING "######": sum'l;
0530   ENDIF 
0540   PRINT "fish."
0550 ENDPROC print'result
0560 
0570 PROC add(REF al,REF ah,bl,bh) CLOSED
0580   al:=al+bl; ah:=ah+bh
0590   IF al>=1000000 THEN al:-1000000; ah:+1
0600 ENDPROC add
Das läuft in 44,67 Sekunden durch:

Code: Alles auswählen

run
Reading fish... 2.75 s
Day 80 = 353079 fish.
Day 256 = 1605400130036 fish.
Total 44.6666667 s

end at 0270
“»So computers are tools of the devil?« thought Newt. He had no problem believing it. Computers had to be the tools of *somebody*, and all he knew for certain was that it definitely wasn't him.” — Neil Gaiman & Terry Pratchett, Good Omens
Antworten