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 
124     /// 
125     ref Vector3d opOpAssign(string op : "+")(const Vector3d v) {
126         x += v.x;
127         y += v.y;
128         z += v.z;
129         return this;
130     }
131     /// 
132     ref Vector3d opOpAssign(string op : "-")(const Vector3d v) {
133         x -= v.x;
134         y -= v.y;
135         z -= v.z;
136         return this;
137     }
138     /// 
139     ref Vector3d opOpAssign(string op : "*")(int n) {
140         x *= n;
141         y *= n;
142         z *= n;
143         return this;
144     }
145     Vector3d turnLeft() {
146         return Vector3d(z, y, -x);
147     }
148     Vector3d turnRight() {
149         return Vector3d(-z, y, x);
150     }
151     Vector3d turnUp() {
152         return Vector3d(x, -z, y);
153     }
154     Vector3d turnDown() {
155         return Vector3d(x, z, -y);
156     }
157     Vector3d move(Dir dir) {
158         Vector3d res = this;
159         switch (dir) with(Dir) {
160         case NORTH:
161             res.z--;
162             break;
163         case SOUTH:
164             res.z++;
165             break;
166         case WEST:
167             res.x--;
168             break;
169         case EAST:
170             res.x++;
171             break;
172         case UP:
173             res.y++;
174             break;
175         case DOWN:
176             res.y--;
177             break;
178         default:
179             break;
180         }
181         return res;
182     }
183 
184     int dot(ref Vector3d v) {
185         return x * v.x + y * v.y + z * v.z;
186     }
187 
188     int squaredLength() {
189         return x*x + y*y + z*z;
190     }
191 }
192 
193 __gshared const Vector3d ZERO3 = Vector3d(0, 0, 0);
194 
195 
196 struct Array(T) {
197 private:
198     int _length;
199     T[] _data;
200 public:
201     T * ptr(int index = 0) {
202         return _data.ptr + index;
203     }
204     void swap(ref Array v) {
205         int tmp;
206         tmp = _length; _length = v._length; v._length = tmp;
207         T[] ptmp;
208         ptmp = _data; _data = v._data; v._data = ptmp;
209     }
210     /// ensure capacity is enough to fit sz items
211     void reserve(int sz) {
212         sz += _length;
213         if (_data.length < sz) {
214             int oldsize = cast(int)_data.length;
215             int newsize = 1024;
216             while (newsize < sz)
217                 newsize <<= 1;
218             _data.length = newsize;
219             for (int i = oldsize; i < newsize; i++)
220                 _data.ptr[i] = T.init;
221             _data.assumeSafeAppend();
222         }
223     }
224     @property int length() {
225         return _length;
226     }
227     /// append single item by ref
228     void append(ref const T value) {
229         if (_length >= _data.length)
230             reserve(cast(int)(_data.length == 0 ? 64 : _data.length * 2 - _length));
231         _data.ptr[_length++] = value;
232     }
233     /// append single item by value
234     void append(T value) {
235         if (_length >= _data.length)
236             reserve(cast(int)(_data.length == 0 ? 64 : _data.length * 2 - _length));
237         _data.ptr[_length++] = value;
238     }
239     /// append single item w/o check
240     void appendNoCheck(ref const T value) {
241         _data.ptr[_length++] = value;
242     }
243     /// append single item w/o check
244     void appendNoCheck(T value) {
245         _data.ptr[_length++] = value;
246     }
247     /// appends same value several times, return pointer to appended items
248     T* append(ref const T value, int count) {
249         reserve(count);
250         int startLen = _length;
251         for (int i = 0; i < count; i++)
252             _data.ptr[_length++] = value;
253         return _data.ptr + startLen;
254     }
255     /// appends same value several times, return pointer to appended items
256     T* append(T value, int count) {
257         reserve(count);
258         int startLen = _length;
259         for (int i = 0; i < count; i++)
260             _data.ptr[_length++] = value;
261         return _data.ptr + startLen;
262     }
263     void clear() {
264         _length = 0;
265     }
266     T get(int index) {
267         return _data.ptr[index];
268     }
269     void set(int index, T value) {
270         _data.ptr[index] = value;
271     }
272     ref T opIndex(int index) {
273         return _data.ptr[index];
274     }
275 }
276 
277 alias FloatArray = Array!(float);
278 alias IntArray = Array!(int);
279 alias CellArray = Array!(cell_t);
280 alias Vector2dArray = Array!(Vector2d);
281 alias Vector3dArray = Array!(Vector3d);
282 
283 
284 
285 struct Position {
286     Vector3d pos;
287     Direction direction;
288     this(ref Position p) {
289         pos = p.pos;
290         direction = p.direction;
291     }
292     this(Vector3d position, Vector3d dir) {
293         pos = position;
294         direction = dir;
295     }
296     //Vector2d calcPlaneCoords(Vector3d v) {
297     //    v = v - pos;
298     //    switch (direction.dir) with(Dir) {
299     //        default:
300     //        case NORTH:
301     //            return Vector2d(v.x, v.y);
302     //        case SOUTH:
303     //            return Vector2d(-v.x, v.y);
304     //        case EAST:
305     //            return Vector2d(v.z, v.y);
306     //        case WEST:
307     //            return Vector2d(-v.z, v.y);
308     //        case UP:
309     //            return Vector2d(-v.z, v.x);
310     //        case DOWN:
311     //            return Vector2d(v.z, v.x);
312     //    }
313     //}
314     void turnLeft() {
315         direction.turnLeft();
316     }
317     void turnRight() {
318         direction.turnRight();
319     }
320     void shiftLeft(int step = 1) {
321         pos += direction.left * step;
322     }
323     void shiftRight(int step = 1) {
324         pos += direction.right * step;
325     }
326     void turnUp() {
327         direction.turnUp();
328     }
329     void turnDown() {
330         direction.turnDown();
331     }
332     void forward(int step = 1) {
333         pos += direction.forward * step;
334     }
335     void backward(int step = 1) {
336         pos -= direction.forward * step;
337     }
338     void moveUp(int step = 1) {
339         pos += direction.up * step;
340     }
341     void moveDown(int step = 1) {
342         pos += direction.down * step;
343     }
344     void moveLeft(int step = 1) {
345         pos += direction.left * step;
346     }
347     void moveRight(int step = 1) {
348         pos += direction.right * step;
349     }
350 }
351 
352 
353 /// returns opposite direction to specified direction
354 Dir opposite(Dir d) {
355     return cast(Dir)(d ^ 1);
356 }
357 
358 Dir turnLeft(Dir d) {
359     switch (d) with (Dir) {
360         case WEST:
361             return SOUTH;
362         case EAST:
363             return NORTH;
364         default:
365         case NORTH:
366             return WEST;
367         case SOUTH:
368             return EAST;
369         case UP:
370             return SOUTH;
371         case DOWN:
372             return NORTH;
373     }
374 }
375 
376 Dir turnRight(Dir d) {
377     switch (d) with (Dir) {
378         case WEST:
379             return NORTH;
380         case EAST:
381             return SOUTH;
382         default:
383         case NORTH:
384             return EAST;
385         case SOUTH:
386             return WEST;
387         case UP:
388             return NORTH;
389         case DOWN:
390             return SOUTH;
391     }
392 }
393 
394 Dir turnUp(Dir d) {
395     switch (d) with (Dir) {
396         case WEST:
397             return UP;
398         case EAST:
399             return UP;
400         default:
401         case NORTH:
402             return UP;
403         case SOUTH:
404             return UP;
405         case UP:
406             return SOUTH;
407         case DOWN:
408             return NORTH;
409     }
410 }
411 
412 Dir turnDown(Dir d) {
413     switch (d) with (Dir) {
414         case WEST:
415             return DOWN;
416         case EAST:
417             return DOWN;
418         default:
419         case NORTH:
420             return DOWN;
421         case SOUTH:
422             return DOWN;
423         case UP:
424             return NORTH;
425         case DOWN:
426             return SOUTH;
427     }
428 }
429 
430 
431 struct Direction {
432     this(int x, int y, int z) {
433         set(x, y, z);
434     }
435     this(Vector3d v) {
436         set(v);
437     }
438     this(Dir d) {
439         set(d);
440     }
441     /// returns Y axis rotation angle in degrees (0, 90, 180, 270)
442     @property float angle() {
443         switch (dir) with (Dir) {
444             default:
445             case NORTH:
446                 return 0;
447             case SOUTH:
448                 return 180;
449             case WEST:
450                 return 90;
451             case EAST:
452                 return 270;
453             case UP:
454             case DOWN:
455                 return 0;
456         }
457     }
458     /// set by direction code
459     void set(Dir d) {
460         switch (d) with (Dir) {
461             default:
462             case NORTH:
463                 set(0, 0, -1);
464                 break;
465             case SOUTH:
466                 set(0, 0, 1);
467                 break;
468             case WEST:
469                 set(-1, 0, 0);
470                 break;
471             case EAST:
472                 set(1, 0, 0);
473                 break;
474             case UP:
475                 set(0, 1, 0);
476                 break;
477             case DOWN:
478                 set(0, -1, 0);
479                 break;
480         }
481     }
482     /// set by vector
483     void set(Vector3d v) { set(v.x, v.y, v.z); }
484     /// set by vector
485     void set(int x, int y, int z) {
486         forward = Vector3d(x, y, z);
487         if (x) {
488             dir = (x > 0) ? Dir.EAST : Dir.WEST;
489         }
490         else if (y) {
491             dir = (y > 0) ? Dir.UP : Dir.DOWN;
492         }
493         else {
494             dir = (z > 0) ? Dir.SOUTH : Dir.NORTH;
495         }
496         switch (dir) with (Dir) {
497             case UP:
498                 up = Vector3d(1, 0, 0);
499                 left = Vector3d(0, 0, 1);
500                 break;
501             case DOWN:
502                 up = Vector3d(1, 0, 0);
503                 left = Vector3d(0, 0, -1);
504                 break;
505             default:
506             case NORTH:
507                 up = Vector3d(0, 1, 0);
508                 left = Vector3d(-1, 0, 0);
509                 break;
510             case SOUTH:
511                 up = Vector3d(0, 1, 0);
512                 left = Vector3d(1, 0, 0);
513                 break;
514             case EAST:
515                 up = Vector3d(0, 1, 0);
516                 left = Vector3d(0, 0, -1);
517                 break;
518             case WEST:
519                 up = Vector3d(0, 1, 0);
520                 left = Vector3d(0, 0, 1);
521                 break;
522         }
523         down = -up;
524         right = -left;
525         forwardUp = forward + up;
526         forwardDown = forward + down;
527         forwardLeft = forward + left;
528         forwardLeftUp = forward + left + up;
529         forwardLeftDown = forward + left + down;
530         forwardRight = forward + right;
531         forwardRightUp = forward + right + up;
532         forwardRightDown = forward + right + down;
533     }
534 
535     void turnLeft() {
536         set(.turnLeft(dir));
537     }
538     void turnRight() {
539         set(.turnRight(dir));
540     }
541     void turnUp() {
542         set(.turnUp(dir));
543     }
544     void turnDown() {
545         set(.turnDown(dir));
546     }
547 
548     Dir dir;
549     Vector3d forward;
550     Vector3d up;
551     Vector3d right;
552     Vector3d left;
553     Vector3d down;
554     Vector3d forwardUp;
555     Vector3d forwardDown;
556     Vector3d forwardLeft;
557     Vector3d forwardLeftUp;
558     Vector3d forwardLeftDown;
559     Vector3d forwardRight;
560     Vector3d forwardRightUp;
561     Vector3d forwardRightDown;
562 }
563 
564 /// returns number of bits to store integer
565 int bitsFor(int n) {
566     int res;
567     for (res = 0; n > 0; res++)
568         n >>= 1;
569     return res;
570 }
571 
572 /// returns 0 for 0, 1 for negatives, 2 for positives
573 int mySign(int n) {
574     if (n > 0)
575         return 1;
576     else if (n < 0)
577         return -1;
578     else
579         return 0;
580 }
581 
582 immutable ulong RANDOM_MULTIPLIER  = 0x5DEECE66D;
583 immutable ulong RANDOM_MASK = ((cast(ulong)1 << 48) - 1);
584 immutable ulong RANDOM_ADDEND = cast(ulong)0xB;
585 
586 struct Random {
587     ulong seed;
588     //Random();
589     void setSeed(ulong value) {
590         seed = (value ^ RANDOM_MULTIPLIER) & RANDOM_MASK;
591     }
592 
593     int next(int bits) {
594         seed = (seed * RANDOM_MULTIPLIER + RANDOM_ADDEND) & RANDOM_MASK;
595         return cast(int)(seed >> (48 - bits));
596     }
597 
598     int nextInt() {
599         return next(31);
600     }
601     int nextInt(int n) {
602         if ((n & -n) == n)  // i.e., n is a power of 2
603             return cast(int)((n * cast(long)next(31)) >> 31);
604         int bits, val;
605         do {
606             bits = next(31);
607             val = bits % n;
608         } while (bits - val + (n - 1) < 0);
609         return val;
610     }
611 }
612 
613 __gshared const Vector3d[6] DIRECTION_VECTORS = [
614     Vector3d(0, 0, -1),
615     Vector3d(0, 0, 1),
616     Vector3d(-1, 0, 0),
617     Vector3d(1, 0, 0),
618     Vector3d(0, 1, 0),
619     Vector3d(0, -1, 0)
620 ];
621 
622 /// 3d array[+-size, +-size, +-size] of T
623 struct Array3d(T) {
624     int _size;
625     int _sizeBits;
626     T[] _cells;
627     void reset(int size) {
628         if (size == 0) {
629             // just clear storage
630             _cells = null;
631             _size = 0;
632             _sizeBits = 0;
633             return;
634         }
635         _size = size;
636         _sizeBits = bitsFor(size) + 1;
637         int arraySize = 1 << (_sizeBits * 3);
638         if (_cells.length < arraySize)
639             _cells.length = arraySize;
640         foreach(ref cell; _cells)
641             cell = T.init;
642     }
643     ref T opIndex(int x, int y, int z) {
644         int index = (x + _size) + ((y + _size) << _sizeBits) + ((z + _size) << (_sizeBits + _sizeBits));
645         return _cells[index];
646     }
647     T * ptr(int x, int y, int z) {
648         int index = (x + _size) + ((y + _size) << _sizeBits) + ((z + _size) << (_sizeBits + _sizeBits));
649         return &_cells[index];
650     }
651 }
652