Day_1
This commit is contained in:
8
2023/gareth/.idea/.gitignore
generated
vendored
Normal file
8
2023/gareth/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
9
2023/gareth/.idea/awesomeProject.iml
generated
Normal file
9
2023/gareth/.idea/awesomeProject.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
2023/gareth/.idea/modules.xml
generated
Normal file
8
2023/gareth/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/awesomeProject.iml" filepath="$PROJECT_DIR$/.idea/awesomeProject.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
61
2023/gareth/day01/day01.go
Normal file
61
2023/gareth/day01/day01.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package day01
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Part1(input string) int {
|
||||
total := 0
|
||||
lines := strings.Split(input, "\r\n")
|
||||
for _, line := range lines {
|
||||
regex := regexp.MustCompile("[a-zA-Z]")
|
||||
numbers := regex.ReplaceAllString(line, "")
|
||||
number := string(numbers[0]) + string(numbers[len(numbers)-1])
|
||||
i, _ := strconv.Atoi(number)
|
||||
total += i
|
||||
}
|
||||
|
||||
return total
|
||||
}
|
||||
|
||||
func Part2(input string) int {
|
||||
values := map[string]string{
|
||||
"one": "1",
|
||||
"two": "2",
|
||||
"three": "3",
|
||||
"four": "4",
|
||||
"five": "5",
|
||||
"six": "6",
|
||||
"seven": "7",
|
||||
"eight": "8",
|
||||
"nine": "9",
|
||||
}
|
||||
lines := strings.Split(input, "\r\n")
|
||||
s := ""
|
||||
|
||||
total := 0
|
||||
for _, line := range lines {
|
||||
numbers := []string{}
|
||||
for _, c := range line {
|
||||
s = s + string(c)
|
||||
if num, err := strconv.Atoi(string(c)); err == nil {
|
||||
numbers = append(numbers, strconv.Itoa(num))
|
||||
s = ""
|
||||
}
|
||||
for key, value := range values {
|
||||
if strings.Contains(s, key) {
|
||||
numbers = append(numbers, value)
|
||||
buffer := s[len(s)-1]
|
||||
s = "" + string(buffer)
|
||||
}
|
||||
}
|
||||
}
|
||||
number := numbers[0] + numbers[len(numbers)-1]
|
||||
i, _ := strconv.Atoi(number)
|
||||
total += i
|
||||
s = ""
|
||||
}
|
||||
return total
|
||||
}
|
||||
25
2023/gareth/day01/day01_test.go
Normal file
25
2023/gareth/day01/day01_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package day01
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPart1(t *testing.T) {
|
||||
r := Part1(`1abc2
|
||||
pqr3stu8vwx
|
||||
a1b2c3d4e5f
|
||||
treb7uchet`)
|
||||
assert.Equal(t, 142, r)
|
||||
}
|
||||
|
||||
func TestPart2(t *testing.T) {
|
||||
r := Part2(`two1nine
|
||||
eightwothree
|
||||
abcone2threexyz
|
||||
xtwone3four
|
||||
4nineeightseven2
|
||||
zoneight234
|
||||
7pqrstsixteen`)
|
||||
assert.Equal(t, 281, r)
|
||||
}
|
||||
1000
2023/gareth/day01/input.txt
Normal file
1000
2023/gareth/day01/input.txt
Normal file
File diff suppressed because it is too large
Load Diff
14
2023/gareth/go.mod
Normal file
14
2023/gareth/go.mod
Normal file
@@ -0,0 +1,14 @@
|
||||
module awesomeProject
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/stretchr/testify v1.8.4
|
||||
golang.org/x/exp v0.0.0-20231127185646-65229373498e
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
12
2023/gareth/go.sum
Normal file
12
2023/gareth/go.sum
Normal file
@@ -0,0 +1,12 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No=
|
||||
golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
12
2023/gareth/main.go
Normal file
12
2023/gareth/main.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"awesomeProject/day01"
|
||||
"awesomeProject/utils"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Printf("part 1: %d\n", day01.Part1(utils.Readfile(01)))
|
||||
fmt.Printf("part 2: %d\n", day01.Part2(utils.Readfile(01)))
|
||||
}
|
||||
74
2023/gareth/utils/grid2d/grid2d.go
Normal file
74
2023/gareth/utils/grid2d/grid2d.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package grid2d
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"adventofcode2022/utils"
|
||||
)
|
||||
|
||||
type Grid[T any] struct {
|
||||
sizeX, sizeY int
|
||||
matrix [][]T
|
||||
empty T
|
||||
}
|
||||
|
||||
func NewGrid[T any](sizeX, sizeY int, empty T) *Grid[T] {
|
||||
matrix := make([][]T, sizeY)
|
||||
rows := make([]T, sizeX*sizeY)
|
||||
for i := 0; i < sizeX*sizeY; i++ {
|
||||
rows[i] = empty
|
||||
}
|
||||
|
||||
j := 0
|
||||
for i := 0; i < sizeY; i++ {
|
||||
matrix[i] = rows[j : j+sizeX : j+sizeX]
|
||||
j += sizeX
|
||||
}
|
||||
return &Grid[T]{
|
||||
sizeX: sizeX,
|
||||
sizeY: sizeY,
|
||||
matrix: matrix,
|
||||
empty: empty,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Grid[T]) SizeX() int {
|
||||
return g.sizeX
|
||||
}
|
||||
|
||||
func (g *Grid[T]) SizeY() int {
|
||||
return g.sizeY
|
||||
}
|
||||
|
||||
func (g *Grid[T]) Get(x, y int) T {
|
||||
if x < 0 || x >= g.sizeX {
|
||||
return g.empty
|
||||
}
|
||||
if y < 0 || y >= g.sizeY {
|
||||
return g.empty
|
||||
}
|
||||
return g.matrix[y][x]
|
||||
}
|
||||
|
||||
func (g *Grid[T]) Set(x, y int, v T) {
|
||||
if x < 0 || x >= g.sizeX {
|
||||
panic("invalid x")
|
||||
}
|
||||
if y < 0 || y >= g.sizeY {
|
||||
panic("invalid y")
|
||||
}
|
||||
g.matrix[y][x] = v
|
||||
}
|
||||
|
||||
func (g *Grid[T]) StringWithFormatter(formatter func(T, int, int) string) string {
|
||||
var r strings.Builder
|
||||
for j := 0; j < g.sizeY; j++ {
|
||||
for i := 0; i < g.sizeX; i++ {
|
||||
_, err := r.WriteString(formatter(g.matrix[j][i], i, j))
|
||||
utils.PanicOnErr(err)
|
||||
}
|
||||
_, err := r.WriteRune('\n')
|
||||
utils.PanicOnErr(err)
|
||||
}
|
||||
return r.String()
|
||||
}
|
||||
45
2023/gareth/utils/inputs/inputs.go
Normal file
45
2023/gareth/utils/inputs/inputs.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package inputs
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"adventofcode2022/utils"
|
||||
"adventofcode2022/utils/grid2d"
|
||||
sparsegrid "adventofcode2022/utils/sparseGrid"
|
||||
)
|
||||
|
||||
func ToInts(input string, sep string) []int {
|
||||
var r []int
|
||||
for _, line := range strings.Split(input, sep) {
|
||||
if line != "" {
|
||||
r = append(r, utils.MustAtoi(line))
|
||||
}
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
func ToGrid2D[T any](input, rowSep, colSep string, empty T, conv func(string) T) *grid2d.Grid[T] {
|
||||
lines := strings.Split(input, rowSep)
|
||||
|
||||
grid := grid2d.NewGrid(len(lines[0]), len(lines), empty)
|
||||
for y, line := range lines {
|
||||
for x, v := range strings.Split(line, colSep) {
|
||||
grid.Set(x, y, conv(v))
|
||||
}
|
||||
}
|
||||
|
||||
return grid
|
||||
}
|
||||
|
||||
func ToSparseGrid[T comparable](input, rowSep, colSep string, empty T, conv func(string) T) *sparsegrid.SparseGrid[T] {
|
||||
lines := strings.Split(input, rowSep)
|
||||
|
||||
grid := sparsegrid.NewGrid(empty)
|
||||
for y, line := range lines {
|
||||
for x, v := range strings.Split(line, colSep) {
|
||||
grid.Set(x, y, conv(v))
|
||||
}
|
||||
}
|
||||
|
||||
return grid
|
||||
}
|
||||
81
2023/gareth/utils/sparseGrid/sparseGrid.go
Normal file
81
2023/gareth/utils/sparseGrid/sparseGrid.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package sparsegrid
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"adventofcode2022/utils"
|
||||
)
|
||||
|
||||
type SparseGrid[T comparable] struct {
|
||||
minX, maxX, minY, maxY int
|
||||
data map[string]T
|
||||
empty T
|
||||
}
|
||||
|
||||
func NewGrid[T comparable](empty T) *SparseGrid[T] {
|
||||
return &SparseGrid[T]{
|
||||
minX: utils.MaxInt,
|
||||
maxX: utils.MinInt,
|
||||
minY: utils.MaxInt,
|
||||
maxY: utils.MinInt,
|
||||
data: map[string]T{},
|
||||
empty: empty,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *SparseGrid[T]) SizeX() (int, int) {
|
||||
return g.minX, g.maxX
|
||||
}
|
||||
|
||||
func (g *SparseGrid[T]) SizeY() (int, int) {
|
||||
return g.minY, g.maxY
|
||||
}
|
||||
|
||||
func (g *SparseGrid[T]) Visited() int {
|
||||
return len(g.data)
|
||||
}
|
||||
|
||||
func (g *SparseGrid[T]) Get(x, y int) T {
|
||||
k := key(x, y)
|
||||
v, ok := g.data[k]
|
||||
if !ok {
|
||||
return g.empty
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func (g *SparseGrid[T]) Set(x, y int, v T) {
|
||||
k := key(x, y)
|
||||
current, ok := g.data[k]
|
||||
if ok && v == current {
|
||||
return
|
||||
} else if !ok && v == g.empty {
|
||||
return
|
||||
} else if v == g.empty {
|
||||
delete(g.data, k)
|
||||
} else {
|
||||
g.data[k] = v
|
||||
g.minX = utils.Min(g.minX, x)
|
||||
g.maxX = utils.Max(g.maxX, x)
|
||||
g.minY = utils.Min(g.minY, y)
|
||||
g.maxY = utils.Max(g.maxY, y)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *SparseGrid[T]) StringWithFormatter(formatter func(T, int, int) string) string {
|
||||
var r strings.Builder
|
||||
for j := g.minY; j <= g.maxY; j++ {
|
||||
for i := g.minX; i <= g.maxX; i++ {
|
||||
_, err := r.WriteString(formatter(g.Get(i, j), i, j))
|
||||
utils.PanicOnErr(err)
|
||||
}
|
||||
_, err := r.WriteRune('\n')
|
||||
utils.PanicOnErr(err)
|
||||
}
|
||||
return r.String()
|
||||
}
|
||||
|
||||
func key(x, y int) string {
|
||||
return fmt.Sprintf("%d:%d", x, y)
|
||||
}
|
||||
207
2023/gareth/utils/utils.go
Normal file
207
2023/gareth/utils/utils.go
Normal file
@@ -0,0 +1,207 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/constraints"
|
||||
)
|
||||
|
||||
func PanicOnErr(err error) {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
const MaxInt = int(^uint(0) >> 1)
|
||||
const MinInt = ^MaxInt
|
||||
|
||||
func Max[T constraints.Ordered](a, b T) T {
|
||||
if a > b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func Min[T constraints.Ordered](a, b T) T {
|
||||
if a < b {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func SliceMinMax[T constraints.Ordered](slice []T) (*T, *T) {
|
||||
if len(slice) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
min := &slice[0]
|
||||
max := &slice[0]
|
||||
for i, v := range slice {
|
||||
if v < *min {
|
||||
min = &slice[i]
|
||||
}
|
||||
if v > *max {
|
||||
max = &slice[i]
|
||||
}
|
||||
}
|
||||
return min, max
|
||||
}
|
||||
|
||||
func MustAtoi(s string) int {
|
||||
v, err := strconv.Atoi(s)
|
||||
PanicOnErr(err)
|
||||
return v
|
||||
}
|
||||
|
||||
// Returns key from map[T]int which has the max value
|
||||
func MapFindMax(m interface{}) interface{} {
|
||||
var maxK interface{} = nil
|
||||
var maxV = MinInt
|
||||
iter := reflect.ValueOf(m).MapRange()
|
||||
for iter.Next() {
|
||||
k := iter.Key()
|
||||
v := int(iter.Value().Int())
|
||||
if v > maxV {
|
||||
maxV = v
|
||||
maxK = k.Interface()
|
||||
}
|
||||
}
|
||||
return maxK
|
||||
}
|
||||
|
||||
// Returns key from map[T]int which has the min value
|
||||
func MapFindMin(m interface{}) interface{} {
|
||||
var minK interface{} = nil
|
||||
var minV = MaxInt
|
||||
iter := reflect.ValueOf(m).MapRange()
|
||||
for iter.Next() {
|
||||
k := iter.Key()
|
||||
v := int(iter.Value().Int())
|
||||
if v < minV {
|
||||
minV = v
|
||||
minK = k.Interface()
|
||||
}
|
||||
}
|
||||
return minK
|
||||
}
|
||||
|
||||
func Readfile(day int) string {
|
||||
filename := fmt.Sprintf("day%02d/input.txt", day)
|
||||
file, err := os.Open(filename)
|
||||
PanicOnErr(err)
|
||||
defer file.Close()
|
||||
|
||||
reader := bufio.NewReader(file)
|
||||
contents, err := io.ReadAll(reader)
|
||||
PanicOnErr(err)
|
||||
|
||||
return strings.TrimSuffix(string(contents), "\n")
|
||||
}
|
||||
|
||||
func ParseToStruct(re *regexp.Regexp, input string, target interface{}) bool {
|
||||
m := re.FindStringSubmatch(input)
|
||||
if m == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var useOffset bool
|
||||
|
||||
for i, name := range re.SubexpNames() {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
var field reflect.Value
|
||||
if name == "" {
|
||||
// use offset
|
||||
if i == 1 {
|
||||
useOffset = true
|
||||
} else if !useOffset {
|
||||
panic("can't mix named and unnamed subexpressions")
|
||||
}
|
||||
field = reflect.ValueOf(target).Elem().Field(i - 1)
|
||||
} else {
|
||||
// use name
|
||||
if i == 1 {
|
||||
useOffset = false
|
||||
} else if useOffset {
|
||||
panic("can't mix named and unnamed subexpressions")
|
||||
}
|
||||
field = reflect.ValueOf(target).Elem().FieldByName(name)
|
||||
}
|
||||
if field.Kind() == reflect.String {
|
||||
field.SetString(m[i])
|
||||
} else if field.Kind() == reflect.Int {
|
||||
v, err := strconv.Atoi(m[i])
|
||||
PanicOnErr(err)
|
||||
field.SetInt(int64(v))
|
||||
} else if field.Kind() == reflect.Uint8 {
|
||||
if len(m[i]) != 1 {
|
||||
panic(fmt.Sprintf("expecting 1 char, got: %s", m[i]))
|
||||
}
|
||||
field.SetUint(uint64(m[i][0]))
|
||||
} else {
|
||||
panic(fmt.Sprintf("unknown kind: %s", field.Kind()))
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func MustParseToStruct(re *regexp.Regexp, input string, target interface{}) {
|
||||
if !ParseToStruct(re, input, target) {
|
||||
panic(fmt.Errorf("failed to parse: %s", input))
|
||||
}
|
||||
}
|
||||
|
||||
func CharToLower(c byte) byte {
|
||||
return strings.ToLower(string(c))[0]
|
||||
}
|
||||
|
||||
func CharToUpper(c byte) byte {
|
||||
return strings.ToUpper(string(c))[0]
|
||||
}
|
||||
|
||||
func Contains(haystack []string, needle string) bool {
|
||||
for _, s := range haystack {
|
||||
if s == needle {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func Abs[T constraints.Signed](x T) T {
|
||||
if x < 0 {
|
||||
return -x
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
func Gcd(x, y int) int {
|
||||
if x <= 0 || y <= 0 {
|
||||
panic(fmt.Errorf("invalid input: %d, %d", x, y))
|
||||
}
|
||||
if x == y {
|
||||
return x
|
||||
}
|
||||
if x > y {
|
||||
return Gcd(x-y, y)
|
||||
} else {
|
||||
return Gcd(x, y-x)
|
||||
}
|
||||
}
|
||||
|
||||
func Sign[T constraints.Signed](x T) int {
|
||||
if x < 0 {
|
||||
return -1
|
||||
} else if x > 0 {
|
||||
return 1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user