fork download
  1. #include <iostream>
  2. #include <algorithm>
  3. #include <stdexcept>
  4. #include <string>
  5. #include <sstream>
  6. #include <vector>
  7. #include <array>
  8. #include <iomanip>
  9.  
  10. enum class sidename
  11. {
  12. a, b, c, d, x, y
  13. };
  14.  
  15. enum class sidetype
  16. {
  17. phpbenelux, php, phpelephant, dwa
  18. };
  19.  
  20. std::string sidename_str(sidename sn) {
  21. switch (sn) {
  22. case sidename::a: return "a";
  23. case sidename::b: return "b";
  24. case sidename::c: return "c";
  25. case sidename::d: return "d";
  26. case sidename::x: return "x";
  27. case sidename::y: return "y";
  28. }
  29. throw std::runtime_error{"invalid sidename"};
  30. }
  31.  
  32. std::string sidetype_str(sidetype st) {
  33. switch (st) {
  34. case sidetype::phpbenelux: return "phpbenelux";
  35. case sidetype::php: return "php";
  36. case sidetype::phpelephant: return "phpelephant";
  37. case sidetype::dwa: return "dwa";
  38. }
  39. throw std::runtime_error{"invalid sidetype"};
  40. }
  41.  
  42. /**
  43.  * cubes define 6 side types (or pictures)
  44.  *
  45.  * cubes calculate for themselves all possible layouts, meaning
  46.  * if you rotate them into some direction, you get a side, followed by side+1, side+2, side+3.
  47.  * there are a few possibilities: reverse order, and in each layout (or "path") you can start
  48.  * rotating the cube on side, side+1, side+2 or side+4 (starting point "shifts").
  49.  */
  50. class cube
  51. {
  52. public:
  53.  
  54. cube(sidetype a, sidetype b, sidetype c, sidetype d, sidetype x, sidetype y)
  55. : a_{a}, b_{b}, c_{c}, d_{d}, x_{x}, y_{y},
  56. directionnames_({{
  57. {sidename::a, sidename::b, sidename::c, sidename::d},
  58. {sidename::x, sidename::b, sidename::y, sidename::d},
  59. {sidename::a, sidename::y, sidename::c, sidename::x} }}),
  60. directions_({{ {a, b, c, d}, {x, b, y, d}, {a, y, c, x} }})
  61. {
  62. for (int i=0; i<4; i++) {
  63. for (auto &sides : directions_) {
  64. // normal insert
  65. layouts_.push_back(sides);
  66.  
  67. // reverse insert
  68. auto sidesrev = sides;
  69. std::reverse(std::begin(sidesrev), std::end(sidesrev));
  70. layouts_.push_back(sidesrev);
  71.  
  72. // shift all
  73. sidetype temp = sides[0];
  74. for (int i=1; i<=3; i++)
  75. sides[i - 1] = sides[i];
  76. sides[3] = temp;
  77. }
  78. }
  79. }
  80.  
  81. const std::vector<std::array<sidetype, 4>> & layouts() { return layouts_; }
  82.  
  83. private:
  84.  
  85. /**
  86.  * This is how I labeled each sidetype:
  87.  *
  88.  * X = a
  89.  * X X X = x b y
  90.  * X = c
  91.  * X = d
  92. */
  93.  
  94. sidetype a_;
  95. sidetype b_;
  96. sidetype c_;
  97. sidetype d_;
  98. sidetype x_;
  99. sidetype y_;
  100.  
  101. std::array<std::array<sidename, 4>, 3> directionnames_;
  102. std::array<std::array<sidetype, 4>, 3> directions_;
  103. std::vector<std::array<sidetype, 4>> layouts_;
  104. };
  105.  
  106. /**
  107.  * helper class that can see if a given solution is a duplicate from a previous solution
  108.  *
  109.  * if you have a solution that is simply the same one, but rotating in a different direction
  110.  * is not really a new solution. also note the four possible starting point in each layout/path.
  111.  * so it will check if duplicates exist in both forward and backward directions, and for each
  112.  * possible four shifts
  113.  */
  114. class solutions
  115. {
  116. public:
  117. solutions()
  118. {}
  119.  
  120. bool is_dupe(std::array<std::array<sidetype, 4>, 4> temp2)
  121. {
  122. // Check if found solution isn't a duplicate
  123. bool duplicate = false;
  124. for (auto &solution : solutions_) {
  125. for (int j=0; j<8; j++) {
  126. duplicate = true;
  127. int sidenum = 0;
  128. for (auto &side : solution) {
  129. auto &temp = temp2[sidenum++];
  130.  
  131. int count = 0;
  132. int offset = j % 4;
  133. if (j < 4) {
  134. // Check if they are duplicates, as we use offsets of +0, +1, +2, +3 we can
  135. // detect shifted duplicate results.
  136. for (auto i = side.begin(); i != side.end(); i++) {
  137. duplicate = duplicate && temp[(count + offset) % 4] == *i;
  138. count++;
  139. }
  140. }
  141. else {
  142. // Check if they are duplicates simply in reverse order, also with the
  143. // detect for shifted duplicates.
  144. for (auto i = side.rbegin(); i != side.rend(); i++) {
  145. duplicate = duplicate && temp[(count + offset) % 4] == *i;
  146. count++;
  147. }
  148. }
  149. }
  150. if (duplicate)
  151. return true;
  152. }
  153. }
  154.  
  155. // Remember found solution, for duplicates checking
  156. solutions_.push_back(temp2);
  157.  
  158. return false;
  159. }
  160.  
  161. private:
  162. std::vector<std::array<std::array<sidetype, 4>, 4>> solutions_;
  163. };
  164.  
  165. int main (int argc, char *argv[])
  166. {
  167. /*
  168.  * on the sheet:
  169.  *
  170.  * cube 4 (sideways)
  171.  *
  172.  * cube 1, 2, 3
  173. */
  174.  
  175. cube one{
  176. sidetype::dwa,
  177. sidetype::phpelephant,
  178. sidetype::phpbenelux,
  179. sidetype::dwa,
  180. sidetype::php,
  181. sidetype::phpbenelux};
  182.  
  183. cube two{
  184. sidetype::phpelephant,
  185. sidetype::phpbenelux,
  186. sidetype::phpbenelux,
  187. sidetype::phpbenelux,
  188. sidetype::php,
  189. sidetype::dwa};
  190.  
  191. cube three{
  192. sidetype::phpbenelux,
  193. sidetype::dwa,
  194. sidetype::phpelephant,
  195. sidetype::php,
  196. sidetype::dwa,
  197. sidetype::phpelephant};
  198.  
  199. cube four{
  200. sidetype::php,
  201. sidetype::phpelephant,
  202. sidetype::phpbenelux,
  203. sidetype::phpelephant,
  204. sidetype::dwa,
  205. sidetype::php};
  206.  
  207. solutions solution;
  208.  
  209. for (auto &cube1sides : one.layouts()) {
  210. for (auto &cube2sides : two.layouts()) {
  211. for (auto &cube3sides : three.layouts()) {
  212. for (auto &cube4sides : four.layouts()) {
  213.  
  214. // Pictures have to be unique on each four cubes to be considered a unique solution..
  215. bool flag = false;
  216. for (int i=0; i<4; i++) {
  217. // .. Also on each four rotations of course
  218. flag = flag || (!(cube1sides[i] != cube2sides[i] &&
  219. cube1sides[i] != cube3sides[i] &&
  220. cube1sides[i] != cube4sides[i] &&
  221. cube2sides[i] != cube3sides[i] &&
  222. cube2sides[i] != cube4sides[i] &&
  223. cube3sides[i] != cube4sides[i]));
  224. }
  225. if (!flag){
  226. // Skip duplicate solutions
  227. if (solution.is_dupe({cube1sides, cube2sides, cube3sides, cube4sides})) {
  228. continue;
  229. }
  230.  
  231. // Print the result
  232. std::cout << "The cube-layout for the solution:" << std::endl << std::endl;
  233.  
  234. static auto print = [](const std::string &cube, decltype(cube1sides) &sides) {
  235. std::cout << cube << ": "
  236. << " front: " << std::setw(15) << sidetype_str(sides[0]) << ", "
  237. << " up: " << std::setw(15) << sidetype_str(sides[1]) << ", "
  238. << " top: " << std::setw(15) << sidetype_str(sides[2]) << ", "
  239. << " back: " << std::setw(15) << sidetype_str(sides[3])
  240. << std::endl;
  241. };
  242.  
  243. print("cube #1", cube1sides);
  244. print("cube #2", cube2sides);
  245. print("cube #3", cube3sides);
  246. print("cube #4", cube4sides);
  247. }
  248. }}}}
  249. }
Success #stdin #stdout 0s 3440KB
stdin
Standard input is empty
stdout
The cube-layout for the solution:

cube #1: 	front:             php, 	up:	    phpelephant, 	top:        phpbenelux, 	back:              dwa
cube #2: 	front:      phpbenelux, 	up:	            dwa, 	top:       phpelephant, 	back:              php
cube #3: 	front:     phpelephant, 	up:	     phpbenelux, 	top:               dwa, 	back:      phpelephant
cube #4: 	front:             dwa, 	up:	            php, 	top:               php, 	back:       phpbenelux