adventofcode/2019/day19/main.go

186 lines
3.4 KiB
Go

package main
import (
"fmt"
"strings"
"time"
intcode "git.bullercodeworks.com/brian/adventofcode/2019/intcode-processor"
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
)
var beam map[string]int
var maxY int
func main() {
pt := helpers.GetArgNumber(1)
prog := intcode.ReadIntCodeFile("input")
beam = make(map[string]int)
if pt == "1" {
part1(prog)
} else {
part2(prog)
}
}
func part1(prog []int) {
var count int
var lastRowStart int
for y := 0; y < 50; y++ {
var foundFirst bool
fmt.Print(strings.Repeat(" ", lastRowStart))
for x := lastRowStart; x < 50; x++ {
out := runCodeAt(prog, x, y)
fmt.Print(out)
beam[c(x, y)] = out
if out == 1 {
if !foundFirst {
lastRowStart = x
}
foundFirst = true
count++
} else if foundFirst {
break
}
}
fmt.Println()
maxY = y
}
fmt.Println("Total:", count)
}
func part2(prog []int) {
shipSize := 100
// Guesses
//x, y := 0, 1000
var x, square int
bot, _ := 1025, 1037
for square != shipSize {
bot++
fmt.Print("Calculating ", bot, "... ")
square, x = maxSquare(prog, bot, bot/2)
fmt.Println(square)
}
fmt.Println(x, bot)
}
func part2Almost(prog []int) {
shipSize := 100
// Guesses
x, y := 0, 1000
var square int
bot, top := 1026, 1037
square, x = maxSquare(prog, y, 0)
lastCheckRow := y
for {
if square > shipSize {
y = y - (y-bot)/2
} else if square < shipSize {
y = y + (top-y)/2
}
if lastCheckRow == y {
break
}
lastCheckRow = y
fmt.Print("Calculating at ", y, "... ")
square, x = maxSquare(prog, y, (y / 2))
if square > 100 && y < top {
top = y
} else if square < 100 && y > bot {
bot = y
}
fmt.Println("Square:", square)
}
fmt.Println("Final Square:", square)
fmt.Println(x, y)
}
func part2Slow(prog []int) {
shipSize := 100
var x, y int
retX, retY := -1, -1
var lastRowStart int
for y = maxY; true; y++ {
var foundFirst bool
fmt.Print(strings.Repeat(" ", lastRowStart))
for x = lastRowStart; x < y; x++ {
out := runCodeAt(prog, x, y)
fmt.Print(out)
beam[c(x, y)] = out
if out == 1 {
if !foundFirst {
lastRowStart = x
}
foundFirst = true
} else if foundFirst {
break
}
}
square, _ := maxSquare(prog, y, lastRowStart)
fmt.Println(":", square)
// Every row, check what the maximum square is
if square >= shipSize {
retY, retX = y, lastRowStart
break
}
}
fmt.Println(retX, ",", retY)
}
// maxSquare returns the square size and the bottom-left x position it starts at
func maxSquare(prog []int, row, firstX int) (int, int) {
for ; firstX < row; firstX++ {
// Find the first X
if runCodeAt(prog, firstX, row) == 0 {
continue
}
var square int
for d := 0; true; d++ {
if runCodeAt(prog, firstX+d, row-d) == 0 {
return square, firstX
}
square++
}
}
return 0, firstX
}
func runCodeAt(prog []int, x, y int) int {
// If we've already cached this pos, just return it
if v, ok := beam[c(x, y)]; ok {
return v
}
var res int
p := intcode.NewProgram(prog)
go func() {
sendInputs(p, []int{x, y})
res = getOutput(p)
}()
p.Run()
beam[c(x, y)] = res
return res
}
func sendInputs(p *intcode.Program, inp []int) {
for k := range inp {
for !p.NeedsInput() {
time.Sleep(1)
}
p.Input(inp[k])
}
}
func getOutput(p *intcode.Program) int {
for !p.NeedsOutput() {
time.Sleep(1)
}
return p.Output()
}
func c(x, y int) string {
return fmt.Sprintf("[%d, %d]", x, y)
}