1 divert(-1)dnl -*- m4 -*-
2 # Usage: m4 [-Dfile=day24.input] day24.m4
3 # Optionally use -Dverbose=1 to see some progress
4 # Optionally use -Dpriority=0|1|2|3|4|5 to choose priority queue algorithms
6 include(`common.m4')ifelse(common(24), `ok', `',
7 `errprint(`Missing common initialization
10 define(`radiation', 1)define(`cold', 2)define(`fire', 4)
11 define(`bludgeoning', 8)define(`slashing', 16)
12 define(`ignore')define(`hit', `(')
13 define(`units', `ignore(')define(`with', `)')
14 define(`an', `ignore(')define(`does', `)')
15 define(`damage', `ignore(')define(`initiative', `)')
16 define(`input', translit((include(defn(`file'))), nl`( );,', `:<.>'))
17 define(`type', 1)define(`max', 0)
18 define(`bump', `ifelse(eval($1<$2), 1, `define(`$1', $2)')')
19 define(`map', `eval(0_$0$3)')
20 define(`_map', `ifelse(`$1', `', `', `ifelse(`$1', `weak', `define(`scale',
21 5)', `$1', `immune', `define(`scale', 0)', `$1', `to', `',
22 `|($1<<scale)')$0(shift($@))')')
23 define(`line', `ifelse(`$1', `Infection', `define(`type', 0)',
24 eval(len(`$1')>20), 1, `_$0(translit(`$1', `<.>', `(,)'))')')
25 define(`_line', `setup(type, $1, $3, map$4, $6, $7, $9)')
26 define(`setup', `bump(`max', $7)define(`type$7', $1)define(`def$7', 0)define(
27 `off$7', 0)define(`units$7', $2)define(`hp$7', $3)define(`mod$7',
28 $4)define(`atk$7', $5)define(`dam$7', $6)')
30 patsubst(defn(`input'), `\([^:]*\):', `line(`\1')')
32 define(`_chew', `line(substr(`$1', 0, index(`$1', `:')))define(`tail',
33 substr(`$1', incr(index(`$1', `:'))))ifelse(index(defn(`tail'), `:'), -1,
34 `', `$0(defn(`tail'))')')
35 define(`chew', `ifelse(eval(`$1 < 200'), 1, `_$0(`$2')', `$0(eval(`$1/2'),
36 substr(`$2', 0, eval(`$1/2')))$0(eval(len(defn(`tail'))` + $1 - $1/2'),
37 defn(`tail')substr(`$2', eval(`$1/2')))')')
38 chew(len(defn(`input')), defn(`input'))
41 include(`priority.m4')
43 define(`prep', `define(`Atk$2', eval(atk$2+$1*type$2))define(`eff$2',
44 eval(units$2*Atk$2))pushdef(`list'eval(1-type$2), $2)')
45 define(`reset', `undefine(`list0')undefine(`list1')forloop(1, 'max`,
47 define(`push', `_$0($1, eff$1)')
48 define(`_push', `ifelse($2, 0, `',
49 `insert(eval(`100000000-$1-$2*'''max``), $1)')')
50 define(`damage', `_$0(eff$1, dam$1, mod$2)')
51 define(`_damage', `eval(`$1*!($2&$3)*(1+!!(($2<<5)&$3))')')
52 define(`try', `ifelse(eff$2, 0, `popdef(`list'type$1)', off$2, 0,
53 `_$0(damage($1, $2), bestd, $2, eff$2)')')
54 define(`_try', `ifelse(eval(`$1>$2||($1&&$1==$2&&$4>='beste`)'), 1,
55 `define(`bestd', $1)define(`bestu', $3)define(`beste', $4)')')
56 define(`select', `ifelse($1, `', `', `define(`bestu', 0)define(`bestd',
57 0)define(`beste', 0)_$0($2)$0(pop)')')
58 define(`_select', `_stack_foreach(`list'type$1, `try($1, ', `)', `t')pair($1,
60 define(`pair', `ifelse($2, 0, `', `define(`def$1', $2)define(`off$2', $1)')')
61 define(`attack', `forloop_rev('max`, 1, `_$0(', `)')')
62 define(`_attack', `kill($1, def$1)')
63 define(`kill', `ifelse($2, `0', `', `_$0($1, $2, eff$2, damage($1, $2),
64 hp$2, Atk$2)define(`def$1', 0)define(`off$2', 0)')')
65 define(`_kill', `ifelse(eval(`$4>=$5'), 1, `-define(`eff$2',
66 eval(`($3/$6>$4/$5)*($3/$6-$4/$5)*$6'))')')
68 define(`round', `ifelse(forloop_arg(1, max, `push')select(pop)attack(), `', `',
69 `ifelse(eval(count%1000), 0, `output(1, `...boost $2, round $1')')define(
70 `count', incr(count))$0(incr($1), $2)')')
71 define(`tally', `+eff$1/Atk$1')
72 define(`battle', `reset($1)round(1, $1)ifelse(ifdef(`list1', $1, 0), 0,
73 `eval(forloop_arg(1, max, `tally'))', `$0(incr($1))')')
74 define(`part1', battle(0))
75 define(`part2', battle(1))