Repository navigation
Expand file tree
/
Copy pathComponentTemplate.hpp
More file actions
175 lines (141 loc) · 4.94 KB
/
Copy pathComponentTemplate.hpp
File metadata and controls
175 lines (141 loc) · 4.94 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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#pragma once
#include "LifeAPI.hpp"
#include "LifeHistory.hpp"
#include "Symmetry.hpp"
#include "NeighbourCount.hpp"
#include "Component.hpp"
struct ComponentTemplate {
LifeState base;
LifeState knownOff;
NeighbourCount count; // This should be more refined and use a full LifeStable
GliderSet gliderSet;
LifeState out;
static ComponentTemplate FromComponent(const Component &component);
LifeState MatchReverse(const LifeState &state, const NeighbourCount &count) const;
LifeState MatchReverse(const LifeState &state) const;
ComponentTemplate Transformed(SymmetryTransform t) const;
ComponentTemplate Moved(std::pair<int, int> p) const;
void NormalisePosition();
// Try to shift glider set to fit in 64x64 torus without wrapping
void ShiftToFitTorus();
uint64_t GetHashNonSymmetrised() const;
uint64_t GetHash() const;
// Debugging only:
std::string RLE() const;
};
ComponentTemplate ComponentTemplate::FromComponent(const Component &component) {
LifeState state = component.Realise();
LifeState everActive;
NeighbourCount startCount(state);
LifeState everDifferentNeighbours;
LifeState everMoreThanOne;
unsigned gen = 0;
bool done = false;
while (!done) {
LifeState prev = state;
NeighbourCount count(state);
everActive |= state ^ component.base;
everDifferentNeighbours |= count.Difference(startCount);
everMoreThanOne |= count.bit1 | count.bit2 | count.bit3;
state.Step();
gen++;
if (state == prev)
done = true;
if (gen > 300)
throw std::runtime_error("Component took too long");
}
LifeState glancing = ~everActive & everActive.ZOI() & (startCount.bit0 & ~startCount.bit1 & ~startCount.bit1);
LifeState relevant = everActive.ZOI() & everDifferentNeighbours & everMoreThanOne & ~glancing;
NeighbourCount count(state);
count.bit0 &= relevant;
count.bit1 &= relevant;
count.bit2 &= relevant;
count.bit3 &= relevant;
LifeState knownOff = ~component.base & ~component.out & everActive.ZOI();
return {component.base & relevant,
knownOff,
count,
component.gliderSet,
component.out & relevant};
}
LifeState ComponentTemplate::MatchReverse(const LifeState &state, const NeighbourCount &stateCount) const {
LifeState candidates = state.MatchLiveAndDead(out, knownOff);
if(candidates.IsEmpty())
return LifeState();
candidates &= stateCount.bit0.MatchLive(count.bit0);
if(candidates.IsEmpty())
return LifeState();
candidates &= stateCount.bit1.MatchLive(count.bit1);
if(candidates.IsEmpty())
return LifeState();
candidates &= stateCount.bit2.MatchLive(count.bit2);
return candidates;
}
LifeState ComponentTemplate::MatchReverse(const LifeState &state) const {
NeighbourCount stateCount(state);
return MatchReverse(state, stateCount);
}
ComponentTemplate ComponentTemplate::Transformed(SymmetryTransform t) const {
return {
base.Transformed(t),
knownOff.Transformed(t),
count.Transformed(t),
gliderSet.Transformed(t),
out.Transformed(t),
};
}
ComponentTemplate ComponentTemplate::Moved(std::pair<int, int> p) const {
return {
base.Moved(p),
knownOff.Moved(p),
count.Moved(p),
gliderSet.Moved(p),
out.Moved(p),
};
}
void ComponentTemplate::NormalisePosition() {
std::array<int, 4> bounds = base.XYBounds();
if (base.IsEmpty())
bounds = out.XYBounds();
*this = Moved({-bounds[0], -bounds[1]});
}
void ComponentTemplate::ShiftToFitTorus() {
auto offset = gliderSet.OffsetToFitTorus();
*this = Moved(offset);
}
uint64_t ComponentTemplate::GetHashNonSymmetrised() const {
uint64_t hash = base.GetHash();
// hash = combine_hashes(hash, knownOff.GetHash());
hash = combine_hashes(hash, out.GetHash());
hash = combine_hashes(hash, count.bit0.GetHash());
hash = combine_hashes(hash, count.bit1.GetHash());
hash = combine_hashes(hash, count.bit2.GetHash());
return hash;
}
uint64_t ComponentTemplate::GetHash() const {
// Calculate hash for all orientations and use the minimum
uint64_t minHash = 0;
using enum SymmetryTransform;
for (auto transform : {Identity, ReflectAcrossX, ReflectAcrossYeqX, ReflectAcrossY,
Rotate90, Rotate180OddBoth, Rotate270, ReflectAcrossYeqNegXP1}) {
ComponentTemplate transformedTempl = Transformed(transform);
transformedTempl.NormalisePosition();
uint64_t hash = transformedTempl.GetHashNonSymmetrised();
if (minHash == 0 || hash < minHash) {
minHash = hash;
}
}
return minHash;
}
std::string ComponentTemplate::RLE() const {
// LifeState marked = count.bit3 | count.bit2 | count.bit1 | count.bit0;
// LifeState original = base & out;
// marked &= ~original;
// LifeHistory history(base | gliderSet.Realise(), LifeState(), marked, original);
// return history.RLEWHeader();
// LifeState marked = out;
// LifeState original = base & out;
// marked &= ~original;
LifeHistory history(base | gliderSet.Realise(), LifeState(), out);
return history.RLEWHeader();
}