201 lines
3.7 KiB
Go
201 lines
3.7 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"math"
|
|
"os"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func processLines(path string, f func(string) (stop bool, err error)) error {
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
stop, err := f(scanner.Text())
|
|
if stop || err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
var memExtractor = regexp.MustCompile(`^mem\[([0-9]+)] = ([0-9]+)`)
|
|
|
|
func powInt(x, y int) int {
|
|
return int(math.Pow(float64(x), float64(y)))
|
|
}
|
|
|
|
func applyMask(mask string, v int) (int, error) {
|
|
for i := 0; i < len(mask); i++ {
|
|
m := mask[len(mask)-i-1]
|
|
switch m {
|
|
case 'X':
|
|
case '1':
|
|
v |= powInt(2, i)
|
|
case '0':
|
|
v &^= powInt(2, i)
|
|
default:
|
|
return 0, fmt.Errorf("could not apply mask %v in position %d", m, i)
|
|
}
|
|
}
|
|
|
|
return v, nil
|
|
}
|
|
|
|
func sprintBinArray(a []int, z int) string {
|
|
r := " "
|
|
|
|
for _, v := range a {
|
|
f := fmt.Sprintf("%%%db(%%d)", z)
|
|
r += fmt.Sprintf(f, v, v)
|
|
}
|
|
|
|
return fmt.Sprintf("[%s]", r)
|
|
}
|
|
|
|
func applyFloatingMask(mask string, v int) ([]int, error) {
|
|
base2 := 2
|
|
results := []int{v}
|
|
|
|
// fmt.Printf("Applying %s to %8b\n", mask, v)
|
|
|
|
for i := 0; i < len(mask); i++ {
|
|
m := mask[len(mask)-i-1]
|
|
// fmt.Printf("Apply %s at %d ", string(m), i)
|
|
|
|
resultLen := len(results)
|
|
for j := 0; j < resultLen; j++ {
|
|
switch m {
|
|
case 'X':
|
|
// Add a 0 mask to end of results
|
|
results = append(results, results[j]|powInt(base2, i))
|
|
// Apply a 1 mask in place
|
|
results[j] &^= powInt(base2, i)
|
|
case '1':
|
|
results[j] |= powInt(base2, i)
|
|
case '0':
|
|
// results[j] &^= powInt(base2, i)
|
|
default:
|
|
return results, fmt.Errorf("could not apply mask %v in position %d", m, i)
|
|
}
|
|
}
|
|
|
|
// fmt.Printf("Result %s\n", sprintBinArray(results, 8))
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
func parseMemValues(line string) (loc int, val int, err error) {
|
|
match := memExtractor.FindStringSubmatch(line)
|
|
if match == nil {
|
|
err = fmt.Errorf("could not extract mem val in %s", line)
|
|
|
|
return
|
|
}
|
|
|
|
loc, err = strconv.Atoi(match[1])
|
|
if err != nil {
|
|
err = fmt.Errorf("error parsing int from %s: %w", line, err)
|
|
|
|
return
|
|
}
|
|
|
|
val, err = strconv.Atoi(match[2])
|
|
if err != nil {
|
|
err = fmt.Errorf("error parsing int from %s: %w", line, err)
|
|
|
|
return
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func part1() {
|
|
var mask string
|
|
|
|
mem := map[int]int{}
|
|
|
|
if err := processLines("input.txt", func(line string) (bool, error) {
|
|
if strings.HasPrefix(line, "mask") {
|
|
mask = strings.TrimPrefix(line, "mask = ")
|
|
} else {
|
|
loc, val, err := parseMemValues(line)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
val, err = applyMask(mask, val)
|
|
if err != nil {
|
|
return false, fmt.Errorf("error applying mask to value on line %s: %w", line, err)
|
|
}
|
|
// fmt.Printf("mem[%d] = %d\n", loc, val)
|
|
mem[loc] = val
|
|
}
|
|
|
|
return false, nil
|
|
}); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
sum := 0
|
|
for _, v := range mem {
|
|
sum += v
|
|
}
|
|
|
|
fmt.Printf("Total value in memory %d\n", sum)
|
|
}
|
|
|
|
func part2() {
|
|
var mask string
|
|
|
|
mem := map[int]int{}
|
|
|
|
if err := processLines("input.txt", func(line string) (bool, error) {
|
|
if strings.HasPrefix(line, "mask") {
|
|
mask = strings.TrimPrefix(line, "mask = ")
|
|
} else {
|
|
loc, val, err := parseMemValues(line)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
locs, err := applyFloatingMask(mask, loc)
|
|
if err != nil {
|
|
return false, fmt.Errorf("error applying mask to value on line %s: %w", line, err)
|
|
}
|
|
for _, l := range locs {
|
|
mem[l] = val
|
|
}
|
|
}
|
|
|
|
return false, nil
|
|
}); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
sum := 0
|
|
for _, v := range mem {
|
|
sum += v
|
|
}
|
|
|
|
fmt.Printf("Total value in memory %d\n", sum)
|
|
}
|
|
|
|
func main() {
|
|
part1()
|
|
part2()
|
|
}
|