diff --git a/18/read.a68 b/18/read.a68 index 3bebf4f..435c7c9 100644 --- a/18/read.a68 +++ b/18/read.a68 @@ -1,58 +1,36 @@ CO data type and some operations for snailfish numbers CO -MODE LISTELEM = STRUCT(UNION(INT,LIST) elem); -MODE LIST = REF[]LISTELEM; +MODE PAIR = STRUCT (NUMBER left, right); +MODE NUMBER = UNION(INT, REF PAIR); -PROC make pair = (UNION(INT,LIST) x, y)LIST: - (HEAP[2]LISTELEM result; elem OF result := (x, y); result); +PROC make pair = (NUMBER x, y)REF PAIR: + HEAP PAIR := (x,y); -PROC append = (REF LIST arr)REF UNION(INT, LIST): - (LIST(arr) IS NIL - | elem OF (arr := HEAP [1]LISTELEM)[1] CO TODO: funny bug in Algol68g if the first [1] is removed; notify Marcel. CO - | HEAP[UPB arr+1]LISTELEM fresh; fresh[1:UPB arr] := arr; arr := fresh; elem OF arr[UPB arr] - ); +PROC dump = (NUMBER data)VOID: + CASE data IN + (INT n): printf(($g(0)$, n)), + (REF PAIR p): (print("["); dump(left OF p); print(","); dump(right OF p); print("]")) + ESAC; -PROC dump list = (LIST data)VOID: +PROC parse = (REF STRING s)NUMBER: BEGIN - print("["); - FOR i TO UPB data DO - IF i > 1 THEN print(",") FI; - CASE elem OF data[i] IN - (INT n) : printf(($g(0)$, n)), - (LIST sub): dump list(sub) - ESAC - OD; - print("]") -END; - -PROC parse = (STRING s)LIST: -BEGIN - INT i := 1; - - PROC parse elem = UNION(INT, LIST): - IF s[i] = "[" THEN - LIST sublist := NIL; - WHILE s[i] /= "]" DO - i +:= 1; - append(sublist) := parse elem; - i +:= 1 - OD; - sublist - ELSE - INT p; char in string(s[i], p, "1234567890"); - p MOD 10 - FI; - - CASE parse elem IN - (LIST result): result - ESAC + CHAR c = s[1]; s := s[2:]; + IF c = "[" THEN + NUMBER lt = parse (s); s := s[2:]; + NUMBER rt = parse (s); s := s[2:]; + make pair (lt, rt) + ELSE + INT p; char in string(c, p, "1234567890"); + p MOD 10 + FI END; -LIST homework = BEGIN - LIST lines := NIL; +[]NUMBER homework = BEGIN + FLEX[0]NUMBER lines; on logical file end(stand in, (REF FILE f)BOOL: done reading); DO STRING s; read((s)); read(new line); - append(lines) := parse(s) + ([UPB lines+1]NUMBER tmp; tmp[1:UPB lines] := lines; lines := tmp); + lines[UPB lines] := parse(s) OD; done reading: lines diff --git a/18/solve.a68 b/18/solve.a68 index 1c94298..1898fe5 100644 --- a/18/solve.a68 +++ b/18/solve.a68 @@ -1,81 +1,78 @@ PR include "read.a68" PR -PROC traverse = (LIST list, PROC(INT,REF UNION(INT,LIST))BOOL visit)VOID: +PROC traverse = (REF NUMBER num, PROC(INT,REF NUMBER)BOOL visit)VOID: BEGIN - PROC dive into = (INT depth, LIST list)VOID: - FOR i TO UPB list DO - BOOL found = visit(depth, elem OF list[i]); - CASE elem OF list[i] IN - (LIST sub): IF NOT found THEN dive into(depth+1, sub) FI - ESAC - OD; - dive into(0,list) + PROC dive into = (INT depth, REF NUMBER num)VOID: + BEGIN + BOOL found = visit(depth, num); + CASE num IN + (REF PAIR sub): IF NOT found THEN + dive into(depth+1, left OF sub); + dive into(depth+1, right OF sub) + FI + ESAC + END; + dive into(0,num) END; -PROC is regular = (LIST pair)BOOL: +PROC is regular = (PAIR tuple)BOOL: (BOOL result := TRUE; + []NUMBER pair = (left OF tuple, right OF tuple); FOR i TO UPB pair WHILE result DO - (elem OF pair[i] | (INT n): ~ | result := FALSE) + (pair[i] | (INT n): ~ | result := FALSE) OD; result); -PROC snailfish reduce = (LIST n)LIST: +PROC snailfish reduce = (REF NUMBER data)VOID: BEGIN - LIST data := n; - REF UNION(INT,LIST) last regular; + REF NUMBER last regular; INT last regular value, add to next regular; BOOL exploded; - PROC explode = (INT depth, REF UNION(INT,LIST) cell)BOOL: - CASE cell IN (LIST pair): - IF depth >= 3 AND is regular(pair) AND NOT exploded THEN - IF REF UNION(INT,LIST) prev cell = last regular; prev cell ISNT NIL THEN - prev cell := last regular value + (elem OF pair[1] | (INT n): n) - FI; - add to next regular := (elem OF pair[2] | (INT n): n); - cell := 0; - exploded := TRUE - ELSE FALSE - FI, - (INT n): - BEGIN - cell := n + add to next regular; - last regular := cell; - last regular value := n; - IF exploded THEN just start again FI - END + PROC explode = (INT depth, REF NUMBER cell)BOOL: + CASE cell IN (REF PAIR pair): + IF depth >= 4 AND is regular(pair) AND NOT exploded THEN + IF REF NUMBER prev cell = last regular; prev cell ISNT NIL THEN + prev cell := last regular value + (left OF pair | (INT n): n) + FI; + add to next regular := (right OF pair | (INT n): n); + cell := 0; + exploded := TRUE + ELSE FALSE + FI, + (INT n): + BEGIN + cell := n + add to next regular; + last regular := cell; + last regular value := n; + IF exploded THEN just start again FI + END ESAC; - PROC split = (INT depth, REF UNION(INT,LIST) cell)BOOL: + PROC split = (INT depth, REF NUMBER cell)BOOL: (cell | (INT n): IF n >= 10 THEN cell := make pair (n%2, (n+1)%2); just start again FI | FALSE); just start again: - CO dump list(data); print(new line); CO + CO dump(data); print(new line); CO exploded := FALSE; last regular := NIL; add to next regular := 0; traverse(data, explode); - traverse(data, split); - data + traverse(data, split) END; -PROC snailfish add = (LIST a,b)LIST: - snailfish reduce(make pair(a,b)); +OP +:= = (REF NUMBER x, NUMBER y)VOID: + snailfish reduce(x := make pair(x,y)); -PROC snailfish abs = (LIST a)INT: -BEGIN - OP ABS = (UNION(INT,LIST) cell)INT: - CASE cell IN +OP ABS = (NUMBER x)INT: + CASE x IN (INT n): n, - (LIST pair): 3*ABS elem OF pair[1] + 2*ABS elem OF pair[2] + (REF PAIR pair): 3*ABS left OF pair + 2*ABS right OF pair ESAC; - ABS a -END; -LIST acc := (elem OF homework[1] | (LIST pair): pair); +NUMBER acc := homework[1]; FOR i FROM 2 TO UPB homework DO - acc := snailfish add(acc, (elem OF homework[i] | (LIST pair): pair)) + acc +:= homework[i] OD; -dump list(acc); -print((snailfish abs(acc), new line)) - +dump(acc); +print((ABS acc, new line)) diff --git a/18/solve2.a68 b/18/solve2.a68 index 8fe1dea..9ff0671 100644 --- a/18/solve2.a68 +++ b/18/solve2.a68 @@ -1,63 +1,66 @@ PR include "read.a68" PR -PROC traverse = (LIST list, PROC(INT,REF UNION(INT,LIST))BOOL visit)VOID: +PROC traverse = (REF NUMBER num, PROC(INT,REF NUMBER)BOOL visit)VOID: BEGIN - PROC dive into = (INT depth, LIST list)VOID: - FOR i TO UPB list DO - BOOL found = visit(depth, elem OF list[i]); - CASE elem OF list[i] IN - (LIST sub): IF NOT found THEN dive into(depth+1, sub) FI - ESAC - OD; - dive into(0,list) + PROC dive into = (INT depth, REF NUMBER num)VOID: + BEGIN + BOOL found = visit(depth, num); + CASE num IN + (REF PAIR sub): IF NOT found THEN + dive into(depth+1, left OF sub); + dive into(depth+1, right OF sub) + FI + ESAC + END; + dive into(0,num) END; -PROC is regular = (LIST pair)BOOL: +PROC is regular = (PAIR tuple)BOOL: (BOOL result := TRUE; + []NUMBER pair = (left OF tuple, right OF tuple); FOR i TO UPB pair WHILE result DO - (elem OF pair[i] | (INT n): ~ | result := FALSE) + (pair[i] | (INT n): ~ | result := FALSE) OD; result); -PROC snailfish reduce = (LIST n)LIST: -BEGIN - PROC deep copy = (LIST data)LIST: - (HEAP[UPB data]LISTELEM copy; - FOR i TO UPB data DO - (elem OF data[i] | (LIST pair): elem OF copy[i] := deep copy(pair) - | copy[i] := data[i]) - OD; - copy); +PRIO COPY = 1; +OP COPY = (NUMBER x)NUMBER: + CASE x IN + (REF PAIR pair): make pair(COPY left OF pair, COPY right OF pair) + OUT x + ESAC; - LIST data := deep copy(n); - REF UNION(INT,LIST) last regular; +PROC snailfish reduce = (NUMBER n)NUMBER: +BEGIN + NUMBER data := COPY n; + REF NUMBER last regular; INT last regular value, add to next regular; BOOL exploded; - PROC explode = (INT depth, REF UNION(INT,LIST) cell)BOOL: - CASE cell IN (LIST pair): - IF depth >= 3 AND is regular(pair) AND NOT exploded THEN - IF REF UNION(INT,LIST) prev cell = last regular; prev cell ISNT NIL THEN - prev cell := last regular value + (elem OF pair[1] | (INT n): n) - FI; - add to next regular := (elem OF pair[2] | (INT n): n); - cell := 0; - exploded := TRUE - ELSE FALSE - FI, - (INT n): - BEGIN - cell := n + add to next regular; - last regular := cell; - last regular value := n; - IF exploded THEN just start again FI - END + PROC explode = (INT depth, REF NUMBER cell)BOOL: + CASE cell IN (REF PAIR pair): + IF depth >= 4 AND is regular(pair) AND NOT exploded THEN + IF REF NUMBER prev cell = last regular; prev cell ISNT NIL THEN + prev cell := last regular value + (left OF pair | (INT n): n) + FI; + add to next regular := (right OF pair | (INT n): n); + cell := 0; + exploded := TRUE + ELSE FALSE + FI, + (INT n): + BEGIN + cell := n + add to next regular; + last regular := cell; + last regular value := n; + IF exploded THEN just start again FI + END ESAC; - PROC split = (INT depth, REF UNION(INT,LIST) cell)BOOL: + PROC split = (INT depth, REF NUMBER cell)BOOL: (cell | (INT n): IF n >= 10 THEN cell := make pair (n%2, (n+1)%2); just start again FI | FALSE); just start again: - CO dump list(data); print(new line); CO + CO dump(data); print(new line); CO exploded := FALSE; last regular := NIL; add to next regular := 0; @@ -66,34 +69,28 @@ just start again: data END; -PROC snailfish add = (LIST a,b)LIST: - snailfish reduce(make pair(a,b)); +CO note: because "INT" is directly convertible into a number, we can't overload "OP +" easily CO +PROC add = (NUMBER x,y)NUMBER: + snailfish reduce(LOC PAIR:=(x,y)); -PROC snailfish abs = (LIST a)INT: -BEGIN - OP ABS = (UNION(INT,LIST) cell)INT: - CASE cell IN +OP ABS = (NUMBER x)INT: + CASE x IN (INT n): n, - (LIST pair): 3*ABS elem OF pair[1] + 2*ABS elem OF pair[2] + (REF PAIR pair): 3*ABS left OF pair + 2*ABS right OF pair ESAC; - ABS a -END; INT max magnitude := -1000; -LIST x1, x2; +NUMBER x1, x2; FOR i TO UPB homework DO FOR j TO UPB homework DO IF i /= j THEN - INT this = snailfish abs( - snailfish add((elem OF homework[i] | (LIST pair): pair), - (elem OF homework[j] | (LIST pair): pair)) - ); + INT this = ABS add(homework[i], homework[j]); (this > max magnitude | max magnitude := this; - x1 := (elem OF homework[i] | (LIST pair): pair); - x2 := (elem OF homework[j] | (LIST pair): pair)) + x1 := homework[i]; + x2 := homework[j]) FI OD OD; -dump list(x1); print(new line); -dump list(x2); print(new line); +dump(x1); print(new line); +dump(x2); print(new line); print((max magnitude, new line))