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

Liam McGillivray yoshi.pit.link.mario at gmail.com
Tue Mar 12 22:00:58 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.
>
> https://dlang.org/spec/operatoroverloading.html
>
> ```d
> struct Direction {
>     private int value;
>
>     Direction opUnary(string op:"++")() {
>         value++;
>         value &= 7;
>         return this;
>     }
>
>     Direction opUnary(string op:"--")() {
>         value--;
>         value &= 7;
>         return this;
>     }
>
>     void opOpAssign(string op:"+")(int amount) {
>         value += amount;
>         value &= 7;
>     }
>
>     void opOpAssign(string op:"-")(int amount) {
>         value -= amount;
>         value &= 7;
>     }
>
>     enum Direction N = Direction(0);
>     enum Direction NE = Direction(1);
>     enum Direction E = Direction(2);
>     enum Direction SE = Direction(3);
>     enum Direction S = Direction(4);
>     enum Direction SW = Direction(5);
>     enum Direction W = Direction(6);
>     enum Direction NW = Direction(7);
> }
>
> unittest {
>      Direction direction = Direction.N;
>      direction++;
>      assert(direction == Direction.NE);
>      direction+=3;
>      assert(direction == Direction.S);
>      direction--;
>      assert(direction == Direction.SE);
>      direction-=4;
>      assert(direction == Direction.NW);
> }
> ```

Interesting. I didn't know that an enum can be defined inside a 
struct like that. I had used functions to get around it.

Here is what I had already mostly written, using help from 
ChatGPT (but only for the opUnary syntax, not the algorithm):
```
struct Direction //One of 8 directions stored in 3 bits
{
     bool[3] d;

     static Direction N() { return 
Direction(d:[false,false,false]); }
     static Direction NE() { return 
Direction(d:[false,false,true]); }
     static Direction E() { return 
Direction(d:[false,true,false]); }
     static Direction SE() { return 
Direction(d:[false,true,true]); }
     static Direction S() { return 
Direction(d:[true,false,false]); }
     static Direction SW() { return 
Direction(d:[true,false,true]); }
     static Direction W() { return Direction(d:[true,true,false]); 
}
     static Direction NW() { return Direction(d:[true,true,true]); 
}

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

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

     auto to(T)() const {
         return cast(T)(d[0] + 2*d[1] + 4*d[2]);
     }
}
```

I am not entirely sure how well it works. I will come back later 
with an updated version with more functions.

I'm not familiar with the syntax of the line `value &= 7;`. Is it 
equivalent to writing `value = value % 7;`?

Anyway, you used an int, but I used an array of 3 bools. I'm 
guessing that mine uses less memory, but I'm not sure how memory 
it adds when it's a struct with functions.


More information about the Digitalmars-d-learn mailing list