1 //-----------------------------------------------------------------------------
2 /** @file libpentobi_base/Variant.cpp
3 @author Markus Enzenberger
4 @copyright GNU General Public License version 3 or later */
5 //-----------------------------------------------------------------------------
6
7 #include "Variant.h"
8
9 #include "CallistoGeometry.h"
10 #include "GembloQGeometry.h"
11 #include "NexosGeometry.h"
12 #include "TrigonGeometry.h"
13 #include "libboardgame_base/RectGeometry.h"
14 #include "libboardgame_base/StringUtil.h"
15
16 namespace libpentobi_base {
17
18 using libboardgame_base::trim;
19 using libboardgame_base::to_lower;
20 using libboardgame_base::PointTransfIdent;
21 using libboardgame_base::PointTransfRefl;
22 using libboardgame_base::PointTransfReflRot180;
23 using libboardgame_base::PointTransfRot90;
24 using libboardgame_base::PointTransfRot180;
25 using libboardgame_base::PointTransfRot270;
26 using libboardgame_base::PointTransfRot90Refl;
27 using libboardgame_base::PointTransfRot270Refl;
28 using libboardgame_base::PointTransfTrigonReflRot60;
29 using libboardgame_base::PointTransfTrigonReflRot120;
30 using libboardgame_base::PointTransfTrigonReflRot240;
31 using libboardgame_base::PointTransfTrigonReflRot300;
32 using libboardgame_base::PointTransfTrigonRot60;
33 using libboardgame_base::PointTransfTrigonRot120;
34 using libboardgame_base::PointTransfTrigonRot240;
35 using libboardgame_base::PointTransfTrigonRot300;
36 using libboardgame_base::RectGeometry;
37
38 //-----------------------------------------------------------------------------
39
get_board_type(Variant variant)40 BoardType get_board_type(Variant variant)
41 {
42 BoardType result = BoardType::classic; // Init to avoid compiler warning
43 switch (variant)
44 {
45 case Variant::duo:
46 case Variant::junior:
47 result = BoardType::duo;
48 break;
49 case Variant::classic:
50 case Variant::classic_2:
51 case Variant::classic_3:
52 result = BoardType::classic;
53 break;
54 case Variant::trigon:
55 case Variant::trigon_2:
56 result = BoardType::trigon;
57 break;
58 case Variant::trigon_3:
59 result = BoardType::trigon_3;
60 break;
61 case Variant::nexos:
62 case Variant::nexos_2:
63 result = BoardType::nexos;
64 break;
65 case Variant::callisto:
66 case Variant::callisto_2_4:
67 result = BoardType::callisto;
68 break;
69 case Variant::callisto_2:
70 result = BoardType::callisto_2;
71 break;
72 case Variant::callisto_3:
73 result = BoardType::callisto_3;
74 break;
75 case Variant::gembloq:
76 case Variant::gembloq_2_4:
77 result = BoardType::gembloq;
78 break;
79 case Variant::gembloq_2:
80 result = BoardType::gembloq_2;
81 break;
82 case Variant::gembloq_3:
83 result = BoardType::gembloq_3;
84 break;
85 }
86 return result;
87 }
88
get_geometry(BoardType board_type)89 const Geometry& get_geometry(BoardType board_type)
90 {
91 const Geometry* result = nullptr; // Init to avoid compiler warning
92 switch (board_type)
93 {
94 case BoardType::duo:
95 result = &RectGeometry<Point>::get(14, 14);
96 break;
97 case BoardType::classic:
98 result = &RectGeometry<Point>::get(20, 20);
99 break;
100 case BoardType::trigon:
101 result = &TrigonGeometry::get(9);
102 break;
103 case BoardType::trigon_3:
104 result = &TrigonGeometry::get(8);
105 break;
106 case BoardType::nexos:
107 result = &NexosGeometry::get();
108 break;
109 case BoardType::callisto:
110 result = &CallistoGeometry::get(4);
111 break;
112 case BoardType::callisto_2:
113 result = &CallistoGeometry::get(2);
114 break;
115 case BoardType::callisto_3:
116 result = &CallistoGeometry::get(3);
117 break;
118 case BoardType::gembloq:
119 result = &GembloQGeometry::get(4);
120 break;
121 case BoardType::gembloq_2:
122 result = &GembloQGeometry::get(2);
123 break;
124 case BoardType::gembloq_3:
125 result = &GembloQGeometry::get(3);
126 break;
127 }
128 return *result;
129 }
130
get_geometry(Variant variant)131 const Geometry& get_geometry(Variant variant)
132 {
133 return get_geometry(get_board_type(variant));
134 }
135
get_geometry_type(Variant variant)136 GeometryType get_geometry_type(Variant variant)
137 {
138 GeometryType result = GeometryType::classic; // Init to avoid compiler warning
139 switch (variant)
140 {
141 case Variant::classic:
142 case Variant::classic_2:
143 case Variant::classic_3:
144 case Variant::duo:
145 case Variant::junior:
146 result = GeometryType::classic;
147 break;
148 case Variant::trigon:
149 case Variant::trigon_2:
150 case Variant::trigon_3:
151 result = GeometryType::trigon;
152 break;
153 case Variant::nexos:
154 case Variant::nexos_2:
155 result = GeometryType::nexos;
156 break;
157 case Variant::callisto:
158 case Variant::callisto_2:
159 case Variant::callisto_2_4:
160 case Variant::callisto_3:
161 result = GeometryType::callisto;
162 break;
163 case Variant::gembloq:
164 case Variant::gembloq_2:
165 case Variant::gembloq_2_4:
166 case Variant::gembloq_3:
167 result = GeometryType::gembloq;
168 break;
169 }
170 return result;
171 }
172
get_nu_colors(Variant variant)173 Color::IntType get_nu_colors(Variant variant)
174 {
175 Color::IntType result = 0; // Init to avoid compiler warning
176 switch (variant)
177 {
178 case Variant::duo:
179 case Variant::junior:
180 case Variant::callisto_2:
181 case Variant::gembloq_2:
182 result = 2;
183 break;
184 case Variant::trigon_3:
185 case Variant::callisto_3:
186 case Variant::gembloq_3:
187 result = 3;
188 break;
189 case Variant::classic:
190 case Variant::classic_2:
191 case Variant::classic_3:
192 case Variant::trigon:
193 case Variant::trigon_2:
194 case Variant::nexos:
195 case Variant::nexos_2:
196 case Variant::callisto:
197 case Variant::callisto_2_4:
198 case Variant::gembloq:
199 case Variant::gembloq_2_4:
200 result = 4;
201 break;
202 }
203 return result;
204 }
205
get_nu_players(Variant variant)206 Color::IntType get_nu_players(Variant variant)
207 {
208 Color::IntType result = 0; // Init to avoid compiler warning
209 switch (variant)
210 {
211 case Variant::duo:
212 case Variant::junior:
213 case Variant::classic_2:
214 case Variant::trigon_2:
215 case Variant::nexos_2:
216 case Variant::callisto_2:
217 case Variant::callisto_2_4:
218 case Variant::gembloq_2:
219 case Variant::gembloq_2_4:
220 result = 2;
221 break;
222 case Variant::classic_3:
223 case Variant::trigon_3:
224 case Variant::callisto_3:
225 case Variant::gembloq_3:
226 result = 3;
227 break;
228 case Variant::classic:
229 case Variant::trigon:
230 case Variant::nexos:
231 case Variant::callisto:
232 case Variant::gembloq:
233 result = 4;
234 break;
235 }
236 return result;
237 }
238
get_piece_set(Variant variant)239 PieceSet get_piece_set(Variant variant)
240 {
241 PieceSet result = PieceSet::classic; // Init to avoid compiler warning
242 switch (variant)
243 {
244 case Variant::classic:
245 case Variant::classic_2:
246 case Variant::classic_3:
247 case Variant::duo:
248 result = PieceSet::classic;
249 break;
250 case Variant::trigon:
251 case Variant::trigon_2:
252 case Variant::trigon_3:
253 result = PieceSet::trigon;
254 break;
255 case Variant::junior:
256 result = PieceSet::junior;
257 break;
258 case Variant::nexos:
259 case Variant::nexos_2:
260 result = PieceSet::nexos;
261 break;
262 case Variant::callisto:
263 case Variant::callisto_2:
264 case Variant::callisto_2_4:
265 case Variant::callisto_3:
266 result = PieceSet::callisto;
267 break;
268 case Variant::gembloq:
269 case Variant::gembloq_2:
270 case Variant::gembloq_2_4:
271 case Variant::gembloq_3:
272 result = PieceSet::gembloq;
273 break;
274 }
275 return result;
276 }
277
get_transforms(Variant variant,vector<unique_ptr<PointTransform<Point>>> & transforms,vector<unique_ptr<PointTransform<Point>>> & inv_transforms)278 void get_transforms(Variant variant,
279 vector<unique_ptr<PointTransform<Point>>>& transforms,
280 vector<unique_ptr<PointTransform<Point>>>& inv_transforms)
281 {
282 transforms.clear();
283 inv_transforms.clear();
284 transforms.emplace_back(new PointTransfIdent<Point>);
285 inv_transforms.emplace_back(new PointTransfIdent<Point>);
286 switch (get_board_type(variant))
287 {
288 case BoardType::duo:
289 transforms.emplace_back(new PointTransfRot270Refl<Point>);
290 inv_transforms.emplace_back(new PointTransfRot270Refl<Point>);
291 break;
292 case BoardType::trigon:
293 transforms.emplace_back(new PointTransfTrigonRot60<Point>);
294 inv_transforms.emplace_back(new PointTransfTrigonRot300<Point>);
295 transforms.emplace_back(new PointTransfTrigonRot120<Point>);
296 inv_transforms.emplace_back(new PointTransfTrigonRot240<Point>);
297 transforms.emplace_back(new PointTransfRot180<Point>);
298 inv_transforms.emplace_back(new PointTransfRot180<Point>);
299 transforms.emplace_back(new PointTransfTrigonRot240<Point>);
300 inv_transforms.emplace_back(new PointTransfTrigonRot120<Point>);
301 transforms.emplace_back(new PointTransfTrigonRot300<Point>);
302 inv_transforms.emplace_back(new PointTransfTrigonRot60<Point>);
303 transforms.emplace_back(new PointTransfRefl<Point>);
304 inv_transforms.emplace_back(new PointTransfRefl<Point>);
305 transforms.emplace_back(new PointTransfTrigonReflRot60<Point>);
306 inv_transforms.emplace_back(new PointTransfTrigonReflRot60<Point>);
307 transforms.emplace_back(new PointTransfTrigonReflRot120<Point>);
308 inv_transforms.emplace_back(new PointTransfTrigonReflRot120<Point>);
309 transforms.emplace_back(new PointTransfReflRot180<Point>);
310 inv_transforms.emplace_back(new PointTransfReflRot180<Point>);
311 transforms.emplace_back(new PointTransfTrigonReflRot240<Point>);
312 inv_transforms.emplace_back(new PointTransfTrigonReflRot240<Point>);
313 transforms.emplace_back(new PointTransfTrigonReflRot300<Point>);
314 inv_transforms.emplace_back(new PointTransfTrigonReflRot300<Point>);
315 break;
316 case BoardType::callisto_2:
317 case BoardType::callisto:
318 case BoardType::callisto_3:
319 transforms.emplace_back(new PointTransfRot90<Point>);
320 inv_transforms.emplace_back(new PointTransfRot270<Point>);
321 transforms.emplace_back(new PointTransfRot180<Point>);
322 inv_transforms.emplace_back(new PointTransfRot180<Point>);
323 transforms.emplace_back(new PointTransfRot270<Point>);
324 inv_transforms.emplace_back(new PointTransfRot90<Point>);
325 transforms.emplace_back(new PointTransfRefl<Point>);
326 inv_transforms.emplace_back(new PointTransfRefl<Point>);
327 transforms.emplace_back(new PointTransfReflRot180<Point>);
328 inv_transforms.emplace_back(new PointTransfReflRot180<Point>);
329 transforms.emplace_back(new PointTransfRot90Refl<Point>);
330 inv_transforms.emplace_back(new PointTransfRot90Refl<Point>);
331 transforms.emplace_back(new PointTransfRot270Refl<Point>);
332 inv_transforms.emplace_back(new PointTransfRot270Refl<Point>);
333 break;
334 case BoardType::classic:
335 case BoardType::gembloq:
336 case BoardType::gembloq_2:
337 case BoardType::gembloq_3:
338 case BoardType::nexos:
339 case BoardType::trigon_3:
340 break;
341 }
342 }
343
has_central_symmetry(Variant variant)344 bool has_central_symmetry(Variant variant)
345 {
346 return variant == Variant::duo || variant == Variant::junior
347 || variant == Variant::trigon_2 || variant == Variant::callisto_2
348 || variant == Variant::gembloq_2;
349 }
350
parse_variant(const string & s,Variant & variant)351 bool parse_variant(const string& s, Variant& variant)
352 {
353 string t = to_lower(trim(s));
354 if (t == "blokus")
355 variant = Variant::classic;
356 else if (t == "blokus two-player")
357 variant = Variant::classic_2;
358 else if (t == "blokus three-player")
359 variant = Variant::classic_3;
360 else if (t == "blokus trigon")
361 variant = Variant::trigon;
362 else if (t == "blokus trigon two-player")
363 variant = Variant::trigon_2;
364 else if (t == "blokus trigon three-player")
365 variant = Variant::trigon_3;
366 else if (t == "blokus duo")
367 variant = Variant::duo;
368 else if (t == "blokus junior")
369 variant = Variant::junior;
370 else if (t == "nexos")
371 variant = Variant::nexos;
372 else if (t == "nexos two-player")
373 variant = Variant::nexos_2;
374 else if (t == "callisto")
375 variant = Variant::callisto;
376 else if (t == "callisto two-player")
377 variant = Variant::callisto_2;
378 else if (t == "callisto two-player four-color")
379 variant = Variant::callisto_2_4;
380 else if (t == "callisto three-player")
381 variant = Variant::callisto_3;
382 else if (t == "gembloq")
383 variant = Variant::gembloq;
384 else if (t == "gembloq two-player")
385 variant = Variant::gembloq_2;
386 else if (t == "gembloq two-player four-color")
387 variant = Variant::gembloq_2_4;
388 else if (t == "gembloq three-player")
389 variant = Variant::gembloq_3;
390 else
391 return false;
392 return true;
393 }
394
parse_variant_id(const string & s,Variant & variant)395 bool parse_variant_id(const string& s, Variant& variant)
396 {
397 string t = to_lower(trim(s));
398 if (t == "classic" || t == "c")
399 variant = Variant::classic;
400 else if (t == "classic_2" || t == "c2")
401 variant = Variant::classic_2;
402 else if (t == "classic_3" || t == "c3")
403 variant = Variant::classic_3;
404 else if (t == "trigon" || t == "t")
405 variant = Variant::trigon;
406 else if (t == "trigon_2" || t == "t2")
407 variant = Variant::trigon_2;
408 else if (t == "trigon_3" || t == "t3")
409 variant = Variant::trigon_3;
410 else if (t == "duo" || t == "d")
411 variant = Variant::duo;
412 else if (t == "junior" || t == "j")
413 variant = Variant::junior;
414 else if (t == "nexos" || t == "n")
415 variant = Variant::nexos;
416 else if (t == "nexos_2" || t == "n2")
417 variant = Variant::nexos_2;
418 else if (t == "callisto" || t == "ca")
419 variant = Variant::callisto;
420 else if (t == "callisto_2" || t == "ca2")
421 variant = Variant::callisto_2;
422 else if (t == "callisto_2_4" || t == "ca24")
423 variant = Variant::callisto_2_4;
424 else if (t == "callisto_3" || t == "ca3")
425 variant = Variant::callisto_3;
426 else if (t == "gembloq" || t == "g")
427 variant = Variant::gembloq;
428 else if (t == "gembloq_2" || t == "g2")
429 variant = Variant::gembloq_2;
430 else if (t == "gembloq_2_4" || t == "g24")
431 variant = Variant::gembloq_2_4;
432 else if (t == "gembloq_3" || t == "g3")
433 variant = Variant::gembloq_3;
434 else
435 return false;
436 return true;
437 }
438
to_string(Variant variant)439 const char* to_string(Variant variant)
440 {
441 const char* result = nullptr; // Init to avoid compiler warning
442 switch (variant)
443 {
444 case Variant::classic:
445 result = "Blokus";
446 break;
447 case Variant::classic_2:
448 result = "Blokus Two-Player";
449 break;
450 case Variant::classic_3:
451 result = "Blokus Three-Player";
452 break;
453 case Variant::duo:
454 result = "Blokus Duo";
455 break;
456 case Variant::junior:
457 result = "Blokus Junior";
458 break;
459 case Variant::trigon:
460 result = "Blokus Trigon";
461 break;
462 case Variant::trigon_2:
463 result = "Blokus Trigon Two-Player";
464 break;
465 case Variant::trigon_3:
466 result = "Blokus Trigon Three-Player";
467 break;
468 case Variant::nexos:
469 result = "Nexos";
470 break;
471 case Variant::nexos_2:
472 result = "Nexos Two-Player";
473 break;
474 case Variant::callisto:
475 result = "Callisto";
476 break;
477 case Variant::callisto_2:
478 result = "Callisto Two-Player";
479 break;
480 case Variant::callisto_2_4:
481 result = "Callisto Two-Player Four-Color";
482 break;
483 case Variant::callisto_3:
484 result = "Callisto Three-Player";
485 break;
486 case Variant::gembloq:
487 result = "GembloQ";
488 break;
489 case Variant::gembloq_2:
490 result = "GembloQ Two-Player";
491 break;
492 case Variant::gembloq_2_4:
493 result = "GembloQ Two-Player Four-Color";
494 break;
495 case Variant::gembloq_3:
496 result = "GembloQ Three-Player";
497 break;
498 }
499 return result;
500 }
501
to_string_id(Variant variant)502 const char* to_string_id(Variant variant)
503 {
504 const char* result = nullptr; // Init to avoid compiler warning
505 switch (variant)
506 {
507 case Variant::classic:
508 result = "classic";
509 break;
510 case Variant::classic_2:
511 result = "classic_2";
512 break;
513 case Variant::classic_3:
514 result = "classic_3";
515 break;
516 case Variant::duo:
517 result = "duo";
518 break;
519 case Variant::junior:
520 result = "junior";
521 break;
522 case Variant::trigon:
523 result = "trigon";
524 break;
525 case Variant::trigon_2:
526 result = "trigon_2";
527 break;
528 case Variant::trigon_3:
529 result = "trigon_3";
530 break;
531 case Variant::nexos:
532 result = "nexos";
533 break;
534 case Variant::nexos_2:
535 result = "nexos_2";
536 break;
537 case Variant::callisto:
538 result = "callisto";
539 break;
540 case Variant::callisto_2:
541 result = "callisto_2";
542 break;
543 case Variant::callisto_2_4:
544 result = "callisto_2_4";
545 break;
546 case Variant::callisto_3:
547 result = "callisto_3";
548 break;
549 case Variant::gembloq:
550 result = "gembloq";
551 break;
552 case Variant::gembloq_2:
553 result = "gembloq_2";
554 break;
555 case Variant::gembloq_2_4:
556 result = "gembloq_2_4";
557 break;
558 case Variant::gembloq_3:
559 result = "gembloq_3";
560 break;
561 }
562 return result;
563 }
564
565 //-----------------------------------------------------------------------------
566
567 } // namespace libpentobi_base
568