Skip to content

Commit c26a54c

Browse files
committed
added javascript encoder
1 parent 18425ee commit c26a54c

File tree

2 files changed

+88
-2
lines changed

2 files changed

+88
-2
lines changed

javascript/index.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,80 @@
11
'use strict'
22

33
exports.parseDeck = parseDeck
4+
exports.encodeDeck = encodeDeck
45

56
const b64 = require('base64-js')
67

78
const CURRENT_VERSION = 2
89
const ENCODE_PREFIX = "ADC"
910

11+
12+
function encodeDeck(deck) {
13+
if (!deck || !deck.heroes || !deck.cards) throw "invalid deck"
14+
15+
const heroes = deck.heroes.sort((a, b) => a.id - b.id)
16+
const cards = deck.cards.sort((a, b) => a.id - b.id)
17+
18+
const encoder = cardEncoder()
19+
encoder.writeVar(heroes.length, 3)
20+
heroes.forEach(it => encoder.writeCard(it.id, it.turn))
21+
encoder.resetPreviousId()
22+
cards.forEach(it => encoder.writeCard(it.id, it.count))
23+
24+
const versionAndHeroes = CURRENT_VERSION << 4 | extractNBitsWithCarry(heroes.length, 3)
25+
const checksum = computeChecksum(encoder.getBytes())
26+
const name = (deck.name || "").substr(0, 63)
27+
28+
const header = [versionAndHeroes, checksum, name.length]
29+
const nameArray = Array.apply(null, { length: name.length }).map((_, i) => name.charCodeAt(i))
30+
31+
const encodedDeck = b64.fromByteArray(header.concat(encoder.getBytes(), nameArray))
32+
const sanitizedDeckCode = ENCODE_PREFIX + encodedDeck.replace(/\//g, "-").replace(/=/g, "_")
33+
34+
return sanitizedDeckCode
35+
}
36+
37+
function cardEncoder() {
38+
const bytes = []
39+
var previousId = 0
40+
41+
function writeVar(value, bitsToSkip) {
42+
if (value < (1 << bitsToSkip)) return
43+
value = value >>> bitsToSkip
44+
while (value > 0) {
45+
bytes.push(extractNBitsWithCarry(value, 7))
46+
value = value >>> 7
47+
}
48+
}
49+
50+
function writeCard(id, n) {
51+
const nPart = n <= 3 ? n - 1 : 3
52+
53+
const delta = id - previousId
54+
previousId = id
55+
const idPart = extractNBitsWithCarry(delta, 5)
56+
57+
bytes.push((nPart << 6) | idPart)
58+
writeVar(delta, 5)
59+
if (n > 3) writeVar(n, 0)
60+
}
61+
62+
return {
63+
writeVar,
64+
writeCard,
65+
resetPreviousId: () => previousId = 0,
66+
getBytes: () => bytes
67+
}
68+
}
69+
70+
function extractNBitsWithCarry(value, bits) {
71+
const bitLimit = 1 << bits
72+
if (value < bitLimit) return value
73+
return bitLimit | (value & (bitLimit - 1))
74+
}
75+
76+
77+
1078
function parseDeck(deckCode) {
1179
if (!deckCode.startsWith(ENCODE_PREFIX)) throw "invalid deck code prefix"
1280
const b64Str = deckCode.substr(ENCODE_PREFIX.length)

javascript/test/index.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,31 @@
11
'use strict'
22

33
const assert = require('assert')
4-
const { parseDeck } = require('../')
4+
const { parseDeck, encodeDeck } = require('../')
55

66
const deck = require('./deck.json')
7+
const DECK_CODE = "ADCJWkTZX05uwGDCRV4XQGy3QGLmqUBg4GQJgGLGgO7AaABR3JlZW4vQmxhY2sgRXhhbXBsZQ__"
8+
9+
describe('encodeDeck', function () {
10+
it('should encode a deck', function () {
11+
const result = encodeDeck(deck)
12+
assert.equal(result, DECK_CODE)
13+
})
14+
15+
it('should encode a deck with unordered cards and heroes', function () {
16+
const newDeck = {
17+
name: deck.name,
18+
heroes: deck.heroes.slice(0).reverse(),
19+
cards: deck.cards.slice(0).reverse()
20+
}
21+
const result = encodeDeck(deck)
22+
assert.equal(result, DECK_CODE)
23+
})
24+
})
725

826
describe('parseDeck', function () {
927
it('should decode v2 deck code', function () {
10-
const result = parseDeck("ADCJWkTZX05uwGDCRV4XQGy3QGLmqUBg4GQJgGLGgO7AaABR3JlZW4vQmxhY2sgRXhhbXBsZQ__")
28+
const result = parseDeck(DECK_CODE)
1129
assert.equal(result.name, deck.name)
1230
assert.equal(areTheCardArraysEqual(result.heroes, deck.heroes), true)
1331
assert.equal(areTheCardArraysEqual(result.cards, deck.cards), true)

0 commit comments

Comments
 (0)