Skip to content

Instantly share code, notes, and snippets.

@upvalue
Last active June 2, 2017 21:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save upvalue/6ad4ed7a657d26fc4d6e3c9bba0ac037 to your computer and use it in GitHub Desktop.
Save upvalue/6ad4ed7a657d26fc4d6e3c9bba0ac037 to your computer and use it in GitHub Desktop.
JavaScript immutable two-dimensional array of arrays
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