@kbr: Also der VIC-20 (oder deutsch VC-20) beeinflusst natürlich wie ich über die Problemlösung nachdenke, aber auch so hätte ich in Python keine Mengen genommen, und das sehe ich in diesem Fall auch nicht als Mikrooptimierung sondern ich gehe da in Python auch mit Lesbarkeit im Hinterkopf dran, also das man das am besten ”vorlesen” kann, wie es dort steht. Und das ganze in relativ vielen kleinen Funktionen/Methoden. Ich sehe da bei Tag 4 eine Funktion die eine Zeile in zwei Assignment-Objekte parst. Und dabei auf eine Klassenmethode zurückgreift, die ein `Assignment` parst, und eine Funktion die viele Zeilen parst und die einfach nur `parse_line()` mit `map()` auf die übergebenen Zeilen anwendet.
Das Assignment könnte den ``in``-Operator überladen um zu schauen ob ein Abschnitt enthalten ist, und zwei Testmethoden die jeweils prüfen ob ein Assignment komplett in einem anderen Assignment enthalten ist, und ob das Assignment sich mit einem anderen Assignment überlappt.
Dann noch pro Aufgabenteil eine Funktion die Assignment-Paare bekommt und jeweils zählt bei wie vielen die Bedingung des Aufgabenteils zutrifft. Beides nicht direkt in der `main()` weil beides testbar sein sollte, also noch zwei Testfälle um das Beispiel aus den Teilaufgaben zu prüfen. Ist für meine Begriffe noch KISS.
Aber hier jetzt erst einmal das was auf dem VIC-20 in 2m52s die beiden Teilergebnisse für Tag 4 ausspuckt:
Code: Alles auswählen
10 TI$="000000":R1=0:R2=0
20 OPEN 2,8,2,"INPUT04,S"
30 IF ST<>0 THEN CLOSE 2:PRINT R1,R2,TI$:END
40 INPUT#2,A$,B$:GOSUB 500:A=S:B=E
50 A$=B$:GOSUB 500:C=S:D=E
60 FA=A>=C AND A<=D
70 FB=B>=C AND B<=D
80 FC=C>=A AND C<=B
90 FD=D>=A AND D<=B
100 IF FA AND FB OR FC AND FD THEN R1=R1+1
200 IF FA OR FB OR FC OR FD THEN R2=R2+1
400 GOTO 30
500 FOR I=1 TO LEN(A$)-1
510 IF MID$(A$,I,1)="-" THEN 530
520 NEXT:STOP:REM NO '-' FOUND
530 S=VAL(MID$(A$,1,I))
540 E=VAL(MID$(A$,I+1))
550 RETURN
Das ist sogar halbwegs verständlich wenn man die Bedeutung der Variablen entziffert hat. Der VIC-20 verhilft hier unfreiwillig zu verständlicherem Code gegenüber dem C64 obwohl es das gleiche BASIC ist. Aber auf dem VIC-20 ist der Ausschnitt den man gleichzeitig vom Programm sehen kann mit 22×23 Zeilen so winzig, dass ich deutlich weniger in die Zeilen packe als auf dem C64. Bei der GW-BASIC-Portierung sieht man das, wie das Programm an Länge verliert und an Breite gewinnt:
Code: Alles auswählen
10 DEFINT A-Z:T1!=TIMER:R1=0:R2=0:DEF FN C(N,S,E)=N>=S AND N<=E
20 OPEN "input04.txt" FOR INPUT AS #1
30 WHILE NOT EOF(1):INPUT#1,A$,B$:GOSUB 500:A=S:B=E:A$=B$:GOSUB 500:C=S:D=E
40 FA=FN C(A,C,D):FB=FN C(B,C,D):FC=FN C(C,A,B):FD=FN C(D,A,B)
50 IF FA AND FB OR FC AND FD THEN R1=R1+1
60 IF FA OR FB OR FC OR FD THEN R2=R2+1
499 WEND:CLOSE 1:PRINT R1,R2:PRINT"In";TIMER-T1!;"seconds.":END
500 I=INSTR(A$,"-"):IF I=0 THEN PRINT"Error: '-' not found in ";A$:END
510 S=VAL(MID$(A$,1,I)):E=VAL(MID$(A$,I+1)):RETURN
In QBasic geht das Programm dann schon in den lesbaren Zustand über und man sieht auch im Ansatz wo die Klasse Sinn machen würde, weil ich dort einen Typ für `Assignment` definiert habe, weil das ja zweimal die gleiche Datenstruktur ist, und das beim Parsen und beim Test ob ein Abschnitt im `Assignment` enthalten ist Argumente zusammenfasst:
Code: Alles auswählen
TYPE Assignment
startSection AS INTEGER
endSection AS INTEGER
END TYPE
t1 = TIMER
DIM r1 AS INTEGER, r2 AS INTEGER
DIM a1 AS Assignment, a2 AS Assignment
DIM a, b, c, d AS INTEGER
r1 = 0: r2 = 0
OPEN "input04.txt" FOR INPUT AS #1
DO WHILE NOT EOF(1)
INPUT #1, a$, b$
ParseAssignment a$, a1: ParseAssignment b$, a2
a = Contains(a2, a1.startSection): b = Contains(a2, a1.endSection)
c = Contains(a1, a2.startSection): d = Contains(a1, a2.endSection)
IF a AND b OR c AND d THEN r1 = r1 + 1
IF a OR b OR c OR d THEN r2 = r2 + 1
LOOP
CLOSE 1: PRINT r1, r2: PRINT "In"; TIMER - t1; "seconds."
FUNCTION Contains% (a AS Assignment, section AS INTEGER)
Contains = section >= a.startSection AND section <= a.endSection
END FUNCTION
SUB ParseAssignment (s AS STRING, a AS Assignment)
DIM i AS INTEGER
i = INSTR(s, "-")
IF i = 0 THEN PRINT "Error: '-' not found in "; s: END
a.startSection = VAL(MID$(s, 1, i))
a.endSection = VAL(MID$(s, i + 1))
END SUB
Und damit man das wirklich mal in OOP sieht, habe ich es noch in Pascal implementiert (mein Informatik-Lehrer wäre wahrscheinlich sehr glücklich):
Code: Alles auswählen
type
TSection = Byte;
TAssignment = object
startSection, endSection: TSection;
procedure InitFromStr(const s: String);
function Contains(section: TSection): Boolean;
function IsEnclosedIn(const other: TAssignment): Boolean;
function Overlaps(const other: TAssignment): Boolean;
end;
var
r1, r2: Word;
f: Text;
line: String;
a1, a2: TAssignment;
procedure TAssignment.InitFromStr(const s: String);
var
i: Byte;
code: Integer;
begin
i := Pos('-', s);
if i = 0 then Halt(1);
Val(Copy(s, 1, i - 1), startSection, code);
if code > 0 then Halt(1);
Val(Copy(s, i + 1, Length(s)), endSection, code);
if code > 0 then Halt(1);
end;
function TAssignment.Contains(section: TSection): Boolean;
begin
Contains := (section >= startSection) and (section <= endSection);
end;
function TAssignment.IsEnclosedIn(const other: TAssignment): Boolean;
begin
IsEnclosedIn := (startSection >= other.startSection)
and (endSection <= other.endSection);
end;
function TAssignment.Overlaps(const other: TAssignment): Boolean;
begin
Overlaps := Self.Contains(other.startSection)
or Self.Contains(other.endSection)
or other.Contains(Self.startSection)
or other.Contains(Self.endSection);
end;
procedure ParseLine(const line: String; var a1, a2: TAssignment);
var
i: Byte;
begin
i := Pos(',', line);
if i = 0 then Halt(1);
a1.InitFromStr(Copy(line, 1, i - 1));
a2.InitFromStr(Copy(line, i + 1, Length(line)));
end;
begin
r1 := 0; r2 := 0;
Assign(f, 'input04.txt');
Reset(f);
while not Eof(f) do begin
ReadLn(f, line);
ParseLine(line, a1, a2);
if a1.IsEnclosedIn(a2) or a2.IsEnclosedIn(a1) then Inc(r1);
if a1.Overlaps(a2) then Inc(r2);
end;
Close(f);
WriteLn(r1, ' ', r2);
end.