day 25 optimize and improve heuristics
[aoc_eblake.git] / 2015 / day21.m4
blob647a86226e9614190d778d752c29aacb94f6a57c
1 divert(-1)dnl -*- m4 -*-
2 # Usage: m4 [-Dfile=day21.input] day21.m4
4 include(`common.m4')ifelse(common(21), `ok', `',
5 `errprint(`Missing common initialization
6 ')m4exit(1)')
8 define(`prep', `define(`boss_hp', $3)define(`boss_damage',
9   $5)define(`boss_armor', $7)')
10 prep(translit(include(defn(`file')), ` 'nl, `,,'))
11 define(`part1', 1000)define(`part2', 0)
13 define(`wc0', 8)define(`wd0', 4)
14 define(`wc1', 10)define(`wd1', 5)
15 define(`wc2', 25)define(`wd2', 6)
16 define(`wc3', 40)define(`wd3', 7)
17 define(`wc4', 74)define(`wd4', 8)
19 define(`ac0', 0)define(`aa0', 0)
20 define(`ac1', 13)define(`aa1', 1)
21 define(`ac2', 31)define(`aa2', 2)
22 define(`ac3', 53)define(`aa3', 3)
23 define(`ac4', 75)define(`aa4', 4)
24 define(`ac5', 102)define(`aa5', 5)
26 define(`rc0', 25)define(`rd0', 1)define(`ra0', 0)
27 define(`rc1', 50)define(`rd1', 2)define(`ra1', 0)
28 define(`rc2', 100)define(`rd2', 3)define(`ra2', 0)
29 define(`rc3', 20)define(`rd3', 0)define(`ra3', 1)
30 define(`rc4', 40)define(`rd4', 0)define(`ra4', 2)
31 define(`rc5', 80)define(`rd5', 0)define(`ra5', 3)
33 define(`limit', `ifelse(a$3, eval($2 - ($1 - $3)), `$0($1, $2, decr($3))',
34   `define(`a$3', incr(a$3))forloop_arg(incr($3), decr($2), `_$0')nextcomb($1,
35   $2)')')
36 define(`_limit', `define(`a$1', incr(defn(`a'decr($1))))')
37 define(`nextcomb', `try(forloop(0, decr($1), `,defn(`a'', `)'))ifelse(
38   eval(a0 < $2 - $1), 1, `limit($1, $2, decr($1))')')
39 define(`comb', `ifelse($1, 0, `try(0)', `forloop_arg(0, decr($1),
40   `_$0')nextcomb($1, $2)')')
41 define(`_comb', `define(`a$1', $1)')
43 # defender hp, attacker damage, defender armor => turns to defeat
44 define(`side', `ifelse(eval($2 > $3), 1, `eval(($1 + $2 - $3 - 1) /
45   ($2 - $3))', $1)')
46 # player (hp, damage, armor), boss (hp, damage, armor) => 1/0 for win/loss
47 define(`battle', `eval(side($4, $2, $6) <= side($1, $5, $3))')
48 # player (wd + rd...), (aa + ra...), (wc + ac + rc...)
49 define(`check', `ifelse(battle(100, ($1), ($2), 'boss_hp`, 'boss_damage`,
50   'boss_armor`), 1, `ifelse(eval(($3) < part1), 1, `define(`part1',
51   eval($3))')', `ifelse(eval(($3) > part2), 1, `define(`part2', eval($3))')')')
52 define(`try1', `check(wd$1, aa$2, wc$1 + ac$2)')
53 define(`try2', `check(wd$1 + rd$3, aa$2 + ra$3, wc$1 + ac$2 + rc$3)')
54 define(`try3', `check(wd$1 + rd$3 + rd$4, aa$2 + ra$3 + ra$4,
55   wc$1 + ac$2 + rc$3 + rc$4)')
56 define(`try', `try$#(W, A$@)')
57 forloop_var(`W', 0, 4, `forloop_var(`A', 0, 5, `try()comb(1, 6)comb(2, 6)')')
59 divert`'part1
60 part2