Created
December 17, 2018 22:35
-
-
Save jemmyw/d7f3ec74101993dac0b0c5c73ab1cd56 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as fs from 'fs'; | |
type Coord = [number, number]; | |
type Direction = 'l' | 'r' | 'u' | 'd'; | |
type Turn = 'l' | 'r' | 's'; | |
type Curve = '\\' | '/'; | |
interface Cart { | |
id: number; | |
direction: Direction | |
coord: Coord; | |
nextTurn?: Turn; | |
crashed?: boolean; | |
} | |
type CoordMap = Map<Coord, Cart>; | |
class Carts { | |
map: Map<string, Cart> = new Map(); | |
set: Set<string> = new Set(); | |
orderedCoords: Coord[] = []; | |
constructor(carts: Cart[]) { | |
carts.sort(sortCarts).forEach(cart => { | |
this.addCart(cart); | |
}) | |
} | |
addCart(cart: Cart) { | |
this.map.set(coordToString(cart.coord), cart); | |
this.set.add(coordToString(cart.coord)); | |
this.orderedCoords.push(cart.coord); | |
} | |
next() { | |
const coords = this.orderedCoords.slice(); | |
this.orderedCoords = []; | |
coords.forEach(coords => { | |
const cs = coordToString(coords); | |
const cart = this.map.get(cs); | |
if (cart) { | |
this.map.delete(cs); | |
this.set.delete(cs); | |
const newCart = nextCart(cart); | |
const nc = coordToString(newCart.coord); | |
if (this.set.has(nc)) { | |
this.map.delete(nc); | |
this.set.delete(nc); | |
// throw new Error(`Crash ${newCart.coord}`); | |
} else { | |
this.addCart(newCart); | |
} | |
} | |
}) | |
this.orderedCoords = this.orderedCoords.sort(sortCoords); | |
} | |
} | |
const input = fs.readFileSync('13.txt') | |
.toString() | |
.split("\n") | |
.map(line => line.split('')); | |
let cardId = 0; | |
const [board, initialCarts] = input.reduce<[string[][], Cart[]]>(([board, carts], line, y) => { | |
const [boardLine, newCarts] = line.reduce<[string[], Cart[]]>( | |
([boardLine, carts], char, x) => { | |
const coord: Coord = [x, y]; | |
switch (char) { | |
case '<': | |
return [boardLine.concat(['-']), carts.concat([{ id: cardId++, coord, direction: 'l' }])] | |
case '>': | |
return [boardLine.concat(['-']), carts.concat([{ id: cardId++, coord, direction: 'r' }])] | |
case '^': | |
return [boardLine.concat(['|']), carts.concat([{ id: cardId++, coord, direction: 'u' }])] | |
case 'v': | |
return [boardLine.concat(['|']), carts.concat([{ id: cardId++, coord, direction: 'd' }])] | |
} | |
return [boardLine.concat([char]), carts] | |
}, [[], []] | |
) | |
return [board.concat([boardLine]), carts.concat(newCarts)]; | |
}, [[], []]) | |
function getTrackAt(c: Coord): string { | |
const [x, y] = c; | |
return board[y][x]; | |
} | |
function coordToString(c: Coord): string { | |
return c.join('x'); | |
} | |
const Curves = { | |
'/': { d: 'l', u: 'r', l: 'd', r: 'u' }, | |
'\\': { d: 'r', u: 'l', l: 'u', r: 'd' } | |
} | |
function getCurveDirection(curve: string, direction: Direction): Direction | null { | |
const ct = Curves[curve]; | |
if (!ct) return null; | |
return ct[direction] as Direction; | |
} | |
const Turns = { | |
l: { d: 'r', u: 'l', l: 'd', r: 'u' }, | |
r: { d: 'l', u: 'r', l: 'u', r: 'd' }, | |
s: { d: 'd', u: 'u', l: 'l', r: 'r' } | |
} | |
function getTurnDirection(turn: Turn, direction: Direction): Direction { | |
return Turns[turn][direction] as Direction; | |
} | |
const NextTurn = { | |
l: 's', | |
s: 'r', | |
r: 'l' | |
} | |
function getNextTurn(turn: Turn): Turn { return NextTurn[turn] as Turn } | |
function nextCartDirection(cart: Cart): [Direction, Coord, Turn] { | |
const [x, y] = cart.coord; | |
const d = cart.direction; | |
const nt = cart.nextTurn || 'l'; | |
let nx = x, ny = y; | |
switch (d) { | |
case 'u': ny -= 1; break; | |
case 'd': ny += 1; break; | |
case 'l': nx -= 1; break; | |
case 'r': nx += 1; break; | |
} | |
const nc: Coord = [nx, ny]; | |
const track = getTrackAt(nc); | |
const ct = getCurveDirection(track, d) | |
if (ct) { | |
return [ct, nc, cart.nextTurn]; | |
} | |
if (track === '+') { | |
return [ | |
getTurnDirection(nt, d), | |
nc, | |
getNextTurn(nt) | |
] | |
} | |
return [d, nc, nt]; | |
} | |
function nextCart(cart: Cart): Cart { | |
const [ | |
direction, coord, nextTurn | |
] = nextCartDirection(cart); | |
const newCart = { | |
...cart, | |
direction, | |
coord, | |
nextTurn | |
} | |
return newCart; | |
} | |
function sortCoords(a: Coord, b: Coord) { | |
if (a[1] === b[1]) return a[0] - b[0]; | |
return a[1] - b[1]; | |
} | |
function sortCarts(a: Cart, b: Cart) { | |
return sortCoords(a.coord, b.coord); | |
} | |
function draw(board:string[][], carts:Carts) { | |
process.stdout.write('\u001B[2J\u001B[0;0f'); | |
for(let y = 0; y < board.length; ++y) { | |
process.stdout.write(String(y).padEnd(3)); | |
for(let x = 0; x < board[y].length; ++x) { | |
if (carts.set.has(coordToString([x, y]))) { | |
const cart = carts.map.get(coordToString([x, y])) | |
if(cart.crashed) { | |
process.stdout.write('X'); | |
} else { | |
process.stdout.write(cart.direction); | |
} | |
} else { | |
process.stdout.write(board[y][x]); | |
} | |
} | |
process.stdout.write("\n"); | |
if(y > process.stdout.rows-10) { break; } | |
} | |
} | |
const carts = new Carts(initialCarts); | |
draw(board, carts); | |
sleep(3); | |
function msleep(n) { | |
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, n); | |
} | |
function sleep(n) { | |
msleep(n*1000); | |
} | |
while (true) { | |
// draw(board, carts); | |
// msleep(10); | |
try { | |
carts.next(); | |
if(carts.set.size === 1) { | |
console.log(carts.set); | |
carts.next(); | |
console.log(carts.set); | |
break; | |
} | |
} catch(err) { | |
draw(board, carts); | |
console.log(err); | |
break; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment