const PACK = { u8(value) { return new Uint8Array([ value & 0xFF ]); }, u16(value) { return new Uint8Array([ (value >> 8) & 0xFF, value & 0xFF ]); }, u32(value) { return new Uint8Array([ (value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF ]); }, }; const UNPACK = { u8(data, index) { let result = 0; if(index + 1 <= data.length) { result = data[index]; index += 1; } return { data: result, index: index }; }, u16(data, index) { let result = 0; if(index + 2 <= data.length) { result = (data[index] << 8) + data[index + 1]; index += 2; } return { data: result, index: index }; }, u32(data, index) { let result = 0; if(index + 4 <= data.length) { result = (data[index] << 24) + (data[index + 1] << 16) + (data[index + 1] << 8) + data[index + 1]; index += 4; } return { data: result, index: index }; }, string(data, index) { let result = UNPACK.u16(data, index); index = result.index; let length = result.data; let dec = new TextDecoder(); let result_str = ""; if(index + length <= data.length) { let bytes = new Uint8Array(length); for(let i = 0; i < length; ++i) { bytes[i] = data[index + i]; } index += length; result_str = dec.decode(bytes); } return { data: result_str, index: index }; }, move(bytes) { function piece_by_id(id) { switch(id) { case 0: return ""; case 1: return "M"; case 2: return "N"; case 3: return "L"; case 4: return "T"; case 5: return "C"; case 6: return "D"; case 7: return "K"; } } /* ** From [6] ** To [6] ** Piece [3] ** Take [3] ** */ let from = (bytes[0] & 0xFC) >> 2; let to = ((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xC0) >> 6); let piece = piece_by_id((bytes[1] & 0x38) >> 3); let take = piece_by_id(bytes[1] & 0x07); let source = (bytes[2] & 0x80) >> 7; switch((bytes[2] & 0x60) >> 5) { case 0: state = ""; case 1: state = "◇"; break; case 2: state = "◈"; break; case 3: state = "◆"; break; } let str = ""; if(state.length > 0) { if(source == 1) { str = "" + piece + " " + state + " " + to; } else { str = "" + from + " " + piece + " " + state + " " + to + " " + take; } if(take != "") { str += " " + take; } } return str; } }; const BITWISE = { lsb(x) { return x & -x; }, ffs(x) { return 31 - Math.clz32(x & -x); }, count(mask) { // source: https://graphics.stanford.edu/~seander/bithacks.html mask = mask|0; mask = mask - ((mask >> 1) & 0x55555555); mask = (mask & 0x33333333) + ((mask >> 2) & 0x33333333); return ((mask + (mask >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; } }; const MATH = { sign(a) { return 1 - ((a < 0) << 1); }, mod(a, b) { return ((a % b) + b) % b }, };