Created
December 15, 2022 22:05
-
-
Save Renari/77a7124ffbd8ce410a7dbcf30fdb863e 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
const fs = require("fs") | |
class Point { | |
x | |
y | |
constructor(x, y) { | |
this.x = x | |
this.y = y | |
} | |
} | |
class Sensor extends Point { | |
beacon | |
length | |
constructor(inputData) { | |
const regex = /^Sensor at x=(-?\d+), y=(-?\d+): closest beacon is at x=(-?\d+), y=(-?\d+)$/gm; | |
const match = regex.exec(inputData) | |
super(parseInt(match[1]), parseInt(match[2])) | |
this.beacon = new Point(parseInt(match[3]), parseInt(match[4])) | |
/** | |
* determine length of the triangle covered by this sensor | |
*/ | |
let leftRightModifier = 0 | |
let upDownModifier = 0 | |
if (this.x > this.beacon.x) { | |
leftRightModifier = 1 | |
} else if (this.x < this.beacon.x) { | |
leftRightModifier = -1 | |
} | |
if (this.y > this.beacon.y) { | |
upDownModifier = -1 | |
} else if (this.y < this.beacon.y) { | |
upDownModifier = 1 | |
} | |
if (leftRightModifier === 0 || upDownModifier === 0) { | |
// the beacon is on the same line as our sensor, so it is at the furthest point | |
this.setLength(this.beacon) | |
} else { | |
let x = this.beacon.x | |
let y = this.beacon.y | |
while(x !== this.x && y !== this.y) { | |
x += leftRightModifier | |
y += upDownModifier | |
} | |
this.setLength(new Point(x, y)) | |
} | |
} | |
/** | |
* Checks if a point is inside this sensors range | |
* @param point the Point to check | |
*/ | |
isInside(point) { | |
const area = this.triangleArea(new Point(this.x, this.y), new Point(this.x + this.length, this.y), new Point(this.x, this.y + this.length)) | |
const positiveBase = new Point(this.x + this.length, this.y) | |
const positiveHeight = new Point(this.x, this.y + this.length) | |
const negativeBase = new Point(this.x - this.length, this.y) | |
const negativeHeight = new Point(this.x, this.y - this.length) | |
// positive positive direction | |
if (area === this.cumulativeArea(point, positiveBase, positiveHeight)) { | |
return true | |
} | |
// positive negative direction | |
if (area === this.cumulativeArea(point, positiveBase, negativeHeight)) { | |
return true | |
} | |
// negative positive direction | |
if (area === this.cumulativeArea(point, negativeBase, positiveHeight)) { | |
return true | |
} | |
// negative negative direction | |
if (area === this.cumulativeArea(point, negativeBase, negativeHeight)) { | |
return true | |
} | |
return false | |
} | |
/** | |
* Calculate the area of a triangle given 3 points | |
*/ | |
triangleArea(point1, point2, point3) { | |
return Math.abs((point1.x*(point2.y-point3.y) + point2.x*(point3.y-point1.y)+ point3.x*(point1.y-point2.y))/2.0) | |
} | |
cumulativeArea(point1, point2, point3) { | |
const area1 = this.triangleArea(point1, point2, point3) | |
const area2 = this.triangleArea(this, point1, point3) | |
const area3 = this.triangleArea(this, point2, point1) | |
return area1 + area2 + area3 | |
} | |
/** | |
* Used to set the range of this sensor | |
* @param point the furthest location that this sensor can reach | |
*/ | |
setLength(point) { | |
this.length = Math.sqrt(Math.pow(this.x - point.x, 2) + Math.pow(this.y - point.y, 2)) | |
} | |
} | |
const input = fs.readFileSync("sample.txt") | |
const lines = input.toString().split('\r\n') | |
const sensors = [] | |
for (let line of lines) { | |
sensors.push(new Sensor(line)) | |
} | |
// since we are checking for y values get highest and smallest x locations | |
let maxX = 0 | |
let minX = 0 | |
for (let sensor of sensors) { | |
if (sensor.x - sensor.length < minX) { | |
minX = sensor.x - sensor.length | |
} | |
if (sensor.x + sensor.length > maxX) { | |
maxX = sensor.x + sensor.length | |
} | |
} | |
let coveredLocations = 0 | |
const y = 10; | |
for (let x = minX; x <= maxX; x++) { | |
let covered = false | |
let symbol = "." | |
for (let sensor of sensors) { | |
if((sensor.x === x && sensor.y === y)) { | |
// this location cannot be covered because it's occupied by a sensor | |
covered = false | |
symbol = "S" | |
break | |
} else if (sensor.beacon.x === x && sensor.beacon.y === y) { | |
// this location cannot be covered because it's occupied by a beacon | |
covered = false | |
symbol = "B" | |
break | |
} | |
if(sensor.isInside(new Point(x, y))) { | |
covered = true | |
symbol = "#" | |
} | |
} | |
if (covered) { | |
coveredLocations++ | |
} | |
process.stdout.write(symbol) | |
} | |
console.log("") | |
console.log(coveredLocations) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment