1 module dminer.core.minetypes;
2 
3 alias cell_t = ubyte;
4 
5 immutable cell_t NO_CELL = 0;
6 immutable cell_t END_OF_WORLD =  253;
7 immutable cell_t VISITED_CELL =  255;
8 immutable cell_t VISITED_OCCUPIED = 254;
9 
10 immutable cell_t BOUND_BOTTOM = 253;
11 immutable cell_t BOUND_SKY =    252;
12 
13 
14 /*
15     World coordinates
16 
17               A UP
18               |
19               |  / NORTH
20               | /
21  WEST         |/
22    -----------|-----------> EAST
23              /|
24             / |
25       SOUTH/  |
26           L   |
27               | DOWN
28 */
29 
30 /// World direction
31 enum Dir : ubyte {
32     NORTH = 0, /// z--
33     SOUTH,     /// z++
34     EAST,      /// x++
35     WEST,      /// x--
36     UP,        /// y++
37     DOWN,      /// y--
38 }
39 
40 // 26 direction masks based on Dir
41 enum DirMask : ubyte {
42     MASK_NORTH = (1 << Dir.NORTH),
43     MASK_SOUTH = (1 << Dir.SOUTH),
44     MASK_EAST = (1 << Dir.EAST),
45     MASK_WEST = (1 << Dir.WEST),
46     MASK_UP = (1 << Dir.UP),
47     MASK_DOWN = (1 << Dir.DOWN),
48     MASK_ALL = 0x3F,
49     //MASK_WEST_UP = (1 << Dir.WEST) | MASK_UP,
50     //MASK_EAST_UP = (1 << Dir.EAST) | MASK_UP,
51     //MASK_WEST_DOWN = (1 << Dir.WEST) | MASK_DOWN,
52     //MASK_EAST_DOWN = (1 << Dir.EAST) | MASK_DOWN,
53     //MASK_NORTH_WEST = MASK_NORTH | MASK_WEST,
54     //MASK_NORTH_EAST = MASK_NORTH | MASK_EAST,
55     //MASK_NORTH_UP = MASK_NORTH | MASK_UP,
56     //MASK_NORTH_DOWN = MASK_NORTH | MASK_DOWN,
57     //MASK_NORTH_WEST_UP = MASK_NORTH | MASK_WEST | MASK_UP,
58     //MASK_NORTH_EAST_UP = MASK_NORTH | MASK_EAST | MASK_UP,
59     //MASK_NORTH_WEST_DOWN = MASK_NORTH | MASK_WEST | MASK_DOWN,
60     //MASK_NORTH_EAST_DOWN = MASK_NORTH | MASK_EAST | MASK_DOWN,
61     //MASK_SOUTH_WEST = MASK_SOUTH | MASK_WEST,
62     //MASK_SOUTH_EAST = MASK_SOUTH | MASK_EAST,
63     //MASK_SOUTH_UP = MASK_SOUTH | MASK_UP,
64     //MASK_SOUTH_DOWN = MASK_SOUTH | MASK_DOWN,
65     //MASK_SOUTH_WEST_UP = MASK_SOUTH | MASK_WEST | MASK_UP,
66     //MASK_SOUTH_EAST_UP = MASK_SOUTH | MASK_EAST | MASK_UP,
67     //MASK_SOUTH_WEST_DOWN = MASK_SOUTH | MASK_WEST | MASK_DOWN,
68     //MASK_SOUTH_EAST_DOWN = MASK_SOUTH | MASK_EAST | MASK_DOWN,
69 }
70 
71 struct Vector2d {
72     int x;
73     int y;
74     this(int xx, int yy) {
75         x = xx;
76         y = yy;
77     }
78     //bool opEqual(Vector2d v) const {
79     //    return x == v.x && y == v.y;
80     //}
81 }
82 
83 immutable Vector2d ZERO2 = Vector2d(0, 0);
84 
85 /// Integer 3d vector: x,y,z
86 struct Vector3d {
87     /// WEST-EAST
88     int x;
89     /// DOWN-UP
90     int y;
91     /// NORTH-SOUTH
92     int z;
93 
94     this(int xx, int yy, int zz) {
95         x = xx;
96         y = yy;
97         z = zz;
98     }
99     //bool opEqual(const Vector3d v) const {
100     //    return x == v.x && y == v.y && z == v.z;
101     //}
102 
103     /// returns vector with all components which are negative of components for this vector
104     Vector3d opUnary(string op : "-")() const {
105         return Vector3d(-x, -y, -z);
106     }
107     /// subtract vectors
108     Vector3d opBinary(string op : "-")(const Vector3d v) const {
109         return Vector3d(x - v.x, y - v.y, z - v.z);
110     }
111     /// add vectors
112     Vector3d opBinary(string op : "+")(const Vector3d v) const {
113         return Vector3d(x + v.x, y + v.y, z + v.z);
114     }
115     ///
116     int opBinary(string op : "*")(const Vector3d v) const {
117         return x*v.x + y*v.y + z*v.z;
118     }
119     /// multiply vector elements by constant
120     Vector3d opBinary(string op : "*")(int n) const {
121         return Vector3d(x * n, y * n, z * n);
122     }
123     /// divide vector elements by constant
124     Vector3d opBinary(string op : "/")(int n) const {
125         return Vector3d(x / n, y / n, z / n);
126     }
127 
128     ///
129     ref Vector3d opOpAssign(string op : "+")(const Vector3d v) {
130         x += v.x;
131         y += v.y;
132         z += v.z;
133         return this;
134     }
135     ///
136     ref Vector3d opOpAssign(string op : "-")(const Vector3d v) {
137         x -= v.x;
138         y -= v.y;
139         z -= v.z;
140         return this;
141     }
142     ///
143     ref Vector3d opOpAssign(string op : "*")(int n) {
144         x *= n;
145         y *= n;
146         z *= n;
147         return this;
148     }
149     Vector3d turnLeft() {
150         return Vector3d(z, y, -x);
151     }
152     Vector3d turnRight() {
153         return Vector3d(-z, y, x);
154     }
155     Vector3d turnUp() {
156         return Vector3d(x, -z, y);
157     }
158     Vector3d turnDown() {
159         return Vector3d(x, z, -y);
160     }
161     Vector3d move(Dir dir) {
162         Vector3d res = this;
163         switch (dir) with(Dir) {
164         case NORTH:
165             res.z--;
166             break;
167         case SOUTH:
168             res.z++;
169             break;
170         case WEST:
171             res.x--;
172             break;
173         case EAST:
174             res.x++;
175             break;
176         case UP:
177             res.y++;
178             break;
179         case DOWN:
180             res.y--;
181             break;
182         default:
183             break;
184         }
185         return res;
186     }
187 
188     int dot(ref Vector3d v) {
189         return x * v.x + y * v.y + z * v.z;
190     }
191 
192     int squaredLength() {
193         return x*x + y*y + z*z;
194     }
195 }
196 
197 __gshared const Vector3d ZERO3 = Vector3d(0, 0, 0);
198 
199 
200 struct Array(T) {
201 private:
202     int _length;
203     T[] _data;
204 public:
205     T * ptr(int index = 0) {
206         return _data.ptr + index;
207     }
208     void swap(ref Array v) {
209         int tmp;
210         tmp = _length; _length = v._length; v._length = tmp;
211         T[] ptmp;
212         ptmp = _data; _data = v._data; v._data = ptmp;
213     }
214     /// ensure capacity is enough to fit sz items
215     void reserve(int sz) {
216         sz += _length;
217         if (_data.length < sz) {
218             int oldsize = cast(int)_data.length;
219             int newsize = 1024;
220             while (newsize < sz)
221                 newsize <<= 1;
222             _data.length = newsize;
223             for (int i = oldsize; i < newsize; i++)
224                 _data.ptr[i] = T.init;
225             _data.assumeSafeAppend();
226         }
227     }
228     @property int length() {
229         return _length;
230     }
231     /// append single item by ref
232     void append(ref const T value) {
233         if (_length >= _data.length)
234             reserve(cast(int)(_data.length == 0 ? 64 : _data.length * 2 - _length));
235         _data.ptr[_length++] = value;
236     }
237     /// append single item by value
238     void append(T value) {
239         if (_length >= _data.length)
240             reserve(cast(int)(_data.length == 0 ? 64 : _data.length * 2 - _length));
241         _data.ptr[_length++] = value;
242     }
243     /// append single item w/o check
244     void appendNoCheck(ref const T value) {
245         _data.ptr[_length++] = value;
246     }
247     /// append single item w/o check
248     void appendNoCheck(T value) {
249         _data.ptr[_length++] = value;
250     }
251     /// appends same value several times, return pointer to appended items
252     T* append(ref const T value, int count) {
253         reserve(count);
254         int startLen = _length;
255         for (int i = 0; i < count; i++)
256             _data.ptr[_length++] = value;
257         return _data.ptr + startLen;
258     }
259     /// appends same value several times, return pointer to appended items
260     T* append(T value, int count) {
261         reserve(count);
262         int startLen = _length;
263         for (int i = 0; i < count; i++)
264             _data.ptr[_length++] = value;
265         return _data.ptr + startLen;
266     }
267     void clear() {
268         _length = 0;
269     }
270     T get(int index) {
271         return _data.ptr[index];
272     }
273     void set(int index, T value) {
274         _data.ptr[index] = value;
275     }
276     ref T opIndex(int index) {
277         return _data.ptr[index];
278     }
279 }
280 
281 alias FloatArray = Array!(float);
282 alias IntArray = Array!(int);
283 alias CellArray = Array!(cell_t);
284 alias Vector2dArray = Array!(Vector2d);
285 alias Vector3dArray = Array!(Vector3d);
286 
287 
288 
289 struct Position {
290     Vector3d pos;
291     Direction direction;
292     this(ref Position p) {
293         pos = p.pos;
294         direction = p.direction;
295     }
296     this(Vector3d position, Vector3d dir) {
297         pos = position;
298         direction = dir;
299     }
300     //Vector2d calcPlaneCoords(Vector3d v) {
301     //    v = v - pos;
302     //    switch (direction.dir) with(Dir) {
303     //        default:
304     //        case NORTH:
305     //            return Vector2d(v.x, v.y);
306     //        case SOUTH:
307     //            return Vector2d(-v.x, v.y);
308     //        case EAST:
309     //            return Vector2d(v.z, v.y);
310     //        case WEST:
311     //            return Vector2d(-v.z, v.y);
312     //        case UP:
313     //            return Vector2d(-v.z, v.x);
314     //        case DOWN:
315     //            return Vector2d(v.z, v.x);
316     //    }
317     //}
318     void turnLeft() {
319         direction.turnLeft();
320     }
321     void turnRight() {
322         direction.turnRight();
323     }
324     void shiftLeft(int step = 1) {
325         pos += direction.left * step;
326     }
327     void shiftRight(int step = 1) {
328         pos += direction.right * step;
329     }
330     void turnUp() {
331         direction.turnUp();
332     }
333     void turnDown() {
334         direction.turnDown();
335     }
336     void forward(int step = 1) {
337         pos += direction.forward * step;
338     }
339     void backward(int step = 1) {
340         pos -= direction.forward * step;
341     }
342     void moveUp(int step = 1) {
343         pos += direction.up * step;
344     }
345     void moveDown(int step = 1) {
346         pos += direction.down * step;
347     }
348     void moveLeft(int step = 1) {
349         pos += direction.left * step;
350     }
351     void moveRight(int step = 1) {
352         pos += direction.right * step;
353     }
354 }
355 
356 
357 /// returns opposite direction to specified direction
358 Dir opposite(Dir d) {
359     return cast(Dir)(d ^ 1);
360 }
361 
362 Dir turnLeft(Dir d) {
363     switch (d) with (Dir) {
364         case WEST:
365             return SOUTH;
366         case EAST:
367             return NORTH;
368         default:
369         case NORTH:
370             return WEST;
371         case SOUTH:
372             return EAST;
373         case UP:
374             return SOUTH;
375         case DOWN:
376             return NORTH;
377     }
378 }
379 
380 Dir turnRight(Dir d) {
381     switch (d) with (Dir) {
382         case WEST:
383             return NORTH;
384         case EAST:
385             return SOUTH;
386         default:
387         case NORTH:
388             return EAST;
389         case SOUTH:
390             return WEST;
391         case UP:
392             return NORTH;
393         case DOWN:
394             return SOUTH;
395     }
396 }
397 
398 Dir turnUp(Dir d) {
399     switch (d) with (Dir) {
400         case WEST:
401             return UP;
402         case EAST:
403             return UP;
404         default:
405         case NORTH:
406             return UP;
407         case SOUTH:
408             return UP;
409         case UP:
410             return SOUTH;
411         case DOWN:
412             return NORTH;
413     }
414 }
415 
416 Dir turnDown(Dir d) {
417     switch (d) with (Dir) {
418         case WEST:
419             return DOWN;
420         case EAST:
421             return DOWN;
422         default:
423         case NORTH:
424             return DOWN;
425         case SOUTH:
426             return DOWN;
427         case UP:
428             return NORTH;
429         case DOWN:
430             return SOUTH;
431     }
432 }
433 
434 
435 struct Direction {
436     this(int x, int y, int z) {
437         set(x, y, z);
438     }
439     this(Vector3d v) {
440         set(v);
441     }
442     this(Dir d) {
443         set(d);
444     }
445     /// returns Y axis rotation angle in degrees (0, 90, 180, 270)
446     @property float angle() {
447         switch (dir) with (Dir) {
448             default:
449             case NORTH:
450                 return 0;
451             case SOUTH:
452                 return 180;
453             case WEST:
454                 return 90;
455             case EAST:
456                 return 270;
457             case UP:
458             case DOWN:
459                 return 0;
460         }
461     }
462     /// set by direction code
463     void set(Dir d) {
464         switch (d) with (Dir) {
465             default:
466             case NORTH:
467                 set(0, 0, -1);
468                 break;
469             case SOUTH:
470                 set(0, 0, 1);
471                 break;
472             case WEST:
473                 set(-1, 0, 0);
474                 break;
475             case EAST:
476                 set(1, 0, 0);
477                 break;
478             case UP:
479                 set(0, 1, 0);
480                 break;
481             case DOWN:
482                 set(0, -1, 0);
483                 break;
484         }
485     }
486     /// set by vector
487     void set(Vector3d v) { set(v.x, v.y, v.z); }
488     /// set by vector
489     void set(int x, int y, int z) {
490         forward = Vector3d(x, y, z);
491         if (x) {
492             dir = (x > 0) ? Dir.EAST : Dir.WEST;
493         }
494         else if (y) {
495             dir = (y > 0) ? Dir.UP : Dir.DOWN;
496         }
497         else {
498             dir = (z > 0) ? Dir.SOUTH : Dir.NORTH;
499         }
500         switch (dir) with (Dir) {
501             case UP:
502                 up = Vector3d(1, 0, 0);
503                 left = Vector3d(0, 0, 1);
504                 break;
505             case DOWN:
506                 up = Vector3d(1, 0, 0);
507                 left = Vector3d(0, 0, -1);
508                 break;
509             default:
510             case NORTH:
511                 up = Vector3d(0, 1, 0);
512                 left = Vector3d(-1, 0, 0);
513                 break;
514             case SOUTH:
515                 up = Vector3d(0, 1, 0);
516                 left = Vector3d(1, 0, 0);
517                 break;
518             case EAST:
519                 up = Vector3d(0, 1, 0);
520                 left = Vector3d(0, 0, -1);
521                 break;
522             case WEST:
523                 up = Vector3d(0, 1, 0);
524                 left = Vector3d(0, 0, 1);
525                 break;
526         }
527         down = -up;
528         right = -left;
529         forwardUp = forward + up;
530         forwardDown = forward + down;
531         forwardLeft = forward + left;
532         forwardLeftUp = forward + left + up;
533         forwardLeftDown = forward + left + down;
534         forwardRight = forward + right;
535         forwardRightUp = forward + right + up;
536         forwardRightDown = forward + right + down;
537     }
538 
539     void turnLeft() {
540         set(.turnLeft(dir));
541     }
542     void turnRight() {
543         set(.turnRight(dir));
544     }
545     void turnUp() {
546         set(.turnUp(dir));
547     }
548     void turnDown() {
549         set(.turnDown(dir));
550     }
551 
552     Dir dir;
553     Vector3d forward;
554     Vector3d up;
555     Vector3d right;
556     Vector3d left;
557     Vector3d down;
558     Vector3d forwardUp;
559     Vector3d forwardDown;
560     Vector3d forwardLeft;
561     Vector3d forwardLeftUp;
562     Vector3d forwardLeftDown;
563     Vector3d forwardRight;
564     Vector3d forwardRightUp;
565     Vector3d forwardRightDown;
566 }
567 
568 /// returns number of bits to store integer
569 int bitsFor(int n) {
570     int res;
571     for (res = 0; n > 0; res++)
572         n >>= 1;
573     return res;
574 }
575 
576 /// returns 0 for 0, 1 for negatives, 2 for positives
577 int mySign(int n) {
578     if (n > 0)
579         return 1;
580     else if (n < 0)
581         return -1;
582     else
583         return 0;
584 }
585 
586 immutable ulong RANDOM_MULTIPLIER  = 0x5DEECE66D;
587 immutable ulong RANDOM_MASK = ((cast(ulong)1 << 48) - 1);
588 immutable ulong RANDOM_ADDEND = cast(ulong)0xB;
589 
590 struct Random {
591     ulong seed;
592     //Random();
593     void setSeed(ulong value) {
594         seed = (value ^ RANDOM_MULTIPLIER) & RANDOM_MASK;
595     }
596 
597     int next(int bits) {
598         seed = (seed * RANDOM_MULTIPLIER + RANDOM_ADDEND) & RANDOM_MASK;
599         return cast(int)(seed >> (48 - bits));
600     }
601 
602     int nextInt() {
603         return next(31);
604     }
605     int nextInt(int n) {
606         if ((n & -n) == n)  // i.e., n is a power of 2
607             return cast(int)((n * cast(long)next(31)) >> 31);
608         int bits, val;
609         do {
610             bits = next(31);
611             val = bits % n;
612         } while (bits - val + (n - 1) < 0);
613         return val;
614     }
615 }
616 
617 __gshared const Vector3d[6] DIRECTION_VECTORS = [
618     Vector3d(0, 0, -1),
619     Vector3d(0, 0, 1),
620     Vector3d(-1, 0, 0),
621     Vector3d(1, 0, 0),
622     Vector3d(0, 1, 0),
623     Vector3d(0, -1, 0)
624 ];
625 
626 /// 3d array[+-size, +-size, +-size] of T
627 struct Array3d(T) {
628     int _size;
629     int _sizeBits;
630     T[] _cells;
631     void reset(int size) {
632         if (size == 0) {
633             // just clear storage
634             _cells = null;
635             _size = 0;
636             _sizeBits = 0;
637             return;
638         }
639         _size = size;
640         _sizeBits = bitsFor(size) + 1;
641         int arraySize = 1 << (_sizeBits * 3);
642         if (_cells.length < arraySize)
643             _cells.length = arraySize;
644         foreach(ref cell; _cells)
645             cell = T.init;
646     }
647     ref T opIndex(int x, int y, int z) {
648         int index = (x + _size) + ((y + _size) << _sizeBits) + ((z + _size) << (_sizeBits + _sizeBits));
649         return _cells[index];
650     }
651     T * ptr(int x, int y, int z) {
652         int index = (x + _size) + ((y + _size) << _sizeBits) + ((z + _size) << (_sizeBits + _sizeBits));
653         return &_cells[index];
654     }
655 }
656