diff --git a/days/19.go b/days/19.go new file mode 100644 index 0000000..02b9fe4 --- /dev/null +++ b/days/19.go @@ -0,0 +1,146 @@ +package days + +import ( + "fmt" + + u "parnic.com/aoc2019/utilities" +) + +type Day19 struct { + program u.IntcodeProgram +} + +func (d *Day19) Parse() { + d.program = u.LoadIntcodeProgram("19p") +} + +func (d Day19) Num() int { + return 19 +} + +func (d *Day19) Part1() string { + grid := make([][]bool, 50) + for y := 0; y < len(grid); y++ { + grid[y] = make([]bool, 50) + } + + count := int64(0) + + for y := 0; y < 50; y++ { + for x := 0; x < 50; x++ { + d.program.Reset() + d.program.RunIn(func(inputStep int) int64 { + if inputStep == 1 { + return int64(x) + } + + return int64(y) + }, func(val int64, state u.IntcodeProgramState) { + res := val == 1 + grid[y][x] = res + if res { + count++ + } + }) + } + } + + // fmt.Println("50x50 tractor view:") + // for y := 0; y < len(grid); y++ { + // for x := 0; x < len(grid[y]); x++ { + // if grid[y][x] { + // fmt.Print("█") + // } else { + // fmt.Print(" ") + // } + // } + // fmt.Println() + // } + + return fmt.Sprintf("Points affected in 50x50 area: %s%d%s", u.TextBold, count, u.TextReset) +} + +func (d *Day19) Part2() string { + f := func(x, y int) bool { + ret := false + d.program.Reset() + d.program.RunIn(func(inputStep int) int64 { + if inputStep == 1 { + return int64(x) + } + return int64(y) + }, func(val int64, state u.IntcodeProgramState) { + ret = val == 1 + }) + + return ret + } + + // find lower bound + // this may not be necessary, but helps seed the bisect with a known-good lower bound + startY := 0 + startX := 0 + for y := 1; startY == 0; y++ { + for x := 0; x < 10*y; x++ { + if f(x, y) { + startY = y + startX = x + break + } + } + } + + lastGoodX := 0 + threshold := 1 + // add 100 to start y since we know it has to be a 100x100 square. + // since we multiply x by 10,000 for the final result, that tells us y cannot be 10k+ + y := u.Bisect(startY+100, 9999, threshold, func(y int) bool { + foundX := false + for x := startX; ; x++ { + // check top left + if !f(x, y) { + if !foundX { + continue + } else { + return true + } + } + if !foundX { + foundX = true + } + + // check top right + if !f(x+99, y) { + return true + } + // check bottom left + if !f(x, y+99) { + continue + } + + // we believe the corners work, so run final validations on the full borders. + // this may not be necessary, but i've seen some rows end up shorter than a + // previous row because of the angle of the beam and our integer fidelity. + // plus it's really not that much more expensive to do to be certain we're correct. + for y2 := y; y2 < y+100; y2++ { + // right wall + if !f(x+99, y2) { + return true + } + // left wall + if !f(x, y2) { + return true + } + } + + lastGoodX = x + return false + } + }) + + // since we invert our bisect success returns, we need to increment y to + // tip back over into the "success" range + y += threshold + result := (lastGoodX * 10000) + y + return fmt.Sprintf("Closest 100x100 square for the ship starts at %d,%d = %s%d%s", lastGoodX, y, u.TextBold, result, u.TextReset) +} diff --git a/inputs/19p.txt b/inputs/19p.txt new file mode 100644 index 0000000..4bdbeb3 --- /dev/null +++ b/inputs/19p.txt @@ -0,0 +1 @@ +109,424,203,1,21102,11,1,0,1105,1,282,21101,0,18,0,1105,1,259,2101,0,1,221,203,1,21102,1,31,0,1105,1,282,21102,1,38,0,1105,1,259,20102,1,23,2,21201,1,0,3,21102,1,1,1,21102,57,1,0,1106,0,303,2102,1,1,222,21002,221,1,3,20101,0,221,2,21101,0,259,1,21101,0,80,0,1105,1,225,21101,44,0,2,21102,91,1,0,1105,1,303,1202,1,1,223,21002,222,1,4,21102,259,1,3,21102,1,225,2,21102,225,1,1,21101,118,0,0,1106,0,225,21002,222,1,3,21101,163,0,2,21101,0,133,0,1106,0,303,21202,1,-1,1,22001,223,1,1,21102,148,1,0,1106,0,259,1202,1,1,223,20101,0,221,4,21001,222,0,3,21102,1,24,2,1001,132,-2,224,1002,224,2,224,1001,224,3,224,1002,132,-1,132,1,224,132,224,21001,224,1,1,21101,195,0,0,105,1,108,20207,1,223,2,21002,23,1,1,21102,-1,1,3,21102,1,214,0,1106,0,303,22101,1,1,1,204,1,99,0,0,0,0,109,5,2101,0,-4,249,22102,1,-3,1,22101,0,-2,2,22101,0,-1,3,21102,250,1,0,1106,0,225,21202,1,1,-4,109,-5,2105,1,0,109,3,22107,0,-2,-1,21202,-1,2,-1,21201,-1,-1,-1,22202,-1,-2,-2,109,-3,2106,0,0,109,3,21207,-2,0,-1,1206,-1,294,104,0,99,22102,1,-2,-2,109,-3,2105,1,0,109,5,22207,-3,-4,-1,1206,-1,346,22201,-4,-3,-4,21202,-3,-1,-1,22201,-4,-1,2,21202,2,-1,-1,22201,-4,-1,1,21202,-2,1,3,21101,0,343,0,1106,0,303,1106,0,415,22207,-2,-3,-1,1206,-1,387,22201,-3,-2,-3,21202,-2,-1,-1,22201,-3,-1,3,21202,3,-1,-1,22201,-3,-1,2,21201,-4,0,1,21101,384,0,0,1105,1,303,1105,1,415,21202,-4,-1,-4,22201,-4,-3,-4,22202,-3,-2,-2,22202,-2,-4,-4,22202,-3,-2,-3,21202,-4,-1,-2,22201,-3,-2,1,21202,1,1,-4,109,-5,2105,1,0 \ No newline at end of file diff --git a/main.go b/main.go index 1a1c0cc..f4b640b 100644 --- a/main.go +++ b/main.go @@ -52,6 +52,7 @@ var dayMap = []day{ &days.Day16{}, &days.Day17{}, &days.Day18{}, + &days.Day19{}, } func main() {