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; }, rotate_blocks(mask) { const r1 = 0x00003F; // first 6 bits const r2 = 0x000FC0; // second 6 bits const r3 = 0x03F000; // third 6 bits let v1 = (r1 & mask) << 3; let v2 = (r2 & mask) << 3; let v3 = (r3 & mask) << 3; v1 = (v1 & r1) | ((v1 & ~r1) >> 6); v2 = (v2 & r2) | ((v2 & ~r2) >> 6); v3 = (v3 & r3) | ((v3 & ~r3) >> 6); return v1 | v2 | v3; }, }; const MATH = { Vec2: class { constructor(x, y) { this.x = x; this.y = y; } }, sign(a) { return 1 - ((a < 0) << 1); }, mod(a, b) { return ((a % b) + b) % b }, }; const COLOR = { rgba(r, g, b, a) { let ur = Math.floor(r * 255); let ug = Math.floor(r * 255); let ub = Math.floor(r * 255); let ua = Math.floor(r * 255); return "rgba(" + ur + "," + ug + "," + ub + "," + ua + ")"; }, }