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  }