1 /* -*- c++ -*-
2 FILE: Puzzlest.cpp
3 RCS REVISION: $Revision: 1.13 $
4 
5 COPYRIGHT: (c) 1999 -- 2003 Melinda Green, Don Hatch, and Jay Berkenbilt - Superliminal Software
6 
7 LICENSE: Free to use and modify for non-commercial purposes as long as the
8     following conditions are adhered to:
9     1) Obvious credit for the source of this code and the designs it embodies
10        are clearly made, and
11     2) Ports and derived versions of 4D Magic Cube programs are not distributed
12        without the express written permission of the authors.
13 
14 DESCRIPTION:
15     Implementation of PuzzleState class
16 */
17 
18 #include "Puzzlest.h"
19 
20 #include "Polymgr.h"
21 #include "Math4d.h"
22 #include "Preferences.h"
23 
24 
25 
PuzzleState(Preferences & p,PolygonManager4D * polymgr)26 PuzzleState::PuzzleState(Preferences& p, PolygonManager4D *polymgr) :
27     preferences(p)
28 {
29     m_polymgr = polymgr;
30     reset(p.getLength());
31 }
32 
33 /*
34  * Set the puzzle to the pristine state
35  */
reset(int new_length)36 void PuzzleState::reset(int new_length)
37 {
38     if (new_length != -1)
39     {
40         this->length = new_length;
41         nstickers = NFACES * length * length * length;
42     }
43     int i, nstickersperface = length * length * length;
44     for(i=0; i<nstickers; ++i)
45         the_state[i] = i / nstickersperface;
46 }
47 
isSolved()48 int PuzzleState::isSolved()
49 {
50     int i, nstickersperface = length * length * length;
51     for(i=0; i<nstickers; ++i)
52         if(the_state[i] !=
53             the_state[i / nstickersperface * nstickersperface])
54             return 0;
55     return 1;
56 }
57 
idToColor(int id)58 int PuzzleState::idToColor(int id)
59 {
60     return the_state[id];
61 }
62 
applyMove(struct stickerspec * grip,int dir,int slicesmask)63 void PuzzleState::applyMove(struct stickerspec *grip, int dir, int slicesmask)
64 {
65     int         i, j;
66     int         dest[MAXSTICKERS];
67     int         nranges, ranges[MAXLENGTH][2];
68     int         mat[4][4];
69     int         sgn, whichax;
70 
71     /*============= this is verbatim from polymgr.c =========*/
72     /*====== FIX THIS === it's a ridiculous hack =============*/
73     // It just got even more ridiculous getting it to compile -- DG
74     {
75         real        center[4], real_stickercoords[4], realmat[4][4];
76         real        total_angle;
77 
78         /*
79          * Note: due to run-time errors, I changed the ternary initialization
80          * of total_angle into a switch statement below. - DG
81          */
82         switch (grip->dim)
83         {
84         case 0:
85             total_angle = 2 * PI / 3 * dir;
86             break;
87         case 1:
88             total_angle = 2 * PI / 2 * dir;
89             break;
90         case 2:
91             total_angle = 2 * PI / 4 * dir;
92             break;
93         default:
94             abort();
95         }
96         /*
97          * Calculate rotation center; it's the center of the face containing
98          * the grip
99          */
100         whichax = -1;
101         for (i = 0; i < NDIMS; ++i)
102         {
103             if (ABS(grip->coords[i]) == 3)
104             {
105                 center[i] = grip->coords[i];
106                 whichax = i;
107             }
108             else
109                 center[i] = 0;
110         }
111         assert(INRANGE(0 <=, whichax, <NDIMS));
112 
113         SET4(real_stickercoords, grip->coords);
114 
115         Math4d::get4dRotMatrix(center, real_stickercoords,
116                                total_angle, realmat);
117         for (i = 0; i < 4; ++i)
118             for (j = 0; j < 4; ++j)
119             {
120                 mat[i][j] = ROUND(realmat[i][j]);
121                 assert(ABS(realmat[i][j] - mat[i][j]) < .0001);
122             }
123         sgn = SGN(center[whichax]);
124         nranges = m_polymgr->makeRangesInt(slicesmask, whichax, sgn, ranges);
125     }
126     /*=========================================================*/
127 
128     for (i = 0; i < nstickers; ++i)
129     {
130         struct stickerspec tempsticker;
131         tempsticker.id_within_cube = i;
132         m_polymgr->fillStickerspecFromId(&tempsticker);
133         for (j = 0; j < nranges; ++j)
134         {
135             if (INRANGE(ranges[j][0] <=, tempsticker.coords[whichax],
136                         <=ranges[j][1]))
137             {
138                 VXM4i(tempsticker.coords, tempsticker.coords, mat);
139                 m_polymgr->fillStickerspecFromCoords(&tempsticker);
140                 assert(INRANGE(0 <=, tempsticker.id_within_cube, <nstickers));
141                 dest[tempsticker.id_within_cube] = the_state[i];
142                 break;
143             }
144         }
145         if (j == nranges)       /* it didn't fall in any of the ranges */
146             dest[i] = the_state[i];
147     }
148 
149 
150     for (i = 0; i < nstickers; ++i)
151         the_state[i] = dest[i];
152 }
153 
154 
dump(FILE * fp)155 void PuzzleState::dump(FILE *fp)
156 {
157     int i, nstickersperface = length * length * length;
158     for (i=0; i<nstickers; ++i)
159     {
160         fprintf(fp, "%d", the_state[i]);
161         if ((i + 1) % nstickersperface == 0)
162             fprintf(fp, "\n");
163     }
164 }
165 
isSane(int state[MAXSTICKERS])166 int PuzzleState::isSane(int state[MAXSTICKERS])
167 {
168     int         i, counts[NFACES];
169 
170     for (i = 0; i < NFACES; ++i)
171         counts[i] = 0;
172     for (i = 0; i < nstickers; ++i)
173         counts[state[i]]++;
174     for (i = 0; i < NFACES; ++i)
175         if (counts[i] != length * length * length)
176             return 0;
177     return 1;
178 }
179 
180 /*
181  * Return 1 on success, 0 on error.
182  * FIX THIS-- decide whether we want to also print an error message.
183  */
read(FILE * fp)184 int PuzzleState::read(FILE *fp)
185 {
186     int         i;
187     int         temp_state[MAXSTICKERS];
188 
189     for (i = 0; i < nstickers; ++i)
190     {
191         if (fscanf(fp, "%1d", &temp_state[i]) != 1)
192             return 0;
193     }
194 
195     if (!isSane(temp_state))
196     {
197         /* fprintf(stderr, "That puzzle state was insane!\n"); */
198         return 0;
199     }
200     else
201     {
202         for (i = 0; i < nstickers; ++i)
203             the_state[i] = temp_state[i];
204         return 1;
205     }
206 }
207 
208 // Local Variables:
209 // c-basic-offset: 4
210 // c-comment-only-line-offset: 0
211 // c-file-offsets: ((defun-block-intro . +) (block-open . 0) (substatement-open . 0) (statement-cont . +) (statement-case-open . +4) (arglist-intro . +) (arglist-close . +) (inline-open . 0))
212 // indent-tabs-mode: nil
213 // End:
214