314 lines
8.1 KiB
Go
314 lines
8.1 KiB
Go
package day8
|
|
|
|
import (
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type Line struct {
|
|
signals []string
|
|
answer []string
|
|
}
|
|
|
|
//
|
|
// This struct will be used to store the possible corresponding patterns
|
|
// A = Top line, B = Left top, ..., I used the same pattern in the AoC problem
|
|
//
|
|
type Possible struct {
|
|
possible []string
|
|
}
|
|
|
|
func Run(dat []byte) (int, int) {
|
|
|
|
lines := strings.Split(string(dat), "\n")
|
|
lineArray := make([]Line, len(lines))
|
|
|
|
for i, v := range lines {
|
|
splitLine := strings.Split(v, " | ")
|
|
lineArray[i] = Line{signals: strings.Split(splitLine[0], " "),
|
|
answer: strings.Split(splitLine[1], " ")}
|
|
}
|
|
|
|
part1 := 0
|
|
for _, value := range lineArray {
|
|
|
|
for _, signal := range value.answer {
|
|
if len(signal) == 2 || len(signal) == 3 || len(signal) == 4 || len(signal) == 7 {
|
|
part1++
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
part2 := 0
|
|
for _, line := range lineArray {
|
|
|
|
currentPossible := make(map[string]Possible)
|
|
|
|
//#1 - Get the unique ones.
|
|
|
|
//#1.1 - Get the number one
|
|
one := getFromLength(line.signals, 2)[0]
|
|
currentPossible[string(one[0])] = Possible{possible: []string{"C", "F"}}
|
|
currentPossible[string(one[1])] = Possible{possible: []string{"C", "F"}}
|
|
|
|
//#1.2 - Get number 7 to work out first link
|
|
seven := getFromLength(line.signals, 3)[0]
|
|
topLink := getOddLetter(seven, one)[0]
|
|
currentPossible[topLink] = Possible{possible: []string{"A"}}
|
|
|
|
//#1.3 - Get the number 4.
|
|
four := getFromLength(line.signals, 4)[0]
|
|
oddLetters := getOddLetter(four, one)
|
|
currentPossible[oddLetters[0]] = Possible{possible: []string{"B", "D"}}
|
|
currentPossible[oddLetters[1]] = Possible{possible: []string{"B", "D"}}
|
|
|
|
//#1.4 - Get the number 8.
|
|
//The 8 will contain the top link which we already know.
|
|
eight := getFromLength(line.signals, 7)[0]
|
|
oddLetters = getOddLetter(eight, four)
|
|
|
|
for _, c := range oddLetters {
|
|
if c != topLink {
|
|
currentPossible[c] = Possible{possible: []string{"E", "G"}}
|
|
}
|
|
}
|
|
|
|
//#2 - Get a number with 5 segments on.
|
|
// We want to get a 3, which contains all of the 7s
|
|
// Choose one that thas the top segment.
|
|
fiveLengthNum := getFromLength(line.signals, 5)
|
|
three := ""
|
|
for _, s := range fiveLengthNum {
|
|
|
|
contains := true
|
|
for _, c := range seven {
|
|
if !strings.Contains(s, string(c)) {
|
|
contains = false
|
|
break
|
|
}
|
|
}
|
|
|
|
if contains {
|
|
three = s
|
|
break
|
|
}
|
|
|
|
}
|
|
|
|
//#2.1 Extra segments in 3 but not in 7
|
|
extraLetters := ""
|
|
commonLetters := ""
|
|
for _, c := range three {
|
|
if !strings.Contains(seven, string(c)) {
|
|
extraLetters += string(c)
|
|
} else {
|
|
if string(c) != topLink {
|
|
commonLetters += string(c)
|
|
}
|
|
}
|
|
}
|
|
|
|
c1 := currentPossible[string(extraLetters[0])].possible[0]
|
|
c2 := currentPossible[string(extraLetters[0])].possible[1]
|
|
c3 := currentPossible[string(extraLetters[1])].possible[0]
|
|
c4 := currentPossible[string(extraLetters[1])].possible[1]
|
|
|
|
//D first then G
|
|
if c1 == "D" && c3 == "G" {
|
|
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"D"}}
|
|
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"G"}}
|
|
} else if c1 == "G" && c3 == "D" {
|
|
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"D"}}
|
|
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"G"}}
|
|
} else if c1 == "D" && c4 == "G" {
|
|
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"D"}}
|
|
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"G"}}
|
|
} else if c1 == "G" && c4 == "D" {
|
|
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"D"}}
|
|
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"G"}}
|
|
} else if c2 == "D" && c3 == "G" {
|
|
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"D"}}
|
|
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"G"}}
|
|
} else if c2 == "G" && c3 == "D" {
|
|
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"D"}}
|
|
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"G"}}
|
|
} else if c2 == "D" && c4 == "G" {
|
|
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"D"}}
|
|
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"G"}}
|
|
} else if c2 == "G" && c4 == "D" {
|
|
currentPossible[string(extraLetters[1])] = Possible{possible: []string{"D"}}
|
|
currentPossible[string(extraLetters[0])] = Possible{possible: []string{"G"}}
|
|
}
|
|
|
|
purgeMap(currentPossible)
|
|
|
|
//#3 - Now all that is left is to find C & F
|
|
//We can use 6 which contains only contains F
|
|
|
|
//Get letters of remaining
|
|
remainingNotFound := make([]string, 0)
|
|
for k, v := range currentPossible {
|
|
if len(v.possible) > 1 {
|
|
remainingNotFound = append(remainingNotFound, k)
|
|
}
|
|
}
|
|
|
|
sixLengthNum := getFromLength(line.signals, 6)
|
|
remainingNotFoundLetter := ""
|
|
remainingNotFoundLetter2 := ""
|
|
|
|
for _, possibleNum := range sixLengthNum {
|
|
|
|
reminingNotFoundNum := 0
|
|
for i := 0; i < len(possibleNum); i++ {
|
|
if string(possibleNum[i]) == remainingNotFound[0] {
|
|
reminingNotFoundNum++
|
|
remainingNotFoundLetter = remainingNotFound[0]
|
|
remainingNotFoundLetter2 = remainingNotFound[1]
|
|
} else if string(possibleNum[i]) == remainingNotFound[1] {
|
|
reminingNotFoundNum++
|
|
remainingNotFoundLetter = remainingNotFound[1]
|
|
remainingNotFoundLetter2 = remainingNotFound[0]
|
|
}
|
|
}
|
|
|
|
if reminingNotFoundNum == 1 {
|
|
break
|
|
}
|
|
|
|
}
|
|
|
|
currentPossible[remainingNotFoundLetter] = Possible{possible: []string{"F"}}
|
|
currentPossible[remainingNotFoundLetter2] = Possible{possible: []string{"C"}}
|
|
|
|
answer := ""
|
|
for _, testNum := range line.answer {
|
|
|
|
testNumArray := make([]string, 0)
|
|
for i := 0; i < len(testNum); i++ {
|
|
testNumArray = append(testNumArray, currentPossible[string(testNum[i])].possible[0])
|
|
}
|
|
|
|
answer += getNum(testNumArray)
|
|
}
|
|
|
|
numAnswer, _ := strconv.Atoi(answer)
|
|
part2 += numAnswer
|
|
|
|
}
|
|
|
|
return part1, part2
|
|
|
|
}
|
|
|
|
func purgeMap(givenMap map[string]Possible) {
|
|
|
|
singleValues := make([]string, 0)
|
|
for _, v := range givenMap {
|
|
if len(v.possible) == 1 {
|
|
singleValues = append(singleValues, v.possible[0])
|
|
}
|
|
}
|
|
|
|
for k, v := range givenMap {
|
|
|
|
//Check that any of the single values are in v
|
|
newValues := make([]string, 0)
|
|
for _, singleValue := range v.possible {
|
|
if !containsInArray(singleValues, singleValue) {
|
|
newValues = append(newValues, singleValue)
|
|
}
|
|
}
|
|
|
|
if len(newValues) > 0 {
|
|
givenMap[k] = Possible{possible: newValues}
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func getNum(arr []string) string {
|
|
|
|
sort.Strings(arr)
|
|
if equals(arr, []string{"A", "B", "C", "E", "F", "G"}) {
|
|
return "0"
|
|
} else if equals(arr, []string{"C", "F"}) {
|
|
return "1"
|
|
} else if equals(arr, []string{"A", "C", "D", "E", "G"}) {
|
|
return "2"
|
|
} else if equals(arr, []string{"A", "C", "D", "F", "G"}) {
|
|
return "3"
|
|
} else if equals(arr, []string{"B", "D", "C", "F"}) {
|
|
return "4"
|
|
} else if equals(arr, []string{"A", "B", "D", "F", "G"}) {
|
|
return "5"
|
|
} else if equals(arr, []string{"A", "B", "D", "E", "F", "G"}) {
|
|
return "6"
|
|
} else if equals(arr, []string{"A", "C", "F"}) {
|
|
return "7"
|
|
} else if equals(arr, []string{"A", "B", "C", "D", "E", "F", "G"}) {
|
|
return "8"
|
|
} else if equals(arr, []string{"A", "B", "C", "D", "F", "G"}) {
|
|
return "9"
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
func getFromLength(arr []string, length int) []string {
|
|
returnArray := make([]string, 0)
|
|
for _, v := range arr {
|
|
if len(v) == length {
|
|
returnArray = append(returnArray, v)
|
|
}
|
|
}
|
|
return returnArray
|
|
}
|
|
|
|
//First parameter is the bigger array
|
|
func getOddLetter(string1 string, string2 string) []string {
|
|
|
|
returnArray := make([]string, 0)
|
|
for _, v := range string1 {
|
|
if !contains(string2, v) {
|
|
returnArray = append(returnArray, string(v))
|
|
}
|
|
}
|
|
return returnArray
|
|
|
|
}
|
|
|
|
func contains(givenString string, value rune) bool {
|
|
for _, v := range givenString {
|
|
if v == value {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func containsInArray(givenArr []string, char string) bool {
|
|
for _, v := range givenArr {
|
|
if v == char {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func equals(arr1 []string, arr2 []string) bool {
|
|
|
|
sort.Strings(arr1)
|
|
sort.Strings(arr2)
|
|
|
|
for i, v := range arr1 {
|
|
if v != arr2[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
} |