package main import ( "bufio" "fmt" "os" "sort" ) const ( DIR_N = -1i DIR_E = 1 DIR_S = 1i DIR_W = -1 TURN_L = -1i TURN_S = 1 TURN_R = 1i ) var width int var input []byte var carts []*complex64 var cartMap map[complex64]*Cart func main() { stdinToByteSlice() setupCarts() //part1() part2() } func part1() { var crashed bool for !crashed { sort.Sort(ByPos(carts)) for _, c := range carts { if !cartMap[*c].tick() { return } } } } var ticks int func part2() { for len(cartMap) > 1 { ticks++ sort.Sort(ByPos(carts)) for _, c := range carts { if *c != 0 { cartMap[*c].tick() } } } for pos := range cartMap { fmt.Printf("🔵: %0.0f,%0.0f\n", real(pos), imag(pos)) } fmt.Println("Ticks: ", ticks) } type Cart struct { pos complex64 dir complex64 nextTurn complex64 } // Tick the cart, return if it's still alive func (c *Cart) tick() bool { // Remove this cart from it's old position // and figure out it's new one delete(cartMap, c.pos) c.pos += c.dir if cart, ok := cartMap[c.pos]; ok { fmt.Printf("❌: %0.0f,%0.0f (%d ticks)\n", real(c.pos), imag(c.pos), ticks) // Remove the cart we crashed into from the map delete(cartMap, c.pos) // And clear the cart's pos, we can ignore them now cart.pos, c.pos = 0, 0 return false } // No crash, figure out the new orientation of the cart cartMap[c.pos] = c if getByte(c.pos) == '+' { c.dir *= c.nextTurn switch c.nextTurn { case TURN_L: c.nextTurn = TURN_S case TURN_S: c.nextTurn = TURN_R case TURN_R: c.nextTurn = TURN_L } } else if getByte(c.pos) == '/' { // Turn counter-clockwise c.dir = complex(-imag(c.dir), -real(c.dir)) } else if getByte(c.pos) == '\\' { // Turn clockwise c.dir = complex(imag(c.dir), real(c.dir)) } return true } // We have to sort the carts on each tick by y,x position // y is the imaginary part, x is the real part type ByPos []*complex64 func (c ByPos) Len() int { return len(c) } func (c ByPos) Swap(i, j int) { c[i], c[j] = c[j], c[i] } func (c ByPos) Less(i, j int) bool { return imag(*c[i]) < imag(*c[j]) || (imag(*c[i]) == imag(*c[j]) && real(*c[i]) < real(*c[j])) } // getByte pulls a byte from the given position in the input func getByte(pos complex64) byte { return input[int(real(pos))+int(imag(pos))*width] } /** * Initialization Functions */ func setupCarts() { cartMap = make(map[complex64]*Cart) for i := 0; i < len(input); i++ { pos := complex(float32(i%width), float32(i/width)) switch getByte(pos) { case '^': cartMap[pos] = &Cart{pos, DIR_N, TURN_L} case '>': cartMap[pos] = &Cart{pos, DIR_E, TURN_L} case 'v': cartMap[pos] = &Cart{pos, DIR_S, TURN_L} case '<': cartMap[pos] = &Cart{pos, DIR_W, TURN_L} default: continue // Not a cart } carts = append(carts, &cartMap[pos].pos) } } func stdinToByteSlice() { scanner := bufio.NewScanner(os.Stdin) for scanner.Scan() { data := scanner.Bytes() if width == 0 { width = len(data) } input = append(input, data...) } }