mirror of
https://github.com/RussellChamp/advent-of-code-2021.git
synced 2026-10-27 21:52:32 +00:00
day 3
This commit is contained in:
1 parent
73933e8e39
commit
32827d0602
3 files changed
+217
-1
No files matched your search
+205
@@ -0,0 +1,205 @@
|
||||
/* Day 3: Binary Diagnostic */
|
||||
package main
|
||||
|
||||
import (
|
||||
"AoC2021/utils/timer"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const BITLENGTH = 12
|
||||
|
||||
func check(e error) {
|
||||
if e != nil {
|
||||
fmt.Println("Oh snap!")
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
fmt.Println("--- Day 3: Binary Diagnostic ---")
|
||||
timer.Start()
|
||||
part1()
|
||||
timer.Tick()
|
||||
fmt.Println()
|
||||
|
||||
part2()
|
||||
timer.Tick()
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func bodgeData(bits [BITLENGTH]int, fn func(int) bool) int {
|
||||
value := 0
|
||||
for idx := 0; idx < BITLENGTH; idx++ {
|
||||
//fmt.Print("bodgeData: comparing ", bits[idx])
|
||||
if fn(bits[idx]) {
|
||||
value += 1 << (BITLENGTH - idx - 1)
|
||||
//fmt.Print(": value is now ", value)
|
||||
}
|
||||
//fmt.Println()
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func part1() {
|
||||
fmt.Println("* Part 1 *")
|
||||
fmt.Println(" Goal: Use the binary numbers in your diagnostic report to calculate the gamma rate and epsilon rate, then multiply them together")
|
||||
fmt.Println(" Answer: What is the power consumption of the submarine?")
|
||||
|
||||
input, err := os.Open("./input.txt")
|
||||
defer input.Close()
|
||||
check(err)
|
||||
|
||||
reader := bufio.NewReader(input)
|
||||
lines := 0
|
||||
var bits [BITLENGTH]int
|
||||
|
||||
activeBit := 0
|
||||
for {
|
||||
if c, _, err := reader.ReadRune(); err != nil {
|
||||
if err == io.EOF {
|
||||
lines++
|
||||
break
|
||||
} else {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
if string(c) == "\n" {
|
||||
lines++
|
||||
activeBit = 0
|
||||
continue
|
||||
} else {
|
||||
val, err := strconv.Atoi(string(c))
|
||||
check(err)
|
||||
bits[activeBit] += val
|
||||
activeBit += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gamma := bodgeData(bits, func(val int) bool { return val > lines/2 })
|
||||
epsilon := bodgeData(bits, func(val int) bool { return val < lines/2 })
|
||||
|
||||
fmt.Printf("Read %d lines from input\n", lines)
|
||||
fmt.Println("bits:", bits)
|
||||
fmt.Printf("Gamma: %d, Epsilon: %d, Solution: %d\n", gamma, epsilon, gamma*epsilon)
|
||||
}
|
||||
|
||||
// compare a byte slice with a filter
|
||||
func byteMatch(value []byte, filter [BITLENGTH]byte) bool {
|
||||
if len(value) != len(filter) {
|
||||
return false
|
||||
}
|
||||
for idx, b := range filter {
|
||||
if b == byte(0) {
|
||||
// once we hit a part of the filter with empty values, we are good
|
||||
return true
|
||||
}
|
||||
if b != value[idx] {
|
||||
// if a part of our value every doesn't match the filter, we are bad
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func getBitCount(input *os.File, position int, filter [BITLENGTH]byte) (int, int) {
|
||||
scanner := bufio.NewScanner(input)
|
||||
count := 0
|
||||
lines := 0
|
||||
for scanner.Scan() {
|
||||
bytes := scanner.Bytes()
|
||||
if !byteMatch(bytes, filter) {
|
||||
continue
|
||||
}
|
||||
lines += 1
|
||||
if len(bytes) < position {
|
||||
panic("not enough bytes")
|
||||
}
|
||||
if bytes[position] == byte('1') {
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
|
||||
return count, lines
|
||||
}
|
||||
|
||||
func gitBitValue(input *os.File, filter [BITLENGTH]byte) int {
|
||||
scanner := bufio.NewScanner(input)
|
||||
value := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
bytes := scanner.Bytes()
|
||||
if !byteMatch(bytes, filter) {
|
||||
continue
|
||||
}
|
||||
// we got a match!
|
||||
for idx, b := range bytes {
|
||||
if b == byte('1') {
|
||||
value += 1 << (BITLENGTH - idx - 1)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func doTheThing(input *os.File, reverse bool) int {
|
||||
var filter [BITLENGTH]byte
|
||||
yesByte, noByte := byte('1'), byte('0')
|
||||
if reverse {
|
||||
yesByte, noByte = byte('0'), byte('1')
|
||||
}
|
||||
|
||||
for idx := 0; idx < BITLENGTH; idx++ {
|
||||
_, err := input.Seek(0, io.SeekStart)
|
||||
check(err)
|
||||
|
||||
ones, lines := getBitCount(input, idx, filter)
|
||||
//fmt.Printf("BC@%d: %d (%d lines) using filter [%s]\n", idx+1, ones, lines, filter)
|
||||
|
||||
if lines == 1 {
|
||||
break
|
||||
}
|
||||
if float64(ones) >= float64(lines)/2 {
|
||||
filter[idx] = yesByte
|
||||
} else {
|
||||
filter[idx] = noByte
|
||||
}
|
||||
}
|
||||
|
||||
_, err := input.Seek(0, io.SeekStart)
|
||||
check(err)
|
||||
|
||||
// fmt.Printf("=> finding value that matches %s\n", filter)
|
||||
value := gitBitValue(input, filter)
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func getGeneratorValue(input *os.File) int {
|
||||
return doTheThing(input, false)
|
||||
}
|
||||
|
||||
func getScrubberValue(input *os.File) int {
|
||||
return doTheThing(input, true)
|
||||
}
|
||||
|
||||
func part2() {
|
||||
fmt.Println("* Part 2 *")
|
||||
fmt.Println(" Goal: Use the binary numbers in your diagnostic report to calculate the oxygen generator rating and CO2 scrubber rating, then multiply them together")
|
||||
fmt.Println(" Answer: What is the life support rating of the submarine?")
|
||||
|
||||
input, err := os.Open("./input.txt")
|
||||
defer input.Close()
|
||||
check(err)
|
||||
|
||||
generator := getGeneratorValue(input)
|
||||
scrubber := getScrubberValue(input)
|
||||
|
||||
fmt.Printf("Generator: %d, Scrubber: %d, Solution: %d\n", generator, scrubber, generator*scrubber)
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
assert "AoC2021/utils/testing"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDay3(t *testing.T) {
|
||||
assert.IsTrue(t, true, "cool")
|
||||
assert.StrEquals(t, "foo", "bar", "baz")
|
||||
}
|
||||
Reference in new issue
Block a user