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
. 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)
?