Last active
December 11, 2019 17:29
-
-
Save Mellen/f4bfb2fe01885a41ee6209a879d19c32 to your computer and use it in GitHub Desktop.
AoC 2019 day 10
This file contains hidden or 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
function Asteroid(position) | |
{ | |
this.position = position; | |
this.slopes = new Map(); | |
} | |
Asteroid.prototype.slopeAndDistance = function(other) | |
{ | |
let xdiff = (other.position.x - this.position.x); | |
let ydiff = (other.position.y - this.position.y); | |
let slope = xdiff / ydiff; | |
this.slopes.set(other, {slope:slope, sign:Math.sign(ydiff)}); | |
}; | |
Asteroid.prototype.seeCount = function() | |
{ | |
let count = 0; | |
let slopeSeen = []; | |
for(let [asteroid, slope] of this.slopes) | |
{ | |
if(typeof(slopeSeen.find(s => s.slope == slope.slope && s.sign == slope.sign)) === 'undefined') | |
{ | |
count++; | |
slopeSeen.push(slope); | |
} | |
} | |
return count; | |
}; | |
Asteroid.prototype.varporisationOrder = function() | |
{ | |
let distances = new Map(); | |
let angles = new Map(); | |
let sortedroids = []; | |
let uniqueangles = new Set(); | |
console.log(`starting x: ${this.position.x} y: ${this.position.y}`); | |
for(let other of this.slopes.keys()) | |
{ | |
let xdiff = other.position.x - this.position.x; | |
let ydiff = this.position.y - other.position.y; | |
let dist = Math.sqrt(xdiff**2 + ydiff**2); | |
distances.set(other, dist); | |
let angle = Math.acos(ydiff/dist); | |
angles.set(other, angle); | |
uniqueangles.add(angle); | |
sortedroids.push([other, angles.get(other), dist]); | |
} | |
sortedroids.sort((A, B) => | |
{ | |
if(angles.get(A[0]) < angles.get(B[0])) | |
{ | |
return -1; | |
} | |
if(angles.get(A[0]) > angles.get(B[0])) | |
{ | |
return 1; | |
} | |
if(angles.get(A[0]) == angles.get(B[0])) | |
{ | |
if(distances.get(A[0]) < distances.get(B[0])) | |
{ | |
return -1; | |
} | |
if(distances.get(A[0]) > distances.get(B[0])) | |
{ | |
return 1; | |
} | |
} | |
return 0; | |
}); | |
let resorted = []; | |
let usedangles = new Set(); | |
while(sortedroids.length > 0) | |
{ | |
let delindex = []; | |
for(let a of sortedroids) | |
{ | |
let [asteroid, angle, distance] = a; | |
if(uniqueangles.has(angle)) | |
{ | |
resorted.push(asteroid); | |
delindex.push(sortedroids.indexOf(a)); | |
usedangles.add(angle); | |
uniqueangles.delete(angle); | |
} | |
if(uniqueangles.size == 0) | |
{ | |
uniqueangles = new Set(usedangles); | |
} | |
} | |
for(let index of delindex) | |
{ | |
sortedroids.splice(index, 1); | |
} | |
} | |
for(let ast of resorted) | |
{ | |
console.log(`${ast.position.x}, ${ast.position.y}, angle: ${angles.get(ast)}, distance: ${distances.get(ast)}`); | |
} | |
return resorted; | |
} | |
function Field(input) | |
{ | |
this.asteroids = []; | |
let rows = input.split('\n'); | |
for(let ri = 0; ri < rows.length; ri++) | |
{ | |
let row = rows[ri]; | |
for(let ci = 0; ci < row.length; ci++) | |
{ | |
let c = row[ci]; | |
if(c === '#') | |
{ | |
let asteroid = new Asteroid({x:ci, y:ri}) | |
this.asteroids.push(asteroid); | |
} | |
} | |
} | |
} | |
Field.prototype.bestAsteroid = function() | |
{ | |
for(let asteroid of this.asteroids) | |
{ | |
for(let otherA of this.asteroids) | |
{ | |
if(asteroid === otherA) | |
{ | |
continue; | |
} | |
asteroid.slopeAndDistance(otherA); | |
} | |
} | |
let bestcount = 0; | |
let besteroid = null; | |
for(let asteroid of this.asteroids) | |
{ | |
let seecount = asteroid.seeCount(); | |
if(seecount > bestcount) | |
{ | |
bestcount = seecount; | |
besteroid = asteroid; | |
} | |
} | |
return [besteroid, bestcount]; | |
} | |
Field.prototype.destroy200 = function() | |
{ | |
let laserPos = this.bestAsteroid()[0]; | |
let order = laserPos.varporisationOrder(); | |
return order[200].position; | |
} | |
function testPart1() | |
{ | |
let input =`.#..##.###...####### | |
##.############..##. | |
.#.######.########.# | |
.###.#######.####.#. | |
#####.##.#.##.###.## | |
..#####..#.######### | |
#################### | |
#.####....###.#.#.## | |
##.################# | |
#####.##.###..####.. | |
..######..##.####### | |
####.##.####...##..# | |
.#####..#.######.### | |
##...#.##########... | |
#.##########.####### | |
.####.#.###.###.#.## | |
....##.##.###..##### | |
.#.#.###########.### | |
#.#.#.#####.####.### | |
###.##.####.##.#..##`; | |
let field = new Field(input); | |
let result = field.bestAsteroid(); | |
console.log('expected x: 11, expected y: 13, expected count: 210'); | |
console.log(`actual x: ${result[0].position.x}, actual y: ${result[0].position.y}, actual count: ${result[1]}`); | |
console.log('passed;', result[0].position.x==11 && result[0].position.y==13 && result[1] == 210); | |
} | |
function part1() | |
{ | |
let input = document.querySelector('pre').innerHTML; | |
let field = new Field(input); | |
return field.bestAsteroid(); | |
} | |
function testPart2() | |
{ | |
let input =`.#..##.###...####### | |
##.############..##. | |
.#.######.########.# | |
.###.#######.####.#. | |
#####.##.#.##.###.## | |
..#####..#.######### | |
#################### | |
#.####....###.#.#.## | |
##.################# | |
#####.##.###..####.. | |
..######..##.####### | |
####.##.####...##..# | |
.#####..#.######.### | |
##...#.##########... | |
#.##########.####### | |
.####.#.###.###.#.## | |
....##.##.###..##### | |
.#.#.###########.### | |
#.#.#.#####.####.### | |
###.##.####.##.#..##`; | |
let field = new Field(input); | |
let result = field.destroy200(); | |
console.log('expected x: 8, expected y: 2'); | |
console.log(`actual x: ${result.x}, actual y: ${result.y}`); | |
console.log('passed;', result.x==8 && result.y==2); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment