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