gan-i3-356-bluetooth
Version:
Library for connecting to and interacting with Bluetooth-enabled Rubik's cubes (GAN)
1 lines • 3.51 kB
JavaScript
export class CubeNumberConverter{static cornersToLehmer(corners){let lehmer=0;const n=corners.length;for(let i=0;i<n-1;i++){let count=0;for(let j=i+1;j<n;j++)corners[i]>corners[j]&&count++;lehmer=lehmer*(n-i)+count}return lehmer}static lehmerToCorners(lehmer){const perm=[],available=Array.from({length:8},((_,i)=>i));for(let i=7;i>=0;i--){const index=lehmer%(i+1);lehmer=Math.floor(lehmer/(i+1)),perm.push(available.splice(index,1)[0])}return perm.reverse()}static edgesToLehmer(edges){let lehmer=0;const n=edges.length;for(let i=0;i<n-1;i++){let count=0;for(let j=i+1;j<n;j++)edges[i]>edges[j]&&count++;lehmer=lehmer*(n-i)+count}return lehmer}static lehmerToEdges(lehmer){const perm=[],available=Array.from({length:12},((_,i)=>i));for(let i=11;i>=0;i--){const index=lehmer%(i+1);lehmer=Math.floor(lehmer/(i+1)),perm.push(available.splice(index,1)[0])}return perm.reverse()}static getCornerOrientations(ca){return ca.slice(0,7).map((c=>c>>3&7))}static getCornerPositions(ca){return ca.map((c=>7&c))}static getEdgeOrientations(ea){return ea.slice(0,11).map((e=>1&e))}static getEdgePositions(ea){return ea.map((e=>e>>1))}static cornerOriToNumber(orientations){let result=0;for(let i=0;i<7;i++)result=3*result+orientations[i];return result}static numberToCornerOri(num){const orientations=[];for(let i=6;i>=0;i--)orientations.unshift(num%3),num=Math.floor(num/3);const sum=orientations.reduce(((a,b)=>a+b),0);return orientations.push((3-sum%3)%3),orientations}static edgeOriToNumber(orientations){let result=0;for(let i=0;i<11;i++)result=2*result+orientations[i];return result}static numberToEdgeOri(num){const orientations=[];for(let i=10;i>=0;i--)orientations.unshift(num%2),num=Math.floor(num/2);const sum=orientations.reduce(((a,b)=>a+b),0);return orientations.push(sum%2),orientations}static cubeStateToNumber(ca,ea){const cornerPositions=this.getCornerPositions(ca),cornerOrientations=this.getCornerOrientations(ca),edgePositions=this.getEdgePositions(ea),edgeOrientations=this.getEdgeOrientations(ea),cornerPermNum=BigInt(this.cornersToLehmer(cornerPositions)),cornerOriNum=BigInt(this.cornerOriToNumber(cornerOrientations)),edgePermNum=BigInt(this.edgesToLehmer(edgePositions));return BigInt(this.edgeOriToNumber(edgeOrientations))+this.EDGE_ORIS*(edgePermNum+this.EDGE_PERMS*(cornerOriNum+this.CORNER_ORIS*cornerPermNum))}static numberToCubeState(cubeNumber){if(cubeNumber<0n||cubeNumber>=this.TOTAL_STATES)throw new Error("Cube number must be between 0 and "+(this.TOTAL_STATES-1n));const edgeOriNum=Number(cubeNumber%this.EDGE_ORIS);cubeNumber/=this.EDGE_ORIS;const edgePermNum=Number(cubeNumber%this.EDGE_PERMS);cubeNumber/=this.EDGE_PERMS;const cornerOriNum=Number(cubeNumber%this.CORNER_ORIS);cubeNumber/=this.CORNER_ORIS;const cornerPermNum=Number(cubeNumber),cornerPositions=this.lehmerToCorners(cornerPermNum),cornerOrientations=this.numberToCornerOri(cornerOriNum),edgePositions=this.lehmerToEdges(edgePermNum),edgeOrientations=this.numberToEdgeOri(edgeOriNum),ca=[];for(let i=0;i<8;i++)ca[i]=cornerOrientations[i]<<3|cornerPositions[i];const ea=[];for(let i=0;i<12;i++)ea[i]=edgePositions[i]<<1|edgeOrientations[i];return{ca:ca,ea:ea}}static cubeNumberToHex(cubeNumber){return cubeNumber.toString(16).padStart(16,"0")}static hexToCubeNumber(hex){return BigInt(`0x${hex}`)}}CubeNumberConverter.TOTAL_STATES=BigInt("43252003274489856000"),CubeNumberConverter.CORNER_PERMS=40320n,CubeNumberConverter.CORNER_ORIS=2187n,CubeNumberConverter.EDGE_PERMS=479001600n,CubeNumberConverter.EDGE_ORIS=2048n;