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