This commit is contained in:
onyx-and-iris 2023-12-04 17:23:02 +00:00
parent 714558f3c1
commit 8aa073b5ad
8 changed files with 210 additions and 0 deletions

5
day-4/go.mod Normal file
View File

@ -0,0 +1,5 @@
module github.com/onyx-and-iris/aoc2023/day-4
go 1.20
require github.com/go-playground/assert v1.2.1

2
day-4/go.sum Normal file
View File

@ -0,0 +1,2 @@
github.com/go-playground/assert v1.2.1 h1:ad06XqC+TOv0nJWnbULSlh3ehp5uLuQEojZY5Tq8RgI=
github.com/go-playground/assert v1.2.1/go.mod h1:Lgy+k19nOB/wQG/fVSQ7rra5qYugmytMQqvQ2dgjWn8=

61
day-4/one.go Normal file
View File

@ -0,0 +1,61 @@
package main
import (
"regexp"
)
type M map[string]interface{}
var allCards []M
var _regex_winning_numbers = regexp.MustCompile(
`^Card (?P<card>[\s\d]+):\s` +
`(?P<winning>[0-9\s]+)\s` +
`\|\s` +
`(?P<mynums>[0-9\s]+)$`)
var _regex_nums = regexp.MustCompile("[0-9]+")
// compareLists returns the number of matching elements between winning and mynums
func compareLists(winningStr string, mynumsStr string) (int, error) {
x, err := numStrToArr(winningStr, []int{})
if err != nil {
return 0, err
}
winning := x
x, err = numStrToArr(mynumsStr, []int{})
if err != nil {
return 0, err
}
mynums := x
n := 0
for _, num := range mynums {
if contains(winning, num) {
n += 1
}
}
return n, nil
}
// one computes points based on matching numbers
func one(lines []string) (int, error) {
for _, line := range lines {
parseAllCards(line)
}
cards = make([]Card, len(lines))
sum := 0
for x, card := range allCards {
m, err := compareLists(card["winning"].(string), card["mynums"].(string))
if err != nil {
return 0, err
}
cards[x].matches = m
if cards[x].matches > 0 {
sum += (pow(2, cards[x].matches-1))
}
}
return sum, nil
}

25
day-4/one_test.go Normal file
View File

@ -0,0 +1,25 @@
package main
import (
"testing"
"github.com/go-playground/assert/v2"
)
func TestCompareLists(t *testing.T) {
//t.Skip("skipping test")
t.Run("Should find 4 matches", func(t *testing.T) {
res, _ := compareLists("41 48 83 86 17", "83 86 6 31 17 9 48 53")
assert.Equal(t, 4, res)
})
t.Run("Should find 2 matches", func(t *testing.T) {
res, _ := compareLists(" 1 21 53 59 44 ", "69 82 63 72 16 21 14 1")
assert.Equal(t, 2, res)
})
t.Run("Should find 0 matches", func(t *testing.T) {
res, _ := compareLists("87 83 26 28 32", "88 30 70 12 93 22 82 36")
assert.Equal(t, 0, res)
})
}

5
day-4/run.sh Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
INPUT="input.txt"
cat $INPUT | go run .

22
day-4/solution.go Normal file
View File

@ -0,0 +1,22 @@
package main
import (
"fmt"
"log"
)
func main() {
lines := readlines()
ans, err := one(lines)
if err != nil {
log.Fatal(err)
}
fmt.Printf("solution one: %d\n", ans)
ans, err = two(lines)
if err != nil {
log.Fatal(err)
}
fmt.Printf("solution two: %d\n", ans)
}

27
day-4/two.go Normal file
View File

@ -0,0 +1,27 @@
package main
// Cards represents a single card.
// it tracks its matching numbers and occurrences
type Card struct {
matches int
occurrences int
}
var cards = []Card{}
// two returns the total number of occurrences for all cards
func two(lines []string) (int, error) {
var sum = 0
for i := range cards {
cards[i].occurrences++
for j := i + 1; j <= i+cards[i].matches; j++ {
cards[j].occurrences += cards[i].occurrences
}
sum += cards[i].occurrences
}
return sum, nil
}

63
day-4/util.go Normal file
View File

@ -0,0 +1,63 @@
package main
import (
"bufio"
"log"
"math"
"os"
"strconv"
)
// readlines reads lines from stdin.
// Then it returns them as an array of strings
func readlines() []string {
lines := []string{}
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan() {
lines = append(lines, scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
return lines
}
func parseAllCards(line string) {
groups := M{}
res := _regex_winning_numbers.FindStringSubmatch(line)
names := _regex_winning_numbers.SubexpNames()
for i := range res {
groups[names[i]] = res[i]
}
allCards = append(allCards, groups)
}
// numStrToArr converts a string of numbers or an array of numbers
func numStrToArr(nums string, arr []int) ([]int, error) {
for _, num := range _regex_nums.FindAllString(nums, -1) {
n, err := strconv.Atoi(num)
if err != nil {
return []int{}, err
}
arr = append(arr, n)
}
return arr, nil
}
// contains returns true if an slice of elements contains a given element
func contains[T comparable](elems []T, v T) bool {
for _, s := range elems {
if v == s {
return true
}
}
return false
}
// pow returns the value of x to the n
func pow(x, n int) int {
return int(math.Pow(float64(x), float64(n)))
}