假设我有一个枚举Direction
,用于指定基数(和心轴间)方向:
public enum Direction
{
None = 0,
Up = 1 << 1,
Down = 1 << 2,
Left = 1 << 3,
Right = 1 << 4,
UpLeft = Up | Left,
UpRight = Up | Right,
DownLeft = Down | Left,
DownRight = Down | Right
}
在不引入冲突方向(向上和向下)的情况下,为了反转任意方向,我可以执行的最短逐位运算是什么?
我知道我可以使用第三语句来有效地处理这个问题
public Direction Inverse (Direction d) {
// Inverse of Direction.None should still be none
if (d == Direction.None) { return d; }
Direction dInvert = (d.HasFlag(Direction. Up)) ? Direction.Down : Direction.Up;
dInvert |= (d.HasFlag(Direction.Left)) ? Direction.Right : Direction.Left;
return dInvert;
}
但我宁愿学习如何处理这种对称的枚举反转&#34;用二元运算符。如果没有代码打高尔夫,我能想到的最好的是
dir ^ (Direction.Up | Direction.Down)
但这显然只有在dir
不包含任何横向&#39;组件的情况下才有效。&#39;
答案 0 :(得分:7)
枚举应该如下所示(从1 << 0 == 1
开始减少一个):
public enum Direction
{
None = 0,
Up = 1 << 0,
Down = 1 << 1,
Left = 1 << 2,
Right = 1 << 3,
UpLeft = Up | Left,
UpRight = Up | Right,
DownLeft = Down | Left,
DownRight = Down | Right
}
让我们分析不同的可能性。这是一个包含标志和相应反转(仅最后8位)的表
+-----------+----------------+----------------+
| Direction | Flags | Inverted |
+---------------------------------------------+
| None | 0000 0000 = 0 | 0000 0000 = 0 |
| Up | 0000 0001 = 1 | 0000 0010 = 2 |
| Down | 0000 0010 = 2 | 0000 0001 = 1 |
| Left | 0000 0100 = 4 | 0000 1000 = 8 |
| Right | 0000 1000 = 8 | 0000 0100 = 4 |
| UpLeft | 0000 0101 = 5 | 0000 1010 = 10 |
| UpRight | 0000 1001 = 9 | 0000 0110 = 6 |
| DownLeft | 0000 0110 = 6 | 0000 1001 = 9 |
| DownRight | 0000 1010 = 10 | 0000 0101 = 5 |
+-----------+----------------+----------------+
组合方向可以用~dir & 0b1111
反转,但我没有看到简单方向的简单按位操作。
让我们看一下十进制值。我们可以尝试推断一个函数。
inv.
^
10 | X
9 | X
8 | X
7 |
6 | X
5 | X
4 | X
3 |
2 | X
1 | X
0 X--+--+--+--+--+--+--+--+--+--+--> flag
0 1 2 3 4 5 6 7 8 9 10
这看起来也不简单。
WolframAlpha可以从这些数字对中插入多项式
结果是:
- (x(x 7 - 40 x 6 + 686 x 5 - 6580 x 4 + 37709 x 3 - 124180 x 2 + 203524 x - 131280))/ 10080
uugh!
我会制作一个反转词典
var inversion = new Dictionary<Direction, Direction> {
[Direction.None] = Direction.None,
[Direction.Up] = Direction.Down,
[Direction.Down] = Direction.Up,
[Direction.Left] = Direction.Right,
[Direction.Right] = Direction.Left,
[Direction.UpLeft] = Direction.DownRight,
[Direction.UpRight] = Direction.DownLeft,
[Direction.DownLeft] = Direction.UpRight,
[Direction.DownRight] = Direction.UpLeft
}
并使用
获得反转方向Direction invDir = inversion[dir];
最后,我发现了一个使用负枚举值的简单解决方案:
如果你这样声明枚举:
public enum Direction
{
None = 0,
Up = 1,
Down = -1,
Left = 4,
Right = -4,
UpLeft = Up + Left,
UpRight = Up + Right,
DownLeft = Down + Left,
DownRight = Down + Right
}
您可以使用二进制补码来取负值
的 ~d + 1
强>
foreach (Direction d in Enum.GetValues(typeof(Direction))) {
Console.WriteLine($"{d} ===> {~d + 1}");
}
打印
无===&gt;无
Up ===&gt;唐氏
DownLeft ===&gt;的UpRight
左===&gt;右
UpLeft ===&gt;彻头彻尾
DownRight ===&gt; UPLEFT
对===&gt;左
UpRight ===&gt; DOWNLEFT
下来===&gt;
仅使用-d
不起作用,因为-
无法应用于枚举。你必须写(Direction)(-((int)dir))
。
答案 1 :(得分:3)
我用两对比特编码方向,一对用于垂直,一对用于水平:
enum Direction
{
None = 0b00_00,
Down = 0b00_01,
Up = 0b00_10,
Right = 0b01_00,
DownRight = 0b01_01,
UpRight = 0b01_10,
Left = 0b10_00,
DownLeft = 0b10_01,
UpLeft = 0b10_10
}
static Direction Inverse(Direction dir)
{
int d = (int)dir;
Direction ret = (Direction)(((d & 0b01_01) << 1) |
((d & 0b10_10) >> 1));
return ret;
}
static bool HasDir(Direction dir, Direction query)
{
return query == (Direction)((int)query & (int)dir);
}
static bool HasUp(Direction dir)
{
return HasDir(dir, Direction.Up);
}
static bool HasDown(Direction dir)
{
return HasDir(dir, Direction.Down);
}
static bool HasRight(Direction dir)
{
return HasDir(dir, Direction.Right);
}
static bool HasLeft(Direction dir)
{
return HasDir(dir, Direction.Left);
}
private static string show(Direction dir)
{
return (HasDown(dir) ? "V" : HasUp(dir) ? "^" : "") +
(HasLeft(dir) ? "<" : HasRight(dir) ? ">" : "");
}
static void Main(string[] args)
{
foreach(Direction dir in Enum.GetValues(typeof(Direction)))
{
Console.WriteLine(show(dir) + " " + show(Inverse(dir)));
}
Console.WriteLine("ciao!");
}
Inverse
操作只需交换两对。
答案 2 :(得分:0)
这是一个可能是什么样子的例子。 Direction
是一个结构,它提供了产生水平和垂直分量的属性,以及一个简单的反演方法。
public enum HorizontalDirection
{
Left = -1,
None = 0,
Right = 1,
}
public enum VerticalDirection
{
Up = -1,
None = 0,
Down = 1,
}
public struct Direction
{
public Direction(HorizontalDirection h) : this(h, VerticalDirection.None) { }
public Direction(VerticalDirection v) : this(HorizontalDirection.None, v) { }
public Direction(HorizontalDirection h, VerticalDirection v)
{
HorizontalComponent = h;
VerticalComponent = v;
}
public HorizontalDirection HorizontalComponent { get; }
public VerticalDirection VerticalComponent { get; }
public Direction Invert() => new Direction(
(HorizontalDirection)(-(int)HorizontalComponent),
(VerticalDirection)(-(int)VerticalComponent));
}