package main import ( "bufio" "fmt" "io/ioutil" "os" "strings" "time" intcode "git.bullercodeworks.com/brian/adventofcode/2019/intcode-processor" helpers "git.bullercodeworks.com/brian/adventofcode/helpers" ) var auto bool func main() { progFileName := "input" if len(os.Args) > 1 && os.Args[1] == "-auto" { auto = true } prog := readIntCodeFile(progFileName) play(prog) } func play(prog []int) { p := intcode.NewProgram(prog) // For part 1, comment out this line p.SetProgramValueAt(0, 2) //p.EnableDebug() maxX, maxY := 0, 0 screen := make(map[string]int) var score int go func() { for { for !p.NeedsOutput() && !p.NeedsInput() { time.Sleep(1) } if p.NeedsOutput() { // There should be three outputs x := p.Output() y := waitForOutput(p) b := waitForOutput(p) if x > maxX { maxX = x } if y > maxY { maxY = y } if x == -1 && y == 0 { score = b } else { screen[coord(x, y)] = b } } if p.NeedsInput() { printScreen(screen, maxX, maxY, score) if auto { ballX, _ := findFirst(4, screen) pddlX, _ := findFirst(3, screen) if ballX < pddlX { p.Input(-1) } else if ballX > pddlX { p.Input(1) } else { p.Input(0) } } else { var gotInput bool for !gotInput { fmt.Print("Input (vimlike): ") reader := bufio.NewReader(os.Stdin) inp, err := reader.ReadString('\n') if err != nil { panic(err) } inp = strings.TrimSpace(inp) switch inp { case "h": p.Input(-1) gotInput = true case "l": p.Input(1) gotInput = true case "j", "k": p.Input(0) gotInput = true } } } } switch p.State() { case intcode.RET_ERR: panic(p.Error()) case intcode.RET_DONE: break } } }() ret := p.Run() if ret == intcode.RET_DONE { fmt.Println("DONE:", score) } else if ret == intcode.RET_ERR { fmt.Println("ERROR") } //part1(screen) } func lookForScore(p *intcode.Program, score int) { var res []int code := p.GetCode() for k, v := range code { if v == score { res = append(res, k) } } if len(res) == 1 { fmt.Println("Score Position:", res[0]) os.Exit(0) } } func part1(s map[string]int) { var cnt int for _, v := range s { if v == 2 { cnt++ } } fmt.Println(cnt, "blocks") } func printScreen(screen map[string]int, maxX, maxY, score int) { //fmt.Print(helpers.CLEAR_SCREEN) fmt.Println("Score:", score) for y := 0; y <= maxY; y++ { for x := 0; x <= maxX; x++ { v, ok := screen[coord(x, y)] if !ok { v = 0 } switch v { case 0: fmt.Print(" ") case 1: fmt.Print("▉") case 2: fmt.Print("░") case 3: fmt.Print("═") case 4: fmt.Print("o") } } fmt.Println() } } func findFirst(val int, screen map[string]int) (int, int) { for k := range screen { if screen[k] == val { return revCoord(k) } } return -1, -1 } // This will block waiting for output func waitForOutput(p *intcode.Program) int { for !p.NeedsOutput() { time.Sleep(1) } return p.Output() } func coord(x, y int) string { return fmt.Sprintf("[%d, %d]", x, y) } func revCoord(c string) (int, int) { var x, y int fmt.Sscanf(c, "[%d, %d]", &x, &y) return x, y } func readIntCodeFile(fn string) []int { dat, err := ioutil.ReadFile(fn) 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)) } return prog }