154 lines
3.0 KiB
Go
154 lines
3.0 KiB
Go
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...)
|
|
}
|
|
}
|