github.com/cycloss/advent-of-code@v0.0.0-20221210145555-15039b95faa6/2021/day8/day8.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "fmt" 6 "log" 7 "os" 8 "strconv" 9 "strings" 10 ) 11 12 type knownsMap map[int]map[byte]bool 13 14 func main() { 15 var file, err = os.Open("day8.txt") 16 if err != nil { 17 log.Fatalf("failed to open file: %v\n", err) 18 } 19 defer file.Close() 20 solve(file) 21 } 22 23 func solve(file *os.File) { 24 var buff = bufio.NewScanner(file) 25 var easyDigitsCount = 0 26 var outputSum = 0 27 for buff.Scan() { 28 var line = buff.Text() 29 easyDigitsCount += countEasyDigits(line) 30 outputSum += sumOutput(line) 31 } 32 fmt.Printf("Part 1 Solution: %d\n", easyDigitsCount) 33 fmt.Printf("Part 2 Solution: %d\n", outputSum) 34 35 } 36 37 var uniqueSegemntSet = map[int]bool{2: true, 4: true, 3: true, 7: true} 38 39 func countEasyDigits(line string) int { 40 var count = 0 41 var split = strings.Split(line, " ") 42 var found = false 43 for _, v := range split { 44 if v == "|" { 45 found = true 46 continue 47 } 48 if found { 49 _, contains := uniqueSegemntSet[len(v)] 50 if contains { 51 count++ 52 } 53 } 54 } 55 return count 56 } 57 58 func sumOutput(line string) int { 59 var nums, output = getNumsAndOutput(line) 60 var knowns = createMapOfKnowns(nums) 61 var fiveSegs = createNSegMap(nums, 5) 62 var sixSegs = createNSegMap(nums, 6) 63 var segMap = map[byte]byte{} 64 var topSeg = findTopSeg(knowns) 65 segMap[topSeg] = 'a' 66 var bottomSeg = findBottomSeg(sixSegs, knowns[4], topSeg) 67 segMap[bottomSeg] = 'g' 68 var bottomLeft = findBottomLeftSeg(knowns, bottomSeg) 69 segMap[bottomLeft] = 'e' 70 var topRight = findTopRight(knowns[1], sixSegs) 71 segMap[topRight] = 'c' 72 var bottomRight = findBottomRight(knowns[1], topRight) 73 segMap[bottomRight] = 'f' 74 var middle = findMiddle(fiveSegs, segMap) 75 segMap[middle] = 'd' 76 var topLeft = findTopLeft(knowns[8], segMap) 77 segMap[topLeft] = 'b' 78 // for k, v := range segMap { 79 // fmt.Printf("key: %s, val: %s\n", string(k), string(v)) 80 // } 81 return calculateOutputSum(output, segMap) 82 } 83 84 func getNumsAndOutput(line string) ([]string, []string) { 85 var split = strings.Split(line, " ") 86 var nums = []string{} 87 var output = []string{} 88 var found = false 89 for _, v := range split { 90 if v == "|" { 91 found = true 92 continue 93 } 94 if found { 95 output = append(output, v) 96 } else { 97 nums = append(nums, v) 98 } 99 } 100 return nums, output 101 } 102 103 func createMapOfKnowns(nums []string) knownsMap { 104 var knowns = knownsMap{} 105 for _, v := range nums { 106 switch len(v) { 107 case 2: 108 knowns[1] = createSetFromNum(v) 109 case 3: 110 knowns[7] = createSetFromNum(v) 111 case 4: 112 knowns[4] = createSetFromNum(v) 113 case 7: 114 knowns[8] = createSetFromNum(v) 115 } 116 } 117 return knowns 118 } 119 120 func createNSegMap(nums []string, n int) []map[byte]bool { 121 var segMap = []map[byte]bool{} 122 for _, v := range nums { 123 if len(v) == n { 124 segMap = append(segMap, createSetFromNum(v)) 125 } 126 } 127 return segMap 128 } 129 130 func createSetFromNum(num string) map[byte]bool { 131 var set = map[byte]bool{} 132 for _, v := range []byte(num) { 133 set[v] = true 134 } 135 return set 136 } 137 138 func findTopSeg(knowns knownsMap) byte { 139 var one = knowns[1] 140 var seven = knowns[7] 141 var diff = diff(one, seven) 142 return takeOne(diff) 143 } 144 145 func findBottomSeg(sixSegs []map[byte]bool, four map[byte]bool, top byte) byte { 146 var inter = sixSegs[0] 147 for _, k := range sixSegs { 148 inter = intersection(inter, k) 149 } 150 var not4 = map[byte]bool{} 151 for k := range inter { 152 var _, found = four[k] 153 if !found { 154 not4[k] = true 155 } 156 } 157 return takeNot(not4, top) 158 } 159 160 func findBottomLeftSeg(knowns knownsMap, bottom byte) byte { 161 var eight = knowns[8] 162 var merged = union(knowns[1], knowns[4]) 163 merged = union(merged, knowns[7]) 164 var diff = diff(eight, merged) 165 return takeNot(diff, bottom) 166 } 167 168 func findTopRight(one map[byte]bool, sixSegs []map[byte]bool) byte { 169 var foundCount = map[byte]int{} 170 for _, seg := range sixSegs { 171 for k := range seg { 172 foundCount[k]++ 173 } 174 } 175 var twoSet = map[byte]bool{} 176 for k, v := range foundCount { 177 if v == 2 { 178 twoSet[k] = true 179 } 180 } 181 return takeOne(intersection(one, twoSet)) 182 } 183 184 func findBottomRight(one map[byte]bool, topRight byte) byte { 185 return takeNot(one, topRight) 186 } 187 188 func findMiddle(fiveSegs []map[byte]bool, segMap map[byte]byte) byte { 189 var inter = fiveSegs[0] 190 for _, v := range fiveSegs { 191 inter = intersection(inter, v) 192 } 193 var b byte 194 for k := range inter { 195 var _, found = segMap[k] 196 if !found { 197 b = k 198 } 199 } 200 return b 201 } 202 203 func findTopLeft(eight map[byte]bool, segMap map[byte]byte) byte { 204 var b byte 205 for k := range eight { 206 var _, found = segMap[k] 207 if !found { 208 b = k 209 } 210 } 211 return b 212 } 213 214 var sets = map[byte]map[byte]bool{'0': {'a': true, 'b': true, 'c': true, 'e': true, 'f': true, 'g': true}, '1': {'c': true, 'f': true}, '2': {'a': true, 'c': true, 'd': true, 'e': true, 'g': true}, '3': {'a': true, 'c': true, 'd': true, 'f': true, 'g': true}, '4': {'b': true, 'c': true, 'd': true, 'f': true}, '5': {'a': true, 'b': true, 'd': true, 'f': true, 'g': true}, '6': {'a': true, 'b': true, 'd': true, 'e': true, 'f': true, 'g': true}, '7': {'a': true, 'c': true, 'f': true}, '8': {'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true}, '9': {'a': true, 'b': true, 'c': true, 'd': true, 'f': true, 'g': true}} 215 216 func calculateOutputSum(output []string, segMap map[byte]byte) int { 217 218 var bytes = []byte{} 219 var translated = translateOutput(output, segMap) 220 for _, transMap := range translated { 221 for k, v := range sets { 222 if sameSet(v, transMap) { 223 bytes = append(bytes, k) 224 } 225 } 226 } 227 228 var res, err = strconv.Atoi(string(bytes)) 229 if err != nil { 230 log.Fatal(err, "output", output, "segmap", segMap, "trans", translated) 231 } 232 return res 233 } 234 235 func translateOutput(output []string, segMap map[byte]byte) []map[byte]bool { 236 var translated = []map[byte]bool{} 237 for _, v := range output { 238 var bytes = []byte(v) 239 var set = map[byte]bool{} 240 for _, b := range bytes { 241 var translation = segMap[b] 242 set[translation] = true 243 } 244 translated = append(translated, set) 245 } 246 return translated 247 } 248 249 func diff(set1, set2 map[byte]bool) map[byte]bool { 250 var diff = map[byte]bool{} 251 for k := range set1 { 252 var _, found = set2[k] 253 if !found { 254 diff[k] = true 255 } 256 } 257 for k := range set2 { 258 var _, found = set1[k] 259 if !found { 260 diff[k] = true 261 } 262 } 263 return diff 264 } 265 266 func intersection(set1, set2 map[byte]bool) map[byte]bool { 267 var intersection = map[byte]bool{} 268 for k := range set1 { 269 var _, found = set2[k] 270 if found { 271 intersection[k] = true 272 } 273 } 274 for k := range set2 { 275 var _, found = set1[k] 276 if found { 277 intersection[k] = true 278 } 279 } 280 return intersection 281 } 282 283 func union(set1, set2 map[byte]bool) map[byte]bool { 284 var union = map[byte]bool{} 285 for k := range set1 { 286 union[k] = true 287 } 288 for k := range set2 { 289 union[k] = true 290 } 291 return union 292 } 293 294 func sameSet(set1, set2 map[byte]bool) bool { 295 for k := range set1 { 296 var _, found = set2[k] 297 if !found { 298 return false 299 } 300 } 301 for k := range set2 { 302 var _, found = set1[k] 303 if !found { 304 return false 305 } 306 } 307 return true 308 } 309 310 func takeNot(set map[byte]bool, b byte) byte { 311 var notTop byte 312 for k := range set { 313 if k != b { 314 notTop = k 315 } 316 } 317 return notTop 318 } 319 320 func takeOne(set map[byte]bool) byte { 321 var b byte 322 for k := range set { 323 b = k 324 } 325 return b 326 }