isundil 7 years ago
parent
commit
3aac055f0a
2 changed files with 242 additions and 0 deletions
  1. 32 0
      d15/input
  2. 210 0
      d15/main.js

+ 32 - 0
d15/input

@@ -0,0 +1,32 @@
+################################
+#######################...######
+######################...#######
+##############...####..G########
+#############....G...G..########
+############...#.......####..###
+###########G.G##..#.G...###..###
+##########....###.....G.G......#
+#########....##....GG..G..###..#
+###########..#................##
+###########..#...#G...........##
+##########...............G.....#
+#####.#####...#####E.......E...#
+####..#####..#######.....G..####
+##.G..####G.#########.E...E...##
+#...####....#########..........#
+#.G.####....#########..........#
+##..####....#########..##......#
+###.###.....#########G.....#.###
+###.##...G...#######..E.....####
+###.....G.....#####E.......#####
+###.......................######
+######..............E.........##
+######......###................#
+#####.......##.................#
+#####.#....##......##........E##
+#######....######.##E.##########
+#######....#########..##########
+######.....#########....########
+####.....###########..E.########
+####...#.###########....########
+################################

+ 210 - 0
d15/main.js

@@ -0,0 +1,210 @@
+
+function readAll(cb) {
+    require("fs").readFile('./input', 'utf8', (err, data) => {
+        var world = new World(),
+            j =0;
+        data.split("\n").forEach(l => {
+            if (l.length) {
+                var line = [];
+                for (var i =0, len = l.length; i < len; ++i) {
+                    var c = l.charAt(i);
+                    line.push(c == '#' ? '#' : '.');
+                    if ("#.".indexOf(c) == -1) {
+                        var u = new Unit(c, i, j);
+                        world.units.push(u);
+                    }
+                }
+                world.area.push(line);
+                ++j;
+            }
+        });
+        cb(world);
+    });
+}
+
+function World() {
+    this.area = [];
+    this.units = [];
+    this.age = -1;
+}
+
+World.prototype.sortUnits = function() {
+    this.units.sort((a, b) => (a.py == b.py ? a.px -b.px : a.py -b.py));
+}
+
+World.prototype.step = function() {
+    this.sortUnits();
+    this.units.forEach(u => u.hp ? u.step(this) : null);
+    ++this.age;
+}
+
+World.prototype.isEmpty = function(px, py) {
+    if (this.area[py][px] == '#')
+        return false;
+    return !this.units.some(u => u.hp && u.px == px && u.py == py);
+}
+
+World.prototype.coordExists = function(px, py) {
+    return px >= 0 && py >= 0 &&
+        px < this.area[0].length &&
+        py < this.area.length;
+}
+
+World.prototype.isReachable = function(from, to) {
+    var map = [],
+        toGo = [{ pos: from, dist: 0}],
+        done = {};
+    if (from[0] == to[0] && from[1] == to[1])
+        return { step: from, dist: 0 };
+    while (toGo.length) {
+        var pos = toGo[0].pos,
+            dist = toGo[0].dist,
+            moves = [[ 0, -1 ], [ -1, 0 ], [ 1, 0 ], [ 0, 1 ]];
+        for (var i =0; i < moves.length; ++i) {
+            var newCoords = [pos[0] +moves[i][0], pos[1] +moves[i][1]];
+            if (this.coordExists(newCoords[0], newCoords[1])) {
+                if (newCoords[0] == to[0] && newCoords[1] == to[1])
+                    return { step: pos, dist: dist +1 };
+                toGo.push({pos: newCoords, dist: dist +1})
+            }
+        }
+        done[pos[0]+'x'+pos[1]] = dist;
+        toGo.splice(0, 1);
+        toGo = toGo.filter(c =>
+            !done[c.pos[0]+'x'+c.pos[1]] &&
+            this.isEmpty(c.pos[0], c.pos[1]));
+        toGo.sort((a, b) => a.dist -b.dist);
+    }
+    return false;
+}
+
+World.prototype.print = function() {
+    var w = [];
+
+    this.sortUnits();
+    this.area.forEach(l => w.push(l.slice()));
+    this.units.forEach(u => u.hp ? w[u.py][u.px] = u.type : null);
+    w.forEach(l => {
+        var lStr = "";
+        l.forEach(c => lStr += c);
+        console.log(lStr);
+    });
+    console.log(this.units.filter(u => u.hp));
+    console.log("Age: ", this.age);
+    var sumHp = 0;
+    this.units.forEach(u => sumHp += u.hp);
+    console.log("Sum hp: ", sumHp);
+    console.log("Outcome: ", sumHp *this.age);
+}
+
+World.prototype.remainingTypes = function() {
+    var types = {};
+    this.units.forEach(u => u.hp ? types[u.type] = true : false);
+    return Object.keys(types);
+}
+
+World.prototype.hasOpponents = function() {
+    return this.remainingTypes().length > 1;
+}
+
+World.prototype.run = function(stopFnc) {
+    while (stopFnc(this))
+        this.step();
+}
+
+function Unit(type, px, py) {
+    this.type = type;
+    this.px = px;
+    this.py = py;
+    this.hp = 200;
+    this.atk = 3;
+}
+
+Unit.prototype.step = function(world) {
+    this.move(world);
+    this.attack(world);
+}
+
+Unit.prototype.range = function(world, except) {
+    var range = [],
+        moves = [[ 0, -1 ], [ -1, 0 ], [ 1, 0 ], [ 0, 1 ]];
+    moves.forEach(m => {
+        if (world.coordExists(this.px +m[0], this.py +m[1]) && (world.isEmpty(this.px +m[0], this.py +m[1]) || (except && (except.px == this.px +m[0] && except.py == this.py +m[1]))))
+            range.push([this.px +m[0], this.py +m[1]]);
+    });
+    return range;
+}
+
+Unit.prototype.move = function(world) {
+    var inRange = [];
+
+    world.units.filter(u => u.hp && u.type !== this.type).forEach(t => t.range(world, this).forEach(r => inRange.push({ unit: t, pos: r })));
+    var reachable = inRange.filter(r => { r.dist = world.isReachable(r.pos, [this.px, this.py]); return r.dist !== false; });
+    var dest = reachable.sort((a, b) => {
+        if (a.dist.dist != b.dist.dist) return a.dist.dist -b.dist.dist;
+        if (a.pos[1] == b.pos[1]) return a.pos[0] -b.pos[0];
+        return a.pos[1] -b.pos[1];
+    })[0];
+    if (dest) {
+        this.px = dest.dist.step[0];
+        this.py = dest.dist.step[1];
+    }
+}
+
+Unit.prototype.attack = function(world) {
+    var units = world.units.filter(u => u.hp && u.type !== this.type && (Math.abs(u.px -this.px) +Math.abs(u.py -this.py)) == 1);
+    if (units.length) {
+        units.sort((a, b) => {
+            var diff = a.hp -b.hp;
+            if (diff) return diff;
+            diff = a.py -b.py;
+            if (diff) return diff;
+            return a.px -b.px;
+        });
+        units[0].takeDamage(this);
+    }
+}
+
+Unit.prototype.takeDamage = function(from) {
+    this.hp = Math.max(0, this.hp -from.atk);
+}
+
+function ex1() {
+    readAll(world => {
+        world.run(world => world.hasOpponents());
+        world.print();
+    });
+}
+
+function ex2(min, max) {
+    readAll(world => {
+        var stopReason = -1,
+            current = Math.floor((min +max) /2);
+        world.units.forEach(u => u.type === 'E' ? u.atk = current : 0);
+        world.run(world => {
+            if (!world.hasOpponents()) {
+                stopReason = 'E';
+                return false;
+            }
+            if (world.units.filter(u => u.hp === 0 && u.type === 'E').length) {
+                stopReason = 'G';
+                return false;
+            }
+            return true;
+        });
+        if (max == min || (min +1 == current && stopReason === 'E')) {
+            console.log("Min atk: " +(stopReason === 'E' ? min : min +1));
+            world.print();
+        } else if (stopReason == 'G') {
+            console.log("Atk " +current +" not enough");
+            ex2(current +1, max);
+        } else {
+            console.log("Atk " +current +" too much");
+            ex2(min, current);
+        }
+    });
+}
+
+ex1();
+ex2(4, 300);
+