Challenge: Make a data type for holding one of 8 directions allowing increment and overflow

Liam McGillivray yoshi.pit.link.mario at gmail.com
Thu Mar 14 01:01:37 UTC 2024


On Tuesday, 12 March 2024 at 06:38:28 UTC, Richard (Rikki) Andrew 
Cattermole wrote:
> By taking advantage of integer wrapping and a bitwise and, its 
> quite a simple problem to solve!
>
> Challenge for the reader: add support for binary operations and 
> toString support.

Last night I pushed the latest commit to the GitHub repository 
for my game. It contains the `Direction` struct in 
[`source/common.d`](https://github.com/LiamM32/Open_Emblem/blob/master/source/common.d). Here it is:

```
struct Direction //One of 8 directions stored in 3 bits
{
     import std.conv;
     import std.traits: isNumeric;

     bool[3] b;

     static Direction N = Direction(b:[false,false,false]);
     static Direction NE = Direction(b:[true,false,false]);
     static Direction E = Direction(b:[false,true,false]);
     static Direction SE = Direction(b:[true,true,false]);
     static Direction S = Direction(b:[false,false,true]);
     static Direction SW = Direction(b:[true,false,true]);
     static Direction W = Direction(b:[false,true,true]);
     static Direction NW = Direction(b:[true,true,true]);

     ref Direction opUnary(string op)() if (op == "++" || op == 
"--") {
         static if (op == "++") const bool up = true;
         else const bool up = false;

         if (b[0]) {
             if (b[1]) b[2] = !b[2];
             b[1] = !b[1];
         }
         b[0] = !b[0];
         return this;
     }

     void opOpAssign(string op)(int amount) if (op == "+" || op == 
"-") {
         amount = amount%8;
         if (amount > 0) for (uint i = 0; i < amount; i++) {
             static if (op=="+") this++;
             else this--;
         } else for (uint i=0; i > amount; i--) {
             static if (op=="+") this--;
             else this++;
         }
     }

     T to(T)() const if(isNumeric!T) {
         return cast(T)(b[0] + 2*b[1] + 4*b[2]);
     }

     T opCast(T)() if (isNumeric!T) {
         return cast(T)(b[0] + 2*b[1] + 4*b[2]);
     }

     T to(T)() const if(is(T==string)) {
         if (this==Direction.N) return "north";
         else if (this==Direction.NE) return "northeast";
         else if (this==Direction.E) return "east";
         else if (this==Direction.SE) return "southeast";
         else if (this==Direction.S) return "south";
         else if (this==Direction.SW) return "southwest";
         else if (this==Direction.W) return "west";
         else if (this==Direction.NW) return "northwest";
         else throw new Exception("Direction.to!: direction has a 
value that should be impossible.");
         //else return ""; //This should never happen.
     }

     bool[3] opCast() const {
         return this.b;
     }

     Direction opposite() const {
         return Direction([b[0], b[1], !b[2]]);
     }

     bool diagonal() {
         return b[0];
     }

     int getAngle() {
         if (this==Direction.N) return 0;
         else if (this==Direction.NE) return 45;
         else if (this==Direction.E) return 90;
         else if (this==Direction.SE) return 135;
         else if (this==Direction.S) return 180;
         else if (this==Direction.SW) return 225;
         else if (this==Direction.W) return 270;
         else if (this==Direction.NW) return 315;
         else throw new Exception("Direction.getAngle: direction 
has a value that should be impossible.");
     }
}
```

The one thing that cant be done on this is doing `direction+8`. 
Perhaps it would have been easier if I had chosen to store the 
value as a ubyte rather than an array of bools. While this is 
probably over-optimized given the large amount of memory in 
today's computers, I like it that it can never be an illegitimate 
value.

There's probably some trick I can use to make it easier to figure 
out the functions to do numerical operations on bits, but I don't 
know how best to cleanly represent this kind of thing in code. 
Maybe I need to look for examples of how it's already done.

I noticed among the options for overloading unary operations are 
the symbols "+" & "-". What operation is being overloaded with 
the function `ref Direction opUnary(string op:"+")(int amount)`?


More information about the Digitalmars-d-learn mailing list