Skip to content

Commit 870861d

Browse files
author
Adrian Reimann
committed
optimisation of day 14 part 1 to solve part 2 for a bigger result set or more steps to run
1 parent 56581ee commit 870861d

File tree

3 files changed

+176
-25
lines changed

3 files changed

+176
-25
lines changed

day_14/14-1.php

+107-25
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
<?php
22

33
//how many times to apply the rules to the template
4-
const STEPS = 10;
4+
if(!isset($steps_to_run)) {
5+
$steps_to_run = 10;
6+
}
57

68
//read input and split it into the initial templates and the polymer rules
79
$template = "";
810
$rules = [];
9-
$input = fopen("testinput.txt", "r");
11+
$input = fopen("input.txt", "r");
1012
while (($input_line = fgets($input)) !== false) {
1113
if(trim($input_line) == "") continue; //skip the empty line between template and rules
1214

@@ -23,36 +25,116 @@
2325
}
2426
fclose($input);
2527

26-
//apply rules until we ran STEPS times
28+
//convert the $template into a pair count
29+
$template_pairs = [];
30+
$template_pieces = str_split($template);
31+
foreach ($template_pieces as $key => $poly) {
32+
if (!isset($template_pieces[$key + 1])) {
33+
break;//for the last key we cannot make another pair so stop here
34+
}
35+
36+
//get the pair
37+
$lookup_pair = $poly . $template_pieces[$key+1];
38+
39+
//if there is no count for this pair, set it to 1
40+
if(!isset($template_pairs[$lookup_pair])) {
41+
$template_pairs[$lookup_pair] = 1;
42+
}
43+
else {
44+
$template_pairs[$lookup_pair]++; //else increase count
45+
}
46+
}
47+
48+
//apply rules until we ran $steps_to_run times
2749
$i = 0;
28-
while ($i < STEPS) {
50+
while ($i < $steps_to_run) {
51+
$template_pairs = applyRulesToPairs($template_pairs, $rules);
52+
$i++;
53+
}
54+
55+
//Count occurrences, order by count, find highest and lowest, and subtract for result
56+
$occurrences = countOccurrences($template_pairs);
57+
$result = array_pop($occurrences) - $occurrences[0];
2958

59+
//result
60+
echo "After " . $steps_to_run . " steps, most common minus least common element quantities result in $result." . PHP_EOL;
61+
62+
63+
/**
64+
* Loop through input list of pairs, create two new pairs for each input pair, using the char obtained from rules.
65+
* Keep count of new pairs based on original pairs.
66+
*
67+
* @author Adrian
68+
* @date_created 2021-12-14
69+
*
70+
* @param array $template_pairs the pairs to apply the polymerization rules to
71+
* @param array $rules rules to apply in the format 'pair' => 'new_char'
72+
*
73+
* @return array the new list of pairs and their counts
74+
*/
75+
function applyRulesToPairs($template_pairs, $rules) {
3076
//start new string as empty
31-
$new_template = '';
32-
$template_pieces = str_split($template);
33-
34-
//for every character, create a lookup of that character and the next
35-
foreach ($template_pieces as $key => $poly) {
36-
if(!isset($template_pieces[$key+1])) {
37-
$new_template .= $poly; //if we are on the last character, just append it - no pair to look up
38-
break;
39-
}
77+
$new_template_pairs = [];
4078

41-
//find new polymer to be added to the middle
42-
$lookup_pair = $poly . $template_pieces[$key+1];
43-
$new_poly = $rules[$lookup_pair];
79+
//loop through the pairs and convert them into the new pairs, keeping the counts related
80+
foreach ($template_pairs as $lookup_pair => $count) {
4481

45-
$new_template .= $poly . $new_poly; //add first char and the new one (second char of the pair will be added on next loop)
82+
//for every pair, we have two new pairs afterwards (as the new letter gets added "in the middle"
83+
$new_pairs = [
84+
substr($lookup_pair, 0 , 1) . $rules[$lookup_pair],
85+
$rules[$lookup_pair] . substr($lookup_pair, 1, 1),
86+
];
87+
88+
foreach ($new_pairs as $new_pair) {
89+
//if there is no count for this pair, set it to as many as there were related lookup pairs
90+
if(!isset($new_template_pairs[$new_pair])) {
91+
$new_template_pairs[$new_pair] = $count;
92+
}
93+
else {
94+
$new_template_pairs[$new_pair] += $count; //else increase count by count of lookup pairs
95+
}
96+
}
4697
}
4798

48-
$template = $new_template;
49-
$i++;
99+
//return the new pairs
100+
return $new_template_pairs;
50101
}
51102

52-
//count occurrences, order by count, find highest and lowest, and subtract
53-
$counter = count_chars($template, 1);
54-
sort($counter);
55-
$result = array_pop($counter) - reset($counter);
103+
/**
104+
* Count occurrences per character and return them ordered ascending.
105+
* Note the "hack" by rounding when splitting the count by 2.
106+
* As we store pairs, every letter is part of two pairs except for the first and last of the initial string.
107+
* Meaning when we split the char count of those two letters (assuming they are not the same, in which case we are fine),
108+
* we get a .5 decimal for their count, which we simply round up to count them as 1 character.
109+
*
110+
* @author Adrian
111+
* @date_created 2021-12-14
112+
*
113+
* @param array $template_pairs the pairs to count occurrences from
114+
*
115+
* @return array occurrence count per character
116+
*/
117+
function countOccurrences(array $template_pairs) {
118+
$occurrences = [];
119+
foreach ($template_pairs as $pair => $count) {
120+
$chars = str_split($pair);
56121

57-
//result
58-
echo "After " . STEPS . " steps, most common minus least common element quantities result in $result." . PHP_EOL;
122+
foreach ($chars as $char) {
123+
if (!isset($occurrences[$char])) {
124+
$occurrences[$char] = $count;
125+
}
126+
else {
127+
$occurrences[$char] += $count;
128+
}
129+
}
130+
}
131+
132+
//loop through and half the occurrences we added
133+
foreach ($occurrences as $key => $occurrence) {
134+
$occurrences[$key] = round($occurrence / 2);
135+
}
136+
137+
//sort and return
138+
sort($occurrences);
139+
return $occurrences;
140+
}

day_14/14-2.php

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<?php
2+
3+
$steps_to_run = 40;
4+
5+
include('14-1.php');

day_14/puzzle.txt

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
--- Day 14: Extended Polymerization ---
2+
3+
The incredible pressures at this depth are starting to put a strain on your submarine. The submarine has polymerization equipment that would produce suitable materials to reinforce the submarine, and the nearby volcanically-active caves should even have the necessary input elements in sufficient quantities.
4+
5+
The submarine manual contains instructions for finding the optimal polymer formula; specifically, it offers a polymer template and a list of pair insertion rules (your puzzle input). You just need to work out what polymer would result after repeating the pair insertion process a few times.
6+
7+
For example:
8+
9+
NNCB
10+
11+
CH -> B
12+
HH -> N
13+
CB -> H
14+
NH -> C
15+
HB -> C
16+
HC -> B
17+
HN -> C
18+
NN -> C
19+
BH -> H
20+
NC -> B
21+
NB -> B
22+
BN -> B
23+
BB -> N
24+
BC -> B
25+
CC -> N
26+
CN -> C
27+
28+
The first line is the polymer template - this is the starting point of the process.
29+
30+
The following section defines the pair insertion rules. A rule like AB -> C means that when elements A and B are immediately adjacent, element C should be inserted between them. These insertions all happen simultaneously.
31+
32+
So, starting with the polymer template NNCB, the first step simultaneously considers all three pairs:
33+
34+
The first pair (NN) matches the rule NN -> C, so element C is inserted between the first N and the second N.
35+
The second pair (NC) matches the rule NC -> B, so element B is inserted between the N and the C.
36+
The third pair (CB) matches the rule CB -> H, so element H is inserted between the C and the B.
37+
38+
Note that these pairs overlap: the second element of one pair is the first element of the next pair. Also, because all pairs are considered simultaneously, inserted elements are not considered to be part of a pair until the next step.
39+
40+
After the first step of this process, the polymer becomes NCNBCHB.
41+
42+
Here are the results of a few steps using the above rules:
43+
44+
Template: NNCB
45+
After step 1: NCNBCHB
46+
After step 2: NBCCNBBBCBHCB
47+
After step 3: NBBBCNCCNBBNBNBBCHBHHBCHB
48+
After step 4: NBBNBNBBCCNBCNCCNBBNBBNBBBNBBNBBCBHCBHHNHCBBCBHCB
49+
50+
This polymer grows quickly. After step 5, it has length 97; After step 10, it has length 3073. After step 10, B occurs 1749 times, C occurs 298 times, H occurs 161 times, and N occurs 865 times; taking the quantity of the most common element (B, 1749) and subtracting the quantity of the least common element (H, 161) produces 1749 - 161 = 1588.
51+
52+
Apply 10 steps of pair insertion to the polymer template and find the most and least common elements in the result. What do you get if you take the quantity of the most common element and subtract the quantity of the least common element?
53+
54+
Your puzzle answer was 2003.
55+
56+
--- Part Two ---
57+
58+
The resulting polymer isn't nearly strong enough to reinforce the submarine. You'll need to run more steps of the pair insertion process; a total of 40 steps should do it.
59+
60+
In the above example, the most common element is B (occurring 2192039569602 times) and the least common element is H (occurring 3849876073 times); subtracting these produces 2188189693529.
61+
62+
Apply 40 steps of pair insertion to the polymer template and find the most and least common elements in the result. What do you get if you take the quantity of the most common element and subtract the quantity of the least common element?
63+
64+
Your puzzle answer was 2276644000111.

0 commit comments

Comments
 (0)