class Grid {
constructor(n, m, grid) {
this.n = n;
this.m = m;
this.grid = grid;
}
*positions() {
for (let y = 0; y < this.m; ++y) {
for (let x = 0; x < this.n; ++x) {
yield [x, y];
}
}
}
*positionsLeft(x, y) {
for (let i = x - 1; i >= 0; --i) {
yield [i, y];
}
}
*positionsRight(x, y) {
for (let i = x + 1; i < this.n; ++i) {
yield [i, y];
}
}
*positionsTop(x, y) {
for (let i = y - 1; i >= 0; --i) {
yield [x, i];
}
}
*positionsBottom(x, y) {
for (let i = y + 1; i < this.m; ++i) {
yield [x, i];
}
}
heightAt(x, y) {
x = Math.floor(x);
y = Math.floor(y);
if (x >= 0 && x < this.n && y >= 0 && y < this.m) {
return this.grid[y * this.n + x];
}
}
everyShorter(positions, h) {
for (const [x, y] of positions) {
if (this.heightAt(x, y) >= h) {
return false;
}
}
return true;
}
countShorter(positions, h) {
let n = 0;
for (const [x, y] of positions) {
++n;
if (this.heightAt(x, y) >= h) {
break;
}
}
return n;
}
visibleAt(x, y) {
const h = this.heightAt(x, y);
return (
(this.everyShorter(this.positionsLeft(x, y), h) && 1) |
(this.everyShorter(this.positionsRight(x, y), h) && 2) |
(this.everyShorter(this.positionsTop(x, y), h) && 4) |
(this.everyShorter(this.positionsBottom(x, y), h) && 8)
);
}
scenicScoreAt(x, y) {
const h = this.heightAt(x, y);
return (
this.countShorter(this.positionsLeft(x, y), h) *
this.countShorter(this.positionsRight(x, y), h) *
this.countShorter(this.positionsTop(x, y), h) *
this.countShorter(this.positionsBottom(x, y), h)
);
}
}