1
0
Fork 0
mirror of https://github.com/Luzifer/aoc2019.git synced 2024-12-22 14:01:17 +00:00

Add solution for Day 19

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2019-12-19 14:23:27 +01:00
parent 84e8a9afa0
commit 3c60b28489
Signed by: luzifer
GPG key ID: DC2729FDD34BE99E
3 changed files with 253 additions and 0 deletions

231
day19.go Normal file
View file

@ -0,0 +1,231 @@
package aoc2019
import (
"io/ioutil"
"log"
"math"
"strings"
"github.com/pkg/errors"
)
type day19Fact uint8
const (
day19FactNoMoveDownPossible day19Fact = 1 << iota
day19FactNoMoveLeftPossible
day19FactNoMoveRightPossible
day19FactNoMoveTopPossible
day19FactOriginNotInBeam
day19FactX100NotInBeam
day19FactY100NotInBeam
)
func (f day19Fact) has(t day19Fact) bool { return f&t != 0 }
func (f day19Fact) String() string {
return map[day19Fact]string{
day19FactNoMoveDownPossible: "NoMoveDownPossible",
day19FactNoMoveLeftPossible: "NoMoveLeftPossible",
day19FactNoMoveRightPossible: "NoMoveRightPossible",
day19FactNoMoveTopPossible: "NoMoveTopPossible",
day19FactOriginNotInBeam: "OriginNotInBeam",
day19FactX100NotInBeam: "X100NotInBeam",
day19FactY100NotInBeam: "Y100NotInBeam",
}[f]
}
func day19CountFieldsInTractorBeam(code []int64, maxX, maxY int64) int64 {
var count int64
for y := int64(0); y <= maxY; y++ {
for x := int64(0); x <= maxX; x++ {
var (
in = make(chan int64)
out = make(chan int64)
)
go executeIntcode(code, in, out)
// Submit coordinates
in <- x
in <- y
// Count fields with tractor beam
o := <-out
count += o
}
}
return count
}
func day19Find100x100ShipPlace(code []int64) int64 {
var (
x, y int64
bvL, bvR int64
)
getBeamVectors := func() {
for x := int64(0); x <= math.MaxInt64; x++ {
var (
in = make(chan int64)
out = make(chan int64)
)
go executeIntcode(code, in, out)
// Submit coordinates
in <- x
in <- 100
// Count fields with tractor beam
o := <-out
switch {
case o == 0 && bvR == 0:
// Did not yet find the beam
case o == 1 && bvL == 0:
// Left beam end has not been set
bvL, bvR = x, x
case o == 1 && x > bvR:
// New right "edge" found
bvR = x
case 0 == 0 && bvR > 0:
// End of right edge found, end
return
}
}
}
checkCoordinate := func(x, y int64) day19Fact {
var facts day19Fact
for flag, c := range map[day19Fact][2]int64{
day19FactNoMoveDownPossible: {x, y + 100},
day19FactNoMoveLeftPossible: {x - 1, y + 99},
day19FactNoMoveRightPossible: {x + 100, y},
day19FactNoMoveTopPossible: {x + 99, y - 1},
day19FactOriginNotInBeam: {x, y},
day19FactX100NotInBeam: {x + 99, y},
day19FactY100NotInBeam: {x, y + 99},
} {
if c[0] < 0 || c[1] < 0 {
// Never check negative coordinates
facts |= flag
continue
}
var (
in = make(chan int64)
out = make(chan int64)
)
defer close(in)
go executeIntcode(code, in, out)
// Submit coordinates
in <- c[0]
in <- c[1]
o := <-out
if o == 0 {
facts |= flag
}
}
return facts
}
// Initially get vectors for beam edges
getBeamVectors()
// Try to get to the best position through movement
var success bool
for !success {
var f = checkCoordinate(x, y)
switch {
case f.has(day19FactOriginNotInBeam):
panic("Origin placed outside beam")
case f.has(day19FactX100NotInBeam) || f.has(day19FactY100NotInBeam):
// Ship does not fit, move further away
y += 100
x = ((bvL * (y / 100)) + (bvR * (y / 100))) / 2
case !f.has(day19FactNoMoveTopPossible):
// Ship can be moved up in beam
y -= 1
case !f.has(day19FactNoMoveLeftPossible):
// Ship can be moved left in beam
x -= 1
case f.has(day19FactNoMoveTopPossible) && f.has(day19FactNoMoveLeftPossible):
// No movement towards ship is possible and ship fits in: Perfect
success = true
}
}
log.Printf("Result before force-move: x=%d y=%d res=%d", x, y, x*10000+y)
// This MIGHT not be the perfect position, force further movement
// by ignoring some factors set above in order to compensate inaccurate
// vectors due to working with integers only
var fX, fY = x, y
for success {
var f = checkCoordinate(fX, fY)
if !f.has(day19FactX100NotInBeam) && !f.has(day19FactY100NotInBeam) {
// Found a better position through forcing
x, y = fX, fY
}
switch {
case !f.has(day19FactNoMoveTopPossible):
// Ship can be moved up in beam
fY -= 1
case f.has(day19FactOriginNotInBeam):
// No further tests, there will be no better position
success = false
default:
fX -= 1
}
}
log.Printf("Result after force-move: x=%d y=%d res=%d", x, y, x*10000+y)
return x*10000 + y
}
func solveDay19Part1(inFile string) (int64, error) {
rawCode, err := ioutil.ReadFile(inFile)
if err != nil {
return 0, errors.Wrap(err, "Unable to read intcode")
}
code, err := parseIntcode(strings.TrimSpace(string(rawCode)))
if err != nil {
return 0, errors.Wrap(err, "Unable to parse intcode")
}
return day19CountFieldsInTractorBeam(code, 49, 49), nil
}
func solveDay19Part2(inFile string) (int64, error) {
rawCode, err := ioutil.ReadFile(inFile)
if err != nil {
return 0, errors.Wrap(err, "Unable to read intcode")
}
code, err := parseIntcode(strings.TrimSpace(string(rawCode)))
if err != nil {
return 0, errors.Wrap(err, "Unable to parse intcode")
}
return day19Find100x100ShipPlace(code), nil
}

