aboutsummaryrefslogtreecommitdiff
path: root/examples/search.js
blob: 92d8d65f833a8d715a3607a177d422fd48024a27 (plain)
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// 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')
const getdims = require('../utils/getdims.js');

function getComp(index){
  return (element,needle) => element[index] - needle[index];
}

function tileToChar(coord){
  let cofactor = [8,16];
  return [coord[0]*cofactor[0], coord[1]*cofactor[1]];
}

function coordmult(coord,factor){
  return [coord[0]*factor, coord[1]*factor]
}

function coordSum(coord, coord){ // This needs to be generalized and standardized (vector arithmetic) in a utils or a library
  return [coord[0]+coord[0], coord[1]+coord[1]];
}

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(this.sort[ind], loc, getComp(ind))-1;
      if (inds[ind] < 0) throw "loc should not be a part of the list";
      this.sort[ind].splice(inds[ind], 0, loc);
    });
    let block = this.block(loc, inds);
    let searchspace = new Space();
    let root = tileToChar(getdims(Array.from(block))[0]);
    //let root = [0,0]; //PLACEHOLDER: get upperleft-most tile in searchspace using getdims.
    // searchspace.comb(this.tiles['2,2'], comb.add, [16,32]);
    block.forEach( (tile) => {searchspace.comb(this.tiles[tile],comb.add,coordSum(tileToChar(tile),coordmult(root,-1)))});
    coords = searchspace.search(searchBlock);
    if (! coords) return coords; // If coords are empty (i.e. no match), return;
    return [ coords[0] ,  coords[1] ];
    //return searchspace.search(searchBlock); // According to space docs, [] on failure and a character location on success
  }
  
  this.block = function(loc,inds,exclude=new Set()){
    let adjacent = new 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+=2) for (let j = 1; this.sort[ind][inds[ind]+i*j] && this.sort[ind][inds[ind]][ind] == this.sort[ind][inds[ind]+i*j][ind]; j++){
        if (! exclude.has(this.sort[ind][inds[ind]]) && this.sort[ind][inds[ind]][1-ind] == this.sort[inds[ind]+i*j][1-ind]){ // Make more readable
          adjacent.add(...this.block(this.sort[ind][inds[ind]+i*j], inds[ind+i*j], exclude=adjacent)); // Already includes itself
        }}
    });
    return adjacent;
  }

  this.del = function(loc){
    delete this.tiles[loc];
    [null,null].forEach( (item,ind) => {
      let theind = bs(this.sort[ind], loc, getComp(ind));
      if (theind < 0) throw "loc must already be a part of the list";
      this.sort[ind].splice(bs(this.sort[ind], loc, getComp(ind)), 1);
    })
  }

  this.has = function(loc){
    if (bs(this.sort[0], loc, getComp(0)) < 0) return false; // Could use ind = 1 just as well, but doesn't really matter
    // bs returns negative if not found.
    else return true;
  }
}

let space = new Space();
space.adhoc('jarvis');
let test = new Search(space);
let tile = new Space();
tile.adhoc('\
                \n\
     jarvis     \n\
                \n\
                \n\
                \n\
                \n\
                \n\
                \n\
');
console.log(test.add([2,2],tile));

module.exports = Search;