mirror of
https://github.com/Luzifer/aoc2019.git
synced 2024-12-22 05:51:16 +00:00
Add solution for Day 11
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
38c9de6a8a
commit
0602aad44e
4 changed files with 194 additions and 0 deletions
172
day11.go
Normal file
172
day11.go
Normal file
|
@ -0,0 +1,172 @@
|
|||
package aoc2019
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/png"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type day11PaintDirective struct {
|
||||
X, Y int
|
||||
Color int64
|
||||
}
|
||||
|
||||
func (d day11PaintDirective) positionKey() string { return fmt.Sprintf("%d:%d", d.X, d.Y) }
|
||||
|
||||
func day11ExecutePaintRobot(inFile string, startPanelColor int64) ([]day11PaintDirective, error) {
|
||||
var (
|
||||
posX, posY int
|
||||
direction int // Clock-hand direction
|
||||
directives = map[string]day11PaintDirective{
|
||||
"0:0": {X: 0, Y: 0, Color: startPanelColor},
|
||||
}
|
||||
)
|
||||
|
||||
move := func() {
|
||||
switch direction {
|
||||
case 0:
|
||||
posY -= 1
|
||||
case 3:
|
||||
posX += 1
|
||||
case 6:
|
||||
posY += 1
|
||||
case 9:
|
||||
posX -= 1
|
||||
default:
|
||||
panic(errors.Errorf("Invalid direction: %d", direction))
|
||||
}
|
||||
}
|
||||
|
||||
rotate := func(dir int64) {
|
||||
var factor int
|
||||
if dir == 1 {
|
||||
// turn right
|
||||
factor = 1
|
||||
} else {
|
||||
// turn left
|
||||
factor = -1
|
||||
}
|
||||
direction = direction + factor*3
|
||||
if direction < 0 {
|
||||
direction += 12
|
||||
}
|
||||
if direction > 11 {
|
||||
direction -= 12
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize code
|
||||
rawCode, err := ioutil.ReadFile(inFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to read intcode")
|
||||
}
|
||||
|
||||
code, err := parseIntcode(strings.TrimSpace(string(rawCode)))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Unable to parse intcode")
|
||||
}
|
||||
|
||||
// Run program in background
|
||||
var (
|
||||
in = make(chan int64, 1)
|
||||
out = make(chan int64, 2)
|
||||
outputs []int64
|
||||
programExit bool
|
||||
wg = new(sync.WaitGroup)
|
||||
)
|
||||
|
||||
go executeIntcode(code, in, out)
|
||||
go func() {
|
||||
for o := range out {
|
||||
outputs = append(outputs, o)
|
||||
wg.Done()
|
||||
}
|
||||
programExit = true
|
||||
}()
|
||||
|
||||
// Start feeding scan results
|
||||
for !programExit {
|
||||
// Get previous directive for current position
|
||||
var dir = day11PaintDirective{X: posX, Y: posY}
|
||||
if d, ok := directives[dir.positionKey()]; ok {
|
||||
dir = d
|
||||
}
|
||||
|
||||
// Feed current color and expect two output
|
||||
wg.Add(2)
|
||||
in <- dir.Color
|
||||
wg.Wait()
|
||||
|
||||
// Set current color
|
||||
dir.Color = outputs[0]
|
||||
directives[dir.positionKey()] = dir
|
||||
// Rotate robot
|
||||
rotate(outputs[1])
|
||||
// Move
|
||||
move()
|
||||
|
||||
// Reset outputs
|
||||
outputs = nil
|
||||
}
|
||||
|
||||
var result []day11PaintDirective
|
||||
for _, v := range directives {
|
||||
result = append(result, v)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func solveDay11Part1(inFile string) (int, error) {
|
||||
dirs, err := day11ExecutePaintRobot(inFile, 0)
|
||||
return len(dirs), errors.Wrap(err, "Unable to execute robot")
|
||||
}
|
||||
|
||||
func solveDay11Part2(inFile string) error {
|
||||
dirs, err := day11ExecutePaintRobot(inFile, 1)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to execute robot")
|
||||
}
|
||||
|
||||
var minX, minY, maxX, maxY = math.MaxInt64, math.MaxInt64, 0, 0
|
||||
for _, dir := range dirs {
|
||||
if dir.X < minX {
|
||||
minX = dir.X
|
||||
}
|
||||
if dir.X > maxX {
|
||||
maxX = dir.X
|
||||
}
|
||||
if dir.Y < minY {
|
||||
minY = dir.Y
|
||||
}
|
||||
if dir.Y > maxY {
|
||||
maxY = dir.Y
|
||||
}
|
||||
}
|
||||
|
||||
colors := map[int64]color.Color{
|
||||
0: color.RGBA{0x0, 0x0, 0x0, 0xff},
|
||||
1: color.RGBA{0xff, 0xff, 0xff, 0xff},
|
||||
}
|
||||
|
||||
img := image.NewRGBA(image.Rect(minX-5, minY-5, maxX+5, maxY+5))
|
||||
for _, dir := range dirs {
|
||||
img.Set(dir.X, dir.Y, colors[dir.Color])
|
||||
}
|
||||
|
||||
w, err := os.Create("day11_image.png")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Unable to open result image file")
|
||||
}
|
||||
defer w.Close()
|
||||
|
||||
return errors.Wrap(png.Encode(w, img), "Unable to store image")
|
||||
}
|
BIN
day11_image.png
Normal file
BIN
day11_image.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 206 B |
1
day11_input.txt
Normal file
1
day11_input.txt
Normal file
|
@ -0,0 +1 @@
|
|||
3,8,1005,8,325,1106,0,11,0,0,0,104,1,104,0,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,0,10,4,10,102,1,8,29,1006,0,41,3,8,1002,8,-1,10,101,1,10,10,4,10,1008,8,0,10,4,10,1001,8,0,54,3,8,102,-1,8,10,101,1,10,10,4,10,1008,8,1,10,4,10,102,1,8,76,1,9,11,10,2,5,2,10,2,1107,19,10,3,8,102,-1,8,10,1001,10,1,10,4,10,1008,8,0,10,4,10,101,0,8,110,2,1007,10,10,2,1103,13,10,1006,0,34,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,102,1,8,142,1006,0,32,1,101,0,10,2,9,5,10,1006,0,50,3,8,1002,8,-1,10,1001,10,1,10,4,10,1008,8,1,10,4,10,101,0,8,179,1,1005,11,10,2,1108,11,10,1006,0,10,1,1004,3,10,3,8,1002,8,-1,10,101,1,10,10,4,10,1008,8,1,10,4,10,1002,8,1,216,1,1002,12,10,2,1102,3,10,1,1007,4,10,2,101,7,10,3,8,1002,8,-1,10,1001,10,1,10,4,10,108,0,8,10,4,10,102,1,8,253,2,104,3,10,1006,0,70,3,8,102,-1,8,10,1001,10,1,10,4,10,108,1,8,10,4,10,102,1,8,282,3,8,1002,8,-1,10,101,1,10,10,4,10,1008,8,0,10,4,10,101,0,8,305,101,1,9,9,1007,9,962,10,1005,10,15,99,109,647,104,0,104,1,21102,838211572492,1,1,21102,342,1,0,1105,1,446,21102,825326674840,1,1,21101,0,353,0,1106,0,446,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,3,10,104,0,104,1,3,10,104,0,104,0,3,10,104,0,104,1,21101,0,29086686211,1,21102,1,400,0,1106,0,446,21102,209420786919,1,1,21101,0,411,0,1105,1,446,3,10,104,0,104,0,3,10,104,0,104,0,21101,0,838337298792,1,21101,434,0,0,1105,1,446,21101,988661154660,0,1,21102,1,445,0,1106,0,446,99,109,2,21201,-1,0,1,21101,40,0,2,21101,0,477,3,21101,0,467,0,1105,1,510,109,-2,2106,0,0,0,1,0,0,1,109,2,3,10,204,-1,1001,472,473,488,4,0,1001,472,1,472,108,4,472,10,1006,10,504,1101,0,0,472,109,-2,2106,0,0,0,109,4,1201,-1,0,509,1207,-3,0,10,1006,10,527,21102,0,1,-3,22102,1,-3,1,22102,1,-2,2,21101,0,1,3,21101,546,0,0,1105,1,551,109,-4,2105,1,0,109,5,1207,-3,1,10,1006,10,574,2207,-4,-2,10,1006,10,574,21201,-4,0,-4,1105,1,642,21201,-4,0,1,21201,-3,-1,2,21202,-2,2,3,21102,1,593,0,1105,1,551,21202,1,1,-4,21102,1,1,-1,2207,-4,-2,10,1006,10,612,21102,0,1,-1,22202,-2,-1,-2,2107,0,-3,10,1006,10,634,21202,-1,1,1,21102,1,634,0,105,1,509,21202,-2,-1,-2,22201,-4,-2,-4,109,-5,2106,0,0
|
21
day11_test.go
Normal file
21
day11_test.go
Normal file
|
@ -0,0 +1,21 @@
|
|||
package aoc2019
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestCalculateDay11_Part1(t *testing.T) {
|
||||
count, err := solveDay11Part1("day11_input.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("Day 11 solver failed: %s", err)
|
||||
}
|
||||
|
||||
t.Logf("Solution Day 11 Part 1: %d", count)
|
||||
}
|
||||
|
||||
func TestCalculateDay11_Part2(t *testing.T) {
|
||||
err := solveDay11Part2("day11_input.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("Day 11 solver failed: %s", err)
|
||||
}
|
||||
|
||||
t.Log("Solution Day 11 Part 2: See day11_image.png")
|
||||
}
|
Loading…
Reference in a new issue