1
day19_input.txt Normal file
View file

@ -0,0 +1 @@
109,424,203,1,21101,11,0,0,1105,1,282,21102,1,18,0,1105,1,259,2102,1,1,221,203,1,21102,1,31,0,1105,1,282,21102,38,1,0,1105,1,259,20101,0,23,2,22102,1,1,3,21101,1,0,1,21101,57,0,0,1105,1,303,2101,0,1,222,21002,221,1,3,21002,221,1,2,21102,1,259,1,21101,0,80,0,1105,1,225,21102,83,1,2,21102,1,91,0,1106,0,303,2101,0,1,223,20102,1,222,4,21101,0,259,3,21101,0,225,2,21101,225,0,1,21101,118,0,0,1106,0,225,20101,0,222,3,21101,34,0,2,21101,133,0,0,1105,1,303,21202,1,-1,1,22001,223,1,1,21102,1,148,0,1106,0,259,1201,1,0,223,20102,1,221,4,20101,0,222,3,21101,12,0,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,20101,0,23,1,21102,1,-1,3,21102,214,1,0,1105,1,303,22101,1,1,1,204,1,99,0,0,0,0,109,5,1202,-4,1,249,22101,0,-3,1,22101,0,-2,2,21201,-1,0,3,21101,0,250,0,1105,1,225,21201,1,0,-4,109,-5,2106,0,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,22101,0,-2,-2,109,-3,2106,0,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,21201,-2,0,3,21101,343,0,0,1105,1,303,1105,1,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,1106,0,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,2106,0,0

21
day19_test.go Normal file
View file

@ -0,0 +1,21 @@
package aoc2019
import "testing"
func TestCalculateDay19_Part1(t *testing.T) {
res, err := solveDay19Part1("day19_input.txt")
if err != nil {
t.Fatalf("Day 19 solver failed: %s", err)
}
t.Logf("Solution Day 19 Part 1: %d", res)
}
func TestCalculateDay19_Part2(t *testing.T) {
res, err := solveDay19Part2("day19_input.txt")
if err != nil {
t.Fatalf("Day 19 solver failed: %s", err)
}
t.Logf("Solution Day 19 Part 2: %d", res)
}