Files
aoc2020/fourteen/day_fourteen.go
2020-12-14 21:21:39 -04:00

200 lines
3.5 KiB
Go

package fourteen
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
type command struct {
mem int
pointer int
mask string
isMask bool
}
type computer struct {
memory map[int]uint64
m map[int]bool
mask string
ones uint64
zeros uint64
input []command
executed bool
}
func (c *computer) load(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
inputs := strings.Split(scanner.Text(), " = ")
if len(inputs) != 2 {
return fmt.Errorf("Unable to parse input %q", scanner.Text())
}
if inputs[0] == "mask" {
c.input = append(c.input, command{
isMask: true,
mask: inputs[1],
})
} else {
var pointer, mem int
count, err := fmt.Sscanf(inputs[0], "mem[%d]", &pointer)
if count != 1 || err != nil {
return fmt.Errorf("Unable to parse memory location from %s", inputs[0])
}
mem, err = strconv.Atoi(inputs[1])
c.input = append(c.input, command{
isMask: false,
mem: mem,
pointer: pointer,
})
}
}
c.memory = make(map[int]uint64, len(c.input))
return nil
}
func newComputer(filename string) *computer {
c := &computer{}
c.mask = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
c.executed = false
if err := c.load(filename); err != nil {
fmt.Println(err.Error())
return nil
}
return c
}
func (c *computer) execute() {
c.executed = true
for _, input := range c.input {
if input.isMask {
c.mask = input.mask
c.ones = 0
c.zeros = 0
for i := 0; i < len(input.mask); i++ {
switch string(input.mask[len(input.mask)-1-i]) {
case "0":
c.zeros += 1 << i
case "1":
c.ones += 1 << i
}
}
continue
}
value := uint64(input.mem)
value |= c.ones
value &^= c.zeros
c.memory[input.pointer] = value
}
}
func (c *computer) executeV2() {
c.executed = true
for _, input := range c.input {
if input.isMask {
c.mask = input.mask
c.ones = 0
c.zeros = 0
for i := 0; i < len(input.mask); i++ {
switch string(input.mask[len(input.mask)-1-i]) {
case "0":
c.zeros += 1 << i
case "1":
c.ones += 1 << i
}
}
continue
}
value := uint64(input.mem)
location := uint64(input.pointer) | c.ones
for _, p := range c.memMask(location) {
c.memory[p] = value
}
}
}
func (c *computer) memMask(p uint64) []int {
locations := []int{0}
for i := 0; i < len(c.mask); i++ {
switch string(c.mask[len(c.mask)-1-i]) {
case "X":
for j, l := range locations {
locations = append(locations, int(l|(1<<i)))
locations[j] = int(l &^ (1 << i))
}
case "1":
for j := 0; j < len(locations); j++ {
locations[j] = int(locations[j] | (1 << i))
}
case "0":
for j := 0; j < len(locations); j++ {
locations[j] = locations[j] | int(p&(1<<i))
}
}
}
return locations
}
func (c *computer) sum(version int) int {
if !c.executed {
switch version {
case 1:
c.execute()
case 2:
c.executeV2()
}
}
sum := 0
for _, v := range c.memory {
sum += int(v)
}
return sum
}
// PartOne Execute the initialization program
func PartOne() string {
c := newComputer("fourteen/input.txt")
if c == nil {
return "Unable to load program"
}
return fmt.Sprintf("The memory value after execution is %d", c.sum(1))
}
// PartTwo Execute the initialization program with version 2
func PartTwo() string {
c := newComputer("fourteen/input.txt")
if c == nil {
return "Unable to load program"
}
return fmt.Sprintf("The memory value after execution is %d", c.sum(2))
}