2022 Day 6

Posted on Dec 6, 2022

Part 1

Problem

Read in a stream of characters and identify the first point at which 4 consecutive characters are unique.

General solution

This is trivial - we simply read it one line of the file, get the first 4 characters into a queue, and then check whether they are unique. If not, move the start point along by one and check the next four characters.

Solution: Go

Although we could read in a file character by character, this would potentially cause a lot of read requests. Given the small size of the input, we can just read in the entire file (one line) and then process it (even if we read the file one character at a time, the operating system may pull in more than one character into a buffer anyway). If the input was large or the system was severely memory-constrained, we could read the file one character at a time.

Once we have the input, we can move through it in chunks of 4 characters. Each character is added to a map of characters we have ‘seen’. If the count of seen characters is 4, then all the characters must be unique and therefore we can print the end index of the chunk (plus one as end indexes are exclusive).

package main

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

func main() {
	const chunkLength = 4

	// ASSUMPTION: There is only one line of input and no errors
	byteInput, _ := os.ReadFile(os.Stdin.Name())
	input := string(byteInput)

	for start, end := 0, chunkLength-1; end < len(input); start, end = start+1, end+1 {
		// Add one to end because second array slice index is exclusive
		chunk := input[start : end+1]
		characters := strings.Split(chunk, "")
		seen := make(map[string]bool)

		for c := range characters {
			seen[characters[c]] = true
		}

		if len(seen) == chunkLength {
			// All characters are unique
			fmt.Println(end + 1)
			os.Exit(0)
		}
	}
}

Part 2

Problem

As part 1, except find the first point at which 14 consecutive characters are unique.

General solution

Identical to part 1, except we examine 14 character chunks.

Solution: Go

Identical to part 1, except we change the chunk size (handily expressed as a constant - what foresight) to 14. The logic is the same as the loop calculates everything from the chunk size.

package main

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

func main() {
	const chunkLength = 14

	// ASSUMPTION: There is only one line of input and no errors
	byteInput, _ := os.ReadFile(os.Stdin.Name())
	input := string(byteInput)

	for start, end := 0, chunkLength-1; end < len(input); start, end = start+1, end+1 {
		// Add one to end because second array slice index is exclusive
		chunk := input[start : end+1]
		characters := strings.Split(chunk, "")
		seen := make(map[string]bool)

		for c := range characters {
			seen[characters[c]] = true
		}

		if len(seen) == chunkLength {
			// All characters are unique
			fmt.Println(end + 1)
			os.Exit(0)
		}
	}
}

Post-solution thoughts

Parts 1 & 2 could be part of a single file if the ‘search for unique chunk’ loop was moved into a function which took the input and chunk size as a parameter and returned the end point.