1 divert(-1)dnl -*- m4 -*-
2 # Usage: m4 [-Dfile=day20.input] day20.m4
3 # Optionally use -Dverbose=1 to see some progress
5 include(`common.m4')ifelse(common(20), `ok', `',
6 `errprint(`Missing common initialization
9 # Other than example and broadcaster, names are two lower letters; avoid
10 # collisions with the nl macro.
11 define(`Nl', defn(`nl'))undefine(`nl')
12 define(`errprintn', `errprint(`$1'Nl())')
13 define(`output', `ifelse(`$#', 0, ``$0'', 'dquote(defn(`output'))`)')
15 define(`input', translit((include(defn(`file'))), Nl`,> ()-', `;..'))
16 define(`bump', `define(`$1', incr($1))')
17 define(`q_h', 0)define(`q_t', 0)
18 define(`sent0', 0)define(`sent1', 0)
19 define(`_send', `bump(`sent$2')define(`q_'q_t,
20 `define(`$1_$3', $2)$3_($2)')bump(`q_t')')
21 define(`send', `_foreach(`_$0(`$1', $2, ', `)', o_$1)')
22 define(`broad', `bump(`sent0')send(`brd', 0)')
23 define(`_flip', `define(`s_$1', $2)send(`$1', $2)')
24 define(`flip', `ifelse($1, 0, `_$0(`$2', eval(!s_$2))')')
25 define(`_conj', `send(`$1', $2)ifelse($2.f_$1, 1.0, `define(`f_$1', cycle)')')
26 define(`conj', `_$0(`$2', eval(!(1_foreach(`first(`*'', `_$2)', i_$2))))')
28 define(`_wire', `define(`o_$1', defn(`o_$1')`,`$2'')define(`i_$2',
29 defn(`i_$2')`,`$1'')define(`$1_$2', 0)ifdef(`$2_', `', `define(`$2_')')')
30 define(`wire', `_foreach(`_$0(`$1', ', `)', $@)')
31 define(`_do', `ifelse(`$1', `b', `wire(`brd', shift(shift($@)))', `$1', `%',
32 `define(`$2_', `flip('$`1, `$2')')wire(shift($@))define(`s_$2', 0)', `$1',
33 `&', `define(`$2_', `conj('$`1, `$2')')define(`f_$2', 0)wire(shift($@))')')
34 define(`do', `_$0(substr(`$1', 0, 1), translit(`$1', `.%&', `,'))')
37 patsubst(defn(`input'), `\([^;]*\);', `do(`\1')')
39 define(`_chew', `do(substr(`$1', 0, index(`$1', `;')))define(
40 `tail', substr(`$1', incr(index(`$1', `;'))))ifelse(index(defn(`tail'),
41 `;'), -1, `', `$0(defn(`tail'))')')
42 define(`chew', `ifelse(eval($1 < 20), 1, `_$0(`$2')', `$0(eval($1/2),
43 substr(`$2', 0, eval($1/2)))$0(eval(len(defn(`tail')) + $1 - $1/2),
44 defn(`tail')substr(`$2', eval($1/2)))')')
45 chew(len(defn(`input')), defn(`input'))
49 define(`_round', `ifelse(q_h, q_t, `', `first(`q_'q_h`()')popdef(`q_'q_h)bump(
51 define(`round', `ifelse(eval($1%500), 0, `output(1, ...$1)')define(`cycle',
53 forloop_arg(1, 1000, `round')
54 define(`part1', mul64(sent0, sent1))
56 # Assumption for part 2: rx is fed by a single conjunction, which in turn is
57 # fed only by other conjunctions that each have a prime period. The LCM is
58 # thus the first time all feeders will cycle high at the same time.
60 define(`grab', ``,f_$1'')
61 define(`part2', `mul(1'foreach(`grab'first(`i_'shift(i_rx)))`)')
62 define(`finish', `round($1)ifelse(part2, 0, `$0(incr($1))')')
64 ', `define(`part2', ``no rx output'')')