1 2#import "Views.h" 3#import "Controller.h" 4 5 6@implementation Rubik 7 8- initAtPoint:(NSPoint)aPoint controller:(id)theCon 9{ 10 NSRect frame; 11 int x, y, z, b1, b2, index; 12 13 frame.origin = aPoint; 14 frame.size.width = frame.size.height = DIMENSION; 15 16 [super initWithFrame:frame]; 17 [self setBoundsSize:NSMakeSize(4.0, 4.0)]; 18 [self setBoundsOrigin:NSMakePoint(-2.0, -2.0)]; 19 20 con = theCon; 21 22 for(x=-1; x<=1; x+=2){ 23 for(y=-1; y<=1; y+=2){ 24 for(z=-1; z<=1; z+=2){ 25 int index = 26 4*(x==-1 ? 0 : 1)+ 27 2*(y==-1 ? 0 : 1)+ 28 (z==-1 ? 0 : 1); 29 vertices[index].x = x; 30 vertices[index].y = y; 31 vertices[index].z = z; 32 vertices[index].index = index; 33 34 colors[index] = 35 [NSColor colorWithDeviceRed:(x==-1 ? 0.0 : 1.0) 36 green:(y==-1 ? 0.0 : 1.0) 37 blue:(z==-1 ? 0.0 : 1.0) 38 alpha:1.0]; 39 [colors[index] retain]; 40 } 41 } 42 } 43 44 index = 0; 45 for(b1=0; b1<=2; b1++){ 46 for(b2=b1+1; b2<=2; b2++){ 47 /* counterclockwise */ 48 int reorient = index + 1-(index/2)%2; 49 int temp; 50 51 face[index][0] = 0; 52 face[index][1] = face[index][0]+(1<<b1); 53 face[index][2] = face[index][1]+(1<<b2); 54 face[index][3] = face[index][2]-(1<<b1); 55 56 index++; 57 58 face[index][0] = 1<<(3-b1-b2); 59 face[index][1] = face[index][0]+(1<<b1); 60 face[index][2] = face[index][1]+(1<<b2); 61 face[index][3] = face[index][2]-(1<<b1); 62 63 index++; 64 65 temp = face[reorient][0]; 66 face[reorient][0] = face[reorient][3]; 67 face[reorient][3] = temp; 68 temp = face[reorient][1]; 69 face[reorient][1] = face[reorient][2]; 70 face[reorient][2] = temp; 71 } 72 } 73 74 for(index=0; index<6; index++){ 75 int vx; 76 77 printf("%d : %d %d %d %d:", index, 78 face[index][0], 79 face[index][1], 80 face[index][2], 81 face[index][3]); 82 83 for(vx=0; vx<4; vx++){ 84 int v1 = face[index][vx], v2 = face[index][(vx+1)%4]; 85 int f; 86 for(f=0; f<6; f++){ 87 if(f!=index){ 88 int e; BOOL found = NO; 89 90 for(e=0; e<4; e++){ 91 if(v1 == face[f][e] && 92 v2 == face[f][(e+3)%4]){ 93 found = YES; 94 95 adjacent[index][vx] = f; 96 edge[index][vx] = (e+3)%4; 97 } 98 } 99 100 if(found==YES){ 101 printf(" (%d %d)", 102 adjacent[index][vx], 103 edge[index][vx]); 104 } 105 } 106 } 107 } 108 109 printf("\n"); 110 } 111 112 113 [self resetCube]; 114 [self recomputeGeometry]; 115 116 return self; 117} 118 119- scramble 120{ 121 int fprev = -1, fcur, index; 122 123 for(index=0; index<SCRAMBLE; index++){ 124 do { 125 fcur = lrand48()%6; 126 } while(fcur==fprev); 127 128 [self rotateFace:fcur clockwise:YES]; 129 130 fprev = fcur; 131 } 132 133 return self; 134} 135 136- resetCube 137{ 138 int f, row, col; 139 140 angle = 0; 141 rprev = rcur = -1; 142 143 memcpy(indexed, vertices, 8*sizeof(Vertex)); 144 memcpy(active, vertices, 8*sizeof(Vertex)); 145 146 for(f=0; f<6; f++){ 147 for(row=0; row<3; row++){ 148 for(col=0; col<3; col++){ 149 data[f][row][col] = f+1; 150 } 151 } 152 } 153 154 return self; 155} 156 157- rotate:(Vertex *)vp aboutUnitVector:(ROT_ACTIVE)rv 158 angle:(double)theta 159 160{ 161 double cosTheta = cos(theta), sinTheta = sin(theta); 162 int index; 163 164 for(index=0; index<8; index++){ 165 Vertex *v = vp+index; 166 double x = v->x, y = v->y, z = v->z; 167 168 switch(rv){ 169 case ROT_X: 170 v->y = y * cosTheta - z * sinTheta; 171 v->z = y * sinTheta + z * cosTheta; 172 break; 173 case ROT_Y: 174 v->x = x * cosTheta - z * sinTheta; 175 v->z = x * sinTheta + z * cosTheta; 176 break; 177 case ROT_Z: 178 v->x = x * cosTheta - y * sinTheta; 179 v->y = x * sinTheta + y * cosTheta; 180 } 181 } 182 183 return self; 184} 185 186- recomputeGeometry 187{ 188 int index, findex, upper; 189 190 if(rcur!=rprev){ 191 [self rotate:active aboutUnitVector:rcur angle:-angle]; 192 memcpy(indexed, active, 8*sizeof(Vertex)); 193 rprev = rcur; 194 195 /* 196 { 197 double 198 dx = indexed[0].x-indexed[1].x, 199 dy = indexed[0].y-indexed[1].y, 200 dz = indexed[0].z-indexed[1].z; 201 202 NSLog(@"%le\n", dx*dx+dy*dy+dz*dz); 203 } 204 */ 205 } 206 207 memcpy(active, indexed, 8*sizeof(Vertex)); 208 [self rotate:active aboutUnitVector:rcur angle:angle]; 209 memcpy(sorted, active, 8*sizeof(Vertex)); 210 211 for(upper=6; upper>=0; upper--){ 212 for(index=0; index<=upper; index++){ 213 if(sorted[index].y>sorted[index+1].y){ 214 Vertex current; 215 current = sorted[index]; 216 sorted[index] = sorted[index+1]; 217 sorted[index+1] = current; 218 } 219 } 220 } 221 222 index = 0; 223 for(index=1; index<8; index++){ 224 double delta = sorted[index].y-sorted[index-1].y; 225 if(delta>DELTA){ 226 break; 227 } 228 } 229 230 if(index==1){ 231 int v = sorted[0].index; 232 233 vis = VIS_F_3; 234 235 findex = 0; 236 for(index=0; index<6; index++){ 237 if(face[index][0]==v || 238 face[index][1]==v || 239 face[index][2]==v || 240 face[index][3]==v){ 241 visface[findex++] = index; 242 } 243 } 244 } else if(index==2){ 245 int v1 = sorted[0].index, v2 = sorted[1].index; 246 247 vis = VIS_F_2; 248 249 findex = 0; 250 for(index=0; index<6; index++){ 251 if((face[index][0]==v1 || 252 face[index][1]==v1 || 253 face[index][2]==v1 || 254 face[index][3]==v1) && 255 (face[index][0]==v2 || 256 face[index][1]==v2 || 257 face[index][2]==v2 || 258 face[index][3]==v2)){ 259 visface[findex++] = index; 260 } 261 } 262 } else { 263 int v1 = sorted[0].index, v2 = sorted[1].index, 264 v3 = sorted[2].index, v4 = sorted[3].index; 265 266 vis = VIS_F_1; 267 268 findex = 0; 269 for(index=0; index<6; index++){ 270 if((face[index][0]==v1 || 271 face[index][1]==v1 || 272 face[index][2]==v1 || 273 face[index][3]==v1) && 274 (face[index][0]==v2 || 275 face[index][1]==v2 || 276 face[index][2]==v2 || 277 face[index][3]==v2) && 278 (face[index][0]==v3 || 279 face[index][1]==v3 || 280 face[index][2]==v3 || 281 face[index][3]==v3) && 282 (face[index][0]==v4 || 283 face[index][1]==v4 || 284 face[index][2]==v4 || 285 face[index][3]==v4)){ 286 visface[findex++] = index; 287 } 288 } 289 } 290 291 [self setNeedsDisplay:YES]; 292 293 return self; 294} 295 296- angle:(id)sender 297{ 298 angle = [sender doubleValue]; 299 rcur = [sender tag]; 300 301 [self recomputeGeometry]; 302 return self; 303} 304 305- (BOOL)solved 306{ 307 int f, row, col; 308 309 for(f=0; f<6; f++){ 310 for(row=0; row<3; row++){ 311 for(col=0; col<3; col++){ 312 if(data[f][row][col]!=data[f][1][1]){ 313 return NO; 314 } 315 } 316 } 317 } 318 319 return YES; 320} 321 322- (void)drawRect:(NSRect)aRect 323{ 324 NSRect bounds = [self bounds]; 325 int findex; 326 327 [colors[0] set]; 328 PSrectfill(bounds.origin.x, bounds.origin.y, 329 bounds.size.width, bounds.size.height); 330 331 PSsetlinewidth(4.0/(float)DIMENSION); 332 333 for(findex=0; findex<vis; findex++){ 334 int f = visface[findex]; 335 NSPoint p0 = { active[face[f][0]].x, 336 active[face[f][0]].z }; 337 NSPoint p1 = { active[face[f][1]].x, 338 active[face[f][1]].z }; 339 NSPoint p2 = { active[face[f][2]].x, 340 active[face[f][2]].z }; 341 342 NSPoint ivall = { p1.x - p0.x, p1.y - p0.y }; 343 NSPoint jvall = { p2.x - p1.x, p2.y - p1.y }; 344 NSPoint ivect = { ivall.x/3.0, ivall.y/3.0 }; 345 NSPoint jvect = { jvall.x/3.0, jvall.y/3.0 }; 346 347 int row, col, k; 348 349 for(row=0; row<3; row++){ 350 for(col=0; col<3; col++){ 351 [colors[data[f][row][col]] set]; 352 353 PSmoveto(p0.x+col*ivect.x+row*jvect.x, 354 p0.y+col*ivect.y+row*jvect.y); 355 PSrlineto(ivect.x, ivect.y); 356 PSrlineto(jvect.x, jvect.y); 357 PSrlineto(-ivect.x, -ivect.y); 358 PSrlineto(-jvect.x, -jvect.y); 359 360 PSfill(); 361 } 362 } 363 364 [colors[7] set]; 365 366 for(k=0; k<=3; k++){ 367 PSmoveto(p0.x+k*ivect.x, p0.y+k*ivect.y); 368 PSrlineto(jvall.x, jvall.y); 369 PSmoveto(p0.x+k*jvect.x, p0.y+k*jvect.y); 370 PSrlineto(ivall.x, ivall.y); 371 } 372 373 PSstroke(); 374 } 375} 376 377- (int)visFaceClicked:(NSPoint)loc 378{ 379 int findex; 380 381 for(findex=0; findex<vis; findex++){ 382 int f = visface[findex]; 383 NSPoint p0 = { active[face[f][0]].x, 384 active[face[f][0]].z }; 385 NSPoint p1 = { active[face[f][1]].x, 386 active[face[f][1]].z }; 387 NSPoint p2 = { active[face[f][2]].x, 388 active[face[f][2]].z }; 389 390 NSPoint ivall = { p1.x - p0.x, p1.y - p0.y }; 391 NSPoint jvall = { p2.x - p1.x, p2.y - p1.y }; 392 393 NSPoint p = { loc.x - p0.x, loc.y - p0.y }; 394 395 float s, t, det; 396 397 det = ivall.x * jvall.y - ivall.y * jvall.x; 398 if(det!=0.0){ 399 s = (p.x * jvall.y - p.y * jvall.x)/det; 400 t = (ivall.x * p.y - ivall.y * p.x)/det; 401 402 if(0.0 <= s && s <= 1.0 && 0.0 <= t && t <= 1.0){ 403 return f; 404 } 405 } 406 } 407 408 return -1; 409} 410 411- rotateFace:(int)f clockwise:(BOOL)flag 412{ 413 int fbuf[3][3]; 414 int row, col; 415 416 int e, lbuf[4][3], offs = (flag==YES ? 3 : 1); 417 418 for(row=0; row<3; row++){ 419 for(col=0; col<3; col++){ 420 fbuf[row][col] = data[f][row][col]; 421 } 422 } 423 424 if(flag==YES){ 425 data[f][0][0] = fbuf[0][2]; 426 data[f][2][0] = fbuf[0][0]; 427 data[f][2][2] = fbuf[2][0]; 428 data[f][0][2] = fbuf[2][2]; 429 430 data[f][0][1] = fbuf[1][2]; 431 data[f][1][0] = fbuf[0][1]; 432 data[f][2][1] = fbuf[1][0]; 433 data[f][1][2] = fbuf[2][1]; 434 } 435 else{ 436 data[f][0][0] = fbuf[2][0]; 437 data[f][2][0] = fbuf[2][2]; 438 data[f][2][2] = fbuf[0][2]; 439 data[f][0][2] = fbuf[0][0]; 440 441 data[f][0][1] = fbuf[1][0]; 442 data[f][1][0] = fbuf[2][1]; 443 data[f][2][1] = fbuf[1][2]; 444 data[f][1][2] = fbuf[0][1]; 445 } 446 447 data[f][1][1] = fbuf[1][1]; 448 449 for(e=0; e<4; e++){ 450 int sface = adjacent[f][e]; 451 int sedge = edge[f][e]; 452 453 switch(sedge){ 454 case 0: 455 lbuf[e][0] = data[sface][0][0]; 456 lbuf[e][1] = data[sface][0][1]; 457 lbuf[e][2] = data[sface][0][2]; 458 break; 459 case 1: 460 lbuf[e][0] = data[sface][0][2]; 461 lbuf[e][1] = data[sface][1][2]; 462 lbuf[e][2] = data[sface][2][2]; 463 break; 464 case 2: 465 lbuf[e][0] = data[sface][2][2]; 466 lbuf[e][1] = data[sface][2][1]; 467 lbuf[e][2] = data[sface][2][0]; 468 break; 469 case 3: 470 lbuf[e][0] = data[sface][2][0]; 471 lbuf[e][1] = data[sface][1][0]; 472 lbuf[e][2] = data[sface][0][0]; 473 } 474 } 475 476 for(e=0; e<4; e++){ 477 int sface = adjacent[f][(e+offs)%4]; 478 int sedge = edge[f][(e+offs)%4]; 479 480 switch(sedge){ 481 case 0: 482 data[sface][0][0] = lbuf[e][0]; 483 data[sface][0][1] = lbuf[e][1]; 484 data[sface][0][2] = lbuf[e][2]; 485 break; 486 case 1: 487 data[sface][0][2] = lbuf[e][0]; 488 data[sface][1][2] = lbuf[e][1]; 489 data[sface][2][2] = lbuf[e][2]; 490 break; 491 case 2: 492 data[sface][2][2] = lbuf[e][0]; 493 data[sface][2][1] = lbuf[e][1]; 494 data[sface][2][0] = lbuf[e][2]; 495 break; 496 case 3: 497 data[sface][2][0] = lbuf[e][0]; 498 data[sface][1][0] = lbuf[e][1]; 499 data[sface][0][0] = lbuf[e][2]; 500 } 501 } 502 503 return self; 504} 505 506 507- (void)mouseDown:(NSEvent *)theEvent 508{ 509 int f; 510 NSPoint curp = [theEvent locationInWindow]; 511 curp = [self convertPoint:curp fromView:nil]; 512 513 if((f=[self visFaceClicked:curp])!=-1){ 514 [self rotateFace:f clockwise:YES]; 515 [self setNeedsDisplay:YES]; 516 517 if([self solved]==YES){ 518 NSRunAlertPanel(@"Congratulations!", @"Cube solved.", 519 @"Ok", nil, nil); 520 } 521 } 522} 523 524- (void)rightMouseDown:(NSEvent *)theEvent 525{ 526 int f; 527 NSPoint curp = [theEvent locationInWindow]; 528 curp = [self convertPoint:curp fromView:nil]; 529 530 if((f=[self visFaceClicked:curp])!=-1){ 531 [self rotateFace:f clockwise:NO]; 532 [self setNeedsDisplay:YES]; 533 534 if([self solved]==YES){ 535 NSRunAlertPanel(@"Congratulations!", @"Cube solved.", 536 @"Ok", nil, nil); 537 } 538 } 539} 540 541@end 542 543