-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPositionSet.cxx
More file actions
140 lines (131 loc) · 3.21 KB
/
Copy pathPositionSet.cxx
File metadata and controls
140 lines (131 loc) · 3.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include "PositionSet.h"
#include <iostream>
#include <iomanip>
std::ostream& operator<<(std::ostream& os, PositionSet const& position_set)
{
os << position_set.name() << ":\n";
for (int z = 3; z >= 0; --z)
for (int x = 0; x <= 3; ++x)
{
os << std::string((3 - x), ' ');
for (int y = 0; y <= 3; ++y)
{
uint64_t bit = (uint64_t)1 << (x + y * 4 + z * 16);
if ((position_set.m_units & bit))
os << " \314\266/";
else
os << " .";
}
os << '\n';
}
return os;
}
void PositionSet::shift_towards(Direction direction)
{
switch (direction.get_index())
{
case x_positive_int:
m_units <<= 1;
break;
case x_negative_int:
m_units >>= 1;
break;
case y_positive_int:
m_units <<= 4;
break;
case y_negative_int:
m_units >>= 4;
break;
case z_positive_int:
m_units <<= 16;
break;
case z_negative_int:
m_units >>= 16;
break;
}
}
PositionSet create_wall(Direction direction)
{
switch (direction.get_index())
{
case x_positive_int:
return PositionSet{(uint64_t)0x1111111111111111 << 3};
case x_negative_int:
return PositionSet{(uint64_t)0x1111111111111111};
case y_positive_int:
return PositionSet{(uint64_t)0xf000f000f000f << 3 * 4};
case y_negative_int:
return PositionSet{(uint64_t)0xf000f000f000f};
case z_positive_int:
return PositionSet{(uint64_t)0xffff << 3 * 16};
case z_negative_int:
return PositionSet{(uint64_t)0xffff};
}
}
std::array<PositionSet, 6> const wall = {
create_wall(x_positive),
create_wall(x_negative),
create_wall(y_positive),
create_wall(y_negative),
create_wall(z_positive),
create_wall(z_negative)
};
void PositionSet::swap_units(PositionSet mask, int distance)
{
uint64_t tmp = mask.m_units & m_units;
if (distance < 0)
{
tmp >>= -distance;
mask.m_units >>= -distance;
}
else
{
tmp <<= distance;
mask.m_units <<= distance;
}
uint64_t diff = tmp ^ (m_units & mask.m_units);
m_units ^= diff;
if (distance < 0)
diff <<= -distance;
else
diff >>= distance;
m_units ^= diff;
}
void PositionSet::invert_axis(Direction direction)
{
PositionSet mask = wall[(~direction).get_index()];
int distance = 3 * direction.step();
swap_units(mask, distance);
mask.shift_towards(direction);
swap_units(mask, direction.step());
}
void PositionSet::swap_axes(Direction direction1, Direction direction2)
{
direction1 = ~direction1;
int const offset = direction1.step() + direction2.step();
PositionSet mask = wall[(~direction1).get_index()] & wall[(~direction2).get_index()];
for (int distance = 3; distance > 0; --distance)
{
swap_units(mask, distance * offset);
PositionSet tmp = mask;
mask.shift_towards(direction1);
tmp.shift_towards(direction2);
mask |= tmp;
}
}
bool PositionSet::shift(Direction direction)
{
if ((*this & wall[direction.get_index()]))
return false;
shift_towards(direction);
return true;
}
void PositionSet::rotate_around(Direction direction)
{
direction = direction.next();
swap_axes(direction, direction.next());
invert_axis(direction);
while (shift(x_negative));
while (shift(y_negative));
while (shift(z_negative));
}