Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
PieceJailPlan.cpp
Go to the documentation of this file.
1#include "PieceJailPlan.hpp"
2
3#include "PiecePlacement.hpp"
4
5#include <cmath>
6
7namespace monopoly::pieces
8{
9 namespace
10 {
11 [[nodiscard]] std::expected<InterpolationVec3, PieceJailPlanError>
12 point(std::uint8_t square) noexcept
13 {
14 const auto pose = tokenOrientation(square);
15 if (!pose) return std::unexpected(PieceJailPlanError::MissingGeometry);
16 return InterpolationVec3{pose->x, pose->y, pose->z};
17 }
18
19 [[nodiscard]] std::uint64_t paddyDistanceTicks(
20 std::uint8_t square, std::uint64_t base) noexcept
21 {
22 if (square > 10 && square < 30)
23 return base + 5U * static_cast<std::uint64_t>(square - 10);
24 if (square >= 30)
25 return base + 5U * static_cast<std::uint64_t>(50 - square);
26 return base + 5U * static_cast<std::uint64_t>(10 - square);
27 }
28
29 [[nodiscard]] bool add(PieceInterpolationPath& path, std::size_t index,
30 InterpolationVec3 a, InterpolationVec3 b,
31 InterpolationVec3 c, InterpolationVec3 d,
32 float tangent = BezierTangentDelta) noexcept
33 {
34 return addBezierSegment(path, index, a, b, c, d, tangent);
35 }
36
37 [[nodiscard]] InterpolationVec3 normalize(InterpolationVec3 value) noexcept
38 {
39 const float length = std::sqrt(value.x * value.x +
40 value.y * value.y + value.z * value.z);
41 if (length <= 0.000001F) return {};
42 return value * (1.0F / length);
43 }
44 }
45
46 std::expected<PieceJailRoutePlan, PieceJailPlanError>
47 planPaddyToToken(std::uint8_t tokenSquare, std::uint64_t startTick,
48 std::uint8_t randomBit)
49 {
50 if (tokenSquare >= 40)
51 return std::unexpected(PieceJailPlanError::InvalidSquare);
52
53 PieceJailRoutePlan result{};
54 result.loadSquare = static_cast<std::uint8_t>((tokenSquare + 1U) % 40U);
55 result.path.startTick = startTick;
56 result.path.endTick = startTick + paddyDistanceTicks(tokenSquare, 60U);
57
58 if (tokenSquare == 10)
59 {
60 result.camera = BoardCameraView::FiveTiles03;
61 result.skipMotion = true;
62 result.path.endTick = startTick;
63 return result;
64 }
65
66 const auto token = point(tokenSquare);
67 if (!token) return std::unexpected(token.error());
68 const auto side = tokenSquare / 10U;
69
70 if (side == 0)
71 {
72 const auto p9 = point(9);
73 if (!p9) return std::unexpected(p9.error());
74 auto v1 = *p9; v1.z += 59.0F;
75 auto t4 = *token; t4.z += 39.0F;
76 auto v4 = t4; v4.z += 19.0F;
77 auto v3 = v4; v4.x -= 32.0F; v3.x += 3.0F;
78 const auto v2 = 0.5F * (v1 + v3);
79 if (!add(result.path, 0, v1, v2, v3, v4))
80 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
81 auto t3 = t4; t3.z += 8.0F;
82 if (!add(result.path, 1, v4, v3, t3, t4, -BezierTangentDelta))
83 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
84 result.camera = tokenSquare > 5 ? BoardCameraView::FiveTiles02 :
86 return result;
87 }
88
89 if (side == 1)
90 {
91 const auto jail = point(10);
92 if (!jail) return std::unexpected(jail.error());
93 auto v1 = *jail; v1.x -= 10.0F;
94 auto t4 = *token; t4.x += 39.0F;
95 auto v4 = t4; v4.x -= 78.0F;
96 const auto v2 = 0.7F * v1 + 0.3F * v4;
97 auto v3 = 0.3F * v1 + 0.7F * v4;
98 if (!add(result.path, 0, v1, v2, v3, v4))
99 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
100
101 auto t1 = v4;
102 auto t2 = v4; t2.x += 8.0F;
103 v4 = t4; v4.x -= 39.0F; v4.z += 22.0F;
104 v3 = v4; v3.x -= 8.0F;
105 if (!add(result.path, 1, t1, t2, v3, v4))
106 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
107 auto t3 = t4; t3.x -= 8.0F;
108 if (!addBezierSegmentSmooth(result.path, 2, t3, t4))
109 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
110 result.camera = tokenSquare < 15 ? BoardCameraView::FiveTiles03 :
112 return result;
113 }
114
115 if (side == 2)
116 {
117 const auto jail = point(10);
118 const auto freeParking = point(20);
119 if (!jail) return std::unexpected(jail.error());
120 if (!freeParking) return std::unexpected(freeParking.error());
121 auto v1 = *jail;
122 auto v4 = *freeParking;
123 auto v3 = v4; v3.z += 26.0F; v3.x += 5.0F;
124 const auto v2 = 0.5F * (v3 + v1);
125 if (!add(result.path, 0, v1, v2, v3, v4))
126 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
127
128 v1 = v4;
129 auto t4 = *token; t4.z -= 39.0F;
130 v4 = t4; v4.z += 78.0F;
131 auto b2 = 0.7F * v1 + 0.3F * v4;
132 v3 = 0.3F * v1 + 0.7F * v4;
133 if (!add(result.path, 1, v1, b2, v3, v4))
134 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
135 auto t1 = v4;
136 auto t2 = v4; t2.z -= 8.0F;
137 v4 = t4; v4.z += 39.0F; v4.y += 25.0F;
138 v3 = v4; v3.z += 8.0F;
139 if (!add(result.path, 2, t1, t2, v3, v4))
140 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
141 auto t3 = t4; t3.z += 8.0F;
142 if (!addBezierSegmentSmooth(result.path, 3, t3, t4))
143 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
144 result.camera = tokenSquare < 22 ? BoardCameraView::CornerFreeParking :
147 return result;
148 }
149
150 const auto p9 = point(9);
151 const auto go = point(0);
152 const auto p39 = point(39);
153 if (!p9) return std::unexpected(p9.error());
154 if (!go) return std::unexpected(go.error());
155 if (!p39) return std::unexpected(p39.error());
156 auto v1 = *p9; v1.z += 39.0F;
157 auto v3 = *go;
158 auto v4 = v3;
159 auto v2 = 0.5F * (v1 + v3); v2.x += 5.0F;
160 v4.x -= 16.0F; v4.z -= 16.0F;
161 if (!add(result.path, 0, v1, v2, v3, v4))
162 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
163
164 auto t4 = *token; t4.x -= 39.0F;
165 auto t2 = *p39; t2.x -= 39.0F;
166 auto t3 = 0.5F * (t4 + v3);
167 if (tokenSquare == 39) { t2.x -= 10.0F; t3.x -= 5.0F; }
168 if (!add(result.path, 1, v4, t2, t3, t4, -BezierTangentDelta))
169 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
170 result.camera = tokenSquare == 30 ?
175 return result;
176 }
177
178 std::expected<PieceJailRoutePlan, PieceJailPlanError>
180 InterpolationVec3 startLocation, std::uint64_t startTick)
181 {
182 if (tokenSquare >= 40)
183 return std::unexpected(PieceJailPlanError::InvalidSquare);
184 const auto drop = point(11);
185 if (!drop) return std::unexpected(drop.error());
186
187 PieceJailRoutePlan result{};
188 result.loadSquare = 11;
189 result.path.startTick = startTick;
190 result.path.endTick = startTick + paddyDistanceTicks(tokenSquare, 40U);
191 const auto side = tokenSquare / 10U;
192 const auto v1 = startLocation;
193 const auto t4 = *drop;
194
195 if (side == 0)
196 {
197 const auto jail = point(10);
198 if (!jail) return std::unexpected(jail.error());
199 auto v3 = *jail; v3.x -= 20.0F; v3.z -= 5.0F;
200 const auto v2 = 0.5F * (v1 + v3);
201 if (!add(result.path, 0, v1, v2, v3, t4))
202 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
203 result.camera = BoardCameraView::CornerJail;
204 return result;
205 }
206
207 if (side == 1)
208 {
209 const auto v2 = 0.7F * v1 + 0.3F * t4;
210 const auto v3 = 0.3F * v1 + 0.7F * t4;
211 if (!add(result.path, 0, v1, v2, v3, t4, -BezierTangentDelta))
212 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
213 result.camera = tokenSquare < 14 ? BoardCameraView::ThreeTiles04 :
215 return result;
216 }
217
218 if (side == 2)
219 {
220 const auto freeParking = point(20);
221 if (!freeParking) return std::unexpected(freeParking.error());
222 auto v4 = *freeParking; v4.x += 10.0F; v4.z += 26.0F;
223 auto v3 = *freeParking; v3.z += 16.0F;
224 const auto v2 = 0.6F * v1 + 0.4F * v3;
225 if (!add(result.path, 0, v1, v2, v3, v4, -BezierTangentDelta))
226 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
227
228 const auto t1 = v4;
229 const auto t2 = v3;
230 v3 = t4; v3.x += 20.0F; v3.z -= 5.0F;
231 v4 = t4; v4.z += 20.0F; v4.x += 20.0F;
232 if (!add(result.path, 1, t1, t2, v3, v4))
233 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
234
235 auto t3 = t4; t3.x += 14.0F;
236 const auto c1 = v4;
237 const auto c2 = v4 + 14.0F * normalize(v3 - v4);
238 if (!add(result.path, 2, c1, c2, t3, t4, -BezierTangentDelta))
239 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
240 result.path.lengths[2] *= 2.0F;
241 result.camera = BoardCameraView::FifteenTiles03;
242 return result;
243 }
244
245 const auto go = point(0);
246 const auto jail = point(10);
247 if (!go) return std::unexpected(go.error());
248 if (!jail) return std::unexpected(jail.error());
249 auto v4 = *go;
250 auto v3 = v4; v3.z -= 24.0F; v3.x -= 5.0F;
251 const auto v2 = 0.6F * v1 + 0.4F * v3;
252 if (!add(result.path, 0, v1, v2, v3, v4))
253 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
254 auto t3 = *jail; t3.x -= 34.0F; t3.z += 6.0F;
255 const auto t2 = 0.5F * (v4 + t3);
256 if (!add(result.path, 1, v4, t2, t3, t4))
257 return std::unexpected(PieceJailPlanError::TooManyBezierSegments);
258 result.camera = tokenSquare < 35 ? BoardCameraView::FifteenTiles12 :
260 return result;
261 }
262}
unsigned index
int token
std::string path
std::uint16_t value
Definition Timers.cpp:16
std::optional< TokenPose > tokenOrientation(std::uint8_t boardSquare) noexcept
constexpr float BezierTangentDelta
std::expected< PieceJailRoutePlan, PieceJailPlanError > planPaddyToJail(std::uint8_t tokenSquare, InterpolationVec3 startLocation, std::uint64_t startTick)
bool addBezierSegmentSmooth(PieceInterpolationPath &path, std::size_t index, InterpolationVec3 c, InterpolationVec3 d, float tangentDelta) noexcept
bool addBezierSegment(PieceInterpolationPath &path, std::size_t index, InterpolationVec3 a, InterpolationVec3 b, InterpolationVec3 c, InterpolationVec3 d, float tangentDelta) noexcept
std::expected< PieceJailRoutePlan, PieceJailPlanError > planPaddyToToken(std::uint8_t tokenSquare, std::uint64_t startTick, std::uint8_t randomBit)
BoardCameraView pickCameraFor15Squares(std::int32_t square) noexcept