//
// The Rubix cube program
// Copyright c Brian P. Vogl
// October 3 - 6, 2018
// Revised JS version
// Started June 14 2018
var CD = [ //new int[6][9]; Color of each square
[ 1, 1, 1, 1, 1, 1, 1, 1, 1 ], // Green face
[ 2, 2, 2, 2, 2, 2, 2, 2, 2 ], // Yellow face
[ 3, 3, 3, 3, 3, 3, 3, 3, 3 ], // Red face
[ 4, 4, 4, 4, 4, 4, 4, 4, 4 ], // Blue face
[ 5, 5, 5, 5, 5, 5, 5, 5, 5 ], // White face
[ 6, 6, 6, 6, 6, 6, 6, 6, 6 ] ]; // Orange face
var AP = [ //new int[12][6][2]; Rotation Rules
[[4,6], [3,6], [3,0], [4,2], [3,2], [3,8]],
[[4,7], [3,7], [3,3], [4,1], [3,1], [3,5]],
[[4,8], [3,8], [3,6], [4,0], [3,0], [3,2]],
[[2,6], [5,0], [1,0], [5,2], [2,0], [4,0]],
[[2,7], [5,3], [1,3], [5,1], [2,3], [4,3]],
[[2,8], [5,6], [1,6], [5,0], [2,6], [4,6]],
[[1,6], [0,6], [0,8], [1,2], [0,2], [0,0]],
[[1,7], [0,7], [0,5], [1,1], [0,1], [0,3]],
[[1,8], [0,8], [0,2], [1,0], [0,0], [0,6]],
[[5,6], [2,8], [4,8], [2,2], [5,8], [1,8]],
[[5,7], [2,5], [4,5], [2,1], [5,5], [1,5]],
[[5,8], [2,2], [4,2], [2,0], [5,2], [1,2]] ];
// Polygon vertices, (X,Y) polygon number (0-2) and index into CD array.
var QP = [ //new int[5][54];
[139,473,475, 93,185,427,521, 47,139,231,381,473,475,567, 2, 93,185,276, // X
427,521, 48,139,230,381,473,475,567, 2, 94,184,276,427,474,521, 48,230,
381,428,520,567, 2, 94,184,276,382,474,566, 48,230,428,520, 94,184,474 ],
[ -8,-10,-10, 8, 8, 6, 6, 24, 24, 24, 22, 20, 20, 22, 40, 40, 40, 40, // Y
36, 36, 56, 56, 56, 52, 50, 50, 52, 70, 72, 72, 70, 66, 80, 66, 86, 86,
82, 96, 96, 82,100,102,102,100,112,112,112,116,116,128,128,132,132,144 ],
[0,2,1,0,0,2,1,0,0,0,2,2,1,1,1,0,0,2,2,1,1,0,2,2,2,1,1, // Polygon type
1,1,2,2,2,0,1,1,2,2,0,0,1,1,1,2,2,0,0,0,1,2,0,0,1,2,0 ],
[0,5,4,0,0,5,4,0,0,0,5,5,4,4,1,0,0,2,5,4,1,0,2,5,5,4,4, // X index into CD
1,1,2,2,5,3,4,1,2,5,3,3,4,1,1,2,2,3,3,3,1,2,3,3,1,2,3 ],
[0,8,6,3,1,7,7,6,4,2,6,5,3,8,8,7,5,6,4,4,7,8,7,3,2,0,5, // Y index into CD
5,6,8,3,1,2,1,4,4,0,5,1,2,2,3,5,0,8,4,0,1,1,7,3,0,2,6 ] ];
var RP = [ //new int[4][42]; Points (X1,Y1)-(X2,Y2) lines
[ 1, 1,139,277,277,139, 1,139,231, 93,185, 47, 93,231, // X1
47,185,139, 1,139, 1,139,336,474,612,612,474,336,336,
474,566,428,520,382,428,566,382,520,474,336,474,336,474 ],
[ 39,129,177,129, 39, -9, 39, 87, 23, 71, 7, 55, 7, 55, // Y1
23, 71, 87, 69,117, 99,147,127,175,127, 37,-11, 37,127,
79,143, 95,159,111,159,111,143, 95, 79, 67, 19, 97, 49 ],
[ 1,139,277,277,139, 1,139,277, 93, 93, 47, 47,231,231, // X2
185,185,139,139,277,139,277,474,612,612,474,336,336,474,
612,428,428,382,382,566,566,520,520,474,474,612,474,612 ],
[129,177,129, 39, -9, 39, 87, 39, 71,161, 55,145, 55,145, // Y2
71,161,177,117, 69,147, 99,175,127, 37,-11, 37,127, 79,
127, 95, 5,111, 21,111, 21, 95, 5,-11, 19, 67, 49, 97 ] ];
var PP = [ 0,2,8,6,1,5,7,3 ];
var canvas = document.getElementById("thecanvas");
canvas.style.backgroundColor = "white";
var ctx;
if(ctx = canvas.getContext('2d'))
{ canvas.oncontextmenu = function (event) {
event.preventDefault();
MousePos(event);
};
do_display(ctx);
document.addEventListener("click", MousePos);
}
function leftofline(rp, xc, yc)
{ // Returns true if point is left of or below the RP line
if(RP[2][rp] == RP[0][rp]) return ( xc < RP[0][rp] );
var m = ((RP[3][rp] - RP[1][rp]) / (RP[2][rp] - RP[0][rp]));
var b = RP[1][rp] - parseInt(RP[0][rp] * m);
return ( yc < ( m * xc + b ));
}
function incenter(rp1, rp2, rp3, rp4, xc, yc)
{ // Returns true if point is in the center of the box bounded by the 4 RP lines.
return( leftofline(rp1, xc, yc) && !leftofline(rp2, xc, yc) &&
leftofline(rp3, xc, yc) && !leftofline(rp4, xc, yc));
}
function MousePos(event)
{ // Determine which face and which button was pressed over it
var bbox = canvas.getBoundingClientRect();
var xs = event.clientX - 20 - bbox.left;
var ys = event.clientY / 2 - 35 - bbox.top;
var buttstate = event.which > 1 ? 1 : 0;
var fc = -1;
if(incenter( 6, 5, 7, 4, xs, ys)) fc = 0; // GREEN Face
if(incenter( 1, 6,16, 0, xs, ys)) fc = 1; // YELLOW Face
if(incenter( 2, 7, 3,16, xs, ys)) fc = 2; // RED Face
if(incenter(21,27,22,28, xs, ys)) fc = 3; // BLUE Face
if(incenter(28,24,23,37, xs, ys)) fc = 4; // WHITE Face
if(incenter(27,25,37,26, xs, ys)) fc = 5; // ORANGE Face
if(fc >= 0)
{ if(buttstate == 0)
{ rotateDn(fc);
}
if(buttstate == 1)
{ rotateUp(fc);
}
do_display();
}
}
function rotateUp(fc) // An upper button was desired
{ var TCD = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
var n, t, p, tmp;
for(n=0; n<=1; n++) // Translate the face of the cube
{ tmp = CD[fc][PP[n*4]];
for(t=0; t<=2; t++) CD[fc][PP[n*4+t]] = CD[fc][PP[n*4+t+1]];
CD[fc][PP[n*4+3]] = tmp;
} // Translate the sides of the cube
for(p=0; p<12; p++) TCD[p] = CD[AP[p][fc][0]][AP[p][fc][1]];
for(n=0; n<=2; n++)
{ tmp = TCD[n];
for(t=0; t<=2; t++) TCD[n+t*3] = TCD[n+(t+1)*3];
TCD[n+9] = tmp;
} for(p=0; p<12; p++) CD[AP[p][fc][0]][AP[p][fc][1]] = TCD[p];
}
function rotateDn(fc) // A lower button was desired
{ var TCD = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
var n, t, p, tmp;
for(n=1; n>=0; n--) // Translate the face of the cube
{ tmp = CD[fc][PP[n*4+3]];
for(t=2; t>=0; t--) CD[fc][PP[n*4+t+1]] = CD[fc][PP[n*4+t]];
CD[fc][PP[n*4]] = tmp;
} // Translate the sides of the cube
for(p=0; p<12; p++) TCD[p] = CD[AP[p][fc][0]][AP[p][fc][1]];
for(n=2; n>=0; n--)
{ tmp = TCD[n+9];
for(t=2; t>=0; t--) TCD[n+(t+1)*3] = TCD[n+t*3];
TCD[n] = tmp;
} for(p=0; p<12; p++) CD[AP[p][fc][0]][AP[p][fc][1]] = TCD[p];
}
function do_display()
{ var k, Xo, Yo;
ctx.beginPath();
ctx.lineWidth=3;
ctx.strokeStyle = '#000000';
var polyX = [ 0, 0, 0, 0, 0 ];
var polyY = [ 0, 0, 0, 0, 0 ];
for(k=0; k < 42; k++) // Draw the cube grid first
{ ctx.moveTo(RP[0][k]+20, (RP[1][k]+35)*2);
ctx.lineTo(RP[2][k]+20, (RP[3][k]+35)*2);
}
ctx.stroke();
ctx.lineWidth=1;
for(var k=0; k<54; k++)
{ Xo = QP[0][k]+20; // Determine the offset of the polygons
Yo = QP[1][k]+35;
polyX[0] = Xo; polyY[0] = 2*Yo;
polyX[4] = Xo; polyY[4] = 2*Yo;
switch(QP[2][k])
{ // Select the polygon to draw
case 0: polyX[1] = Xo-45; polyY[1] = 2*(Yo+15);
polyX[2] = Xo; polyY[2] = 2*(Yo+30);
polyX[3] = Xo+45; polyY[3] = 2*(Yo+15); break;
case 1: polyX[1] = Xo; polyY[1] = 2*(Yo+28);
polyX[2] = Xo+44; polyY[2] = 2*(Yo+44);
polyX[3] = Xo+44; polyY[3] = 2*(Yo+16); break;
case 2: polyX[1] = Xo-44; polyY[1] = 2*(Yo+16);
polyX[2] = Xo-44; polyY[2] = 2*(Yo+44);
polyX[3] = Xo; polyY[3] = 2*(Yo+28); break;
}
ctx.beginPath();
ctx.moveTo(polyX[0], polyY[0]);
ctx.lineTo(polyX[1], polyY[1]);
ctx.lineTo(polyX[2], polyY[2]);
ctx.lineTo(polyX[3], polyY[3]);
ctx.closePath();
switch(CD[QP[3][k]][QP[4][k]])
{ // Select the color to appear on the face of the polygon
case 1 : ctx.fillStyle = 'green'; break;
case 2 : ctx.fillStyle = 'yellow'; break;
case 3 : ctx.fillStyle = 'red'; break;
case 4 : ctx.fillStyle = 'blue'; break;
case 5 : ctx.fillStyle = 'white'; break;
case 6 : ctx.fillStyle = 'orange'; break;
} // Finally draw the polygon.
ctx.fill();
ctx.stroke();
}
}