Code for the Advent of Code event
aoc
advent-of-code
1replacements = {}
2
3sequence = {}
4
5copy = (tbl) ->
6 return tbl unless type(tbl) == 'table'
7 {k, copy v for k, v in pairs tbl}
8
9parse = (line) ->
10 source, replace = line\match '(%a+) => (%a+)'
11
12 if source and replace
13 replacements[source] = {} unless replacements[source]
14 replacements[source][#replacements[source] + 1] = replace
15 elseif line\match '%a+'
16 sequence = [element for element in line\gmatch '[A-Z][a-z]?']
17
18count_molecules = ->
19 generated = {}
20 count = 0
21 for source, targets in pairs replacements
22 for i = 1, #sequence
23 continue unless sequence[i] == source
24 for target in *targets
25 seq = copy sequence
26 seq[i] = target
27 str = table.concat seq, ''
28 count += 1 unless generated[str]
29 generated[str] = true
30 count
31
32parse_sequence = (str) ->
33 [element for element in str\gmatch '[A-Z][a-z]?']
34
35reformat = (sequence using nil) ->
36 new_seq = {}
37 for elements in *sequence
38 for element in elements\gmatch '[A-Z][a-z]?'
39 new_seq[#new_seq + 1] = element
40 new_seq
41
42reduce = (current, counter, target, mapping) ->
43 --coroutine.yield -1 if counter > 1
44 coroutine.yield counter if str == target
45
46 for source, replace in pairs mapping
47 --for i = 1, #current
48 new, num = current\gsub(source, replace, 1)
49 coroutine.yield -1 if num == 0 or #new > #current
50 reduce new, counter + 1, target, mapping
51
52get_counts = (current, target, mapping) ->
53 coroutine.wrap -> reduce current, 1, target, mapping
54
55get_reverse_mapping = ->
56 mapping = {}
57
58 for k, v in pairs replacements
59 for key in *v
60 mapping[key] = k
61
62 mapping
63
64make_molecule = ->
65 reverse = get_reverse_mapping!
66
67 molecule = table.concat sequence, ''
68
69 counts = {}
70
71 for count in get_counts molecule, 'e', reverse
72 continue if count == -1
73 print count
74 counts[#counts + 1] = count
75
76{ :parse, :count_molecules, :make_molecule }