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