1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
// A search utility for arbitrary (new) tileUpdates.
// Provides `add` functionality, which auto-checks adjacency with other blocks. Subsequently, it searches them
// Provides `del` functionality, which should be used with auto-deletion
const bs = require('binary-search');
const Space = require('../space');
const comb = require('../utils/comb.js')
function getComp(index){
return (element,needle) => element[index] - needle[index];
}
function Search(searchBlock){ // searchBlock should be a Space object.
this.tiles = {}; // Object which stores Spaces.
this.sort = [[],[]]; // Vertically/horizontally sorted list of tiles for fast addition, deletion, and searching
this.add = function(loc, space){ // loc should be [tileY,tileX] and space Space.
this.tiles[loc] = space;
let inds = Array(2); // Records horizontal and vertical indices for insertion. Then actually inserts the item.
[null,null].forEach( (item, ind) => {
inds[ind] = -bs(sort[ind], loc, getComp(ind))-1;
if (inds[ind] < 0) throw "loc should not be a part of the list";
sort[ind].splice(inds[ind], 0, loc);
});
let block = this.block(inds);
let searchspace = new Space();
block.forEach( (tile) => {searchspace.comb(tiles[tile],comb.add,[tile[0]*8,tile[1]*16])});
return searchspace.search(searchBlock); // According to space docs, [] on failure and a character location on success
}
this.block = function(loc,inds,exclude=Set()){
let adjacent = Set([loc]);
exclude.add(loc);
[null,null].forEach( (item, ind) => {
// inds[ind] is address, so check neighbors on sort[ind] (up, then down)
// until sort[ind][inds[ind]][ind] != sort[ind][otherind][ind].
// on each, if sort[ind][otherind][1-ind] == sort[ind][inds[ind]][1-ind],
// add to adjacent and search it with exclude=adjacent. Add that to adjacent
let addr = inds[ind];
for (let i = -1; i <= 1; i++) for (let j = 1; sort[ind][inds[ind]][ind] == sort[ind][inds[ind]+i*j][ind]; j++)
if (! exclude.has(sort[ind][inds[ind]]) && sort[ind][inds[ind]][1-ind] == sort[inds[ind]+i*j][1-ind]){ // Make more readable
adjacent.add(...this.block(sort[ind][inds[ind]+i*j], inds[ind+i*j], exclude=adjacent)); // Already includes itself
}
return adjacent;
});
}
this.del = function(loc){
delete tiles[loc];
[null,null].forEach( (item,ind) => {
let theind = bs(sort[ind], loc, getComp(ind));
if (theind < 0) throw "loc must already be a part of the list";
sort[ind].splice(bs(sort[ind], loc, getComp(ind)), 1);
})
}
}
module.exports = Search;
|