1 divert(-1)dnl -*- m4 -*-
2 # Usage: m4 [-Dgoal=N] [-Dhashsize=H] [-Dfile=day14.input] day14.m4
3 # Optionally use -Dverbose=1 to see some progress
4 # Optionally use -Donly=[12] to skip a part
6 include(`common.m4')ifelse(common(14, 4999999), `ok', `',
7 `errprint(`Missing common initialization
10 ifdef(`goal', `', `define(`goal', translit(include(defn(`file')), nl))')
12 define(`I', defn(`incr'))define(`D', defn(`define'))define(`N', defn(`defn'))
13 define(`S', defn(`substr'))define(`F', defn(`ifdef'))
14 define(`E', defn(`ifelse'))define(`X', defn(`index'))
15 define(`rev', `ifelse(`$1', `', `', `$0(substr(`$1', 1))substr(`$1', 0, 1)')')
16 # Define E0 through E9, where En(recipes, recent, nexta, remaining) pushes
17 # recipe N by bumping recipes, extending recent, and updating nexta/remaining
18 define(`prep', `_$0(`$1', `$', `1', `2', `3', `4')')
19 define(`_prep', `define(`E$1', `I(`$2$3'),`$1$2$4',A$2$6(`$1',`$2$5')')')
20 forloop_arg(0, 9, `prep')
21 # Enhance E1 (if goal ends in 1) to end iteration if recent matches goal
22 define(`prep', `_$0(substr(goal, decr(len(goal))), `$', `1', `2', `3')')
23 define(`_prep', `define(`E$1', defn(`E$1')`E(X(`$2$4','dquote(substr(rev(
24 goal), 1))`),`-1',,`c(`$2$3',`$2$4',`$2$5')')')')
26 # Define E10 through E18 to push 1 then the second digit
27 define(`prep', `define(`E1$1', `E$1('defn(`E1')`)')')
28 forloop_arg(0, 8, `prep')
29 # Map eMN($@) to E[M+N]($@)
30 define(`prep', `_$0(eval(`$1', 10, 2), eval(`$1/10+$1%10'))')
31 define(`_prep', `define(`e$1', defn(`E$2'))')
32 forloop_arg(0, 99, `prep')
33 # Define A0 through A9, where A[remaining](value, nexta) either reduces
34 # remaining or defines a[nexta], producing new nexta/remaining
35 define(`A0', `a$2(`$1',I(`$2'))I(`$2'),$1')
36 define(`prep', `define(`A$1', $`2,'decr(`$1'))')
37 forloop_arg(1, 9, `prep')
38 # Initial contents of the final array entry. When called as aN(wrap) (from
39 # do), it forwards to a[wrap]; when called as aN(nexta, nexta+1) (from A0),
40 # it defines a[nexta] and sets nexta+1 as the next unused entry
41 define(`a', `E(`$2',,`a$1',`D(`a$2',N(`a'))D(`$0',``$1',`$2'')')')
42 # Prepopulate the leading array entries, where aN => value, nexta
43 define(`a0', ``3',`4'')define(`a1', ``7',`9'')define(`a2', ``3',`4'')
44 define(`a3', ``0',`4'')define(`a4', ``1',`6'')define(`a5', ``0',`6'')
45 define(`a6', ``1',`8'')define(`a7', ``2',`10'')define(`a8', ``4',`13'')
46 define(`a9', ``5',`15'')define(`a10', ``1',`12'')define(`a12', ``8',`21'')
47 define(`a13', ``9',`23'')define(`a15', ``6',`22'')define(`a21', ``1',`23'')
48 define(`a22', ``0',`23'')define(`a23', ``7',`24'')define(`a24', defn(`a'))
49 define(`need', eval(incr(goal)+9))
50 define(`rename', `define(`$2', defn(`$1'))popdef(`$1')')
51 define(`do100000', `output(1, `...$1')rename(`$0', `do'eval(
52 `$1+100000'))rename(`do'incr(`$1'), `do'eval(`$1+100001'))')
53 define(`do100001', `output(1, `...$1')rename(`$0', `do'eval(
54 `$1+100000'))rename(`do'decr(`$1'), `do'eval(`$1+99999'))')
55 # do(idx1, idx2, recipes, recent, nexta, remaining)
56 define(`do', `F(`$0$3',`$0$3(`$3',`$4')')_$0(a$1(`$6'),a$2(`$6'),`$3','dnl
57 `S(`$4',0,s),`$5',`$6')')
58 # _do(val1, nextidx1, val2, nextidx2, recipes, recent, nexta, remaining)
59 define(`_do', `do(`$2',`$4',e$1$3(`$5',`$6',`$7',`$8'))')
60 define(`s', decr(len(goal)))pushdef(`s', 9)
61 define(`do'need, `define(`part1', rev(substr(`$2', 0, 10)))popdef(`do'incr(
63 define(`do'incr(need), `define(`part1', rev(substr(`$2', 1, 10)))popdef(`s')')
64 ifelse(defn(`only'), 1, `
65 define(`do'need, defn(`do'need)`pushdef(`_do')')
66 define(`do'incr(need), defn(`do'incr(need))`pushdef(`_do')')
69 define(`c', `define(`part2', eval($1 + 1 - len(goal) - index(`$2',
70 'substr(rev(goal), 1)`)))output(1, `array grew to $3')pushdef(`_do')')
72 # Begin iterating after 24 recipes are known: elf1 is at a4, elf2 is
73 # at a13, the 10 most recently added recipes are 1 at slot 14 to 7 at
74 # slot 23, and we have 7 steps to go before a24 gets marked used
75 do(`4', `13', `24', `7015297761', `24', `7')