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