File indexing completed on 2024-04-14 04:02:09
0001 /* 0002 SPDX-FileCopyrightText: 2008 Ian Wadham <iandw.au@gmail.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef CUBE_H 0008 #define CUBE_H 0009 0010 #include <QObject> 0011 0012 #include "kbkglobal.h" 0013 0014 class GameGLView; 0015 0016 class Cubie; // Forward declaration of Cube's component. 0017 0018 // Face-sticker colors are in the order of axes X/Y/Z then -ve/+ve direction. 0019 // INTERNAL is the color of the material of which the cube is made (eg. gray). 0020 enum FaceColor {INTERNAL, LEFT, RIGHT, BOTTOM, TOP, BACK, FRONT}; 0021 0022 /** 0023 * The Cube class represents a Rubik's Cube in an abstract way. 0024 * 0025 * Actually the "cube" is a rectangular parallelepiped, which can have unequal 0026 * sides, like a brick, or can be one layer thick, like a mat. The cube is 0027 * made up of many "cubies" (small cubes) stacked in a 3-D array. The original 0028 * Rubik's Cube was an array of 3x3x3 cubies, but in this version the sides can 0029 * have any number of cubies between 1 and 6, but only one side can be 1 cubie 0030 * long, otherwise the puzzle becomes too easy (e.g. the dimensions can be 0031 * 1x2x2, 6x6x6, 4x1x3, 3x4x5, etc.). 0032 * 0033 * The six faces of the cube are covered in stickers of six different colors. 0034 * Cubies are dark grey, but can have stickers on one, two or three of their 0035 * six faces, depending on whether they are located in the middle of a cube 0036 * face, on a cube edge or at a cube corner. If all cube dimensions are 3 or 0037 * more, some cubies will be hidden and will have no stickers (e.g. a 3x3x3 0038 * cube has one hidden cubie). To save time when handling large cubes, we do 0039 * not draw hidden cubies. 0040 * 0041 * The cube can be "shuffled" by rotating "slices" of cubies that lie in the 0042 * same plane, analogous to slices of a loaf of bread. The faces of the cube 0043 * then become a jumble of colors. 0044 * 0045 * The object of the game is to "solve" a shuffled cube, by selecting and 0046 * rotating slices in sequence so that all the cube faces end up with their 0047 * original colors. 0048 * 0049 * This class holds the current position of the cube, using an abstract set 0050 * of co-ordinates that simplify procedures such as creating, painting and 0051 * moving a cube. Firstly, all cubies are of size 2x2x2. This means that 0052 * the centre of a cubie always has integer co-ordinates, regardless of 0053 * whether the number of cubies in a side is even or odd. 0054 * 0055 * The origin of the co-ordinates is at the centre of gravity of the cube and 0056 * the centres of the cubies have positive and negative co-ordinates running 0057 * from there. Looking at one co-ordinate only of a line of cubies, we have: 0058 * 0059 * Centres of 3 cubies: |-2 | 0 | +2| - End faces at -3 and +3 0060 * 0061 * Centres of 4 cubies: |-3 |-1 | +1| +3| - End faces at -4 and +4 0062 * 0063 * Note that the origin (zero) is between two cubies when the number of cubies 0064 * in the line is even. More importantly, note that the end faces of the line, 0065 * which will have stickers, are always at -N and +N, where N is the number 0066 * of cubies in the line. In a full cube, consisting of LxMxN cubies, the six 0067 * colored faces are at distances -L, +L, -M, +M, -N and +N from the origin. 0068 * 0069 * A slice (see above) is represented as all cubies whose centres have the same 0070 * value in one of the co-ordinates. That value also gives the location of the 0071 * slice and the axis around which to rotate the slice. For example, in a 0072 * 3x3x3 cube, the slice containing the right-hand face will consist of all 0073 * cubies whose centres have X-coordinate = +2 and the axis around which the 0074 * slice rotates is the X-axis itself, which runs from left to right through 0075 * the centre of the cube (the origin of co-ordinates). 0076 * 0077 * Finally, looking at the screen, the X-axis runs from left to right, the 0078 * Y-axis runs from bottom to top (as in mathematics) and the Z-axis runs from 0079 * back to front (out of the screen towards you), which is as in OpenGL library 0080 * usage. Last but not least, the co-ordinates of points such as the centre of 0081 * a cubie are stored in arrays of size 3 (e.g. the X, Y and Z co-ordinates of 0082 * a point P are in array elements P[0], P[1] and P[3] and the X, Y and Z axes 0083 * are now the "0", "1" and "2" axes. 0084 * 0085 * This is handy because just two numbers, an axis number and a co-ordinate 0086 * value can represent any slice or face of the cube. For example the top and 0087 * bottom faces of a 3x3x3 cube are (1,3) and (1,-3) and the central horizontal 0088 * slice is (1,0), representing the planes Y = +3 and Y = -3 and the 9 cubies 0089 * whose centres have Y = 0. 0090 */ 0091 class Cube : public QObject 0092 { 0093 public: 0094 /** 0095 * Constructor for the Cube object 0096 * @param parent The parent widget 0097 * @param xlen The number of cubies in the X direction (left to right) 0098 * @param ylen The number of cubies in the Y direction (bottom to top) 0099 * @param zlen The number of cubies in the Z direction (back to front) 0100 */ 0101 explicit Cube (QObject * parent = nullptr, int xlen = 3, int ylen = 3, int zlen = 3); 0102 ~Cube() override; 0103 0104 void drawCube (GameGLView * gameGLView, float cubieSize); 0105 void moveSlice (Axis axis, int location, Rotation direction); 0106 0107 void setMoveInProgress (Axis axis, int location); 0108 void setMoveAngle (int angle); 0109 void setBlinkingOn (Axis axis, int location); 0110 void setBlinkingOff (); 0111 0112 bool findSticker (double position [nAxes], float myCubieSize, 0113 int faceCentre [nAxes]); 0114 int faceNormal (int faceCentre [3]); 0115 double convToOpenGL (int internalCoord, double cubieSize); 0116 0117 private: 0118 void addStickers (); // Add colored stickers to the faces. 0119 0120 int sizes [nAxes]; // The number of cubies on each axis. 0121 QList<Cubie *> cubies; // The list of cubies in the cube. 0122 0123 Axis moveInProgressAxis; 0124 int moveInProgressSlice; 0125 int moveInProgressAngle; 0126 }; 0127 0128 class Cubie : public QObject 0129 { 0130 public: 0131 /** 0132 * Constructor for the Cubie object 0133 * @param centre The co-ordinates of the central point (int [nAxes]) 0134 */ 0135 explicit Cubie (int centre [nAxes]); 0136 ~Cubie () override; 0137 0138 void rotate (Axis axis, int location, Rotation direction); 0139 0140 void addSticker (FaceColor color, Axis axis, int location, int sign); 0141 0142 bool hasNoStickers (); 0143 0144 void drawCubie (GameGLView * gameGLView, float cubieSize, 0145 Axis axis, int slice, int angle); 0146 0147 double findCloserSticker (double distance, double location [], 0148 int faceCentre []); 0149 void setBlinkingOn (Axis axis, int location, int cubeBoundary); 0150 void setBlinkingOff (); 0151 0152 void printAll (); 0153 void printChanges (); 0154 0155 private: 0156 int originalCentre [nAxes]; // Original location of the cubie. 0157 int currentCentre [nAxes]; // Current location of the cubie. 0158 0159 typedef struct { // Define type "Sticker". 0160 FaceColor color; 0161 bool blinking; 0162 int originalFaceCentre [nAxes]; 0163 int currentFaceCentre [nAxes]; 0164 } Sticker; 0165 0166 QList<Sticker *> stickers; // The stickers on the cubie (if any). 0167 }; 0168 0169 #endif // CUBE_H