Day 14 solution
This commit is contained in:
@@ -144,3 +144,12 @@ There are 837 dots after 1 fold
|
|||||||
#### # #### ### # # ## # # ##
|
#### # #### ### # # ## # # ##
|
||||||
This is the activation code
|
This is the activation code
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Day fourteen
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ ./aoc2021 --fourteen
|
||||||
|
The solution for "fourteen" is:
|
||||||
|
The result of subtracting the least from most common element quantities is 2988
|
||||||
|
The result of subtracting the least from most common element quantities is 3572761917024
|
||||||
|
```
|
||||||
|
102
fourteen/input.txt
Normal file
102
fourteen/input.txt
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
VFHKKOKKCPBONFHNPHPN
|
||||||
|
|
||||||
|
VS -> B
|
||||||
|
HK -> B
|
||||||
|
FO -> P
|
||||||
|
NC -> F
|
||||||
|
VN -> C
|
||||||
|
BS -> O
|
||||||
|
HS -> K
|
||||||
|
NS -> C
|
||||||
|
CV -> P
|
||||||
|
NV -> C
|
||||||
|
PH -> H
|
||||||
|
PB -> B
|
||||||
|
PK -> K
|
||||||
|
HF -> P
|
||||||
|
FV -> C
|
||||||
|
NN -> H
|
||||||
|
VO -> K
|
||||||
|
VP -> P
|
||||||
|
BC -> B
|
||||||
|
KK -> S
|
||||||
|
OK -> C
|
||||||
|
PN -> H
|
||||||
|
SB -> V
|
||||||
|
KO -> P
|
||||||
|
KH -> C
|
||||||
|
KS -> S
|
||||||
|
FP -> B
|
||||||
|
PV -> B
|
||||||
|
BO -> C
|
||||||
|
OS -> H
|
||||||
|
NB -> S
|
||||||
|
SP -> C
|
||||||
|
HN -> N
|
||||||
|
FN -> B
|
||||||
|
PO -> O
|
||||||
|
FS -> O
|
||||||
|
NH -> B
|
||||||
|
SO -> P
|
||||||
|
OB -> S
|
||||||
|
KC -> C
|
||||||
|
OO -> H
|
||||||
|
BB -> V
|
||||||
|
SC -> F
|
||||||
|
NP -> P
|
||||||
|
SH -> C
|
||||||
|
BH -> O
|
||||||
|
BP -> F
|
||||||
|
CC -> S
|
||||||
|
BN -> H
|
||||||
|
SS -> P
|
||||||
|
BF -> B
|
||||||
|
VK -> P
|
||||||
|
OV -> H
|
||||||
|
FC -> S
|
||||||
|
VB -> S
|
||||||
|
PF -> N
|
||||||
|
HH -> O
|
||||||
|
HC -> V
|
||||||
|
CH -> B
|
||||||
|
HP -> H
|
||||||
|
FF -> H
|
||||||
|
VF -> V
|
||||||
|
CS -> F
|
||||||
|
KP -> F
|
||||||
|
OP -> H
|
||||||
|
KF -> F
|
||||||
|
PP -> V
|
||||||
|
OC -> C
|
||||||
|
PS -> F
|
||||||
|
ON -> H
|
||||||
|
BK -> B
|
||||||
|
HV -> S
|
||||||
|
CO -> K
|
||||||
|
FH -> C
|
||||||
|
FB -> F
|
||||||
|
OF -> V
|
||||||
|
SN -> S
|
||||||
|
PC -> K
|
||||||
|
NF -> F
|
||||||
|
NK -> P
|
||||||
|
NO -> P
|
||||||
|
CP -> P
|
||||||
|
CK -> S
|
||||||
|
HB -> H
|
||||||
|
BV -> C
|
||||||
|
SF -> K
|
||||||
|
HO -> H
|
||||||
|
OH -> B
|
||||||
|
KV -> S
|
||||||
|
KN -> F
|
||||||
|
SK -> K
|
||||||
|
VH -> S
|
||||||
|
CN -> S
|
||||||
|
VC -> P
|
||||||
|
CB -> H
|
||||||
|
SV -> S
|
||||||
|
VV -> P
|
||||||
|
CF -> F
|
||||||
|
FK -> F
|
||||||
|
KB -> V
|
24
fourteen/main.go
Normal file
24
fourteen/main.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
package fourteen
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type Fourteen struct {
|
||||||
|
polymer polymer
|
||||||
|
}
|
||||||
|
|
||||||
|
func Init(filepath string) *Fourteen {
|
||||||
|
fourteen := &Fourteen{
|
||||||
|
polymer: polymer{},
|
||||||
|
}
|
||||||
|
|
||||||
|
fourteen.polymer.load(filepath)
|
||||||
|
return fourteen
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Fourteen) Answer() string {
|
||||||
|
return fmt.Sprintf("The result of subtracting the least from most common element quantities is %d", d.polymer.elementCount(10))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Fourteen) FollowUp() string {
|
||||||
|
return fmt.Sprintf("The result of subtracting the least from most common element quantities is %d", d.polymer.elementCountMap(40))
|
||||||
|
}
|
146
fourteen/polymer.go
Normal file
146
fourteen/polymer.go
Normal file
@@ -0,0 +1,146 @@
|
|||||||
|
package fourteen
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type polymer struct {
|
||||||
|
template string
|
||||||
|
rules map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *polymer) load(filename string) error {
|
||||||
|
file, err := os.Open(filename)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
|
||||||
|
p.rules = map[string]string{}
|
||||||
|
scannedTemplate := false
|
||||||
|
for scanner.Scan() {
|
||||||
|
if !scannedTemplate {
|
||||||
|
p.template = scanner.Text()
|
||||||
|
|
||||||
|
scannedTemplate = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if scanner.Text() == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var pair, insert string
|
||||||
|
if count, err := fmt.Sscanf(scanner.Text(), "%s -> %s", &pair, &insert); count != 2 || err != nil {
|
||||||
|
return fmt.Errorf("expected to scan 2 values from %q, found %d: %w", scanner.Text(), count, err)
|
||||||
|
}
|
||||||
|
p.rules[pair] = insert
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *polymer) elementCount(size int) int {
|
||||||
|
result := p.step(size)
|
||||||
|
elemCounts := map[rune]int{}
|
||||||
|
|
||||||
|
for _, r := range result {
|
||||||
|
elemCounts[r]++
|
||||||
|
}
|
||||||
|
|
||||||
|
min := len(result)
|
||||||
|
max := 0
|
||||||
|
for _, v := range elemCounts {
|
||||||
|
if v < min {
|
||||||
|
min = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v > max {
|
||||||
|
max = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max - min
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *polymer) elementCountMap(size int) int {
|
||||||
|
_, counts := p.stepMap(size)
|
||||||
|
|
||||||
|
min := -1
|
||||||
|
max := -1
|
||||||
|
for _, v := range counts {
|
||||||
|
if v < min || min == -1 {
|
||||||
|
min = v
|
||||||
|
}
|
||||||
|
|
||||||
|
if v > max {
|
||||||
|
max = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return max - min
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *polymer) stepMap(steps int) (map[string]int, map[string]int) {
|
||||||
|
pairs := map[string]int{}
|
||||||
|
counts := map[string]int{}
|
||||||
|
|
||||||
|
// Build initial pairs and counts from template
|
||||||
|
for i := 0; i < len(p.template)-1; i++ {
|
||||||
|
// Count first element from pair
|
||||||
|
counts[string(p.template[i])]++
|
||||||
|
pairs[fmt.Sprintf("%c%c", p.template[i], p.template[i+1])]++
|
||||||
|
// If this is the last pair add the second element
|
||||||
|
if i == len(p.template)-2 {
|
||||||
|
counts[string(p.template[i+1])]++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < steps; i++ {
|
||||||
|
pairs, counts = p.stepMapOne(pairs, counts)
|
||||||
|
}
|
||||||
|
|
||||||
|
return pairs, counts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *polymer) stepMapOne(pairs map[string]int, counts map[string]int) (map[string]int, map[string]int) {
|
||||||
|
newPairs := map[string]int{}
|
||||||
|
for k, v := range pairs {
|
||||||
|
result := p.rules[k]
|
||||||
|
counts[result] += (1 * v)
|
||||||
|
pair1 := fmt.Sprintf("%c%s", k[0], result)
|
||||||
|
pair2 := fmt.Sprintf("%s%c", result, k[1])
|
||||||
|
newPairs[pair1] += 1 * v
|
||||||
|
newPairs[pair2] += 1 * v
|
||||||
|
}
|
||||||
|
|
||||||
|
return newPairs, counts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *polymer) step(steps int) string {
|
||||||
|
seed := p.template
|
||||||
|
for i := 0; i < steps; i++ {
|
||||||
|
seed = p.stepOne(seed)
|
||||||
|
}
|
||||||
|
|
||||||
|
return seed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *polymer) stepOne(from string) string {
|
||||||
|
result := ""
|
||||||
|
for i := 0; i < len(from)-1; i++ {
|
||||||
|
// Add first element from pair
|
||||||
|
result += string(from[i])
|
||||||
|
// Lookup and add element result from pair
|
||||||
|
pair := fmt.Sprintf("%c%c", from[i], from[i+1])
|
||||||
|
result += p.rules[pair]
|
||||||
|
// If this is the last pair add the second element
|
||||||
|
if i == len(from)-2 {
|
||||||
|
result += string(from[i+1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
72
fourteen/polymer_test.go
Normal file
72
fourteen/polymer_test.go
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
package fourteen
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func Test_read(t *testing.T) {
|
||||||
|
p := polymer{}
|
||||||
|
if err := p.load("test_input.txt"); err != nil {
|
||||||
|
t.Log(err)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.template != "NNCB" {
|
||||||
|
t.Logf("Expected template of NNCB, found %s", p.template)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(p.rules) != 16 {
|
||||||
|
t.Logf("Expected 16 rules, found %d", len(p.rules))
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_step(t *testing.T) {
|
||||||
|
p := polymer{}
|
||||||
|
p.load("test_input.txt")
|
||||||
|
|
||||||
|
if result := p.step(1); result != "NCNBCHB" {
|
||||||
|
t.Logf("Expected NCNBCHB, found %s", result)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := p.step(2); result != "NBCCNBBBCBHCB" {
|
||||||
|
t.Logf("Expected NBCCNBBBCBHCB, found %s", result)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := p.step(3); result != "NBBBCNCCNBBNBNBBCHBHHBCHB" {
|
||||||
|
t.Logf("Expected NBBBCNCCNBBNBNBBCHBHHBCHB, found %s", result)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := p.step(4); result != "NBBNBNBBCCNBCNCCNBBNBBNBBBNBBNBBCBHCBHHNHCBBCBHCB" {
|
||||||
|
t.Logf("Expected NBBNBNBBCCNBCNCCNBBNBBNBBBNBBNBBCBHCBHHNHCBBCBHCB, found %s", result)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_elemCount(t *testing.T) {
|
||||||
|
p := polymer{}
|
||||||
|
p.load("test_input.txt")
|
||||||
|
|
||||||
|
if result := p.elementCount(10); result != 1588 {
|
||||||
|
t.Logf("Expected a result of 1588, got %d", result)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_elemMapCount(t *testing.T) {
|
||||||
|
p := polymer{}
|
||||||
|
p.load("test_input.txt")
|
||||||
|
|
||||||
|
if result := p.elementCountMap(10); result != 1588 {
|
||||||
|
t.Logf("Expected a result of 1588, got %d", result)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
if result := p.elementCountMap(40); result != 2188189693529 {
|
||||||
|
t.Logf("Expected a result of 2188189693529, got %d", result)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
}
|
18
fourteen/test_input.txt
Normal file
18
fourteen/test_input.txt
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
NNCB
|
||||||
|
|
||||||
|
CH -> B
|
||||||
|
HH -> N
|
||||||
|
CB -> H
|
||||||
|
NH -> C
|
||||||
|
HB -> C
|
||||||
|
HC -> B
|
||||||
|
HN -> C
|
||||||
|
NN -> C
|
||||||
|
BH -> H
|
||||||
|
NC -> B
|
||||||
|
NB -> B
|
||||||
|
BN -> B
|
||||||
|
BB -> N
|
||||||
|
BC -> B
|
||||||
|
CC -> N
|
||||||
|
CN -> C
|
3
main.go
3
main.go
@@ -9,6 +9,7 @@ import (
|
|||||||
"unsupervised.ca/aoc2021/eleven"
|
"unsupervised.ca/aoc2021/eleven"
|
||||||
"unsupervised.ca/aoc2021/five"
|
"unsupervised.ca/aoc2021/five"
|
||||||
"unsupervised.ca/aoc2021/four"
|
"unsupervised.ca/aoc2021/four"
|
||||||
|
"unsupervised.ca/aoc2021/fourteen"
|
||||||
"unsupervised.ca/aoc2021/nine"
|
"unsupervised.ca/aoc2021/nine"
|
||||||
"unsupervised.ca/aoc2021/one"
|
"unsupervised.ca/aoc2021/one"
|
||||||
"unsupervised.ca/aoc2021/seven"
|
"unsupervised.ca/aoc2021/seven"
|
||||||
@@ -61,6 +62,8 @@ func main() {
|
|||||||
day = twelve.Init("twelve/input.txt")
|
day = twelve.Init("twelve/input.txt")
|
||||||
case "thirteen":
|
case "thirteen":
|
||||||
day = thirteen.Init("thirteen/input.txt")
|
day = thirteen.Init("thirteen/input.txt")
|
||||||
|
case "fourteen":
|
||||||
|
day = fourteen.Init("fourteen/input.txt")
|
||||||
default:
|
default:
|
||||||
fmt.Printf("%q does not have a solution.\n", flagParts[1])
|
fmt.Printf("%q does not have a solution.\n", flagParts[1])
|
||||||
help()
|
help()
|
||||||
|
Reference in New Issue
Block a user