This commit is contained in:
nim-ka
2021-12-29 03:15:45 -05:00
commit a37eee947f
9 changed files with 1529 additions and 0 deletions

178
grid.js Normal file
View File

@@ -0,0 +1,178 @@
class Grid {
constructor(w, h, fill = 0) {
this.width = w
this.height = h
this.data = utils.createGridArray(w, h, fill)
}
forEach(func) {
this.data.map((r, y) => r.map((e, x) => func(e, new Point(x, y), this)))
return this
}
mapMut(func) { return this.forEach((e, pt, grid) => grid.set(pt, func(e, pt, grid))) }
fill(n) { return this.mapMut(() => n) }
fillFromArr(arr) {
if (arr[0].length != this.width) {
console.warn(`Grid.fillFromArr: Row size ${arr[0].length} does not match grid width ${this.width}`)
}
if (arr.length != this.height) {
console.warn(`Grid.fillFromArr: Column size ${arr.length} does not match grid height ${this.height}`)
}
return this.mapMut((_, pt) => arr[pt.y][pt.x])
}
fillFromStr(str) { return this.fillFromArr(str.split("\n")) }
static fromStr(str) {
let arr = str.split("\n")
return new Grid(arr[0].length, arr.length).fillFromArr(arr)
}
get(pt) {
if (this.contains(pt)) {
return this.data[pt.y][pt.x]
} else {
console.error("Grid.get: Grid does not contain point " + pt + ":\n" + this)
}
}
set(pt, val) {
if (this.contains(pt)) {
this.data[pt.y][pt.x] = val
} else {
console.error("Grid.set: does not contain point " + pt + ":\n" + this)
}
}
getColumn(x) {
if (x >= 0 && x < this.width) {
return this.data.map((row) => row[x])
} else {
console.error("Grid.getColumn: does not contain column " + x + ":\n" + this)
}
}
getRow(y) {
if (y >= 0 && y < this.height) {
return this.data[y]
} else {
console.error("Grid.getRow: does not contain row " + y + ":\n" + this)
}
}
getSection(pt1, pt2) {
if (pt2.x >= pt1.x && pt2.y >= pt2.y) {
return new Grid(pt2.x - pt1.x + 1, pt2.y - pt1.y + 1).mapMut((_, pt) => this.get(pt.add(pt1)))
} else {
console.error("Grid.getSection: Second point " + pt2 + " behind first point " + pt1 + ":\n" + this)
}
}
findAll(func) {
let points = []
this.forEach((e, pt, grid) => func(e, pt, grid) ? points.push(pt) : 0)
return points
}
contains(pt) { return pt.x >= 0 && pt.x < this.width && pt.y >= 0 && pt.y < this.height }
getAdjNeighbors(pt) { return pt.getUnfilteredAdjNeighbors().filter((pt) => this.contains(pt)) }
getDiagNeighbors(pt) { return pt.getUnfilteredDiagNeighbors().filter((pt) => this.contains(pt)) }
getAllNeighbors(pt) { return pt.getUnfilteredAllNeighbors().filter((pt) => this.contains(pt)) }
getAdjNeighborsThat(pt, func) { return pt.getUnfilteredAdjNeighbors().filter((pt) => this.contains(pt) && func(pt)) }
getDiagNeighborsThat(pt, func) { return pt.getUnfilteredDiagNeighbors().filter((pt) => this.contains(pt) && func(pt)) }
getAllNeighborsThat(pt, func) { return pt.getUnfilteredAllNeighbors().filter((pt) => this.contains(pt) && func(pt)) }
static BFS_CONTINUE = 0
static BFS_STOP = 1
static BFS_END = 2
bfs(pt, func, limit = 1000) {
let visited = [].pt
let toVisit = [pt].pt
let count = 0
let end
toVisit[0].path = [pt]
out: while (toVisit.length > 0 && count++ < limit) {
let newToVisit = [].pt
toVisit.sort()
for (let i = 0; i < toVisit.length; i++) {
let result = func(this.get(toVisit[i]), toVisit[i], this, visited);
if (result == Grid.BFS_CONTINUE) {
newToVisit.pushUniq(...this.getAdjNeighborsThat(toVisit[i], (pt) => !pt.isIn(visited)).map((pt) => (pt.path = [...toVisit[i].path, pt], pt)))
}
if (result == Grid.BFS_END) {
end = toVisit[i]
break out
}
}
visited.pushUniq(...toVisit)
toVisit = newToVisit
}
if (count >= limit) {
console.warn("Limit reached. Aborted.")
}
return end || visited[visited.length - 1]
}
transpose() {
this.data = this.data.transpose()
this.width = this.data[0].length
this.height = this.data.length
return this
}
reflectX() {
this.data = this.data.map((row) => row.reverse())
return this
}
reflectY() {
this.data.reverse()
return this
}
rotate90() { return this.transpose().reflectX() }
rotate180() { return this.reflectX().reflectY() }
rotate270() { return this.reflectX().transpose() }
rotate(n) {
for (let i = 0; i < Math.abs(n); i++) {
this[n > 0 ? "rotate90" : "rotate270"]()
}
return this
}
allTransformations() {
return [
this.copy(),
this.copy().rotate90(),
this.copy().rotate180(),
this.copy().rotate270(),
this.copy().reflectX(),
this.copy().reflectX().transpose().reflectX(),
this.copy().reflectY(),
this.copy().transpose()
]
}
copy() { return new Grid(this.width, this.height).mapMut((_, pt) => this.get(pt).copyDeep()) }
toString(sep = "\t", ...pts) { return this.data.map((r, y) => r.map((e, x) => new Point(x, y).isIn(pts) ? "P" : e).join(sep)).join("\n") }
print(sep = "\t", ...pts) { console.log(this.toString(sep, pts)) }
}