1 /* BurrTools
2  *
3  * BurrTools is the legal property of its developers, whose
4  * names are listed in the COPYRIGHT file, which is included
5  * within the source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11 
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16 
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  */
21 #include "movementcache.h"
22 
23 #include "voxel.h"
24 #include "problem.h"
25 
26 #include <string.h>
27 
28 /* the hash function. I don't know how well it performs, but it seems to be okay */
moHashValue(unsigned int s1,unsigned int s2,int dx,int dy,int dz,unsigned char t1,unsigned char t2)29 static unsigned int moHashValue(unsigned int s1, unsigned int s2, int dx, int dy, int dz, unsigned char t1, unsigned char t2) {
30   unsigned int val = dx * 0x10101010;
31   val +=             dy * 0x14814814;
32   val +=             dz * 0x95145951;
33   val +=             t1 * 0x1A54941A;
34   val +=             t2 * 0x5AA59401;
35   val +=             s1 * 0x01059a04;
36   val +=             s2 * 0x9af42682;
37   return val;
38 }
39 
40 /* double the hash table size and copy the old elements into
41  * the new table
42  */
moRehash(void)43 void movementCache_c::moRehash(void) {
44   unsigned int oldSize = moTableSize;
45 
46   /* the new size, roughly twice the old size but odd */
47   moTableSize = 2*moTableSize + 1;
48 
49   /* allocate new table */
50   moEntry ** newHash = new moEntry * [moTableSize];
51   memset(newHash, 0, moTableSize * sizeof(moEntry*));
52 
53   /* copy the elements */
54   for (unsigned int i = 0; i < oldSize; i++) {
55 
56     while (moHash[i]) {
57 
58       /* remove from old table */
59       moEntry * e = moHash[i];
60       moHash[i] = e->next;
61 
62       /* enter into new one */
63       unsigned int h = moHashValue(e->s1, e->s2, e->dx, e->dy, e->dz, e->t1, e->t2) % moTableSize;
64       e->next = newHash[h];
65       newHash[h] = e;
66     }
67   }
68 
69   /* delete the old table and make the new table the current one */
70   delete [] moHash;
71   moHash = newHash;
72 }
73 
movementCache_c(const problem_c * puzzle)74 movementCache_c::movementCache_c(const problem_c * puzzle) : gt(puzzle->getGridType()) {
75 
76   /* initial table */
77   moTableSize = 101;
78   moHash = new moEntry * [moTableSize];
79   memset(moHash, 0, moTableSize * sizeof(moEntry*));
80   moEntries = 0;
81 
82   /* initialize the shape array with the shapes from the
83    * puzzle problem. The shape with transformation 0 is just
84    * a pointer into the puzzle, so don't delete them later on
85    */
86   num_shapes = puzzle->partNumber();
87 
88   num_transformations = puzzle->getGridType()->getSymmetries()->getNumTransformations();
89 
90   shapes = new const voxel_c ** [num_shapes];
91   for (unsigned int s = 0; s < num_shapes; s++) {
92     shapes[s] = new const voxel_c * [num_transformations];
93     memset(shapes[s], 0, num_transformations * sizeof(voxel_c*));
94     shapes[s][0] = puzzle->getShapeShape(s);
95   }
96 
97   /* initialize the piece array */
98   pieces = new unsigned int [puzzle->pieceNumber()];
99 
100   int pos = 0;
101 
102   for (unsigned int s = 0; s < puzzle->partNumber(); s++)
103     for (unsigned int i = 0; i < puzzle->getShapeMax(s); i++)
104       pieces[pos++] = s;
105 
106 }
107 
~movementCache_c()108 movementCache_c::~movementCache_c() {
109 
110   /* delete the hash nodes */
111   for (unsigned int i = 0; i < moTableSize; i++) {
112 
113     while (moHash[i]) {
114       moEntry * e = moHash[i];
115       moHash[i] = e->next;
116 
117       delete [] e->move;
118       delete e;
119     }
120   }
121   delete [] moHash;
122 
123   /* the shape with transformation 0 is just
124    * a pointer into the puzzle, so don't delete them
125    *
126    * but all the others are created by us, so we free them
127    */
128   for (unsigned int s = 0; s < num_shapes; s++) {
129     for (unsigned int t = 1; t < num_transformations; t++)
130       if (shapes[s][t])
131         delete shapes[s][t];
132     delete [] shapes[s];
133   }
134 
135   delete [] shapes;
136   delete [] pieces;
137 }
138 
getTransformedShape(unsigned int s,unsigned char t)139 const voxel_c * movementCache_c::getTransformedShape(unsigned int s, unsigned char t) {
140 
141   if (!shapes[s][t])
142   {
143     // our required orientation doesn't exist, so we calculate it
144 
145     voxel_c * sh = gt->getVoxel(shapes[s][0]);
146     bt_assert2(sh->transform(t));
147 
148     // in the single threaded case simply enter our new shape
149     shapes[s][t] = sh;
150   }
151 
152   return shapes[s][t];
153 }
154 
getMoValue(int dx,int dy,int dz,unsigned char t1,unsigned char t2,unsigned int p1,unsigned int p2,unsigned int * movements)155 void movementCache_c::getMoValue(int dx, int dy, int dz, unsigned char t1, unsigned char t2, unsigned int p1, unsigned int p2, unsigned int * movements)
156 {
157   /* find out the shapes that the pieces have */
158   unsigned int s1 = pieces[p1];
159   unsigned int s2 = pieces[p2];
160 
161   unsigned int h = moHashValue(s1, s2, dx, dy, dz, t1, t2);
162 
163   moEntry * e = moHash[h % moTableSize];
164 
165   /* check the list of nodes in the current hash bucket */
166   while (e && (e->dx != dx || e->dy != dy || e->dz != dz ||
167                e->t1 != t1 || e->t2 != t2 || e->s1 != s1 || e->s2 != s2))
168     e = e->next;
169 
170   /* check, if we found the required node */
171   if (!e)
172   {
173     /* no is not found, enter a new node into the table */
174     e = new moEntry;
175     e->dx = dx; e->dy = dy; e->dz = dz;
176     e->t1 = t1; e->t2 = t2;
177     e->s1 = s1; e->s2 = s2;
178     e->move = moCalcValues(getTransformedShape(s1, t1), getTransformedShape(s2, t2), dx, dy, dz);
179 
180     if (++moEntries > moTableSize) moRehash();
181 
182     e->next = moHash[h % moTableSize];
183     moHash[h % moTableSize] = e;
184   }
185 
186   /* return the values */
187   memcpy(movements, e->move, numDirections()*sizeof(unsigned int));
188 }
189