275 lines
5.9 KiB
Go
275 lines
5.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
|
|
h "git.bullercodeworks.com/brian/adventofcode/helpers"
|
|
)
|
|
|
|
func main() {
|
|
inp := h.StdinToStringSlice()
|
|
solve(inp)
|
|
}
|
|
|
|
func solve(inp []string) {
|
|
var segments []seg
|
|
for i := range inp {
|
|
pts := strings.Split(inp[i], "|")
|
|
var patterns [][]byte
|
|
for _, v := range strings.Fields(pts[0]) {
|
|
patterns = append(patterns, []byte(v))
|
|
}
|
|
var output [][]byte
|
|
for _, v := range strings.Fields(pts[1]) {
|
|
output = append(output, []byte(v))
|
|
}
|
|
segments = append(segments, DeduceSeg(patterns, output))
|
|
}
|
|
|
|
var c1, c4, c7, c8 int
|
|
var total int
|
|
for i := range segments {
|
|
c1 += segments[i].instances(1)
|
|
c4 += segments[i].instances(4)
|
|
c7 += segments[i].instances(7)
|
|
c8 += segments[i].instances(8)
|
|
total += segments[i].value()
|
|
}
|
|
|
|
fmt.Println("# Part 1")
|
|
fmt.Println("1,4,7,8 appear", c1+c4+c7+c8, "times")
|
|
fmt.Println("")
|
|
fmt.Println("# Part 2")
|
|
fmt.Println("Total", total)
|
|
}
|
|
|
|
type seg struct {
|
|
N, NE, SE, S, SW, NW, C byte
|
|
Zero, One, Two, Three, Four, Five, Six, Seven, Eight, Nine []byte
|
|
Output []int
|
|
}
|
|
|
|
func DeduceSeg(pInput, oInput [][]byte) seg {
|
|
segments := []byte{'a', 'b', 'c', 'd', 'e', 'f', 'g'}
|
|
// 0, 3, 5, 9
|
|
var patterns [][]byte
|
|
for _, p := range pInput {
|
|
sort.Slice(p, func(i int, j int) bool { return p[i] < p[j] })
|
|
patterns = append(patterns, p)
|
|
}
|
|
var output [][]byte
|
|
for _, o := range oInput {
|
|
sort.Slice(o, func(i int, j int) bool { return o[i] < o[j] })
|
|
output = append(output, o)
|
|
}
|
|
var removeFromSegments = func(v ...byte) {
|
|
for k := range v {
|
|
rem := -1
|
|
for b := range segments {
|
|
if segments[b] == v[k] {
|
|
rem = b
|
|
}
|
|
}
|
|
if rem > -1 {
|
|
segments = append(segments[:rem], segments[rem+1:]...)
|
|
}
|
|
}
|
|
}
|
|
var removeFromPatterns = func(v ...[]byte) {
|
|
for k := range v {
|
|
rem := -1
|
|
for i := range patterns {
|
|
if string(patterns[i]) == string(v[k]) {
|
|
rem = i
|
|
}
|
|
}
|
|
if rem > -1 {
|
|
patterns = append(patterns[:rem], patterns[rem+1:]...)
|
|
}
|
|
}
|
|
}
|
|
s := seg{
|
|
N: '-',
|
|
NE: '-',
|
|
SE: '-',
|
|
S: '-',
|
|
SW: '-',
|
|
NW: '-',
|
|
C: '-',
|
|
}
|
|
for i := range patterns {
|
|
switch {
|
|
case len(patterns[i]) == 2:
|
|
s.One = patterns[i]
|
|
case len(patterns[i]) == 4:
|
|
s.Four = patterns[i]
|
|
case len(patterns[i]) == 3:
|
|
s.Seven = patterns[i]
|
|
case len(patterns[i]) == 7:
|
|
s.Eight = patterns[i]
|
|
}
|
|
}
|
|
removeFromPatterns(s.One, s.Four, s.Seven, s.Eight)
|
|
|
|
//First, we know the N segment, it's what shows up in 'seven' , but not in 'one'
|
|
for i := range s.Seven {
|
|
if bytes.IndexByte(s.One, s.Seven[i]) == -1 {
|
|
s.N = s.Seven[i]
|
|
removeFromSegments(s.N)
|
|
break
|
|
}
|
|
}
|
|
|
|
// Six length numbers:
|
|
// 0, 9, 6
|
|
// We know that 'seven' is inside of 'nine' and 'zero' but not 'six'
|
|
for _, p := range patterns {
|
|
if len(p) == 6 {
|
|
for _, v := range s.Seven {
|
|
if bytes.IndexByte(p, v) == -1 {
|
|
// 'v' also has to be the NE segment
|
|
s.NE = v
|
|
removeFromSegments(s.NE)
|
|
s.Six = p
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
removeFromPatterns(s.Six)
|
|
|
|
for _, v := range s.Seven {
|
|
if v != s.N && v != s.NE {
|
|
s.SE = v
|
|
removeFromSegments(s.SE)
|
|
}
|
|
}
|
|
|
|
// Five length numbers: 2, 3, 5
|
|
// Two is missing the SE segment
|
|
// Five is missing the NE segment
|
|
for _, p := range patterns {
|
|
if len(p) == 5 {
|
|
if bytes.IndexByte(p, s.SE) == -1 {
|
|
s.Two = p
|
|
}
|
|
if bytes.IndexByte(p, s.NE) == -1 {
|
|
s.Five = p
|
|
}
|
|
}
|
|
}
|
|
removeFromPatterns(s.Two, s.Five)
|
|
|
|
// The remaining 5 length is Three
|
|
for _, p := range patterns {
|
|
if len(p) == 5 {
|
|
s.Three = p
|
|
break
|
|
}
|
|
}
|
|
removeFromPatterns(s.Three)
|
|
|
|
// Nine is the same as Five except for NE
|
|
for _, p := range patterns {
|
|
for _, b := range p {
|
|
if b != s.NE && bytes.IndexByte(s.Five, b) == -1 {
|
|
s.Zero = p
|
|
break
|
|
}
|
|
}
|
|
}
|
|
removeFromPatterns(s.Zero)
|
|
s.Nine = patterns[0]
|
|
|
|
// NW is the non-SE that is missing from Two
|
|
for _, b := range segments {
|
|
if b != s.SE && bytes.IndexByte(s.Two, b) == -1 {
|
|
s.NW = b
|
|
removeFromSegments(s.NW)
|
|
break
|
|
}
|
|
}
|
|
// SW is the segment in Six that's not in Five
|
|
for _, b := range segments {
|
|
if bytes.IndexByte(s.Five, b) == -1 && bytes.IndexByte(s.Six, b) != -1 {
|
|
s.SW = b
|
|
removeFromSegments(s.SW)
|
|
}
|
|
}
|
|
// C is the remaining segment in Four that's not in 0
|
|
for _, b := range segments {
|
|
if bytes.IndexByte(s.Zero, b) == -1 && bytes.IndexByte(s.Four, b) != -1 {
|
|
s.C = b
|
|
removeFromSegments(s.C)
|
|
}
|
|
}
|
|
// The last segment is S
|
|
s.S = segments[0]
|
|
|
|
// Now fill in the outputs
|
|
for i := range output {
|
|
s.Output = append(s.Output, s.valueOf(output[i]))
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
func (s seg) instances(v int) int {
|
|
var t int
|
|
for _, o := range s.Output {
|
|
if o == v {
|
|
t++
|
|
}
|
|
}
|
|
return t
|
|
}
|
|
|
|
func (s seg) value() int {
|
|
var retStr string
|
|
for _, o := range s.Output {
|
|
retStr = retStr + h.Itoa(o)
|
|
}
|
|
return h.Atoi(retStr)
|
|
}
|
|
|
|
func (s seg) valueOf(b []byte) int {
|
|
sort.Slice(b, func(i int, j int) bool { return b[i] < b[j] })
|
|
switch string(b) {
|
|
case string(s.Zero):
|
|
return 0
|
|
case string(s.One):
|
|
return 1
|
|
case string(s.Two):
|
|
return 2
|
|
case string(s.Three):
|
|
return 3
|
|
case string(s.Four):
|
|
return 4
|
|
case string(s.Five):
|
|
return 5
|
|
case string(s.Six):
|
|
return 6
|
|
case string(s.Seven):
|
|
return 7
|
|
case string(s.Eight):
|
|
return 8
|
|
case string(s.Nine):
|
|
return 9
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func (s seg) String() string {
|
|
ret := fmt.Sprintf("%s\n", string([]byte{' ', s.N, s.N, s.N, s.N, ' '}))
|
|
ret = fmt.Sprintf("%s%s\n", ret, string([]byte{s.NW, ' ', ' ', ' ', ' ', s.NE}))
|
|
ret = fmt.Sprintf("%s%s\n", ret, string([]byte{s.NW, ' ', ' ', ' ', ' ', s.NE}))
|
|
ret = fmt.Sprintf("%s%s\n", ret, string([]byte{' ', s.C, s.C, s.C, s.C, ' '}))
|
|
ret = fmt.Sprintf("%s%s\n", ret, string([]byte{s.SW, ' ', ' ', ' ', ' ', s.SE}))
|
|
ret = fmt.Sprintf("%s%s\n", ret, string([]byte{s.SW, ' ', ' ', ' ', ' ', s.SE}))
|
|
ret = fmt.Sprintf("%s%s\n", ret, string([]byte{' ', s.S, s.S, s.S, s.S, ' '}))
|
|
return ret
|
|
}
|