Last active
June 2, 2017 21:54
-
-
Save upvalue/6ad4ed7a657d26fc4d6e3c9bba0ac037 to your computer and use it in GitHub Desktop.
JavaScript immutable two-dimensional array of arrays
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
class ArrayView { | |
constructor(array, x, y, width, height) { | |
this.array = array; | |
this.x = x; | |
this.y = y; | |
// Automatic bounding | |
// x = 30, width of backing array = 50, width of this = 30 | |
// width = 50 - 30 = 20 | |
let max_width = array.width - x; | |
let max_height = array.width - y; | |
/*if(max_width != width || max_height != height) { | |
console.log(`Automatically bounding array slice to ${max_width} x ${max_height}`); | |
}*/ | |
this.width = Math.min(max_width, width); | |
this.height = Math.min(max_height, height); | |
this.rows = (function*() { | |
for(let y = 0; y != this.height; y++) { | |
const idx = ((this.y + y) * this.array.height) + this.x; | |
const tmp = this.array.data.slice(idx, idx + this.width); | |
yield [y, tmp]; | |
} | |
}).bind(this); | |
} | |
get(x, y) { | |
return this.array.data[this.y + y][this.x + x]; | |
} | |
} | |
class Immutable2DArray { | |
constructor(copy_or_width, height) { | |
if(typeof copy_or_width == 'number') { | |
this.width = copy_or_width; | |
this.height = height; | |
this.data = Array(height * copy_or_width); | |
} else { | |
this.width = copy_or_width.width; | |
this.height = copy_or_width.height; | |
this.data = copy_or_width.data.slice(); | |
for(let i = 0; i != this.data.length; i++) { | |
if(Array.isArray(this.data[i])) { | |
this.data[i] = this.data[i].slice(); | |
} | |
} | |
} | |
} | |
_index(x, y) { | |
const idx = (y * this.height) + x; | |
if(idx > this.data.length) { | |
throw new Error(`Attempt to access ${x},${y} at array of dimensions ${this.width}x${this.height}`); | |
} | |
return idx; | |
} | |
get(x, y) { | |
const idx = this._index(x, y); | |
return this.data[idx]; | |
} | |
occupied(x, y) { | |
const val = this.get(x, y); | |
return val != null && val.length > 0; | |
} | |
add(x, y, value) { | |
const copy = new Immutable2DArray(this); | |
const idx = this._index(x, y); | |
if(copy.data[idx]) { | |
copy.data[idx] = this.data[idx].slice().push(value); | |
} else { | |
copy.data[idx] = [value]; | |
} | |
return copy; | |
} | |
// Mutate in place, for efficiency's sake | |
mutateRemove(x, y, value) { | |
const idx = this._index(x, y); | |
this.data[idx] = this.data[idx].filter((item) => item != value); | |
if(this.data[idx].length == 0) this.data[idx] = undefined; | |
} | |
mutateAdd(x, y, value) { | |
const idx = this._index(x, y); | |
if(this.data[idx]) { | |
this.data[idx].push(value); | |
} else { | |
this.data[idx] = [value]; | |
} | |
return this; | |
} | |
view(x, y, width, height) { | |
return new ArrayView(this, x, y, width, height); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment