1function createBoard(n, str){ 2 var parts = str.split(/\r?\n|\r| |\n/g); 3 var freq; 4 if(parts.length <= 1){ 5 freq = 0.40; 6 }else if(parts.length == 2 && !isNaN(parseFloat(parts[1]))){ 7 freq = Math.max(0,parseFloat(parts[1])); 8 }else{ 9 freq = -1; 10 } 11 12 var PIECE_CHARS = "PNBRQKHSOA"; 13 var SIDE_COUNT = 6; 14 var board = []; 15 for(var s = 0; s < SIDE_COUNT; s++){ 16 board[s] = []; 17 for(var x = 0; x < n; x++){ 18 board[s][x] = []; 19 for(var y = 0; y < n; y++){ 20 if(freq == -1){ 21 var ya = y; 22 var xa = x; 23 if(s != 1){ 24 ya = (B_N-1-y); 25 } 26 if(s == 1){ 27 xa = (B_N-1-x); 28 } 29 var stringy = arr_index_safe(parts,1+s*B_N+ya); 30 var x2 = Math.min(xa,stringy.length-1); 31 var ch = stringy.toUpperCase().charAt(x2); 32 if(ch == '-'){ 33 board[s][x][y] = 0; 34 }else{ 35 var type = PIECE_CHARS.indexOf(ch); 36 var player = 1-Math.floor((stringy.charCodeAt(x2)-65)/32); 37 board[s][x][y] = 1+type+player*PIECE_TYPE_COUNT; 38 } 39 }else{ 40 if(Math.random() < freq){ 41 var pt = WEIRD_PIECES ? PIECE_TYPE_COUNT : NORMAL_TYPE_COUNT; 42 var team = Math.floor(Math.random()*2); 43 board[s][x][y] = 1+Math.floor(Math.random()*pt+team*PIECE_TYPE_COUNT); 44 }else{ 45 board[s][x][y] = 0; 46 } 47 } 48 } 49 } 50 } 51 return board; 52} 53function arr_index_safe(arr, n){ 54 var result = ""; 55 if(n < arr.length){ 56 result = arr[n]; 57 } 58 while(result.length < B_N){ 59 result += "-"; 60 } 61 return result; 62} 63function createCube(n, basic){ 64 var SIDE_COUNT = 6; 65 var cube = []; 66 for(var s = 0; s < SIDE_COUNT; s++){ 67 cube[s] = []; 68 for(var x = 0; x < n; x++){ 69 cube[s][x] = []; 70 for(var y = 0; y < n; y++){ 71 if(basic){ 72 cube[s][x][y] = [0,0]; // 0 = no check, 1 = on check path, 2 = perpetrator of check 73 }else if(BOARD_RUBIK){ 74 cube[s][x][y] = s; 75 }else{ 76 cube[s][x][y] = (x+y)%2; 77 } 78 } 79 } 80 } 81 return cube; 82} 83function createRotGrid(n){ 84 var SIDE_COUNT = 6; 85 var rotGrid = new Array(); 86 for(var s = 0; s < SIDE_COUNT; s++){ 87 rotGrid[s] = new Array(); 88 for(var x = 0; x < n; x++){ 89 rotGrid[s][x] = new Array(); 90 for(var y = 0; y < n; y++){ 91 rotGrid[s][x][y] = Math.random()*2*Math.PI; 92 } 93 } 94 } 95 return rotGrid; 96} 97function createValidDest(n){ 98 var SIDE_COUNT = 6; 99 var b = []; 100 for(var s = 0; s < SIDE_COUNT; s++){ 101 b[s] = []; 102 for(var x = 0; x < n; x++){ 103 b[s][x] = []; 104 for(var y = 0; y < n; y++){ 105 b[s][x][y] = []; 106 } 107 } 108 } 109 return b; 110} 111function createVisualBorders(n){ 112 var SIDE_COUNT = 6; 113 var vb = []; 114 for(var s = 0; s < SIDE_COUNT; s++){ 115 vb[s] = []; 116 for(var d = 0; d < 2; d++){ 117 vb[s][d] = []; 118 for(var z = 0; z < n+1; z++){ 119 vb[s][d][z] = [0,0]; 120 } 121 } 122 } 123 return vb; 124} 125function translateToSide(c, s){ 126 c.rotateX(-PI/2); 127 if(s == 1){ 128 c.rotateY(PI); 129 } 130 if(s >= 2){ 131 c.rotateX(PI/2); 132 c.rotateY((s-2)*PI/2); 133 } 134} 135function calculateScoresAndCheck(){ 136 scores = new Array(2); 137 for(var p = 0; p < 2; p++){ 138 scores[p] = new Array(PIECE_TYPE_COUNT+1); 139 for(var t = 0; t < PIECE_TYPE_COUNT+1; t++){ 140 scores[p][t] = 0; 141 } 142 } 143 var kingLocations = [[0,0,0],[0,0,0]]; 144 for(var s = 0; s < board.length; s++){ 145 for(var x = 0; x < B_N; x++){ 146 for(var y = 0; y < B_N; y++){ 147 var b = board[s][x][y]; 148 if(b >= 1){ 149 var player = getPlayerOf(b); 150 var type = getTypeOf(b); 151 scores[player][type] += 1; 152 scores[player][PIECE_TYPE_COUNT] += PIECE_SCORES[type]; 153 if(type == KING_TYPE){ 154 kingLocations[player][0] = s; 155 kingLocations[player][1] = x; 156 kingLocations[player][2] = y; 157 } 158 } 159 } 160 } 161 } 162 checkCube = createCube(B_N,true); 163 checks = [0, 0]; 164 for(var p = 0; p < 2; p++){ 165 if(scores[p][KING_TYPE] == 1){ // you have one king left, who is check-able. 166 var k = kingLocations[p]; 167 kingCheckCheck(k[0],k[1],k[2],p); 168 } 169 } 170 detectWinner(); 171} 172function drawBoard(c, board, sca){ 173 var time_now = Date.now(); 174 var drawSliceMove = shouldDrawSliceMove(); 175 var sliceInfo; 176 var sliceProg; 177 if(drawSliceMove){ 178 var src = lastMoveLocation[0]; 179 var dst = lastMoveLocation[1]; 180 sliceInfo = getSliceInfo(src, dst); 181 sliceProg = cosInter((time_now-lastMoveTime)/TRANSITION_TIME); 182 drawInnerSlice(c, sliceInfo, sliceProg, sca); 183 } 184 for(var s = 0; s < 6; s++){ 185 c.push(); 186 translateToSide(c,s); 187 drawSide(c,board,sca,s,time_now,drawSliceMove,sliceInfo,sliceProg); 188 c.pop(); 189 } 190 drawMovingPiece(c, board, sca,time_now); 191} 192 193function drawBorders(x,y,sca){ 194 for(var dire = 0; dire < 2; dire++){ 195 if(x == dire*(B_N-1)){ 196 var startY = (y == 0) ? -0.1*sca : 0; 197 var endY = (y == B_N-1) ? sca+0.1*sca : sca; 198 c.push(); 199 c.translate(dire*sca,0,-0.1*sca); 200 c.fill(0,0,0); 201 c.rect(-0.1*sca,startY,0.2*sca,endY-startY); 202 c.pop(); 203 } 204 if(y == dire*(B_N-1)){ 205 var startX = (x == 0) ? -0.1*sca : 0; 206 var endX = (x == B_N-1) ? sca+0.1*sca : sca; 207 c.push(); 208 c.translate(0,dire*sca,-0.1*sca); 209 c.fill(0,0,0); 210 c.rect(startX,-0.1*sca,endX-startX,0.2*sca); 211 c.pop(); 212 } 213 } 214} 215 216function drawSide(c, board, sca, side, time_now, drawSliceMove, sliceInfo, sliceProg){ 217 var n = board[0].length; 218 c.push(); 219 c.translate(-n/2*sca,-n/2*sca,-sca*n/2); 220 for(var d = 0; d < 2; d++){ 221 for(var z = 0; z < n+1; z++){ 222 if(d == 0){ 223 vb[side][d][z][0] = c.screenPosition(z*sca,0,0); 224 vb[side][d][z][1] = c.screenPosition(z*sca,n*sca,0); 225 }else if(d == 1){ 226 vb[side][d][z][0] = c.screenPosition(0,z*sca,0); 227 vb[side][d][z][1] = c.screenPosition(n*sca,z*sca,0); 228 } 229 } 230 } 231 c.pop(); 232 233 for(var x = 0; x < n; x++){ 234 for(var y = 0; y < n; y++){ 235 var tile = cube[side][x][y]; 236 c.fill(PLAYER_COLORS[tile][0]); 237 c.push(); 238 if(drawSliceMove){ 239 getSliceRotation(c, side, x, y, sliceInfo, sliceProg); 240 } 241 c.translate(-n/2*sca,-n/2*sca,-sca*n/2); 242 c.translate(x*sca,y*sca,0); 243 c.rect(0.02*sca,0.02*sca,0.96*sca,0.96*sca); 244 245 c.push(); 246 c.translate(0,0,0.001*sca); 247 c.fill(PLAYER_COLORS[tile][1]); 248 c.rect(0,0,sca,sca); 249 if(!GO_OVER_EDGES){ 250 drawBorders(x,y,sca); 251 } 252 c.pop(); 253 if(isValidOption(side,x,y)){ 254 drawSmallSquare(c,sca,VALID_COLOR[Math.min(VALID_COLOR.length-1,cube[side][x][y])],0.12,0.001); 255 } 256 if(side == selection[0] && x == selection[1] && y == selection[2]){ 257 drawSmallSquare(c,sca,SELECTION_COLOR,0.125,0.001); 258 } 259 var check_col = SHOW_CHECK[0] ? Math.max(checkCube[side][x][y][0],checkCube[side][x][y][1]) : 0; 260 if(check_col >= 1){ 261 var ccd = darken(CHECK_COLOR,0.3+0.7*checkColorFac(time_now)); 262 drawSmallSquare(c,sca,ccd,0.25,0.002); 263 } 264 var piece = board[side][x][y]; 265 if(piece >= 1){ 266 c.push(); 267 if(shouldDrawTransition(time_now) && (side == lastMoveLocation[1][0] && x == lastMoveLocation[1][1] && y == lastMoveLocation[1][2])){ 268 var fac = 1-cosInter((time_now-lastMoveTime)/TRANSITION_TIME); 269 if(lastMovePiece >= 1){ 270 drawPiece(lastMovePiece, sca, fac, rotGrid[side][x][y],0,0,check_col,time_now); 271 } 272 }else{ 273 drawPiece(piece, sca, 1.0, rotGrid[side][x][y],0,0,check_col,time_now); 274 } 275 c.pop(); 276 } 277 c.pop(); 278 } 279 } 280} 281function checkColorFac(time_now){ 282 return 0.5+0.5*Math.sin(time_now*2*(2*Math.PI)/1000); 283} 284function darken(COL, val){ 285 return [COL[0]*val,COL[1]*val,COL[2]*val]; 286} 287function drawSmallSquare(c,sca,col,ratio,height){ 288 c.fill(col); 289 c.push(); 290 c.translate(0,0,-height*sca); 291 c.rect(sca*ratio,sca*ratio,sca*(1-ratio*2),sca*(1-ratio*2)); 292 c.pop(); 293} 294function drawMovingPiece(c, board, sca, time_now){ 295 if(shouldDrawTransition(time_now)){ 296 var tile = deepIndex(board,lastMoveLocation[1]); 297 298 var fac = 1-cosInter((time_now-lastMoveTime)/TRANSITION_TIME); 299 300 var step = Math.min(Math.max(Math.floor(fac*travelPath.length),0),travelPath.length-1); 301 302 var step_fac = fac*travelPath.length-step; 303 var startLoc = travelPath[step][0].slice(); 304 var endLoc = travelPath[step][1].slice(); 305 var end_OOB = travelPath[step][2].slice(); 306 307 308 if(end_OOB.length >= 3){ 309 startLoc = end_OOB.slice() 310 } 311 var s = startLoc[0]; 312 var x = interp(startLoc[1],endLoc[1],step_fac); 313 var y = interp(startLoc[2],endLoc[2],step_fac); 314 315 var sL = travelPath[0][0]; 316 var eL = travelPath[travelPath.length-1][1]; 317 var startRot = rotGrid[sL[0]][sL[1]][sL[2]]; 318 var endRot = rotGrid[eL[0]][eL[1]][eL[2]]; 319 320 if(!inBoundsXY(x+0.5,y+0.5)){ 321 var pointer = [s,x+0.5,y+0.5]; 322 var dire = [0,0]; 323 var result = goOverEdge(pointer,dire,0); 324 s = result[0][0]; 325 x = result[0][1]-0.5; 326 y = result[0][2]-0.5; 327 328 } 329 330 var rotation = cosInterp(startRot,endRot,fac); 331 c.push(); 332 translateToSide(c,s); 333 c.translate(-B_N/2*sca,-B_N/2*sca,-sca*B_N/2); 334 c.translate(x*sca,y*sca,0); 335 var rotX = 0; 336 if(x < 0){ 337 rotX = -x*Math.PI/2; 338 }else if(x >= B_N-1){ 339 rotX = -(x-(B_N-1))*Math.PI/2; 340 } 341 var rotY = 0; 342 if(y < 0){
343 rotY = y*Math.PI/2; 344 }else if(y >= B_N-1){ 345 rotY = (y-(B_N-1))*Math.PI/2; 346 } 347 var L = lastMoveLocation[1]; 348 var ch = checkCube[L[0]][L[1]][L[2]]; 349 var check_col = SHOW_CHECK[0] ? Math.max(ch[0],ch[1]) : 0; 350 if(lastMoveLocation[2] == -1 || getTypeOf(tile) == PAWN_TYPE){ 351 drawPiece(tile, sca, 1.0, rotation,rotX,rotY,check_col,time_now); 352 }else{ 353 drawPiece(lastMoveLocation[2], sca, fac, rotation,rotX,rotY,check_col,time_now); 354 drawPiece(tile, sca, 1-fac, rotation,rotX,rotY,check_col,time_now); 355 } 356 c.pop(); 357 } 358} 359function interp(a,b,x){ 360 return a+(b-a)*x; 361} 362function cosInterp(a,b,x){ 363 return a+(b-a)*cosInter(x); 364} 365function color_interp(a,b,x){ 366 return [interp(a[0],b[0],x),interp(a[1],b[1],x),interp(a[2],b[2],x)]; 367} 368 369function drawPiece(piece, sca, size, rotation, rotX, rotY, check_val, time_now){ 370 c.push(); 371 c.translate(0.5*sca,0.5*sca,0); 372 c.scale(0.195*size*sca); 373 c.rotateY(rotX); 374 c.rotateX(rotY); 375 c.rotateZ(rotation); 376 377 c.rotateX(-0.5*Math.PI); 378 var col = PLAYER_COLORS[getPlayerOf(piece)][2]; 379 if(check_val >= 2){ 380 col = color_interp(col,CHECK_COLOR,0.6*checkColorFac(time_now)); 381 } 382 c.fill(col); 383 c.model(pieceModels[getTypeOf(piece)]); 384 c.pop(); 385} 386function shouldDrawTransition(time_now){ 387 var moveAge = time_now-lastMoveTime; 388 if(moveAge < TRANSITION_TIME){ 389 return (lastMoveType != 3); 390 }else{ 391 return false; 392 } 393} 394function shouldDrawSliceMove(){ 395 var now = Date.now(); 396 var moveAge = now-lastMoveTime; 397 if(moveAge < TRANSITION_TIME){ 398 return (lastMoveType == 3); 399 }else{ 400 return false; 401 } 402} 403function cosInter(x){ 404 return 0.5-0.5*Math.cos(x*Math.PI); 405} 406function setWorldDrawings(c){ 407 c.background(BG_COLOR); 408 c.noStroke(); 409 410 c.directionalLight(255, 255, 230, -1, 0.7, -1.3); 411 c.directionalLight(255, 255, 230, 0.7, 0, -1); 412 c.directionalLight(255, 255, 230, 1, 0.7, 1.3); 413 c.directionalLight(255, 255, 230, -0.7, -1.3, 1); 414 415 if(pressed){ 416 rotY += 0.005*(mouseX-prev_mouseX); 417 rotX += -0.005*(mouseY-prev_mouseY); 418 if(abs(prev_mouseX-mouseX) >= 2 || abs(prev_mouseY-mouseY) >= 2){ 419 moved = true; 420 } 421 prev_mouseX = mouseX; 422 prev_mouseY = mouseY; 423 } 424 c.rotateX(rotX); 425 c.rotateY(rotY); 426} 427function invert2x2(m){ 428 var a = m[0][0]; 429 var b = m[0][1]; 430 var c = m[1][0]; 431 var d = m[1][1]; 432 var result = new Array(); 433 for(var i = 0; i < 2; i++){ 434 result[i] = new Array(); 435 for(var j = 0; j < 2; j++){ 436 result[i][j] = 0; 437 } 438 } 439 var det = a*d-b*c; 440 if(det < 0){ 441 return -1; 442 } 443 result[0][0] = d/det; 444 result[1][1] = a/det; 445 result[0][1] = -b/det; 446 result[1][0] = -c/det; 447 return result; 448} 449function vectorTimes2x2(v2,A){ 450 if(v2 instanceof p5.Vector) { 451 var v = [v2.x,v2.y]; 452 }else{ 453 var v = v2; 454 } 455 return [v[0]*A[0][0]+v[1]*A[1][0],v[0]*A[0][1]+v[1]*A[1][1]]; 456} 457function diff(a, b){ 458 return [a.x-b.x,a.y-b.y]; 459} 460function pluralize(p, t){ 461 if(scores[p][t] == 1){ 462 return scores[p][t]+" "+PIECE_NAMES[t]; 463 }else{ 464 return scores[p][t]+" "+PIECE_NAMES[t]+"s"; 465 } 466} 467function drawUI(c){ 468 push(); 469 translate(-W_W/2,-W_H/2); 470 drawArsenals(); 471 drawAlerts(); 472 drawTogs(); 473 drawHistory(); 474 drawPP_UI(); 475 pop(); 476} 477function drawArsenals(){ 478 ui.background(PLAYER_COLORS[turn][0]); 479 ui.noStroke(); 480 ui.fill(PLAYER_COLORS[turn][1]); 481 ui.textFont('Arial', 22); 482 ui.textSize(22); 483 484 var x = 12; 485 486 var pName = "Any"; 487 if(TAKE_TURNS){ 488 pName = PLAYER_NAMES[turn]; 489 } 490 ui.text(pName+"'s turn!",x,30); 491 492 for(var p = 0; p < 2; p++){ 493 ui.text(PLAYER_NAMES[p]+"'s arsenal:",x,80+290*p); 494 var t_count = WEIRD_PIECES ? PIECE_TYPE_COUNT : NORMAL_TYPE_COUNT; 495 for(var t = 0; t < t_count+1; t++){ 496 var pointy = ""; 497 if(t < t_count){ 498 pointy = " ("+PIECE_SCORES[t]+"p)"; 499 } 500 var t2 = t; 501 if(!WEIRD_PIECES && t == t_count){ 502 t2 = PIECE_TYPE_COUNT; 503 } 504 ui.text(pluralize(p,t2)+pointy,x,80+290*p+(t+1)*22); 505 } 506 } 507 var options = [TAKE_TURNS,GO_OVER_EDGES,ENEMY_COLOR_MUD,BOARD_RUBIK,WEIRD_PIECES]; 508 for(var op = 0; op < 5; op++){ 509 var str = OPTION_NAMES[op]+" "; 510 if(options[op]){ 511 str += "Yes"; 512 }else{ 513 str += "No"; 514 } 515 ui.text(str,x,660+op*22); 516 } 517 ui.text("Size: "+B_N+"x"+B_N+"x"+B_N,x,660+110); 518 image(ui,20,20); 519} 520function drawAlerts(){ 521 if(winner >= 0){ 522 drawAlert([PLAYER_NAMES[winner].toUpperCase(),"WINS THE GAME!","","But I'll let you keep","going, because I'm","so nice."],[0,0,255],PLAYER_COLORS[winner][0],PLAYER_COLORS[winner][1]); 523 }else if(checks[0] >= 1 && checks[1] >= 1){ 524 drawAlert(["Somehow, both","players are in","check right now.","","How is this","happening."],CHECK_COLOR,PLAYER_COLORS[0][0],PLAYER_COLORS[0][1]); 525 }else if((checks[0] >= 1|| checks[1] >= 1) && SHOW_CHECK[0]){ 526 var p = checks[0] ? 0 : 1; 527 drawAlert([PLAYER_NAMES[p]+" is in check","from a",PLAYER_NAMES[1-p]+" "+PIECE_NAMES[checks[p]-1]+".","",PLAYER_NAMES[p]+", get your","king to safety!"],CHECK_COLOR,PLAYER_COLORS[p][0],PLAYER_COLORS[p][1]); 528 } 529} 530function drawTogs(){ 531 for(var t = 0; t < toggles.length; t++){ 532 var tog = toggles[t]; 533 var col = (tog[0] ? 255 : 0); 534 var tc = toggles[t][6]; 535 tc.noStroke(); 536 tc.background(col); 537 tc.textFont('Arial', 22); 538 tc.textSize(22); 539 tc.fill(255-col); 540 tc.text(tog[5],10,30); 541 tc.text((tog[0] ? "Yes" : "No"),10,55); 542 image(tc,tog[1],tog[2]); 543 } 544} 545function drawHistory(){ 546 var can_click = [(history_index >= 1),(game_history.length > history_index+1)]; 547 var hc = history_UI[5]; 548 hc.background(BG_COLOR); 549 hc.noStroke(); 550 for(var a = 0; a < 2; a++){ 551 var h = history_UI[1+a]; 552 hc.fill(can_click[a] ? 255 : 158); 553 hc.rect(h[0],h[1],h[2],h[3]); 554 hc.fill(can_click[a] ? 0 : 98); 555 hc.beginShape(); 556 hc.vertex(h[0]+50-30*a,h[1]+15); 557 hc.vertex(h[0]+50-30*a,h[1]+55); 558 hc.vertex(h[0]+15+40*a,h[1]+35); 559 hc.endShape(CLOSE); 560 } 561 hc.fill(darken(BG_COLOR,0.8)); 562 var h = history_UI[3]; 563 hc.rect(h[0],h[1],h[2],h[3]); 564 hc.fill(darken(BG_COLOR,0.2)); 565 var f1 = (game_history.length <= 1 ? 0 : history_index/(game_history.length-1)); 566 var f2 = 1/game_history.length; 567 var w = Math.max(h[4],f2*h[2]); 568 hc.rect(h[0]+f1*(h[2]-w),h[1],w,h[3]); 569 570 hc.textFont('Arial', 30); 571 hc.textSize(22); 572 hc.textAlign(CENTER); 573 hc.fill(0); 574 hc.text(history_index+" / "+(game_history.length-1),history_UI[4][0],history_UI[4][1]); 575 image(hc,history_UI[0][0],history_UI[0][1]); 576} 577function getPlayerOf(b){ 578 return Math.floor((b-1)/PIECE_TYPE_COUNT); 579} 580function getTypeOf(b){ 581 return (b-1)%PIECE_TYPE_COUNT; 582} 583function deepIndex(arr,index){ 584 return arr[index[0]][index[1]][index[2]]; 585} 586function drawPP_UI(){ 587 if(pawnPromotionInfo[0]){ 588 var pc = PP_UI[3]; 589 var player = getPlayerOf(deepIndex(board,pawnPromotionInfo[1])); 590 pc.noStroke(); 591 pc.background(PLAYER_COLORS[player][0]); 592 pc.fill(PLAYER_COLORS[player][1]); 593 pc.textFont('Arial', 22); 594 pc.textSize(22); 595 pc.textAlign(CENTER); 596 pc.text("Promote to:",PP_UI[2][0],PP_UI[2][1]); 597 for(var i = 0; i < PAWN_PROMOTION_OPTIONS.length; i++){ 598 var t = PAWN_PROMOTION_OPTIONS[i]; 599 if(WEIRD_PIECES || t < NORMAL_TYPE_COUNT){ 600 pc.fill(128,128,128,64+64*(i%2)); 601 var y = PP_UI[1][1]+i*PP_UI[1][3]; 602 var h = PP_UI[1][3]
603 pc.rect(PP_UI[1][0],y,PP_UI[1][2],h); 604 pc.fill(PLAYER_COLORS[player][1]); 605 pc.text(PIECE_NAMES[t],PP_UI[2][0],y+h*0.7); 606 } 607 } 608 image(pc,PP_UI[0][0],PP_UI[0][1]); 609 } 610} 611function drawAlert(strs,col1,col2,col3){ 612 alert.noStroke(); 613 alert.background(col1); 614 alert.fill(col2); 615 alert.rect(20,20,220,220); 616 alert.fill(col3); 617 alert.textFont('Arial', 22); 618 alert.textSize(22); 619 for(var i = 0; i < strs.length; i++){ 620 alert.text(strs[i],30,50+25*i); 621 } 622 image(alert,W_W-280,20); 623} 624function customGameButton(){ 625 var newGameString = document.getElementById("newGame").value; 626 createNewGame(newGameString); 627} 628function standardGameButton(){ 629 createNewGame("YYYYY7\nhhopp--\nhrbbp--\nonrqs--\npnakp--\nppspp--\n-------\n-------\n--PPOHH\n--PBBRH\n--SQRNO\n--PKANP\n--PPSPP\n-------\n-------"); 630} 631function sandboxGameButton(){ 632 createNewGame("NYNYY7 0.4"); 633} 634function walledGameButton(){ 635 createNewGame("YNYYY7\nhhopp--\nhrbbp--\nonrqs--\npnakp--\nppspp--\n-------\n-------\n--PPOHH\n--PBBRH\n--SQRNO\n--PKANP\n--PPSPP\n-------\n-------"); 636} 637function simpleGameButton(){ 638 createNewGame("YYNYN5\nhnpp-\nnbrp-\npqkp-\npppp-\n-----\n-PPNH\n-PRBN\n-PKQP\n-PPPP\n-----\n\n\n\n\nh\n\n\n\n\n----h\nH\n\n\n\n\n----H"); 639} 640function createNewGame(str){ 641 document.getElementById("newGame").value = str; 642 var parts = str.split(/\r?\n|\r| |\n/g); 643 var options = parts[0].toUpperCase(); 644 TAKE_TURNS = (options.charAt(0) == 'Y'); 645 GO_OVER_EDGES = (options.charAt(1) == 'Y'); 646 ENEMY_COLOR_MUD = (options.charAt(2) == 'Y'); 647 BOARD_RUBIK = (options.charAt(3) == 'Y'); 648 WEIRD_PIECES = (options.charAt(4) == 'Y'); 649 B_N = 7; 650 if(options.length >= 6){ 651 B_N = Math.min(Math.max(Number(options.substring(5,options.length)),2),20); 652 } 653 clearSelection(); 654 winner = -1; 655 board = createBoard(B_N, str); 656 cube = createCube(B_N, false); 657 game_history = []; 658 turn = 0; 659 appendGameHistory(); 660 history_index = 0; 661 checkCube = createCube(B_N,true); 662 rotGrid = createRotGrid(B_N); 663 validDest = createValidDest(B_N); 664 vb = createVisualBorders(B_N); 665 calculateScoresAndCheck(); 666 lastMoveTime = 0; 667} 668 669function getClickedOn(s,inverse,mX,mY,d){ 670 var orig = vb[s][0][0][0]; 671 var mouseB = vectorTimes2x2([mX-orig.x,mY-orig.y],inverse); 672 673 var n = board[0].length; 674 for(var z = 0; z < n+1; z++){ 675 var p1 = vectorTimes2x2(diff(vb[s][d][z][0],orig),inverse); 676 var p2 = vectorTimes2x2(diff(vb[s][d][z][1],orig),inverse); 677 var e = 1-d; 678 var m = (p2[e]-p1[e])/(p2[d]-p1[d]); 679 var b = -p1[d]*m+p1[e]; 680 if(mouseB[e] <= mouseB[d]*m+b){ 681 return z-1; 682 } 683 } 684 return -1; 685} 686function drawWireframe(){ 687 var colors = [[255,0,0],[255,128,0],[255,255,0],[0,255,0],[0,0,255],[128,0,255]]; 688 for(var s = 0; s < 6; s++){ 689 strokeWeight(2); 690 stroke(colors[s]); 691 for(var d = 0; d < 2; d++){ 692 for(var z = 0; z < 8; z++){ 693 var x1 = vb[s][d][z][0].x; 694 var y1 = vb[s][d][z][0].y; 695 var x2 = vb[s][d][z][1].x; 696 var y2 = vb[s][d][z][1].y; 697 line(x1,y1,x2,y2); 698 } 699 } 700 } 701} 702function inBounds(point){ 703 var x = point[1]; 704 var y = point[2]; 705 return inBoundsXY(x,y); 706} 707function inBoundsXY(x,y){ 708 return (x >= 0 && x < B_N && y >= 0 && y < B_N); 709} 710function getLastMoveType(dst){ 711 var v = validDest[dst[0]][dst[1]][dst[2]]; 712 return v[v.length-1][3]; 713} 714function doMove(src, dst, transformTo){ 715 lastMoveLocation[0] = src; 716 lastMoveLocation[1] = dst; 717 lastMoveLocation[2] = -1; 718 lastMoveTime = Date.now(); 719 lastMoveType = getLastMoveType(dst); 720 721 if(lastMoveType == 3){ 722 sliceMove(src,dst); 723 }else{ 724 lastMovePiece = board[dst[0]][dst[1]][dst[2]]; 725 board[dst[0]][dst[1]][dst[2]] = board[src[0]][src[1]][src[2]]; 726 if(transformTo >= 0){ 727 lastMoveLocation[2] = board[src[0]][src[1]][src[2]]; 728 board[dst[0]][dst[1]][dst[2]] = transformTo; 729 } 730 board[src[0]][src[1]][src[2]] = 0; 731 travelPath = validDest[dst[0]][dst[1]][dst[2]]; 732 } 733 if(TAKE_TURNS){ 734 turn = 1-turn; 735 } 736 clearSelection(); 737 calculateScoresAndCheck(); 738 appendGameHistory(); 739} 740function appendGameHistory(){ 741 if(history_index < game_history.length-1){ 742 game_history = game_history.slice(0,history_index+1); 743 } 744 game_history.push([deepCopy(board),deepCopy(cube),turn,winner]); 745 history_index = game_history.length-1; 746} 747function loadFromGameHistory(){ 748 board = deepCopy(game_history[history_index][0]); 749 cube = deepCopy(game_history[history_index][1]); 750 turn = game_history[history_index][2]; 751 winner = game_history[history_index][3]; 752 clearSelection(); 753 calculateScoresAndCheck(); 754 lastMoveTime = 0; 755} 756function detectWinner(){ 757 if(winner == -1){ 758 for(var p = 0; p < 2; p++){ 759 if(scores[p][5] == 0){ 760 winner = 1-p; 761 } 762 } 763 } 764} 765function index_flip(arr){ 766 var result = new Array(5); 767 for(var i = 0; i < 2; i++){ 768 result[i] = arr[i].slice(); 769 } 770 result[2] = B_N-1-arr[2]; 771 result[3] = arr[3]; 772 result[4] = arr[4]; 773 return result; 774} 775function invertA(arr){ 776 var result = new Array(4); 777 result[2] = arr[2]; 778 for(var i = 0; i < 2; i++){ 779 result[i] = arr[i].slice(); 780 result[i][1] = arr[i][3]; 781 result[i][3] = arr[i][1]; 782 } 783 result[3] = -arr[3]; 784 result[4] = arr[4]; 785 return result; 786} 787 788function getSliceInfo(src, dst){ 789 var sFace = src[0]; 790 var eFace = dst[0]; 791 792 // the first array are the sides that are cycled, where the first four are the ones we care about, and the last two are the "left and right" sides to be rotated. 793 // the second array is the "axis" (row, column, upside-down row, upside-down column) of those sides to be altered, respectively. 794 // The third info is the index of the row, the fourth is the direction of it, and the fifth is the axis of rotation in world space (M, S, or E). 795
796 var M = [[0,2,1,4,3,5],[0,0,2,2],src[1],1,0]; 797 var M_if = [[0,2,1,4,3,5],[0,0,2,2],B_N-1-src[1],1,0]; 798 var S = [[0,3,1,5,4,2],[1,0,1,2],src[2],1,1]; 799 var S_alt = [[0,3,1,5,4,2],[1,0,1,2],src[1],1,1]; 800 var S_alt_if = [[0,3,1,5,4,2],[1,0,1,2],B_N-1-src[1],1,1]; 801 var E = [[2,3,4,5,0,1],[1,1,1,1],src[2],1,2]; 802 803 var sliceInfo = [ 804 [[], [], M, S, invertA(M), invertA(S)], 805 [[], [], invertA(M_if), invertA(S), M_if, S], 806 [invertA(M), M, [], E, [], invertA(E)], 807 [invertA(S_alt), S_alt, invertA(E), [], E, []], 808 [M_if, invertA(M_if), [], invertA(E), [], E], 809 [S_alt_if, invertA(S_alt_if), E, [], invertA(E), []] 810 ]; 811 return sliceInfo[sFace][eFace]; 812} 813 814function sliceMove(src, dst){ 815 var sliceInfo = getSliceInfo(src, dst); 816 sliceMoveBoth(sliceInfo[0],sliceInfo[1],sliceInfo[2],sliceInfo[3]); 817} 818 819function sliceMoveBoth(faces,axes,index,dire){ 820 sliceMoveInner(board,faces,axes,index); 821 sliceMoveInner(cube,faces,axes,index); 822 if(index == 0){ 823 rotateFace(board, faces[4], dire); 824 rotateFace(cube, faces[4], dire); 825 }else if(index == B_N-1){ 826 rotateFace(board, faces[5], -dire); 827 rotateFace(cube, faces[5], -dire); 828 } 829} 830 831function rotateFace(arr, f, dire){ 832 var newFace = new Array(B_N); 833 for(var x = 0; x < B_N; x++){ 834 newFace[x] = new Array(B_N); 835 for(var y = 0; y < B_N; y++){ 836 if(dire > 0){ 837 newFace[x][y] = arr[f][y][B_N-1-x]; 838 }else{ 839 newFace[x][y] = arr[f][B_N-1-y][x]; 840 } 841 } 842 } 843 arr[f] = newFace; 844} 845 846function sliceMoveInner(arr,faces,axes,index){ 847 var ph_values = getSlice(arr,faces[3],axes[3],index); 848 for(var i = 2; i >= 0; i--){ 849 var slice_values = getSlice(arr,faces[i],axes[i],index); 850 setSlice(arr,faces[i+1],axes[i+1],index,slice_values); 851 } 852 setSlice(arr,faces[0],axes[0],index,ph_values); 853} 854 855function getSlice(arr,face,axis,index){ 856 var result = new Array(B_N); 857 for(var i = 0; i < B_N; i++){ 858 var j = i; 859 var jindex = index; 860 if(axis == 1 || axis == 2){ 861 j = B_N-1-i; 862 } 863 if(axis == 2 || axis == 3){ 864 jindex = B_N-1-index; 865 } 866 if(axis%2 == 0){ 867 result[i] = arr[face][jindex][j]; 868 }else{ 869 result[i] = arr[face][j][jindex]; 870 } 871 } 872 return result; 873} 874function setSlice(arr,face,axis,index,values){ 875 var result = new Array(B_N); 876 for(var i = 0; i < B_N; i++){ 877 var j = i; 878 var jindex = index; 879 if(axis == 1 || axis == 2){ 880 j = B_N-1-i; 881 } 882 if(axis == 2 || axis == 3){ 883 jindex = B_N-1-index; 884 } 885 if(axis%2 == 0){ 886 arr[face][jindex][j] = values[i]; 887 }else{ 888 arr[face][j][jindex] = values[i]; 889 } 890 } 891} 892function drawInnerSlice(c, sliceInfo, sliceProg, sca){ 893 var b = B_N*sca; 894 var index = sliceInfo[2]; 895 var dire = sliceInfo[3]; 896 897 for(var ss = 0; ss < 4; ss++){ // two different sides of the slice. 898 if((index == 0 && ss < 2) || (index == B_N-1 && ss >= 2)){ 899 continue; 900 } 901 c.push(); 902 if(sliceInfo[4] == 0){ // M slice 903 c.rotateY(Math.PI/2); 904 }else if(sliceInfo[4] == 1){ // S slice 905 c.rotateY(Math.PI); 906 }else if(sliceInfo[4] == 2){ // E slice 907 c.rotateX(-Math.PI/2); 908 } 909 c.translate(0,0,-b/2+(index+Math.floor(ss/2))*sca); 910 if(ss%2 == 0){ // half of the inner slice squares should be on the rotating slice, and half should be on the stable remainder. 911 c.rotateZ(dire*sliceProg*Math.PI/2); 912 } 913 c.fill(INSIDE_COLOR); 914 c.rect(-b/2,-b/2,b,b); 915 c.pop(); 916 } 917} 918function getSliceRotation(c, s, x, y, sliceInfo, sliceProg){ 919 var rotating = false; 920 var axis_choice = 0; 921 var faces = sliceInfo[0]; 922 var index = sliceInfo[2]; 923 var dire = sliceInfo[3]; 924 for(var ss = 0; ss < 4; ss++){ 925 if(faces[ss] == s){ 926 var axis = sliceInfo[1][ss]; 927 for(var i = 0; i < B_N; i++){ 928 var j = i; 929 var jindex = index; 930 if(axis == 1 || axis == 2){ 931 j = B_N-1-i; 932 } 933 if(axis == 2 || axis == 3){ 934 jindex = B_N-1-index; 935 } 936 if(axis%2 == 0){ 937 if(jindex == x && j == y){ 938 // WILL ROTATE! 939 rotating = true; 940 axis_choice = axis; 941 } 942 }else{ 943 if(j == x && jindex == y){ 944 // WILL ROTATE! 945 rotating = true; 946 axis_choice = axis; 947 } 948 } 949 } 950 } 951 } 952 var fac = -PI/2*sliceInfo[3]*(1-sliceProg); 953 if(rotating){ 954 if(mouseX < 100){ 955 fac = 0; 956 } 957 c.rotateZ(axis_choice*PI/2); 958 c.rotateX(fac); 959 c.rotateZ(-axis_choice*PI/2); 960 } 961 if(index == 0){ 962 if(s == faces[4]){ 963 c.rotateZ(fac); 964 } 965 }else if(index == B_N-1){ 966 if(s == faces[5]){ 967 c.rotateZ(-fac); 968 } 969 } 970 return 0; 971} 972 973function areSamePoint(a, b){ 974 return (a[0] == b[0] && a[1] == b[1] && a[2] == b[2]); 975} 976function clearSelection(){ 977 selection = [-1,-1,-1]; 978 pawnPromotionInfo = [false,0,0]; 979 validDest = createValidDest(B_N); 980} 981 982function splatoonSpread(loc, player, boundaryType, check_check){ 983 var dires = [[0,1],[1,0],[0,-1],[-1,0]]; 984 var locationList = [loc.slice()]; 985 var checklist = []; // for checking for if any splatoons are checking the king. 986 var typeToSee = SPLATOON_TYPE + (boundaryType ? 1 : 2) + (player == 0 ? 0 : PIECE_TYPE_COUNT); // if doing a king-check-check, which piece would you be "scared" to see in your line-of-vision? 987 while(locationList.length >= 1){
988 var currLoc = locationList.shift(); 989 var s = currLoc[0]; 990 var x = currLoc[1]; 991 var y = currLoc[2]; 992 if(ENEMY_COLOR_MUD && cube[s][x][y] == 1-player){ 993 continue; // banned because you're on the opposite color (toxic stuff) 994 } 995 var move_type = boundaryType ? 4 : 5; 996 for(var d = 0; d < dires.length; d++){ 997 var x_a = x+dires[d][0]; 998 var y_a = y+dires[d][1]; 999 var appLoc = [s,x_a,y_a]; 1000 var newLoc = appLoc; 1001 if(!inBounds(appLoc) && GO_OVER_EDGES){ 1002 newLoc = goOverEdge(appLoc,[0,0],1)[0]; 1003 } 1004 var s_n = newLoc[0]; 1005 var x_n = newLoc[1]; 1006 var y_n = newLoc[2]; 1007 if(inBoundsXY(x_n,y_n) && !areSamePoint(newLoc,loc) && boundaryType == (cube[s][x][y] == cube[s_n][x_n][y_n]) && validDest[s_n][x_n][y_n].length == 0 && 1008 (!ENEMY_COLOR_MUD || cube[s_n][x_n][y_n] != 1-player)){ 1009 var t = board[s_n][x_n][y_n]; 1010 var moveType = (t == 0 || (t <= PIECE_TYPE_COUNT) != (player == 0)) ? move_type : -1; 1011 var validDestChain = validDest[s][x][y].slice(); 1012 validDestChain.unshift([newLoc.slice(),currLoc.slice(),appLoc,moveType]); 1013 validDest[s_n][x_n][y_n] = validDestChain; 1014 locationList.push(newLoc); 1015 1016 if(check_check && t == typeToSee){ 1017 for(var v = 0; v < validDestChain.length; v++){ 1018 checklist.push(validDestChain[v][0]); 1019 } 1020 checklist.push(loc); 1021 } 1022 } 1023 } 1024 } 1025 if(check_check){ // cleanse the validDest array, since no piece is actually selected. 1026 validDest = createValidDest(B_N); 1027 return checklist; 1028 } 1029} 1030function isValidOption(side,x,y){ 1031 if(pawnPromotionInfo[0]){ 1032 var p = pawnPromotionInfo[2]; 1033 return (side == p[0] && x == p[1] && y == p[2]); 1034 } 1035 if(validDest[side][x][y].length >= 1){ 1036 var v = validDest[side][x][y]; 1037 return (v[0][3] >= 0); 1038 }else{ 1039 return false; 1040 } 1041} 1042 1043var DIRE_TYPES = [ // HERE ARE THE FIVE FUNDAMENTAL DIRECTION TYPES 1044 [[0,1],[0,-1],[1,0],[-1,0]], // orthogonal direction (rook) 1045 [[1,1],[1,-1],[-1,1],[-1,-1]], // diagonal direction (bishop) 1046 [[1,0],[1,0],[1,0],[1,0], 1047 [-1,0],[-1,0],[-1,0],[-1,0], 1048 [0,1],[0,1],[0,1],[0,1], 1049 [0,-1],[0,-1],[0,-1],[0,-1] 1050 ], // knight direction (simplified for the weird corner case) 1051 [[0,1,1],[0,-1,1],[1,0,1],[-1,0,1]], // hand turn (Rubik's slice move) 1052 [], // splatoon 1053 ]; 1054 // 1st number is the direction type (index) the piece can do. The second number is whether it can move 1055 // 2nd number whether the piece can: 1056 // 0) move 1 tile into an empty space, only 1057 // 1) move 1 tile to capture. only 1058 // 2) move 1 tile into empty OR to capture 1059 // 3) do a slice turn on the puzzle 1060 // 4) sliding motion, unlimited until it hits a piece or enemy color 1061 // 5) weird knight behavior (this doesn't count as a DIRE_TYPE because internally, a knight move is considered a 3-step move) 1062 // 3rd number is whether this move can still go over edges if GOE is disabled. 1063 // 4th number is whether the move bans same-color movement (nootnoots) 1064 var PIECE_DIRES = [ 1065 [[0,0,0,0],[1,1,0,0]], // pawn 1066 [[2,5,0,0]], // knight 1067 [[1,4,0,0]], // bishop 1068 [[0,4,0,0]], // rook 1069 [[1,4,0,0],[0,4,0,0]], // queen 1070 [[0,2,0,0],[1,2,0,0]], // king 1071 [[0,2,0,0],[1,2,0,0],[3,3,1,0]], // hand 1072 [[4,0,0,0],[0,2,0,0]], // splatoon 1073 [[1,4,0,1],[0,4,0,1],[2,5,0,1]], // nootnoot 1074 [[1,4,0,0],[0,4,0,0],[2,5,0,0]] // amazon 1075 ]; 1076 1077function checkForPawnPromotion(s, boardX, boardY){ 1078 var b = deepIndex(board,selection); 1079 var player = getPlayerOf(b); 1080 var t = cube[s][boardX][boardY] 1081 if(getTypeOf(b) == PAWN_TYPE && t == 1-player){ // is this a pawn about to be promoted? 1082 pawnPromotionInfo[0] = true; 1083 pawnPromotionInfo[1] = selection.slice(); 1084 pawnPromotionInfo[2] = [s,boardX,boardY]; 1085 return true; 1086 } 1087 return false; 1088} 1089 1090function setSelection(s, boardX, boardY){ 1091 if(isValidOption(s,boardX,boardY)){ 1092 if(!checkForPawnPromotion(s, boardX, boardY)){ 1093 var dest = [s,boardX,boardY]; 1094 doMove(selection,dest,-1); 1095 } 1096 return; 1097 } 1098 var tile = board[s][boardX][boardY]; 1099 var type = getTypeOf(tile); 1100 var player = getPlayerOf(tile); 1101 if(tile == 0 || (TAKE_TURNS && player != turn)){ 1102 clearSelection(); 1103 return; 1104 } 1105 selection = [s,boardX,boardY]; 1106 validDest = createValidDest(B_N); 1107 for(var dt = 0; dt < PIECE_DIRES[type].length; dt++){ 1108 var dire_type = PIECE_DIRES[type][dt][0]; 1109 var dire_power = PIECE_DIRES[type][dt][1]; 1110 var dire_goe = PIECE_DIRES[type][dt][2]; 1111 var dire_noot = PIECE_DIRES[type][dt][3]; 1112 if(dire_type == 4){ // splatoon spread 1113 splatoonSpread([s,boardX,boardY], player, (dire_type == 4), false); 1114 } 1115 if(ENEMY_COLOR_MUD && dire_type == 3 && cube[s][boardX][boardY] == 1-player){ 1116 continue; // if ECM is on, the hand can't turn on an enemy color. 1117 } 1118 for(var d = 0; d < DIRE_TYPES[dire_type].length; d++){ 1119 var dire = DIRE_TYPES[dire_type][d].slice(); 1120 if(DIRE_TYPES[dire_type][d].length >= 3){ 1121 dire[0] *= B_N; 1122 dire[1] *= B_N; 1123 } 1124 var pointer = [s,boardX,boardY]; 1125 var prevPointer = [s,boardX,boardY];
1126 var validDestChain = []; 1127 var keepGoing = true; 1128 var steps = 0; 1129 while(keepGoing){ 1130 if(dire_power == 5){ 1131 dire = knightDire(dire,d,steps); 1132 } 1133 var OOB_pointer = []; 1134 pointer[1] += dire[0]; 1135 pointer[2] += dire[1]; 1136 if(!inBounds(pointer)){ 1137 if (GO_OVER_EDGES || dire_goe == 1){ // allow going over the edges if that feature is allowed, OR you're a hand. 1138 OOB_pointer = pointer.slice(); 1139 var results = goOverEdge(pointer,dire,1); 1140 pointer = results[0]; 1141 dire = results[1]; 1142 if(!inBounds(pointer)){ // weird corner case 1143 keepGoing = false; 1144 } 1145 }else{ 1146 keepGoing = false; 1147 } 1148 } 1149 1150 if(pointer[0] == s && pointer[1] == boardX && pointer[2] == boardY){ // you looped back to where you were. 1151 keepGoing = false; 1152 } 1153 if(dire_noot == 1 && inBounds(pointer)){ // banning the same-color moves of nootnoots 1154 var c = cube[pointer[0]][pointer[1]][pointer[2]]; 1155 var prevC = cube[prevPointer[0]][prevPointer[1]][prevPointer[2]]; 1156 var firstC = cube[s][boardX][boardY]; 1157 if((dire_power == 5 && steps == 2 && c == firstC) || (dire_power != 5 && c == prevC)){ 1158 keepGoing = false; 1159 } 1160 } 1161 if(keepGoing){ 1162 var t = board[pointer[0]][pointer[1]][pointer[2]]; 1163 var c = cube[pointer[0]][pointer[1]][pointer[2]]; 1164 var blocked = (t >= 1); 1165 var sameTeam = ((t <= PIECE_TYPE_COUNT) == (tile <= PIECE_TYPE_COUNT)); 1166 var validMove = false; 1167 if(ENEMY_COLOR_MUD && type == 5 && c == 1-player){ // the king can't travel onto enemy territory 1168 validMove = false; 1169 keepGoing = false; 1170 }else if(dire_power == 0){ 1171 if(!blocked){ 1172 validMove = true; 1173 } 1174 keepGoing = false; 1175 }else if(dire_power == 1){ 1176 if(blocked && !sameTeam){ 1177 validMove = true; 1178 } 1179 keepGoing = false; 1180 }else if(dire_power == 2 || dire_power == 3){ 1181 if(!blocked || !sameTeam || dire_power == 3){ 1182 validMove = true; 1183 } 1184 keepGoing = false; 1185 }else if(dire_power == 4){ 1186 if(blocked){ 1187 validMove = (!sameTeam); 1188 keepGoing = false; 1189 }else if(ENEMY_COLOR_MUD && c == 1-player){ 1190 keepGoing = false; 1191 validMove = true; 1192 }else{ 1193 validMove = true; 1194 } 1195 }else if(dire_power == 5){ // knight weirdness 1196 if(steps < 2){ 1197 validMove = false; 1198 keepGoing = true; 1199 }else{ 1200 validMove = (!blocked || !sameTeam); 1201 keepGoing = false; 1202 } 1203 } 1204 if(validMove || keepGoing){ 1205 validDestChain.unshift([pointer.slice(),prevPointer.slice(),OOB_pointer.slice(),dire_power]); 1206 } 1207 if(validMove){ 1208 validDest[pointer[0]][pointer[1]][pointer[2]] = validDestChain.slice(); 1209 } 1210 prevPointer = pointer.slice(); 1211 } 1212 steps++; 1213 } 1214 } 1215 } 1216} 1217// check is calculated by pretending the king is every type of piece, and seeing which enemy pieces are "visible". 1218function kingCheckCheck(s, boardX, boardY, player){ 1219 var start_c = cube[s][boardX][boardY]; 1220 for(var type = 0; type < 3; type++){ // First three directions: Ortho, diag, and knight. 1221 for(var d = 0; d < DIRE_TYPES[type].length; d++){ 1222 var dire = DIRE_TYPES[type][d].slice(); 1223 var pointer = [s,boardX,boardY]; 1224 var cPath = [pointer.slice()]; 1225 var keepGoing = true; 1226 var steps = 0; 1227 var prevC = cube[s][boardX][boardY]; 1228 var hadSameColorMove = false;
1229 while(keepGoing){ 1230 if(type == 2){ // knight movement 1231 dire = knightDire(dire,d,steps); 1232 } 1233 pointer[1] += dire[0]; 1234 pointer[2] += dire[1]; 1235 if(!inBounds(pointer)){ 1236 if (GO_OVER_EDGES){ 1237 var results = goOverEdge(pointer,dire,1); 1238 pointer = results[0]; 1239 dire = results[1]; 1240 if(!inBounds(pointer)){ // weird corner case 1241 keepGoing = false; 1242 } 1243 }else{ 1244 keepGoing = false; 1245 } 1246 } 1247 if(pointer[0] == s && pointer[1] == boardX && pointer[2] == boardY){ // you looped back to where you were. 1248 keepGoing = false; 1249 } 1250 steps++; 1251 if(keepGoing){ 1252 var t = board[pointer[0]][pointer[1]][pointer[2]]; 1253 var c = cube[pointer[0]][pointer[1]][pointer[2]]; 1254 if((type != 2 && c == prevC) || (type == 2 && steps == 3 && c == start_c)){ 1255 hadSameColorMove = true; 1256 } 1257 prevC = c; 1258 var blocked = ((t >= 1) && !(type == 2 && steps < 3)); 1259 var enemyTeam = ((t <= PIECE_TYPE_COUNT) != (player == 0)); 1260 if(type == 2 && steps < 3){ // knight weirdness - the 0th and 3rd squares on a knight's path should show a check warning path, but NOT the 1st and 2nd pieces. 1261 }else{ 1262 cPath.push(pointer.slice()); 1263 } 1264 if(blocked){ 1265 if(enemyTeam){ 1266 var pt = getTypeOf(t); 1267 if(ENEMY_COLOR_MUD && start_c == player && pt == KING_TYPE){ // an enemy king cannot attack you on your color. 1268 continue; 1269 } 1270 var validAttack = false; 1271 for(var m = 0; m < PIECE_DIRES[pt].length; m++){ 1272 if(PIECE_DIRES[pt][m][0] == type && !(PIECE_DIRES[pt][m][3] == 1 && hadSameColorMove)){ // If the king's line-of-sight hits a piece, let's see... does the piece's moveset include that move? And, if there was a same-color move, is it a nootnoot? 1273 var dire_power = PIECE_DIRES[pt][m][1]; 1274 var ONE_STEP = (dire_power == 1 || dire_power == 2); 1275 var SLIDE = (dire_power == 4); 1276 var KNIGHT = (dire_power == 5); 1277 if(SLIDE || (ONE_STEP && steps == 1) || (KNIGHT && steps == 3)){ 1278 validAttack = true; 1279 } 1280 } 1281 } 1282 if(validAttack){ 1283 for(var c = 0; c < cPath.length; c++){ 1284 var val = (c == 0 || c == cPath.length-1) ? 2 : 1; 1285 checkCube[cPath[c][0]][cPath[c][1]][cPath[c][2]][player] = val; 1286 } 1287 checks[player] = pt+1; // This variable being set to non-zero tells us, THAT PLAYER IS IN CHECK, and WHICH TYPE OF PIECE IS INFLICTING CHECK. 1288 } 1289 } 1290 keepGoing = false; 1291 } 1292 if(type == 2 && steps >= 3){ // knight weirdness 1293 keepGoing = false; 1294 } 1295 if(type != 2 && ENEMY_COLOR_MUD && c == player && steps >= 1){ // If you're the black king, black tiles (your own) stops white opponents! 1296 keepGoing = false; 1297 } 1298 } 1299 } 1300 } 1301 } 1302 var sp = splatoonSpread([s, boardX, boardY], 1-player, true, true); // SPLATOON CHECK CHECK - pretend you're a splatoon of the opposite color 1303 if(sp.length >= 1){ 1304 for(var i = 0; i < sp.length; i++){ 1305 var L = sp[i]; 1306 var val = (i == 0 || i == sp.length-1) ? 2 : 1; 1307 checkCube[L[0]][L[1]][L[2]][player] = val; 1308 } 1309 checks[player] = SPLATOON_TYPE; 1310 } 1311} 1312 1313function knightDire(dire,d,steps){ 1314 var startDist = 1+d%2; 1315 if(steps == startDist){ // the knight should turn 1316 var turnDire = -1+2*(Math.floor(d/2)%2); 1317 if(dire[0] == 0){ 1318 return [turnDire,0]; 1319 }else{ 1320 return [0,turnDire]; 1321 } 1322 }else{ // the knight should not turn 1323 return dire; 1324 } 1325} 1326function goOverEdge(pointer,dire,m){ 1327 var s = pointer[0]; 1328 var x = pointer[1]; 1329 var y = pointer[2]; 1330 if(s == 0){ 1331 if(y >= B_N){ 1332 return [[2,x,y-B_N],[dire[0],dire[1]]]; 1333 }else if(y < 0){ 1334 return [[4,B_N-m-x,-m-y],[-dire[0],-dire[1]]]; 1335 } 1336 if(x >= B_N){ 1337 return [[5,B_N-m-y,x-B_N],[-dire[1],dire[0]]]; 1338 }else if(x < 0){ 1339 return [[3,y,-m-x],[dire[1],-dire[0]]]; 1340 } 1341 }else if(s == 1){ 1342 if(y >= B_N){ 1343 return [[2,B_N-m-x,B_N*2-m-y],[-dire[0],-dire[1]]]; 1344 }else if(y < 0){ 1345 return [[4,x,B_N+y],[dire[0],dire[1]]]; 1346 } 1347 if(x >= B_N){ 1348 return [[3,y,B_N*2-m-x],[dire[1],-dire[0]]]; 1349 }else if(x < 0){ 1350 return [[5,B_N-m-y,B_N+x],[-dire[1],dire[0]]]; 1351 } 1352 }else{ 1353 if(x >= B_N){ 1354 return [[((s-2)+3)%4+2,x-B_N,y],[dire[0],dire[1]]]; 1355 }else if(x < 0){ 1356 return [[((s-2)+1)%4+2,x+B_N,y],[dire[0],dire[1]]]; 1357 } 1358 if(s == 2){ 1359 if(y >= B_N){ 1360 return [[1,B_N-m-x,B_N*2-m-y],[-dire[0],-dire[1]]]; 1361 }else if(y < 0){ 1362 return [[0,x,B_N+y],[dire[0],dire[1]]]; 1363 } 1364 }else if(s == 3){ 1365 if(y >= B_N){ 1366 return [[1,B_N*2-m-y,x],[-dire[1],dire[0]]]; 1367 }else if(y < 0){ 1368 return [[0,-m-y,x],[-dire[1],dire[0]]]; 1369 } 1370 }else if(s == 4){ 1371 if(y >= B_N){ 1372 return [[1,x,y-B_N],[dire[0],dire[1]]]; 1373 }else if(y < 0){ 1374 return [[0,B_N-m-x,-m-y],[-dire[0],-dire[1]]]; 1375 } 1376 }else if(s == 5){ 1377 if(y >= B_N){ 1378 return [[1,y-B_N,B_N-m-x],[dire[1],-dire[0]]]; 1379 }else if(y < 0){ 1380 return [[0,y+B_N,B_N-m-x],[dire[1],-dire[0]]]; 1381 } 1382 } 1383 } 1384 return [pointer,dire]; 1385} 1386function detectChessSquareClick(mX,mY){ 1387 var hitSomething = false;
1388 for(var s = 0; s < 6; s++){ 1389 var matrix = [diff(vb[s][0][0][1],vb[s][0][0][0]),diff(vb[s][1][0][1],vb[s][0][0][0])]; 1390 var inverse = invert2x2(matrix); 1391 if(inverse == -1){ 1392 //back side face 1393 }else{ 1394 var boardX = getClickedOn(s,inverse,mX,mY,0); 1395 var boardY = getClickedOn(s,inverse,mX,mY,1); 1396 if(boardX >= 0 && boardY >= 0){ 1397 setSelection(s,boardX,boardY); 1398 hitSomething = true; 1399 } 1400 } 1401 } 1402 if(pawnPromotionInfo[0]){ // a pawn is being promoted, so don't clear the selection just yet. 1403 }else if(!hitSomething){ 1404 validDest = createValidDest(B_N); 1405 clearSelection(); 1406 } 1407} 1408function spinCamera(){ 1409 if(CAMERA_SPIN_SLOW[0]){ 1410 var diff = Date.now()-lastCameraTime; 1411 rotY += diff*0.000034; 1412 lastCameraTime = Date.now(); 1413 } 1414} 1415 1416var TAKE_TURNS = true; 1417var GO_OVER_EDGES = false; 1418var ENEMY_COLOR_MUD = false; 1419var BOARD_RUBIK = true; // 0 = rubiks cube, 1 = chessboard 1420var WEIRD_PIECES = true; 1421var SHOW_CHECK = [true,1650,850,240,70,"Show check warnings?"]; 1422var CAMERA_SPIN_SLOW = [false,1650,760,240,70,"Spin camera slowly?"]; 1423var toggles = [SHOW_CHECK,CAMERA_SPIN_SLOW]; 1424var history_UI = [[1390,960,500,90],[0,0,70,70],[430,0,70,70],[90,50,320,20,20],[250,30]]; 1425var PP_UI = [[1650,380,240,350],[20,50,200,40],[120,35]]; 1426 1427var OPTION_NAMES = ["Take turns?","Go over edges?","Enemy color mud?","Rubik's colors?","Weird pieces?"]; 1428 1429var TRANSITION_TIME = 1200; // milliseconds 1430var PIECE_SCORES = [1,3,3,5,9,20,4,3,6,10]; 1431var PIECE_NAMES = ["pawn","knight","bishop","rook","queen","king","hand","splatoon","nootnoot","amazon","point"]; 1432var PAWN_PROMOTION_OPTIONS = [0,1,2,3,6,7,8]; 1433var pawnPromotionInfo = [false,0,0]; 1434var PAWN_TYPE = 0; 1435var KING_TYPE = 5; 1436var SPLATOON_TYPE = 7; 1437 1438var turn = 0; 1439var W_W = 1920; 1440var W_H = 1080; 1441var B_N = 7; 1442var PIECE_TYPE_COUNT = 10; 1443var NORMAL_TYPE_COUNT = 7; 1444var PLAYER_COLORS = [ 1445[[255,255,255],[0,0,0],[255,235,241]], 1446[[0,0,0],[255,255,255],[90,90,90]], 1447[[0,40,255],[0,0,0],[0,40,255]], 1448[[255,140,0],[0,0,0],[255,140,0]], 1449[[0,180,0],[0,0,0],[0,180,0]], 1450[[255,0,0],[0,0,0],[255,0,0]]]; 1451var INSIDE_COLOR = [160,136,100]; 1452var PLAYER_NAMES = ["White","Black","Blue","Orange","Green","Red"]; 1453var SELECTION_COLOR = [128,255,128]; 1454var CHECK_COLOR = [255,0,0]; 1455var BG_COLOR = [100,200,255]; 1456var VALID_COLOR = [[220,170,0],[255,255,0]]; 1457var board; 1458var cube; 1459var checkCube; 1460var checks; 1461var rotGrid; 1462var validDest; 1463var vb; 1464 1465var pieceModels = new Array(); 1466var playerTurn = 0; 1467var selection = [-1,-1,-1]; 1468 1469var rotX = 0; 1470var rotY = 0; 1471var prev_mouseX = 0; 1472var prev_mouseY = 0; 1473var moved = false; 1474var pressed = false; 1475var lastMoveLocation = [[-1,-1,-1],[-1,-1,-1],-1]; 1476var lastMoveTime = 0; 1477var lastMovePiece = 0; 1478var lastMoveType = 0; 1479var travelPath = []; 1480var scores = []; 1481var winner = -1; 1482var lastCameraTime = -1; 1483var ui; 1484var game_history = []; 1485var history_index = 0; 1486var alert; 1487for(var p = 0; p < PIECE_TYPE_COUNT; p++){ 1488 let m; 1489 pieceModels[p] = m; 1490} 1491let c; 1492 1493function preload(){ 1494 console.log("eee!"); 1495 for(var p = 0; p < PIECE_TYPE_COUNT; p++){ 1496 pieceModels[p] = loadModel("models/piece"+p+".obj"); 1497 } 1498 console.log("fff!"); 1499} 1500function setup() { 1501 console.log("STARTING!"); 1502 createCanvas(W_W, W_H, WEBGL); 1503 console.log("1!"); 1504 c = createGraphics(W_W, W_H, WEBGL); 1505 console.log("b!"); 1506 addScreenPositionFunction(c); 1507 console.log("c!"); 1508 sandboxGameButton(); 1509 console.log("d!"); 1510 ui = createGraphics(260,900); 1511 alert = createGraphics(260,260); 1512 console.log("e!"); 1513 for(var t = 0; t < toggles.length; t++){ 1514 var tog = toggles[t]; 1515 tog.push(createGraphics(tog[3],tog[4])); 1516 } 1517 console.log("f!"); 1518 history_UI.push(createGraphics(history_UI[0][2],history_UI[0][3])); 1519 PP_UI.push(createGraphics(PP_UI[0][2],PP_UI[0][3])); 1520 console.log("g!"); 1521}; 1522 1523function draw() { 1524 spinCamera(); 1525 c.push(); 1526 setWorldDrawings(c); 1527 var sca = 690/(B_N+2); 1528 drawBoard(c, board, sca); 1529 c.pop(); 1530 1531 background(255,255,255); 1532 image(c,-W_W/2,-W_H/2); 1533 //drawWireframe(); 1534 drawUI(); 1535} 1536function mousePressed(){ 1537 var clickedTog = false; 1538 for(var t = 0; t < toggles.length; t++){ 1539 var tog = toggles[t]; 1540 if(mouseX >= tog[1] && mouseX < tog[1]+tog[3] && mouseY >= tog[2] && mouseY < tog[2]+tog[4]){ 1541 tog[0] = !tog[0]; 1542 clickedTog = true; 1543 lastCameraTime = Date.now(); 1544 } 1545 } 1546 for(var a = 0; a < 2; a++){ 1547 var a1 = history_UI[0]; 1548 var a2 = history_UI[a+1]; 1549 var ax = a1[0]+a2[0]; 1550 var ay = a1[1]+a2[1]; 1551 var aw = a2[2]; 1552 var ah = a2[3]; 1553 if(mouseX >= ax && mouseX < ax+aw && mouseY >= ay && mouseY < ay+ah){ 1554 if((a == 0 && history_index >= 1) || (a == 1 && history_index < game_history.length-1)){ 1555 history_index += -1+2*a; 1556 loadFromGameHistory(); 1557 clickedTog = true; 1558 } 1559 } 1560 } 1561 if(pawnPromotionInfo[0]){ 1562 var p = PP_UI[0]; 1563 if(mouseX >= p[0] && mouseX < p[0]+p[2] && mouseY >= p[1] && mouseY < p[1]+p[3]){ 1564 var px = PP_UI[0][0]+PP_UI[1][0]; 1565 var py = PP_UI[0][1]+PP_UI[1][1]; 1566 var pw = PP_UI[1][2]; 1567 var ph = PP_UI[1][3]; 1568 var pth = ph*PAWN_PROMOTION_OPTIONS.length; 1569 if(mouseX >= px && mouseX < px+pw && mouseY >= py && mouseY < py+pth){ 1570 var choice = Math.floor((mouseY-py)/ph); 1571 if(WEIRD_PIECES || PAWN_PROMOTION_OPTIONS[choice] < NORMAL_TYPE_COUNT){ 1572 var src = pawnPromotionInfo[1]; 1573 var player = getPlayerOf(deepIndex(board,src)); 1574 var t = 1+PAWN_PROMOTION_OPTIONS[choice]+player*PIECE_TYPE_COUNT; 1575 doMove(pawnPromotionInfo[1],pawnPromotionInfo[2],t); 1576 clearSelection(); 1577 clickedTog = true; 1578 } 1579 } 1580 }else{ 1581 clearSelection(); 1582 } 1583 } 1584 if(!clickedTog && mouseX >= 0 && mouseX < W_W && mouseY >= 0 && mouseY < W_H){ 1585 pressed = true; 1586 moved = false;
1587 prev_mouseX = mouseX; 1588 prev_mouseY = mouseY; 1589 } 1590} 1591function deepCopy(arr){ 1592 var result = [arr.length]; 1593 for(var i = 0; i < arr.length; i++){ 1594 result[i] = [arr[i].length]; 1595 for(var j = 0; j < arr[i].length; j++){ 1596 result[i][j] = arr[i][j].slice(); 1597 } 1598 } 1599 return result; 1600} 1601function keyPressed(){ 1602 if (keyCode == SHIFT) { 1603 } 1604} 1605function mouseReleased(){ 1606 if(!moved){ 1607 var mY = mouseY-W_H/2; 1608 var mX = mouseX-W_W/2; 1609 detectChessSquareClick(mX,mY); 1610 } 1611 pressed = false; 1612}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.