DEV Community

Discussion on: AoC Day 2: Inventory Management System

Collapse
 
bjarnemagnussen profile image
Bjarne Magnussen

I am using Advent of Code to learn Golang, and here is the solution I came up with. Suggestions for improvements are always welcome!

Part 1:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strings"
)

// readLines reads a whole file into memory
// and returns a slice of its lines.
func readLines(path string) ([]string, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    var lines []string
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    return lines, scanner.Err()
}

func main() {
    boxes, err := readLines("input")
    if err != nil {
        panic(err)
    }

    var twos, threes int
    for _, box := range boxes {
        // Iterate through each box letter-by-letter and check if letters appear
        // two or three times:
        two, three := false, false
        for _, letter := range box {
            if !two && strings.Count(box, string(letter)) == 2 {
                twos++
                two = true
            } else if !three && strings.Count(box, string(letter)) == 3 {
                threes++
                three = true
            }
            if two && three {
                // We already found the maximum number of appearing letters we count
                break
            }
        }
    }
    checksum := twos * threes
    fmt.Printf("Checksum is: %d\n", checksum)
}

Part 2:

package main

import (
    "bufio"
    "fmt"
    "os"
)

// readLines reads a whole file into memory
// and returns a slice of its lines.
func readLines(path string) ([]string, error) {
    file, err := os.Open(path)
    if err != nil {
        return nil, err
    }
    defer file.Close()

    var lines []string
    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        lines = append(lines, scanner.Text())
    }
    return lines, scanner.Err()
}

func findSimilar(boxes []string) string {
    // For each box name we remove the i'th element and store the rest of the
    // name inside a map:
    visited := make(map[int]map[string]bool)
    for _, box := range boxes {
        // Go through each  box:
        for i := range box {
            // Remove i'th character from box name:
            subname := box[:i] + box[i+1:]
            // Check if we have already visited a similar box name:
            _, ok := visited[i][subname]
            if !ok {
                // If we have never encountered a similar box name, add it:
                _, ok := visited[i]
                if !ok {
                    sub := make(map[string]bool)
                    visited[i] = sub
                }
                visited[i][subname] = true
            } else {
                // We have encounter a similar box name, return it:
                return subname
            }
        }
    }
    return ""
}

func main() {
    boxes, err := readLines("input")
    if err != nil {
        panic(err)
    }
    subname := findSimilar(boxes)
    fmt.Println(subname)
}

My idea was to use a dictionary and store the subnames and see if we encounter one we have already visited. Since there should only be one match we can immediately return it. I learned a lot about using maps in Golang!

I am also using Python that I have more experience with to cross check solutions. I have tried to implement it with readability in mind, not performance.

Part 1:

with open('input') as f:
    boxes = f.readlines()

twos, threes = 0, 0
for box in boxes:
    twos += any([box.count(letter) == 2 for letter in set(box)])
    threes += any([box.count(letter) == 3 for letter in set(box)])
checksum = twos * threes

print('Checksum {}'.format(checksum))

Part 2:

with open('input') as f:
    boxes = f.readlines()


def closest_boxes():
    visited = {}
    for box in boxes:
        for i in range(len(box)):
            if i not in visited:
                visited[i] = set()
            subname = box[0:i] + box[i+1:]
            if subname in visited[i]:
                return subname
            else:
                visited[i].add(subname)


print(closest_boxes())