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() } }