Skip to content

Instantly share code, notes, and snippets.

@towc
Created December 16, 2018 12:08
Show Gist options
  • Select an option

  • Save towc/dd844d1dc80566cb374c147a48734fbe to your computer and use it in GitHub Desktop.

Select an option

Save towc/dd844d1dc80566cb374c147a48734fbe to your computer and use it in GitHub Desktop.
const fs = require('fs');
const [WALL, EMPTY, ELF, GOB] = [0, 1, 'elf', 'gob'];
const maxDist = 200;
let ents = [];
const coord = (x, y) => ({ x, y });
const delta = (pos, x, y) => ({ x: pos.x + x, y: pos.y + y });
const cell = pos => board[pos.y][pos.x];
const setCell = (pos, v) => board[pos.y][pos.x] = v;
const addEnt = (x, y, type) => {
const ent = { x, y, hp: 200, type };
ents.push(ent);
return ent;
}
console._log = console.constructor.prototype.log.bind(console);
console.log = () => {};
const inputs = {
file: fs.readFileSync('aoc-input-15', 'utf-8'),
edge1: // 67
`####
##E#
#GG#
####`,
edge2: // 71
`#####
#GG##
#.###
#..E#
#.#G#
#.E##
#####`
}
const board = inputs.file
.split('\n')
.map((l, y) =>
l.split('')
.map((c, x) => {
switch (c) {
case '#': return WALL;
case '.': return EMPTY;
case 'E': return addEnt(x, y, ELF);
case 'G': return addEnt(x, y, GOB);
}
console.log('wut', c, x, y)
}));
const log = () => {
let str = board.map(l => l.map(c =>
c === WALL ? '#'
: c === EMPTY ? '.'
: c.type === ELF ? 'E'
: c.type === GOB ? 'G'
: '?'
).join('')).join('\n')
console._log(rounds)
console._log(str);
console._log(ents.map(e => [e.type, e.hp]).join('|'))
}
const getNeighbours = pos => [
delta(pos, 0, -1),
delta(pos, -1, 0),
delta(pos, 1, 0),
delta(pos, 0, 1)
];
const checkTile = (ent, pos) => {
const checked = [ent, pos];
let toCheck = getNeighbours(pos);
let nextCheck = [];
let dist = 0;
distCheck:
while(++dist < maxDist) {
for(const pos of toCheck) {
const v = cell(pos);
if (v === EMPTY) {
const neighbours = getNeighbours(pos)
.filter(p => {
if (checked.some(q => q.x === p.x && q.y === p.y) || nextCheck.some(q => q.x === p.x && q.y === p.y)) {
return false;
}
const c = cell(p);
return c === EMPTY || c.dead || (c.type && c.type !== ent.type);
});
nextCheck.push(...neighbours)
}
if (!v.dead && v.type && v.type !== ent.type) {
break distCheck;
}
checked.push(pos);
};
toCheck = nextCheck;
nextCheck = [];
}
return dist;
}
const getNextTile = ent => {
const tiles = getNeighbours(ent)
.filter(p => cell(p) === EMPTY)
.map(p => ({ x: p.x, y: p.y, v: checkTile(ent, p) }))
.filter(c => c.v < maxDist);
return tiles.sort((a, b) => a.v - b.v || a.y - b.y || a.x - b.x)[0];
}
const getNextEnemy = ent => {
return getNeighbours(ent)
.map(p => cell(p))
.filter(c => !c.dead && c.type && c.type !== ent.type)
.sort((a, b) => a.hp - b.hp || a.y - b.y || a.x - b.x)
[0];
}
const attack = (ent, enemy) => {
enemy.hp -= 3;
if (enemy.hp <= 0) {
enemy.dead = true;
setCell(enemy, EMPTY);
}
}
let rounds = 0;
loop: while(++rounds < 10000) {
ents.sort((a, b) => a.y - b.y || a.x - b.x);
for(let i = 0; i < ents.length; ++i) {
const ent = ents[i];
console.log('trying', i, ent);
console.group();
if (ent.dead) {
console.groupEnd();
continue;
}
const enemy = getNextEnemy(ent);
if (enemy) {
attack(ent, enemy);
} else {
const nextTile = getNextTile(ent);
console.log({ nextTile })
if (nextTile) {
setCell(ent, EMPTY);
ent.x = nextTile.x;
ent.y = nextTile.y;
setCell(ent, ent);
}
const enemy = getNextEnemy(ent);
if (enemy) {
attack(ent, enemy);
}
}
console.groupEnd();
}
ents = ents.filter(ent => !ent.dead);
if (ents.every(ent => ent.type === ents[0].type)) {
console._log('end state');
log();
console._log('ended in ' + rounds);
const sum = ents.reduce((a, e) => a + e.hp, 0);
console._log(sum, sum * (rounds-1)); // use this
break;
}
log();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment