Skip to content

Commit

Permalink
Add gametree.getHash()
Browse files Browse the repository at this point in the history
  • Loading branch information
yishn committed Mar 18, 2020
1 parent 6331e41 commit bab9f71
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 21 deletions.
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ A node is represented by an object of the following form:

```js
{
id: <Primitive>,
data: {
[property: <String>]: <Array<Primitive>>
},
parentId: <Primitive> | null,
children: <Array<NodeObject>>
id: <Primitive>,
data: {
[property: <String>]: <Array<Primitive>>
},
parentId: <Primitive> | null,
children: <Array<NodeObject>>
}
```

Expand All @@ -58,7 +58,7 @@ children of nodes with an object of the following form:

```js
{
[id: <Primitive>]: <Primitive>
[id: <Primitive>]: <Primitive>
}
```

Expand Down Expand Up @@ -200,6 +200,11 @@ Equivalent to `[...tree.listCurrentNodes(currents)].length`.
Calculates and returns the height of the tree as an integer. This value will be
cached across mutations when possible.

#### `tree.getHash()`

Calculates and returns a hash of the whole tree as a string. This value will
be cached.

#### `tree.getStructureHash()`

Calculates and returns a hash of the tree structure as a string. This value will
Expand Down
33 changes: 19 additions & 14 deletions src/GameTree.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const Draft = require('./Draft')
const hasher = require('./hasher')

class GameTree {
constructor({getId = null, merger = null, root = null} = {}) {
Expand All @@ -17,6 +18,7 @@ class GameTree {
this._nodeCache = {}
this._idAliases = {}
this._heightCache = null
this._hashCache = null
this._structureHashCache = null
}

Expand Down Expand Up @@ -214,20 +216,7 @@ class GameTree {

getStructureHash() {
if (this._structureHashCache == null) {
// Simple hash function adapted from
// https://github.com/darkskyapp/string-hash

let hash = (() => {
let result = 5381

return str => {
for (let i = 0; i < str.length; i++) {
result = (result * 33) ^ str.charCodeAt(i)
}

return result
}
})()
let hash = hasher.new()

let inner = node => {
hash('[' + JSON.stringify(node.id) + ',')
Expand All @@ -241,6 +230,22 @@ class GameTree {
return (this._structureHashCache >>> 0) + ''
}

getHash() {
if (this._hashCache == null) {
let hash = hasher.new()

let inner = node => {
hash('[' + JSON.stringify(node.data) + ',')
node.children.forEach(inner)
return hash(']')
}

this._hashCache = inner(this.root)
}

return (this._hashCache >>> 0) + ''
}

onCurrentLine(id, currents) {
let node = this.get(id)
let {parentId} = node
Expand Down
14 changes: 14 additions & 0 deletions src/hasher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
exports.new = function() {
// Simple hash function adapted from
// https://github.com/darkskyapp/string-hash

let result = 5381

return str => {
for (let i = 0; i < str.length; i++) {
result = (result * 33) ^ str.charCodeAt(i)
}

return result
}
}
18 changes: 18 additions & 0 deletions tests/GameTree.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,21 @@ t.test('getStructureHash method', t => {

t.end()
})

t.test('getHash method', t => {
let hash = tree.getHash()

let tree2 = tree.mutate(draft => {
draft.addToProperty(draft.root.id, 'MA', 'aa')
draft.removeProperty(childId1, 'MA')
})

let tree3 = tree2.mutate(draft => {
draft.appendNode(draft.root.id, {})
})

t.notEqual(hash, tree2.getStructureHash())
t.notEqual(hash, tree3.getStructureHash())

t.end()
})

0 comments on commit bab9f71

Please sign in to comment.