adventofcode/2019/day11/main.go

189 lines
3.3 KiB
Go

package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
"sync"
"time"
intcode "git.bullercodeworks.com/brian/adventofcode/2019/intcode-processor"
helpers "git.bullercodeworks.com/brian/adventofcode/helpers"
)
// Pass the program name and the problem part number in parameters
// Default: "input", and part 2
func main() {
progFileName := "input"
part := 2
if len(os.Args) > 1 {
progFileName = os.Args[1]
if len(os.Args) == 3 {
part = helpers.Atoi(os.Args[2])
}
}
dat, err := ioutil.ReadFile(progFileName)
if err != nil {
fmt.Println("Error reading program file:", err.Error())
os.Exit(1)
}
var prog []int
stringDat := strings.TrimSpace(string(dat))
for _, v := range strings.Split(stringDat, ",") {
prog = append(prog, helpers.Atoi(v))
}
// Pass the program and the problem part to solve:
solve(prog, part)
}
func solve(inp []int, pt int) {
painter := NewPainter()
if pt == 2 {
painter.Paint(1)
}
p := intcode.NewProgram(inp)
go func() {
for {
for !p.NeedsInput() {
time.Sleep(1)
}
p.Input(painter.GetPanelColor())
for !p.NeedsOutput() {
time.Sleep(1)
}
painter.Paint(p.Output())
for !p.NeedsOutput() {
time.Sleep(1)
}
painter.Turn(p.Output())
switch p.State() {
case intcode.RET_ERR:
panic(p.Error())
case intcode.RET_DONE:
break
}
}
}()
res := p.Run()
if res == intcode.RET_DONE {
fmt.Println("DONE")
} else if res == intcode.RET_ERR {
fmt.Println("ERROR")
}
painter.Print()
fmt.Println("Painted Panels:", len(painter.panels))
fmt.Println("Paint Used:", painter.paintCount)
}
const (
DIR_N = iota
DIR_E
DIR_S
DIR_W
)
type Painter struct {
dir int
loc helpers.Coordinate
panels map[string]int
paintCount int
minX, minY int
maxX, maxY int
panelMutex *sync.Mutex
}
func NewPainter() *Painter {
p := Painter{
dir: DIR_N,
loc: helpers.Coordinate{X: 0, Y: 0},
panels: make(map[string]int),
panelMutex: &sync.Mutex{},
}
return &p
}
func (p *Painter) GetPanelColor() int {
if v, ok := p.panels[p.loc.String()]; ok {
return v
}
return 0
}
func (p *Painter) Paint(color int) {
p.panelMutex.Lock()
p.panels[p.loc.String()] = color
p.paintCount++
p.panelMutex.Unlock()
}
func (p *Painter) Turn(dir int) {
if dir == 0 {
p.dir--
} else {
p.dir++
}
if p.dir == DIR_W+1 {
p.dir = DIR_N
} else if p.dir == DIR_N-1 {
p.dir = DIR_W
}
// After turning we move forward
switch p.dir {
case DIR_N:
p.loc.Y--
case DIR_E:
p.loc.X++
case DIR_S:
p.loc.Y++
case DIR_W:
p.loc.X--
}
if p.loc.X < p.minX {
p.minX = p.loc.X
}
if p.loc.X > p.maxX {
p.maxX = p.loc.X
}
if p.loc.Y < p.minY {
p.minY = p.loc.Y
}
if p.loc.Y > p.maxY {
p.maxY = p.loc.Y
}
}
func (p *Painter) Print() {
for x := p.minX; x <= p.maxX; x++ {
for y := p.minY; y <= p.maxY; y++ {
c := helpers.Coordinate{x, y}
if c.X == p.loc.X && c.Y == p.loc.Y {
switch p.dir {
case DIR_N:
fmt.Print("^")
case DIR_E:
fmt.Print(">")
case DIR_S:
fmt.Print("v")
case DIR_W:
fmt.Print("<")
}
} else {
p.panelMutex.Lock()
if v, ok := p.panels[c.String()]; ok {
if v == 1 {
fmt.Print("#")
} else {
fmt.Print(".")
}
} else {
fmt.Print(".")
}
p.panelMutex.Unlock()
}
}
fmt.Println()
}
}