Skip to content

Instantly share code, notes, and snippets.

@jemmyw
Created December 17, 2018 22:35
Show Gist options
  • Save jemmyw/d7f3ec74101993dac0b0c5c73ab1cd56 to your computer and use it in GitHub Desktop.
Save jemmyw/d7f3ec74101993dac0b0c5c73ab1cd56 to your computer and use it in GitHub Desktop.
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