mirror of
https://github.com/RussellChamp/advent-of-code-2021.git
synced 2026-10-27 21:52:32 +00:00
day 8 work and jumbled together
This commit is contained in:
1 parent
e76cb1a355
commit
c7ea0afedc
18 files changed
+457
-21
No files matched your search
+2
-2
@@ -37,8 +37,8 @@ func part1() {
|
||||
fmt.Println(" Answer: How many measurements are larger than the previous measurement?")
|
||||
|
||||
input, err := os.Open("./input.txt")
|
||||
defer input.Close()
|
||||
check(err)
|
||||
defer input.Close()
|
||||
|
||||
scanner := bufio.NewScanner(input)
|
||||
|
||||
@@ -67,8 +67,8 @@ func part2() {
|
||||
fmt.Println(" Answer: How many sums are larger than the previous sum?")
|
||||
|
||||
input, err := os.Open("./input.txt")
|
||||
defer input.Close()
|
||||
check(err)
|
||||
defer input.Close()
|
||||
|
||||
scanner := bufio.NewScanner(input)
|
||||
|
||||
|
||||
+3
-3
@@ -1,14 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
assert "AoC2021/utils/testing"
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPrintPip(t *testing.T) {
|
||||
DEBUG = false
|
||||
str := GetPip(1, 1, 1, 100)
|
||||
assert.StrEquals(t, str, "", "Should return an empty string")
|
||||
assert.EqualsStr(t, str, "", "Should return an empty string")
|
||||
|
||||
DEBUG = true
|
||||
cases := []struct {
|
||||
@@ -24,7 +24,7 @@ func TestPrintPip(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
str := GetPip(c.first, c.previous, c.current, c.total)
|
||||
assert.StrEquals(t, str, c.expected, c.msg)
|
||||
assert.EqualsStr(t, str, c.expected, c.msg)
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
assert "AoC2021/utils/testing"
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDay2(t *testing.T) {
|
||||
assert.IsTrue(t, true, "cool")
|
||||
assert.StrEquals(t, "foo", "bar", "baz")
|
||||
assert.EqualsStr(t, "foo", "bar", "baz")
|
||||
}
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
assert "AoC2021/utils/testing"
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDay3(t *testing.T) {
|
||||
assert.IsTrue(t, true, "cool")
|
||||
assert.StrEquals(t, "foo", "bar", "baz")
|
||||
assert.EqualsStr(t, "foo", "bar", "baz")
|
||||
}
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
assert "AoC2021/utils/testing"
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDay4(t *testing.T) {
|
||||
assert.IsTrue(t, true, "cool")
|
||||
assert.StrEquals(t, "foo", "bar", "baz")
|
||||
assert.EqualsStr(t, "foo", "bar", "baz")
|
||||
}
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
assert "AoC2021/utils/testing"
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDay6(t *testing.T) {
|
||||
assert.IsTrue(t, true, "cool")
|
||||
assert.StrEquals(t, "foo", "bar", "baz")
|
||||
assert.EqualsStr(t, "foo", "bar", "baz")
|
||||
}
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
assert "AoC2021/utils/testing"
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDay7(t *testing.T) {
|
||||
assert.IsTrue(t, true, "cool")
|
||||
assert.StrEquals(t, "foo", "bar", "baz")
|
||||
assert.EqualsStr(t, "foo", "bar", "baz")
|
||||
}
|
||||
+232
@@ -0,0 +1,232 @@
|
||||
/* Day 8: Seven Segment Search */
|
||||
package main
|
||||
|
||||
import (
|
||||
"AoC2021/utils/arrays"
|
||||
"AoC2021/utils/bits"
|
||||
"AoC2021/utils/log"
|
||||
"AoC2021/utils/timer"
|
||||
"bufio"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func check(e error) {
|
||||
if e != nil {
|
||||
log.Println(log.DEBUG, "Oh snap!")
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
log.Println(log.NORMAL, "--- Day 8: Seven Segment Search ---")
|
||||
timer.Start()
|
||||
part1()
|
||||
timer.Tick()
|
||||
log.Println(log.NORMAL)
|
||||
|
||||
part2()
|
||||
timer.Tick()
|
||||
log.Println(log.NORMAL)
|
||||
}
|
||||
|
||||
func part1() {
|
||||
log.Println(log.NORMAL, "* Part 1 *")
|
||||
log.Println(log.NORMAL, " Goal: For now, focus on the easy digits.")
|
||||
log.Println(log.NORMAL, " Answer: In the output values, how many times do digits 1, 4, 7, or 8 appear?")
|
||||
|
||||
input, err := os.Open("./input.txt")
|
||||
check(err)
|
||||
defer input.Close()
|
||||
|
||||
scanner := bufio.NewScanner(input)
|
||||
lines := 0
|
||||
ones := 0
|
||||
fours := 0
|
||||
sevens := 0
|
||||
eights := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
fields := strings.Split(scanner.Text(), " | ")
|
||||
if len(fields) != 2 {
|
||||
panic("Read invalid input line")
|
||||
}
|
||||
_ = strings.Fields(fields[0])
|
||||
// count all the ones, fours, sevens, and eights in the output strings based on how many segments are lit up
|
||||
outputDigits := strings.Fields(fields[1])
|
||||
for _, d := range outputDigits {
|
||||
switch len(d) {
|
||||
case 2:
|
||||
ones += 1
|
||||
case 3:
|
||||
sevens += 1
|
||||
case 4:
|
||||
fours += 1
|
||||
case 7:
|
||||
eights += 1
|
||||
}
|
||||
}
|
||||
lines++
|
||||
}
|
||||
|
||||
total := ones + fours + sevens + eights
|
||||
log.Printf(log.NORMAL, "Read %d lines from input\n", lines)
|
||||
log.Printf(log.NORMAL, "We counted %d ones, %d fours, %d sevens, and %d eights for a total of %d\n", ones, fours, sevens, eights, total)
|
||||
}
|
||||
|
||||
func part2() {
|
||||
log.Println(log.NORMAL, "* Part 2 *")
|
||||
log.Println(log.NORMAL, " Goal: For each entry, determine all of the wire/segment connections and decode the four-digit output values")
|
||||
log.Println(log.NORMAL, " Answer: What do you get if you add up all of the output values?")
|
||||
|
||||
input, err := os.Open("./input.txt")
|
||||
check(err)
|
||||
defer input.Close()
|
||||
|
||||
scanner := bufio.NewScanner(input)
|
||||
lines := 0
|
||||
total := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
fields := strings.Split(scanner.Text(), " | ")
|
||||
if len(fields) != 2 {
|
||||
panic("Read invalid input line")
|
||||
}
|
||||
inputFields := strings.Fields(fields[0])
|
||||
segMap := createPatternMap(arrays.MapStrToInt(inputFields, ParseField))
|
||||
log.Println(log.DEBUG, "Created pattern", segMap)
|
||||
|
||||
outputFields := strings.Fields(fields[1])
|
||||
|
||||
fieldValue := 0
|
||||
fieldsCount := len(outputFields)
|
||||
for idx, field := range outputFields {
|
||||
fValue := segMap[ParseField(field)]
|
||||
log.Printf(log.DIAGNOSTIC, "field %s => %d; ", field, fValue)
|
||||
fieldValue += fValue * int(math.Pow10(fieldsCount-idx-1))
|
||||
}
|
||||
total += fieldValue
|
||||
|
||||
log.Println(log.DIAGNOSTIC)
|
||||
log.Printf(log.DIAGNOSTIC, "Unscrambled %s => %d\n", outputFields, fieldValue)
|
||||
lines++
|
||||
}
|
||||
|
||||
log.Printf(log.NORMAL, "Read %d lines from input\n", lines)
|
||||
log.Printf(log.NORMAL, "Calculated total is %d\n", total)
|
||||
}
|
||||
|
||||
// Represent a segment as a 7-bit value
|
||||
/* Segment values are aligned as below
|
||||
* aaaa
|
||||
* b c
|
||||
* b c
|
||||
* dddd
|
||||
* e f
|
||||
* e f
|
||||
* gggg
|
||||
|
||||
* segment 'a' is found in [0, 2, 3, 5, 6, 7, 8, 9] but not [1, 4]
|
||||
* segment 'b' is found in [0, 4, 5, 6, 8, 9] but not [1, 2, 3, 7]
|
||||
* segment 'c' is found in [0, 1, 2, 3, 4, 7, 8, 9] but not [5, 6]
|
||||
* segment 'd' is found in [2, 3, 4, 5, 6, 8, 9] but not [0, 1, 7]
|
||||
* segment 'e' is found in [0, 2, 6, 8] but not [1, 3, 4, 5, 7, 9]
|
||||
* segment 'f' is found in [0, 1, 3, 4, 5, 6, 7, 8, 9] but not [2]
|
||||
* segment 'g' is found in [0, 2, 3, 5, 6, 8, 9] but not [1, 4, 7]
|
||||
*/
|
||||
|
||||
// parse a field from a string value to a bit-map int value (eg 'cda' to b1101 => 13)
|
||||
func ParseField(field string) int {
|
||||
value := 0
|
||||
for _, c := range field {
|
||||
value += 1 << int(rune(c)-rune('a'))
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// func getDefaultMap() map[int]int {
|
||||
// return map[int]int{
|
||||
// ParseField("abcefg"): 0,
|
||||
// ParseField("cf"): 1,
|
||||
// ParseField("acdeg"): 2,
|
||||
// ParseField("acdfg"): 3,
|
||||
// ParseField("bcdf"): 4,
|
||||
// ParseField("abdfg"): 5,
|
||||
// ParseField("abdefg"): 6,
|
||||
// ParseField("acf"): 7,
|
||||
// ParseField("abcdefg"): 8,
|
||||
// ParseField("abcdfg"): 9}
|
||||
// }
|
||||
|
||||
// Given a list of a all 10 possible 7-segment displays create a map that can be used to unscramble values
|
||||
func createPatternMap(input []int) map[int]int {
|
||||
// initialize our translation map that will convert from character to character (eg wire 'a' actually goes to segment 'c')
|
||||
segMap := make(map[int]int)
|
||||
|
||||
// first find and map all the values that can be known by counting segments
|
||||
// find the only pattern that matches '1'
|
||||
one := arrays.FindFirstInt(input, bits.ByBitCount(2))
|
||||
|
||||
// next find the one that matches '7'
|
||||
seven := arrays.FindFirstInt(input, bits.ByBitCount(3))
|
||||
|
||||
// next find the one that matches '4'
|
||||
four := arrays.FindFirstInt(input, bits.ByBitCount(4))
|
||||
|
||||
// the one that matches '8' will be the only one with 7 segments but tells us nothing about what those segments map to
|
||||
eight := arrays.FindFirstInt(input, bits.ByBitCount(7))
|
||||
|
||||
// the two segments in '1' will match 'c' or 'f' but we don't know yet
|
||||
// the additional segment in '7' will map to segment 'a'
|
||||
segMap['a'] = seven - one
|
||||
// the two additional segments in '4' will match 'b' or 'd' but we're not sure which ones yet
|
||||
|
||||
// all of '0', '6' and '9' have 6 segments
|
||||
// the six-segment field that shares only 1 side with '1' is '6'
|
||||
six := arrays.FindFirstInt(input, func(v int) bool { return bits.ByBitCount(6)(v) && bits.MatchingOnBits(one, v) == 1 })
|
||||
|
||||
// and we know that the segment not in six is 'c'
|
||||
segMap['c'] = eight - six
|
||||
// and the other value 'f' will be the other segment in '1'
|
||||
segMap['f'] = one - segMap['c']
|
||||
// but we can't yet place '0' or '9' with what we know
|
||||
|
||||
// all of '2', '3', and '5' have 5 segments
|
||||
// three is the only 5 segment field that matches 3 bits in '7'
|
||||
three := arrays.FindFirstInt(input, func(v int) bool { return bits.ByBitCount(5)(v) && bits.MatchingOnBits(seven, v) == 3 })
|
||||
// the additional two segments are 'd' ang 'g' but we can't place them yet
|
||||
// five is the other 5 segment field that matches 3 bits in '4'
|
||||
five := arrays.FindFirstInt(input, func(v int) bool { return bits.ByBitCount(5)(v) && v != three && bits.MatchingOnBits(four, v) == 3 })
|
||||
// segments 'b', 'd', and 'g' can't yet be placed
|
||||
// but segment 'e' is what we get by subtracting five from six
|
||||
segMap['e'] = six - five
|
||||
|
||||
// the last five segment number must be 2
|
||||
two := arrays.FindFirstInt(input, func(v int) bool { return bits.ByBitCount(5)(v) && v != three && v != five })
|
||||
|
||||
// segment 'g' is the only one that doesn't appear in '1', '4', or '7' and is not 'e'
|
||||
segMap['g'] = eight - bits.BitwiseAndA(one, four, seven, segMap['e'])
|
||||
// segment 'd' is '3' minus 'a', 'c', 'f', and 'g'
|
||||
segMap['d'] = three - segMap['a'] - segMap['c'] - segMap['f'] - segMap['g']
|
||||
|
||||
// then we know that zero is eight minus 'd'
|
||||
zero := eight - segMap['d']
|
||||
// and nine will be eight minus 'e'
|
||||
nine := eight - segMap['e']
|
||||
|
||||
log.Println(log.DIAGNOSTIC, "segMap", segMap)
|
||||
|
||||
return map[int]int{
|
||||
zero: 0,
|
||||
one: 1,
|
||||
two: 2,
|
||||
three: 3,
|
||||
four: 4,
|
||||
five: 5,
|
||||
six: 6,
|
||||
seven: 7,
|
||||
eight: 8,
|
||||
nine: 9,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDay8ParseField(t *testing.T) {
|
||||
assert.EqualsInt(t, ParseField("abc"), 7, "should parse fields correctly")
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
assert "AoC2021/utils/testing"
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
@@ -11,4 +11,7 @@ build:
|
||||
cd day-$(day); go run .
|
||||
|
||||
test:
|
||||
cd day-$(day); go test
|
||||
cd day-$(day); go test
|
||||
|
||||
test-utils:
|
||||
go test ./utils/*
|
||||
@@ -0,0 +1,49 @@
|
||||
package arrays
|
||||
|
||||
func FindFirst(list []string, filter func(string) bool) string {
|
||||
for _, item := range list {
|
||||
if filter(item) {
|
||||
return item
|
||||
}
|
||||
}
|
||||
panic("No item found that matches criteria")
|
||||
}
|
||||
|
||||
func FindFirstInt(list []int, filter func(int) bool) int {
|
||||
for _, item := range list {
|
||||
if filter(item) {
|
||||
return item
|
||||
}
|
||||
}
|
||||
panic("No item found that matches criteria")
|
||||
}
|
||||
|
||||
func FindAll(list []string, filter func(string) bool) []string {
|
||||
var filteredList []string
|
||||
for _, item := range list {
|
||||
if filter(item) {
|
||||
filteredList = append(filteredList, item)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredList
|
||||
}
|
||||
|
||||
func FindAllInt(list []int, filter func(int) bool) []int {
|
||||
var filteredList []int
|
||||
for _, item := range list {
|
||||
if filter(item) {
|
||||
filteredList = append(filteredList, item)
|
||||
}
|
||||
}
|
||||
|
||||
return filteredList
|
||||
}
|
||||
|
||||
func MapStrToInt(input []string, fn func(string) int) []int {
|
||||
var retVals []int
|
||||
for _, s := range input {
|
||||
retVals = append(retVals, fn(s))
|
||||
}
|
||||
return retVals
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package arrays
|
||||
|
||||
import (
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFindFirst(t *testing.T) {
|
||||
list := []string{"foo", "bar", "baz"}
|
||||
filter := func(s string) bool { return s == "baz" }
|
||||
item := FindFirst(list, filter)
|
||||
|
||||
assert.EqualsStr(t, item, "baz", "should find item baz")
|
||||
}
|
||||
|
||||
func TestFindFirstInt(t *testing.T) {
|
||||
list := []int{1, 3, 4, 5}
|
||||
filter := func(i int) bool { return i%2 == 0 }
|
||||
item := FindFirstInt(list, filter)
|
||||
|
||||
assert.EqualsInt(t, item, 4, "should find even number")
|
||||
}
|
||||
|
||||
func TestFindAll(t *testing.T) {
|
||||
list := []string{"hello", "world", "foo"}
|
||||
filter := func(s string) bool { return len(s) > 3 }
|
||||
items := FindAll(list, filter)
|
||||
|
||||
assert.EqualsInt(t, len(items), 2, "should filter lists of strings")
|
||||
}
|
||||
|
||||
func TestFindAllInt(t *testing.T) {
|
||||
list := []int{1, 3, 99, 200, 9000}
|
||||
filter := func(i int) bool { return i > 50 }
|
||||
items := FindAllInt(list, filter)
|
||||
|
||||
assert.EqualsInt(t, len(items), 3, "should filter lists of ints")
|
||||
}
|
||||
|
||||
func TestMapStrToInt(t *testing.T) {
|
||||
list := []string{"alice", "bob", "carol"}
|
||||
mapFn := func(s string) int { return int(s[0]) }
|
||||
|
||||
items := MapStrToInt(list, mapFn)
|
||||
|
||||
assert.EqualsInt(t, items[0], int('a'), "should run map function across all strings")
|
||||
}
|
||||
@@ -9,9 +9,16 @@ func IsTrue(t *testing.T, expr bool, message string) {
|
||||
}
|
||||
}
|
||||
|
||||
func StrEquals(t *testing.T, actual, expected, message string) {
|
||||
func EqualsStr(t *testing.T, actual, expected, message string) {
|
||||
if actual != expected {
|
||||
t.Logf("Expected value '%s' but got '%s': %s", expected, actual, message)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func EqualsInt(t *testing.T, actual, expected int, message string) {
|
||||
if actual != expected {
|
||||
t.Logf("Expected value '%d' but got '%d': %s", expected, actual, message)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package bits
|
||||
|
||||
func GetBitCount(val int) int {
|
||||
count := 0
|
||||
for val != 0 {
|
||||
count += val & 1
|
||||
val >>= 1
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
// returns the number of matching bits in the two value's binary expression
|
||||
func MatchingOnBits(v1 int, v2 int) int {
|
||||
count := 0
|
||||
for v1 != 0 && v2 != 0 {
|
||||
if v1&1 == 1 && v2&1 == 1 {
|
||||
count += 1
|
||||
}
|
||||
v1 >>= 1
|
||||
v2 >>= 1
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
func BitwiseAnd(v1 int, v2 int) int {
|
||||
val := 0
|
||||
for block := 1; v1 != 0 || v2 != 0; block <<= 1 {
|
||||
if v1&1 == 1 || v2&1 == 1 {
|
||||
val += block
|
||||
}
|
||||
if v1 > 0 {
|
||||
v1 >>= 1
|
||||
}
|
||||
if v2 > 0 {
|
||||
v2 >>= 1
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
func BitwiseAndA(a ...int) int {
|
||||
total := 0
|
||||
for _, i := range a {
|
||||
total = BitwiseAnd(total, i)
|
||||
}
|
||||
|
||||
return total
|
||||
}
|
||||
|
||||
func ByBitCount(size int) func(int) bool {
|
||||
return func(val int) bool { return GetBitCount(val) == size }
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package bits
|
||||
|
||||
import (
|
||||
"AoC2021/utils/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetBitCount(t *testing.T) {
|
||||
assert.EqualsInt(t, GetBitCount(0), 0, "should count zero bits")
|
||||
assert.EqualsInt(t, GetBitCount(15), 4, "should count bits")
|
||||
assert.EqualsInt(t, GetBitCount(16), 1, "should not count empty bits")
|
||||
}
|
||||
func TestMatchingOnBits(t *testing.T) {
|
||||
assert.EqualsInt(t, MatchingOnBits(5 /*101*/, 13 /*1101*/), 2, "should match 2 bits")
|
||||
}
|
||||
|
||||
func TestBitwiseAnd(t *testing.T) {
|
||||
assert.EqualsInt(t, BitwiseAnd(7 /*111*/, 18 /*10010*/), 23 /*10111*/, "should bitwise add")
|
||||
}
|
||||
|
||||
func TestBitwiseAndA(t *testing.T) {
|
||||
assert.EqualsInt(t, BitwiseAndA(1, 4, 8, 12), 13 /*1101*/, "should bitwise add lists")
|
||||
}
|
||||
|
||||
func TestByBitCount(t *testing.T) {
|
||||
twoBitFilter := ByBitCount(2)
|
||||
assert.IsTrue(t, twoBitFilter(17 /*10001*/), "should count bits")
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package filters
|
||||
|
||||
func ByLength(size int) func(string) bool {
|
||||
return func(val string) bool { return len(val) == size }
|
||||
}
|
||||
+4
-3
@@ -3,9 +3,10 @@ package log
|
||||
import "fmt"
|
||||
|
||||
const (
|
||||
NONE = 0
|
||||
NORMAL = 1
|
||||
DEBUG = 2
|
||||
NONE = 0
|
||||
NORMAL = 1
|
||||
DEBUG = 2
|
||||
DIAGNOSTIC = 3
|
||||
)
|
||||
|
||||
var LOG_LEVEL = NORMAL
|
||||
|
||||
Reference in new issue
Block a user