diff --git a/day-5/data.go b/day-5/data.go new file mode 100644 index 0000000..d789ba4 --- /dev/null +++ b/day-5/data.go @@ -0,0 +1,19 @@ +package main + +type Data struct { + dest int + source int + offset int +} + +var seeds = []int{} + +var dataMap = map[string][]Data{ + "seed-to-soil": make([]Data, 0), + "soil-to-fertilizer": make([]Data, 0), + "fertilizer-to-water": make([]Data, 0), + "water-to-light": make([]Data, 0), + "light-to-temperature": make([]Data, 0), + "temperature-to-humidity": make([]Data, 0), + "humidity-to-location": make([]Data, 0), +} diff --git a/day-5/go.mod b/day-5/go.mod new file mode 100644 index 0000000..1ee3b8e --- /dev/null +++ b/day-5/go.mod @@ -0,0 +1,7 @@ +module github.com/onyx-and-iris/aoc2023/day-5 + +go 1.20 + +require github.com/sirupsen/logrus v1.9.3 + +require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect diff --git a/day-5/go.sum b/day-5/go.sum new file mode 100644 index 0000000..21f9bfb --- /dev/null +++ b/day-5/go.sum @@ -0,0 +1,15 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/day-5/one.go b/day-5/one.go new file mode 100644 index 0000000..8fda1e8 --- /dev/null +++ b/day-5/one.go @@ -0,0 +1,49 @@ +package main + +import ( + log "github.com/sirupsen/logrus" +) + +var identifiers = []string{"seed-to-soil", "soil-to-fertilizer", "fertilizer-to-water", "water-to-light", "light-to-temperature", "temperature-to-humidity", "humidity-to-location"} + +func next(i int, datapoint int) int { + if i == len(identifiers) { + return datapoint + } + + dest := func() int { + datas := dataMap[identifiers[i]] + dest := 0 + for _, data := range datas { + if datapoint >= data.source && datapoint <= data.source+data.offset { + dest = data.dest + (datapoint - data.source) + break + } + } + if dest == 0 { + dest = datapoint + } + return dest + }() + //log.Debug(identifiers[i], ": ", dest) + return next(i+1, dest) +} + +// one returns the lowest location +func one(lines []string) (int, error) { + lowest := 0 + parseLines(lines) + + for _, seed := range seeds { + location := next(0, seed) + log.Info(location) + if lowest == 0 { + lowest = location + } + if location < lowest { + lowest = location + } + } + + return lowest, nil +} diff --git a/day-5/solution.go b/day-5/solution.go new file mode 100644 index 0000000..fc95902 --- /dev/null +++ b/day-5/solution.go @@ -0,0 +1,27 @@ +package main + +import ( + "fmt" + + log "github.com/sirupsen/logrus" +) + +func init() { + log.SetLevel(log.DebugLevel) +} + +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) +} diff --git a/day-5/two.go b/day-5/two.go new file mode 100644 index 0000000..8a47f1a --- /dev/null +++ b/day-5/two.go @@ -0,0 +1,78 @@ +package main + +import ( + "fmt" + "math" + "sync" + "sync/atomic" + "time" + + log "github.com/sirupsen/logrus" +) + +type WaitGroupCount struct { + sync.WaitGroup + count int64 +} + +func (wg *WaitGroupCount) Add(delta int) { + atomic.AddInt64(&wg.count, int64(delta)) + wg.WaitGroup.Add(delta) +} + +func (wg *WaitGroupCount) Done() { + atomic.AddInt64(&wg.count, -1) + wg.WaitGroup.Done() +} + +func (wg *WaitGroupCount) GetCount() int { + return int(atomic.LoadInt64(&wg.count)) +} + +var wg = WaitGroupCount{} + +//var checked = make([]bound, 0) + +type bound struct { + start int + end int +} + +var bounds = []bound{} + +// two returns the lowest location +func two(lines []string) (int, error) { + lowest := math.MaxInt + + for i := 0; i < len(seeds); i += 2 { + bounds = append(bounds, bound{start: seeds[i], end: seeds[i] + seeds[i+1]}) + } + + startTime := time.Now() + + go func() { + for { + elapsed := time.Since(startTime) + fmt.Printf("[%s] wg count: %d\n", elapsed.Round(time.Second), wg.GetCount()) + time.Sleep(time.Second) + } + }() + + for _, bound := range bounds { + wg.Add(1) + go func(start int, end int) { + defer wg.Done() + for i := start; i < end; i++ { + location := next(0, i) + if location < lowest { + lowest = location + } + } + }(bound.start, bound.end) + log.Info(bound, " completed") + } + + wg.Wait() + + return lowest - 1, nil // returning a value one too high? not sure why. +} diff --git a/day-5/util.go b/day-5/util.go new file mode 100644 index 0000000..c6503e3 --- /dev/null +++ b/day-5/util.go @@ -0,0 +1,73 @@ +package main + +import ( + "bufio" + "log" + "os" + "regexp" + "strconv" + "strings" + "unicode" +) + +// 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 +} + +// parseLines parses input to a data map +func parseLines(lines []string) { + var _regex_identifier = regexp.MustCompile(`(?P[\w-]+) map[:]`) + + f := func(c rune) bool { + return !unicode.IsDigit(c) + } + + for i := 0; i < len(lines); i++ { + if i == 0 { + seeds = convertToInts(strings.FieldsFunc(lines[i], f)) + continue + } + + m := _regex_identifier.FindStringSubmatch(lines[i]) + if len(m) == 2 { + for i = i + 1; i < len(lines) && len(lines[i]) != 0; i++ { + nums := convertToInts(strings.FieldsFunc(lines[i], f)) + dataMap[m[1]] = append(dataMap[m[1]], Data{dest: nums[0], source: nums[1], offset: nums[2]}) + } + } + } +} + +// convertToInts converts a string representing ints to an array of ints +func convertToInts(data []string) []int { + nums := []int{} + for _, elem := range data { + n, _ := strconv.Atoi(elem) + nums = append(nums, n) + } + return nums +} + +/* +func isChecked(i int) bool { + for _, bound := range checked { + if i > bound.start && i < bound.end { + return true + } + } + return false +} +*/