Skip to content

Instantly share code, notes, and snippets.

@Roemerb
Created December 3, 2022 21:56
Show Gist options
  • Save Roemerb/14bfd3424b34b1c3936ab8a37ead8c9b to your computer and use it in GitHub Desktop.
Save Roemerb/14bfd3424b34b1c3936ab8a37ead8c9b to your computer and use it in GitHub Desktop.
package day3
import (
"bufio"
"errors"
"fmt"
"log"
"os"
)
var RucksackContents [][]byte
func Run() {
readRucksackContents("./day3/3.txt")
fmt.Println("Total dupe score: ", getTotalDupeScore(RucksackContents))
// Part 2
splitScore := 0
split := splitRucksacksInGroups(RucksackContents, 3)
for groupNr, group := range split {
fmt.Println("Group ", groupNr)
fmt.Print("\t")
for _, rucksack := range group {
fmt.Print(string(rucksack), ", ")
}
commonItem := findCommonItemInRucksackGroup(group)
commonItemScore, _ := getItemPriorityScore(commonItem)
splitScore += commonItemScore
fmt.Print(" have in common: ", commonItem, " (", string(commonItem), ") score: ", commonItemScore)
fmt.Print("\n")
}
fmt.Println("The total priority score for the split rucksacks is", splitScore)
}
func ReadInputToFile(path string) *os.File {
content, err := os.Open(path)
if err != nil {
log.Fatal("Cannot read input: ", err)
}
return content
}
func readRucksackContents(path string) {
content := ReadInputToFile(path)
scanner := bufio.NewScanner(content)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
str := scanner.Text()
RucksackContents = append(RucksackContents, []byte(str))
}
}
func findDuplicatesInRucksack(rucksack []byte) []byte {
var halfSize int = (len(rucksack) / 2)
firstHalf := rucksack[0:halfSize]
secondHalf := rucksack[halfSize:]
// Find the unique characters in the first half
uniqChars := make(map[byte]bool)
for _, char := range firstHalf {
// Ignore line-break chars
if char == 10 {
continue
}
if !uniqChars[char] {
uniqChars[char] = true
}
}
// Find which of the unique chars also exists in the second half
dupes := make(map[byte]bool)
for _, char := range secondHalf {
if uniqChars[char] {
if !dupes[char] {
dupes[char] = true
}
}
}
var dupeChars []byte
for char, _ := range dupes {
dupeChars = append(dupeChars, char)
}
return dupeChars
}
// getItemPriorityScore translates a byte into the appropriate
// score for that item.
//
// a-z have scores 1-26
// A-Z have scores 27-52
//
// However, the byte value for these characters is actually the
// opposite way around so the scores for uppercase and lowercase
// items must be calculated differently.
func getItemPriorityScore(item byte) (int, error) {
if item >= 97 && item <= 122 {
return int(item) % 96, nil
} else if item >= 65 && item <= 90 {
return (int(item) % 64) + 26, nil
}
return -1, errors.New("item is invalid")
}
func getDupeScoreForRucksack(rucksack []byte) int {
var score int = 0
dupes := findDuplicatesInRucksack(rucksack)
for _, dupe := range dupes {
itemScore, err := getItemPriorityScore(dupe)
if err != nil {
log.Fatal(err)
}
score += itemScore
}
return score
}
func getTotalDupeScore(rucksacks [][]byte) int {
var totalScore int = 0
for _, rucksack := range rucksacks {
totalScore += getDupeScoreForRucksack(rucksack)
}
return totalScore
}
func splitRucksacksInGroups(rucksacks [][]byte, groupSize int) map[int][][]byte {
nGroups := len(rucksacks) / groupSize
groups := make(map[int][][]byte)
for i := 0; i < nGroups; i++ {
groups[i] = rucksacks[i*groupSize : i*groupSize+groupSize]
}
return groups
}
func findCommonItemInRucksackGroup(rucksackGroup [][]byte) byte {
for _, c := range rucksackGroup[0] {
if arrContains(rucksackGroup[1], c) && arrContains(rucksackGroup[2], c) {
return c
}
}
return 0
}
func arrContains(arr []byte, s byte) bool {
for _, c := range arr {
if c == s {
return true
}
}
return false
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment