From 0d86e1c187d554da414ec752ddf27263a1ed7be8 Mon Sep 17 00:00:00 2001 From: Markus Witt Date: Thu, 15 Dec 2022 19:53:29 +0100 Subject: [PATCH] feat: test possible solutions for 15 2 --- 15.go | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 15_test.go | 21 +++++-- main.go | 2 +- 3 files changed, 197 insertions(+), 8 deletions(-) diff --git a/15.go b/15.go index f364b2f..2173ad6 100644 --- a/15.go +++ b/15.go @@ -2,15 +2,19 @@ package main import ( "fmt" + "log" "regexp" "strconv" "strings" + "sync" ) -type AOC202215MapPoint int +type AOC202215MapPoint uint8 +type AOC202215MapPointUsed bool const ( - MPBeacon AOC202215MapPoint = iota + MPEmpty AOC202215MapPoint = iota + MPBeacon MPSensor MPNoBeacon ) @@ -24,6 +28,16 @@ type AOC202215SensorBeacon struct { type AOC202215Map struct { SensorBeacons []*AOC202215SensorBeacon Map map[int]map[int]AOC202215MapPoint + IntMap [][]AOC202215MapPointUsed + RowMap []AOC202215MapPointUsed +} + +func (m *AOC202215Map) PrintIntMap() string { + rows := []string{} + for _, row := range m.IntMap { + rows = append(rows, fmt.Sprintf("%+v", row)) + } + return strings.Join(rows, "\n") } func (m *AOC202215Map) SetPoint(x, y int, pt AOC202215MapPoint) { @@ -77,6 +91,117 @@ func (m *AOC202215Map) PopulateMapROI(row int) { } } +func (m *AOC202215Map) PopulateMapSparse(min, max int) { + for _, sb := range m.SensorBeacons { + for y := sb.Sensor[1] - sb.Distance; y <= sb.Sensor[1]+sb.Distance; y++ { + if y < min || y > max { + continue + } + + xDelta := sb.Distance - absInt(sb.Sensor[1]-y) + for _, x := range []int{sb.Sensor[0] - xDelta, sb.Sensor[0] + xDelta} { + if x < min || x > max { + continue + } + m.SetPoint(x, y, MPNoBeacon) + } + } + m.SetPoint(sb.Beacon[0], sb.Beacon[1], MPBeacon) + m.SetPoint(sb.Sensor[0], sb.Sensor[1], MPSensor) + } +} + +func (m *AOC202215Map) PopulateIntMap(min, max int) { + m.IntMap = make([][]AOC202215MapPointUsed, max) + for _, sb := range m.SensorBeacons { + for y := sb.Sensor[1] - sb.Distance; y <= sb.Sensor[1]+sb.Distance; y++ { + if y < min || y >= max { + continue + } + + if m.IntMap[y] == nil { + m.IntMap[y] = make([]AOC202215MapPointUsed, max) + } + + xDelta := sb.Distance - absInt(sb.Sensor[1]-y) + for x := sb.Sensor[0] - xDelta; x <= sb.Sensor[0]+xDelta; x++ { + if x < min || x >= max { + continue + } + m.IntMap[y][x] = true + } + } + m.IntMap[sb.Beacon[1]][sb.Beacon[0]] = true + m.IntMap[sb.Sensor[1]][sb.Sensor[0]] = true + } +} + +func (m *AOC202215Map) PopulateIntMapROI(row, min, max int) { + m.RowMap = make([]AOC202215MapPointUsed, max+2) + for _, sb := range m.SensorBeacons { + yMin := sb.Sensor[1] - sb.Distance + yMax := sb.Sensor[1] + sb.Distance + if yMin > row || yMax < row { + continue + } + + xDelta := sb.Distance - absInt(sb.Sensor[1]-row) + xMin := sb.Sensor[0] - xDelta + if xMin < min { + xMin = min + } + xMax := sb.Sensor[0] + xDelta + if xMax > max { + xMax = max + } + for x := xMin; x <= xMax; x++ { + m.RowMap[x] = true + } + + if sb.Beacon[1] == row && sb.Beacon[0] > min && sb.Beacon[0] < max { + m.RowMap[sb.Beacon[0]] = true + } + + if sb.Sensor[1] == row && sb.Sensor[0] > min && sb.Sensor[0] < max { + m.RowMap[sb.Sensor[0]] = true + } + } +} + +func (m *AOC202215Map) GetIntMapROI(row, min, max int) []AOC202215MapPointUsed { + rowMap := make([]AOC202215MapPointUsed, max+2) + for _, sb := range m.SensorBeacons { + yMin := sb.Sensor[1] - sb.Distance + yMax := sb.Sensor[1] + sb.Distance + if yMin > row || yMax < row { + continue + } + + xDelta := sb.Distance - absInt(sb.Sensor[1]-row) + xMin := sb.Sensor[0] - xDelta + if xMin < min { + xMin = min + } + xMax := sb.Sensor[0] + xDelta + if xMax > max { + xMax = max + } + for x := xMin; x <= xMax; x++ { + rowMap[x] = true + } + + if sb.Beacon[1] == row && sb.Beacon[0] > min && sb.Beacon[0] < max { + rowMap[sb.Beacon[0]] = true + } + + if sb.Sensor[1] == row && sb.Sensor[0] > min && sb.Sensor[0] < max { + rowMap[sb.Sensor[0]] = true + } + } + + return rowMap +} + func (m *AOC202215Map) ParseInput(input string) error { m.SensorBeacons = []*AOC202215SensorBeacon{} re := regexp.MustCompile(`Sensor at x=(-?\d+), y=(-?\d+): closest beacon is at x=(-?\d+), y=(-?\d+)`) @@ -135,3 +260,56 @@ func AOC2022151(input string) (string, error) { return fmt.Sprintf("%d", res), nil } + +func AOC2022152Helper(input string, min, max int) (int, error) { + sbMap := &AOC202215Map{} + err := sbMap.ParseInput(input) + if err != nil { + return 0, fmt.Errorf("can't parse input: %v", err) + } + + match := [][]int{} + wg := sync.WaitGroup{} + mtx := sync.Mutex{} + for y := min; y <= max; y++ { + wg.Add(1) + y := y + go func() { + rowMap := sbMap.GetIntMapROI(y, min, max) + + for i := 0; i < len(rowMap)-2; i++ { + if !rowMap[i] { + continue + } + if !rowMap[i+1] && rowMap[i+2] { + log.Printf("possible Match: %d/%d", i+1, y) + mtx.Lock() + match = append(match, []int{i + 1, y}) + mtx.Unlock() + } + } + wg.Done() + }() + } + + wg.Wait() + + if len(match) == 1 { + return match[0][0]*4000000 + match[0][1], nil + } + + if len(match) > 1 { + return 0, fmt.Errorf("found more than one match: %+v", match) + } + + return 0, fmt.Errorf("couldn't find match") +} + +func AOC2022152(input string) (string, error) { + res, err := AOC2022152Helper(input, 0, 4000000) + if err != nil { + return "", err + } + + return fmt.Sprintf("%d", res), nil +} diff --git a/15_test.go b/15_test.go index ca29179..4af6840 100644 --- a/15_test.go +++ b/15_test.go @@ -2,10 +2,11 @@ package main import "testing" -func TestAOC2022151(t *testing.T) { +func TestAOC202215(t *testing.T) { test := struct { input string - result int + first int + second int }{ input: `Sensor at x=2, y=18: closest beacon is at x=-2, y=15 Sensor at x=9, y=16: closest beacon is at x=10, y=16 @@ -21,7 +22,8 @@ Sensor at x=17, y=20: closest beacon is at x=21, y=22 Sensor at x=16, y=7: closest beacon is at x=15, y=3 Sensor at x=14, y=3: closest beacon is at x=15, y=3 Sensor at x=20, y=1: closest beacon is at x=15, y=3`, - result: 26, + first: 26, + second: 56000011, } got, err := AOC2022151Helper(test.input, 10) @@ -29,7 +31,16 @@ Sensor at x=20, y=1: closest beacon is at x=15, y=3`, t.Fatalf("AOC2022151Helper() err: %v", err) } - if got != test.result { - t.Errorf("AOC2022151Helper() missmatch:\nwant: %d\ngot: %d", test.result, got) + if got != test.first { + t.Errorf("AOC2022151Helper() missmatch:\nwant: %d\ngot: %d", test.first, got) + } + + got, err = AOC2022152Helper(test.input, 0, 20) + if err != nil { + t.Fatalf("AOC2022152Helper() err: %v", err) + } + + if got != test.second { + t.Errorf("AOC2022152Helper() missmatch:\nwant: %d\ngot: %d", test.second, got) } } diff --git a/main.go b/main.go index cb9219b..a44bda3 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,7 @@ func main() { 10: {AOC2022101, AOC2022102}, 12: {AOC2022121, AOC2022122}, 14: {AOC2022141, AOC2022142}, - 15: {AOC2022151}, + 15: {AOC2022151, AOC2022152}, } days := []int{} for day := range tasks {