1

I'm trying to implement DLX in Javascript and I'm running into problems with updating self-referencing objects literals.

This function takes a binary matrix and returns a matrix where every '1' of the matrix is an object referencing it's closed '1' in all cardinal directions.

export const constructDataObjects = matrix => {
  for (let i = 0; i < matrix.length; i++) {
    for (let j = 0; j < matrix.length; j++) {
      let u = j - 1;
      let d = j + 1;
      let l = i - 1;
      let r = i + 1;

      if (matrix[i][j] === 0) continue;

      // Check edge cases.
      if (u < 0) u = matrix.length - 1;
      if (d >= matrix.length) d = 0;
      if (l < 0) l = matrix.length - 1;
      if (r >= matrix.length) r = 0;

      // Increment and decrement directions, with bound checks.
      // On hitting a bound, circle around and start from the other side.
      while (matrix[i][u] === 0) u = u - 1 < 0 ? matrix.length - 1 : u - 1;
      while (matrix[i][d] === 0) d = d + 1 >= matrix.length ? 0 : d + 1;
      while (matrix[l][j] === 0) l = l - 1 < 0 ? matrix.length - 1 : l - 1;
      while (matrix[r][j] === 0) r = r + 1 >= matrix.length ? 0 : r + 1;


      matrix[i][j] = {
        _u: undefined,
        _d: undefined,
        _l: undefined,
        _r: undefined,
        get u () { return this._u },
        set u (v) { return this._u = v },
        get d () { return this._d },
        set d (v) { return this._d = v },
        get l () { return this._l },
        set l (v) { return this._l = v },
        get r () { return this._r },
        set r (v) { return this._r = v },
        c : null,
        debug: `i:${i}, j:${j}, u:${u}, d:${d}, l:${l}, r:${r}`
      };
      matrix[i][j].u = matrix[i][u]
      matrix[i][j].d = matrix[i][d]
      matrix[i][j].l = matrix[l][j]
      matrix[i][j].r = matrix[r][j]

    }
  }

  return matrix;
};

I asked a question before when I ran into problems with creating self-references in object literal declarations and was suggested to use getters. Now in DLX the objects in the data structure need to be able to change. How can I create editable self-referencing object literals?


I believe this problem can be reduced to

let a = arr => {
  for(let i = 0; i < arr.length; i++) {
    arr[i] = {
      curr: arr[i],
      first: arr[0],
      last: arr[arr.length - 1], 
    }
  }
  return arr
}


console.log(a([1,2]))

For clarity let me denote *first as a reference to the object in arr[0] and *second as a reference to the object in arr[1].

Now a([1,2]) produces

[ { curr: 1, first: 1, last: 2 },
  { curr: 2, first: *first, last: 2 } ]

What I want is

[ { curr: *first, first: *first, last: *second } },
  { curr: *second, first: *first, last: *second } ]

Add the getters

let a = arr => {
  for(let i = 0; i < arr.length; i++) {
    arr[i] = {
      get curr () { return arr[i] },
      get first () { return arr[0] },
      get last () { return arr[arr.length - 1] }
    }
  }
  return arr
}

console.log(a([1,2]))

Now a([1,2]) produces what I want

[ { curr: *first, first: *first, last: *second } },
  { curr: *second, first: *first, last: *second } ]

Lets add the ability to update the objects. Here is where I'm stuck. This is what I've tried and it doesn't work:

let a = arr => {
  for(let i = 0; i < arr.length; i++) {
    arr[i] = {
      _curr: undefined,
      _first: undefined,
      _last: undefined,
      get curr () { return this._curr },
      set curr (v) { this._curr = v },
      get first () { return this._first },
      set first (v) { this._first = v },
      get last () { return this._last },
      set last (v) { this._last = v },
    }
    arr[i].curr = arr[i]
    arr[i].first = arr[0]
    arr[i].last = arr[arr.length - 1]
  }
  return arr
}

console.log(a([1,2]))

As you can see from the console output a([1,2]) produces

[ { curr: *first, first: *first, last: 2 },
  { curr: *second, first: *first, last: *second } ]

What I want is

[ { curr: *first, first: *first, last: *second } },
  { curr: *second, first: *first, last: *second } ]

How do I keep the behaviour enabled by using getters while also allowing the objects to be updatable?

Red Mercury
  • 3,971
  • 1
  • 26
  • 32

1 Answers1

1

You cannot make a property that references an object before you had created that object. I would suggest instead that you give each cell a getter method (or property) that accesses the next cell when it is called, not when the cell is constructed.

export function constructDataObjects(matrix) {
  const size = matrix.length; // assumed quadratic
  for (let i = 0; i < size; i++) {
    for (let j = 0; j < size; j++) {
      if (matrix[i][j] === 0) continue;

      // Increment and decrement directions, with bound checks.
      // On hitting a bound, circle around and start from the other side.
      let u = j;
      do { u--; if (u < 0) u = size - 1; } while (matrix[i][u] === 0);
      let d = j;
      do { d++; if (d >= size) d = 0; } while (matrix[i][d] === 0);
      let l = i;
      do { l--; if (l < 0) l = size - 1; } while (matrix[l][j] === 0);
      let r = i;
      do { r++; if (r >= size) r = 0; } while (matrix[r][j] === 0);

      matrix[i][j] = {
        u,
        d,
        l,
        r,
        getUp()    { return matrix[i][this.u] },
        getDown()  { return matrix[i][this.d] },
        getLeft()  { return matrix[this.l][j]; },
        getRight() { return matrix[this.r][j]; },
        c : null,
        debug: `i:${i}, j:${j}, u:${u}, d:${d}, l:${l}, r:${r}`
      };
    }
  }
  return matrix;
}

Alternatively, for really creating a circular structure, you should create the objects first, with empty properties, and then fill them afterwards. You can even avoid iterating in two directions then.

export function constructDataObjects(matrix) {
  const size = matrix.length; // assumed quadratic
  for (let i = 0; i < size; i++) {
    for (let j = 0; j < size; j++) {
      if (matrix[i][j] !== 0) {
        matrix[i][j] = {
          i,
          j,
          u: null,
          d: null,
          l: null,
          r: null,
          c: null
        };
      }
    }
  }
  for (let i = 0; i < size; i++) {
    let j = 0;
    while (matrix[i][j] === 0 && j < size) j++;
    const first = matrix[i][j];
    let cur = first;
    while (j < size) {
      do { j++; } while (j < size && matrix[i][j] === 0);
      const next = matrix[i][j];
      cur.d = next;
      next.u = cur;
      cur = next;
    }
    if (first) {
      cur.d = first;
      first.u = cur;
    }
  }
  for (let j = 0; j < size; j++) {
    let i = 0;
    while (matrix[i][j] === 0 && i < size) i++;
    const first = matrix[i][j];
    let cur = first;
    while (i < size) {
      do { i++; } while (i < size && matrix[i][j] === 0);
      const next = matrix[i][j];
      cur.r = next;
      next.l = cur;
      cur = next;
    }
    if (first) {
      cur.r = first;
      first.l = cur;
    }
  }
  return matrix;
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • 1
    Thanks a lot for the response Bergi. I can see how this will work. Clever use of the do-while there! As suggested by another SO user I'm looking into first mapping over the matrix to turn the '1' primitives into objects which I **can** reference and only then build the data structure. That seems to work fine as well. In any case I think you answer could be accepted. Give me a second to code this up – Red Mercury Apr 25 '18 at 19:48