├── .gitignore ├── Artwork ├── icon.ico ├── icon.png └── icon.psd ├── CubeCommon ├── Cube.cpp ├── Cube.h ├── CubeCommon.h ├── CubeCommon.vcxproj ├── CubeCommon.vcxproj.filters ├── CubeError.cpp ├── CubeError.h ├── CubeTypes.cpp ├── CubeTypes.h ├── Makefile ├── StringUtilities.cpp ├── StringUtilities.h ├── stdafx.cpp ├── stdafx.h ├── utilities.cpp └── utilities.h ├── Doc ├── FOP-Project-Guide @ Rubiks-solution-en_398409200.pdf ├── format2.txt ├── format2_oneline.txt ├── good.txt ├── image1.png ├── image2.png └── random_data.txt ├── LICENSE ├── MagicCube.sln ├── MagicCube ├── BruteForceSolver.cpp ├── BruteForceSolver.h ├── CommandHandlers.cpp ├── CommandHandlers.h ├── Config.h ├── CubeClient.cpp ├── CubeClient.h ├── CubeSolver.cpp ├── CubeSolver.h ├── GeneralSolver.cpp ├── GeneralSolver.h ├── Graphics.cpp ├── Graphics.h ├── Input.cpp ├── Input.h ├── MagicCube.cpp ├── MagicCube.h ├── MagicCube.vcxproj ├── MagicCube.vcxproj.filters ├── NoXYZFilter.cpp ├── NoXYZFilter.h ├── RandomSolver.cpp ├── RandomSolver.h ├── ReadMe.txt ├── ReduceFilter.cpp ├── ReduceFilter.h ├── Rendering.cpp ├── Rendering.h ├── RotationAnimation.cpp ├── RotationAnimation.h ├── SolverError.cpp ├── SolverError.h ├── StepFilter.cpp ├── StepFilter.h ├── TcpClient.cpp ├── TcpClient.h ├── Vertices.cpp ├── Vertices.h ├── stdafx.cpp ├── stdafx.h ├── utilities.cpp └── utilities.h ├── MagicCubeServer ├── CommandHandlers.cpp ├── CommandHandlers.h ├── Config.h ├── Config.json ├── CubeServer.cpp ├── CubeServer.h ├── CubeSession.cpp ├── CubeSession.h ├── MagicCubeServer.cpp ├── MagicCubeServer.h ├── MagicCubeServer.vcxproj ├── MagicCubeServer.vcxproj.filters ├── Makefile ├── RoomInfo.cpp ├── RoomInfo.h ├── Session.cpp ├── Session.h ├── TcpServer.cpp ├── TcpServer.h ├── stdafx.cpp ├── stdafx.h ├── utilities.cpp └── utilities.h ├── Makefile ├── NetworkCommon ├── Makefile ├── ManualEvent.cpp ├── ManualEvent.h ├── NetworkCommon.h ├── NetworkCommon.vcxproj ├── NetworkCommon.vcxproj.filters ├── NetworkConfig.h ├── NetworkTypes.cpp ├── NetworkTypes.h ├── Package.cpp ├── Package.h ├── stdafx.cpp └── stdafx.h ├── PROBLEM.md ├── README.md └── lib ├── linux ├── libevent.a └── libglfw3.a ├── osx ├── libevent.a └── libglfw3.a ├── win ├── glfw3.dll ├── glfw3.lib ├── glfw3dll.lib ├── libevent.lib ├── libevent_core.lib └── libevent_extras.lib └── winx64 ├── glfw3.dll ├── glfw3.lib ├── glfw3dll.lib ├── libevent.lib ├── libevent_core.lib └── libevent_extras.lib /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | 198 | include 199 | 200 | .DS_Store 201 | 202 | Static_Release 203 | NOGL_Static_Release 204 | -------------------------------------------------------------------------------- /Artwork/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/Artwork/icon.ico -------------------------------------------------------------------------------- /Artwork/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/Artwork/icon.png -------------------------------------------------------------------------------- /Artwork/icon.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/Artwork/icon.psd -------------------------------------------------------------------------------- /CubeCommon/Cube.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "CubeError.h" 5 | 6 | extern map CharColorMap; 7 | extern map ColorCharMap; 8 | 9 | class Cube 10 | { 11 | public: 12 | Cube(); 13 | 14 | // copy 15 | Cube(const Cube&); 16 | 17 | // copy 18 | const Cube& operator=(const Cube&); 19 | 20 | 21 | ~Cube(); 22 | 23 | cube_t subCubes[3][3][3]; 24 | // x y z 25 | /* 26 | y 27 | | 28 | | 29 | | 30 | |________x 31 | /_/_/_/ 32 | /_/_/_/ 33 | /_/_/_/ 34 | z 35 | */ 36 | 37 | bool Deserialize(string); 38 | string Serialize(); 39 | void SaveState(); 40 | void DoMethod(CubeRotateMethod); 41 | void R(); 42 | void Ri(); 43 | void L(); 44 | void Li(); 45 | void B(); 46 | void Bi(); 47 | void D(); 48 | void Di(); 49 | void F(); 50 | void Fi(); 51 | void U(); 52 | void Ui(); 53 | void RotateLeft(); 54 | void RotateRight(); 55 | void RotateUp(); 56 | void RotateDown(); 57 | void RotateClockwise(); 58 | void RotateCounterClockwise(); 59 | bool CheckL(); 60 | bool CheckR(); 61 | bool CheckU(); 62 | bool CheckD(); 63 | bool CheckF(); 64 | bool CheckB(); 65 | bool Check(); 66 | 67 | // completely same, not only equivalent 68 | bool operator==(const Cube&); 69 | bool operator!=(const Cube&); 70 | 71 | // TODO 72 | bool Equivalent(const Cube&); 73 | 74 | private: 75 | cube_t oldSubCubes[3][3][3]; 76 | }; 77 | 78 | -------------------------------------------------------------------------------- /CubeCommon/CubeCommon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CubeTypes.h" 4 | #include "utilities.h" 5 | #include "StringUtilities.h" 6 | #include "Cube.h" 7 | #include "CubeError.h" 8 | 9 | -------------------------------------------------------------------------------- /CubeCommon/CubeCommon.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 14 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Headers 23 | 24 | 25 | Headers 26 | 27 | 28 | Headers 29 | 30 | 31 | Headers 32 | 33 | 34 | Headers 35 | 36 | 37 | Headers 38 | 39 | 40 | Headers 41 | 42 | 43 | 44 | 45 | Sources 46 | 47 | 48 | Sources 49 | 50 | 51 | Sources 52 | 53 | 54 | Sources 55 | 56 | 57 | Sources 58 | 59 | 60 | Sources 61 | 62 | 63 | -------------------------------------------------------------------------------- /CubeCommon/CubeError.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CubeError.h" 3 | 4 | 5 | CubeError::CubeError() 6 | { 7 | } 8 | 9 | 10 | CubeError::~CubeError() 11 | { 12 | } 13 | -------------------------------------------------------------------------------- /CubeCommon/CubeError.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class CubeError 6 | { 7 | public: 8 | string what; 9 | 10 | CubeError(); 11 | CubeError(string what) : what(what) 12 | {} 13 | 14 | ~CubeError(); 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /CubeCommon/CubeTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CubeTypes.h" 3 | 4 | map CubeRotateMethodName = 5 | { 6 | {ROTATE_NONE , "NONE"}, 7 | {ROTATE_FRONT , "F" }, 8 | {ROTATE_BACK , "B" }, 9 | {ROTATE_LEFT , "L" }, 10 | {ROTATE_RIGHT , "R" }, 11 | {ROTATE_UP , "U" }, 12 | {ROTATE_DOWN , "D" }, 13 | {ROTATE_WHOLEX , "X" }, 14 | {ROTATE_WHOLEY , "Y" }, 15 | {ROTATE_WHOLEZ , "Z" }, 16 | {ROTATE_NONEi , "NONE"}, 17 | {ROTATE_FRONTi , "Fi" }, 18 | {ROTATE_BACKi , "Bi" }, 19 | {ROTATE_LEFTi , "Li" }, 20 | {ROTATE_RIGHTi , "Ri" }, 21 | {ROTATE_UPi , "Ui" }, 22 | {ROTATE_DOWNi , "Di" }, 23 | {ROTATE_WHOLEXi, "Xi" }, 24 | {ROTATE_WHOLEYi, "Yi" }, 25 | {ROTATE_WHOLEZi, "Zi" } 26 | }; 27 | 28 | map CubeRotateMethodEnumName = 29 | { 30 | { ROTATE_NONE , "ROTATE_NONE" }, 31 | { ROTATE_FRONT , "ROTATE_FRONT" }, 32 | { ROTATE_BACK , "ROTATE_BACK" }, 33 | { ROTATE_LEFT , "ROTATE_LEFT" }, 34 | { ROTATE_RIGHT , "ROTATE_RIGHT" }, 35 | { ROTATE_UP , "ROTATE_UP" }, 36 | { ROTATE_DOWN , "ROTATE_DOWN" }, 37 | { ROTATE_WHOLEX , "ROTATE_WHOLEX" }, 38 | { ROTATE_WHOLEY , "ROTATE_WHOLEY" }, 39 | { ROTATE_WHOLEZ , "ROTATE_WHOLEZ" }, 40 | { ROTATE_NONEi , "ROTATE_NONEi" }, 41 | { ROTATE_FRONTi , "ROTATE_FRONTi" }, 42 | { ROTATE_BACKi , "ROTATE_BACKi" }, 43 | { ROTATE_LEFTi , "ROTATE_LEFTi" }, 44 | { ROTATE_RIGHTi , "ROTATE_RIGHTi" }, 45 | { ROTATE_UPi , "ROTATE_UPi" }, 46 | { ROTATE_DOWNi , "ROTATE_DOWNi" }, 47 | { ROTATE_WHOLEXi, "ROTATE_WHOLEXi" }, 48 | { ROTATE_WHOLEYi, "ROTATE_WHOLEYi" }, 49 | { ROTATE_WHOLEZi, "ROTATE_WHOLEZi" } 50 | }; 51 | 52 | map NameToCubeRotateMethod = 53 | { 54 | {"NONE", ROTATE_NONE }, 55 | {"F" , ROTATE_FRONT }, 56 | {"B" , ROTATE_BACK }, 57 | {"L" , ROTATE_LEFT }, 58 | {"R" , ROTATE_RIGHT }, 59 | {"U" , ROTATE_UP }, 60 | {"D" , ROTATE_DOWN }, 61 | {"X" , ROTATE_WHOLEX }, 62 | {"Y" , ROTATE_WHOLEY }, 63 | {"Z" , ROTATE_WHOLEZ }, 64 | {"Fi" , ROTATE_FRONTi }, 65 | {"Bi" , ROTATE_BACKi }, 66 | {"Li" , ROTATE_LEFTi }, 67 | {"Ri" , ROTATE_RIGHTi }, 68 | {"Ui" , ROTATE_UPi }, 69 | {"Di" , ROTATE_DOWNi }, 70 | {"Xi" , ROTATE_WHOLEXi}, 71 | {"Yi" , ROTATE_WHOLEYi}, 72 | {"Zi" , ROTATE_WHOLEZi} 73 | }; 74 | -------------------------------------------------------------------------------- /CubeCommon/CubeTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | typedef unsigned int cube_t; // 0bMETA DATA ffff bbbb llll rrrr uuuu dddd 7 | 8 | #define GET_FRONT(x) ((CubeColor)(((x)&0xF00000)>>20)) 9 | #define GET_BACK(x) ((CubeColor)(((x)&0x0F0000)>>16)) 10 | #define GET_LEFT(x) ((CubeColor)(((x)&0x00F000)>>12)) 11 | #define GET_RIGHT(x) ((CubeColor)(((x)&0x000F00)>>8)) 12 | #define GET_UP(x) ((CubeColor)(((x)&0x0000F0)>>4)) 13 | #define GET_DOWN(x) ((CubeColor)(((x)&0x00000F)>>0)) 14 | 15 | #define SET_FRONT(x) (((x)&0xF)<<20) 16 | #define SET_BACK(x) (((x)&0xF)<<16) 17 | #define SET_LEFT(x) (((x)&0xF)<<12) 18 | #define SET_RIGHT(x) (((x)&0xF)<<8) 19 | #define SET_UP(x) (((x)&0xF)<<4) 20 | #define SET_DOWN(x) (((x)&0xF)<<0) 21 | 22 | #define MAKE_CUBE(f, b, l, r, u, d) (SET_FRONT(f)|SET_BACK(b)|SET_LEFT(l)|SET_RIGHT(r)|SET_UP(u)|SET_DOWN(d)) 23 | 24 | #define ROTATE_LEFT(x) MAKE_CUBE(GET_RIGHT(x), GET_LEFT(x), GET_FRONT(x), GET_BACK(x), GET_UP(x), GET_DOWN(x)) 25 | #define ROTATE_RIGHT(x) MAKE_CUBE(GET_LEFT(x), GET_RIGHT(x), GET_BACK(x), GET_FRONT(x), GET_UP(x), GET_DOWN(x)) 26 | #define ROTATE_UP(x) MAKE_CUBE(GET_DOWN(x), GET_UP(x), GET_LEFT(x), GET_RIGHT(x), GET_FRONT(x), GET_BACK(x)) 27 | #define ROTATE_DOWN(x) MAKE_CUBE(GET_UP(x), GET_DOWN(x), GET_LEFT(x), GET_RIGHT(x), GET_BACK(x), GET_FRONT(x)) 28 | #define ROTATE_CLK(x) MAKE_CUBE(GET_FRONT(x), GET_BACK(x), GET_DOWN(x), GET_UP(x), GET_LEFT(x), GET_RIGHT(x)) //clockwise 29 | #define ROTATE_CCLK(x) MAKE_CUBE(GET_FRONT(x), GET_BACK(x), GET_UP(x), GET_DOWN(x), GET_RIGHT(x), GET_LEFT(x)) //counter-clockwise 30 | 31 | #define FL_EDGE 0][1][2 // front left edge 32 | #define FR_EDGE 2][1][2 // front right edge 33 | #define FU_EDGE 1][2][2 // front up edge 34 | #define FD_EDGE 1][0][2 // front down edge 35 | #define BL_EDGE 0][1][0 // back left edge 36 | #define BR_EDGE 2][1][0 // back right edge 37 | #define BU_EDGE 1][2][0 // back up edge 38 | #define BD_EDGE 1][0][0 // back down edge 39 | #define UL_EDGE 0][2][1 // up left edge 40 | #define UR_EDGE 2][2][1 // up right edge 41 | #define DL_EDGE 0][0][1 // down left edge 42 | #define DR_EDGE 2][0][1 // down right edge 43 | 44 | #define F_CENTRE 1][1][2 // front centre 45 | #define B_CENTRE 1][1][0 // back centre 46 | #define L_CENTRE 0][1][1 // left centre 47 | #define R_CENTRE 2][1][1 // right centre 48 | #define U_CENTRE 1][2][1 // up centre 49 | #define D_CENTRE 1][0][1 // down centre 50 | 51 | #define FLU_CORNER 0][2][2 // front left up corner 52 | #define FLD_CORNER 0][0][2 // front left down corner 53 | #define FRU_CORNER 2][2][2 // front right up corner 54 | #define FRD_CORNER 2][0][2 // front right down corner 55 | #define BLU_CORNER 0][2][0 // back left up corner 56 | #define BLD_CORNER 0][0][0 // back left down corner 57 | #define BRU_CORNER 2][2][0 // back right up corner 58 | #define BRD_CORNER 2][0][0 // back right down corner 59 | 60 | #define IsColorMatch1(cube, color1) \ 61 | (((GET_FRONT(cube) == color1) +\ 62 | (GET_BACK(cube) == color1) +\ 63 | (GET_LEFT(cube) == color1) +\ 64 | (GET_RIGHT(cube) == color1) +\ 65 | (GET_UP(cube) == color1) +\ 66 | (GET_DOWN(cube) == color1)) == 1) 67 | 68 | #define IsColorMatch2(cube, color1, color2) \ 69 | (((GET_FRONT(cube) == color1) +\ 70 | (GET_BACK(cube) == color1) +\ 71 | (GET_LEFT(cube) == color1) +\ 72 | (GET_RIGHT(cube) == color1) +\ 73 | (GET_UP(cube) == color1) +\ 74 | (GET_DOWN(cube) == color1) +\ 75 | (GET_FRONT(cube) == color2) +\ 76 | (GET_BACK(cube) == color2) +\ 77 | (GET_LEFT(cube) == color2) +\ 78 | (GET_RIGHT(cube) == color2) +\ 79 | (GET_UP(cube) == color2) +\ 80 | (GET_DOWN(cube) == color2)) == 2) 81 | 82 | #define IsColorMatch3(cube, color1, color2, color3) \ 83 | (((GET_FRONT(cube) == color1) +\ 84 | (GET_BACK(cube) == color1) +\ 85 | (GET_LEFT(cube) == color1) +\ 86 | (GET_RIGHT(cube) == color1) +\ 87 | (GET_UP(cube) == color1) +\ 88 | (GET_DOWN(cube) == color1) +\ 89 | (GET_FRONT(cube) == color2) +\ 90 | (GET_BACK(cube) == color2) +\ 91 | (GET_LEFT(cube) == color2) +\ 92 | (GET_RIGHT(cube) == color2) +\ 93 | (GET_UP(cube) == color2) +\ 94 | (GET_DOWN(cube) == color2) +\ 95 | (GET_FRONT(cube) == color3) +\ 96 | (GET_BACK(cube) == color3) +\ 97 | (GET_LEFT(cube) == color3) +\ 98 | (GET_RIGHT(cube) == color3) +\ 99 | (GET_UP(cube) == color3) +\ 100 | (GET_DOWN(cube) == color3)) == 3) 101 | 102 | #define FIND_EDGE(subCubes, color1, color2, stmtFL, stmtFR, stmtFU, stmtFD, stmtBL, stmtBR, stmtBU, stmtBD, stmtUL, stmtUR, stmtDL, stmtDR) \ 103 | if (IsColorMatch2(subCubes[FL_EDGE], color1, color2)) \ 104 | { \ 105 | stmtFL; \ 106 | }\ 107 | else if (IsColorMatch2(subCubes[FR_EDGE], color1, color2))\ 108 | {\ 109 | stmtFR; \ 110 | }\ 111 | else if (IsColorMatch2(subCubes[FU_EDGE], color1, color2))\ 112 | {\ 113 | stmtFU; \ 114 | }\ 115 | else if (IsColorMatch2(subCubes[FD_EDGE], color1, color2))\ 116 | {\ 117 | stmtFD; \ 118 | }\ 119 | else if (IsColorMatch2(subCubes[BL_EDGE], color1, color2))\ 120 | {\ 121 | stmtBL; \ 122 | }\ 123 | else if (IsColorMatch2(subCubes[BR_EDGE], color1, color2))\ 124 | {\ 125 | stmtBR; \ 126 | }\ 127 | else if (IsColorMatch2(subCubes[BU_EDGE], color1, color2))\ 128 | {\ 129 | stmtBU; \ 130 | }\ 131 | else if (IsColorMatch2(subCubes[BD_EDGE], color1, color2))\ 132 | {\ 133 | stmtBD; \ 134 | }\ 135 | else if (IsColorMatch2(subCubes[UL_EDGE], color1, color2))\ 136 | {\ 137 | stmtUL; \ 138 | }\ 139 | else if (IsColorMatch2(subCubes[UR_EDGE], color1, color2))\ 140 | {\ 141 | stmtUR; \ 142 | }\ 143 | else if (IsColorMatch2(subCubes[DL_EDGE], color1, color2))\ 144 | {\ 145 | stmtDL; \ 146 | }\ 147 | else if (IsColorMatch2(subCubes[DR_EDGE], color1, color2))\ 148 | {\ 149 | stmtDR; \ 150 | } 151 | 152 | #define FIND_CORNER(subCubes, color1, color2, color3, stmtFLU, stmtFLD, stmtFRU, stmtFRD, stmtBLU, stmtBLD, stmtBRU, stmtBRD) \ 153 | if (IsColorMatch3(subCubes[FLU_CORNER], color1, color2, color3)) \ 154 | { \ 155 | stmtFLU; \ 156 | }\ 157 | else if (IsColorMatch3(subCubes[FLD_CORNER], color1, color2, color3))\ 158 | {\ 159 | stmtFLD; \ 160 | }\ 161 | else if (IsColorMatch3(subCubes[FRU_CORNER], color1, color2, color3))\ 162 | {\ 163 | stmtFRU; \ 164 | }\ 165 | else if (IsColorMatch3(subCubes[FRD_CORNER], color1, color2, color3))\ 166 | {\ 167 | stmtFRD; \ 168 | }\ 169 | else if (IsColorMatch3(subCubes[BLU_CORNER], color1, color2, color3))\ 170 | {\ 171 | stmtBLU; \ 172 | }\ 173 | else if (IsColorMatch3(subCubes[BLD_CORNER], color1, color2, color3))\ 174 | {\ 175 | stmtBLD; \ 176 | }\ 177 | else if (IsColorMatch3(subCubes[BRU_CORNER], color1, color2, color3))\ 178 | {\ 179 | stmtBRU; \ 180 | }\ 181 | else if (IsColorMatch3(subCubes[BRD_CORNER], color1, color2, color3))\ 182 | {\ 183 | stmtBRD; \ 184 | } 185 | 186 | enum CubeColor 187 | { 188 | COLOR_UNUSED, 189 | COLOR_WHITE, 190 | COLOR_YELLOW, 191 | COLOR_ORANGE, 192 | COLOR_RED, 193 | COLOR_GREEN, 194 | COLOR_BLUE, 195 | COLOR_INVALID = 0xF 196 | }; 197 | 198 | // i means inverse, +10 -> i 199 | enum CubeRotateMethod 200 | { 201 | ROTATE_NONE, 202 | ROTATE_FRONT, 203 | ROTATE_BACK, 204 | ROTATE_LEFT, 205 | ROTATE_RIGHT, 206 | ROTATE_UP, 207 | ROTATE_DOWN, 208 | ROTATE_WHOLEX, // whole up 209 | ROTATE_WHOLEY, // whole left 210 | ROTATE_WHOLEZ, // whole clockwise 211 | ROTATE_NONEi, 212 | ROTATE_FRONTi, 213 | ROTATE_BACKi, 214 | ROTATE_LEFTi, 215 | ROTATE_RIGHTi, 216 | ROTATE_UPi, 217 | ROTATE_DOWNi, 218 | ROTATE_WHOLEXi, // whole down 219 | ROTATE_WHOLEYi, // whole right 220 | ROTATE_WHOLEZi // whole counter-clockwise 221 | }; 222 | 223 | typedef vector CubeSteps; 224 | 225 | extern map CubeRotateMethodName; 226 | extern map CubeRotateMethodEnumName; 227 | extern map NameToCubeRotateMethod; 228 | 229 | #define FORMAT1_LENGTH (3*3*3*6) // 3*3*3 sub cubes, each sub cube has 6 surfaces 230 | #define FORMAT2_LENGTH (3*3*6) // 6 surfaces, each surface has 3*3 blocks -------------------------------------------------------------------------------- /CubeCommon/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = CubeCommon 2 | 3 | SOURCES := $(shell ls *.cpp) 4 | OBJECTS := $(patsubst %.cpp, build/%.o, $(SOURCES)) 5 | 6 | # compiler 7 | INC_DIR = ../include/osx 8 | CC_FLAGS = -O2 -Wall -std=c++11 -I $(INC_DIR) -I ../include 9 | 10 | .PHONY: all 11 | all: 12 | -mkdir build 13 | make lib$(PROJECT).a 14 | 15 | build/%.o: %.cpp %.h CubeTypes.h utilities.h 16 | $(CC) -c $(CC_FLAGS) -o $@ $< 17 | 18 | lib$(PROJECT).a: $(OBJECTS) 19 | $(AR) rcs build/lib$(PROJECT).a $(OBJECTS) 20 | 21 | .PHONY: clean 22 | clean: 23 | -rm build/* 24 | -rm -rf build 25 | -------------------------------------------------------------------------------- /CubeCommon/StringUtilities.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "StringUtilities.h" 3 | 4 | // http://stackoverflow.com/questions/236129/split-a-string-in-c 5 | vector &split(const string &s, char delim, vector &elems) 6 | { 7 | stringstream ss(s); 8 | string item; 9 | while (getline(ss, item, delim)) 10 | { 11 | elems.push_back(item); 12 | } 13 | return elems; 14 | } 15 | 16 | vector split(const string &s, char delim) 17 | { 18 | vector elems; 19 | split(s, delim, elems); 20 | return elems; 21 | } 22 | 23 | char toUpper(char c) 24 | { 25 | if (c < 'a' || c > 'z') return c; 26 | return c & ~32; 27 | } 28 | 29 | char toLower(char c) 30 | { 31 | if (c < 'A' || c > 'Z') return c; 32 | return c | 32; 33 | } 34 | 35 | string toUpperString(string str) 36 | { 37 | transform(str.begin(), str.end(), str.begin(), toUpper); 38 | return str; 39 | } 40 | 41 | string toLowerString(string str) 42 | { 43 | transform(str.begin(), str.end(), str.begin(), toLower); 44 | return str; 45 | } 46 | 47 | bool endsWith(const string &fullString, const string &ending) 48 | { 49 | if (fullString.length() >= ending.length()) 50 | { 51 | return (0 == fullString.compare(fullString.length() - ending.length(), ending.length(), ending)); 52 | } 53 | else 54 | { 55 | return false; 56 | } 57 | } -------------------------------------------------------------------------------- /CubeCommon/StringUtilities.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | vector split(const string&, char); 6 | char toUpper(char); 7 | char toLower(char); 8 | string toUpperString(string); 9 | string toLowerString(string); 10 | bool endsWith(const string&, const string&); 11 | -------------------------------------------------------------------------------- /CubeCommon/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /CubeCommon/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/CubeCommon/stdafx.h -------------------------------------------------------------------------------- /CubeCommon/utilities.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "utilities.h" 3 | 4 | string stepsToString(CubeSteps &steps, char delim) 5 | { 6 | string r; 7 | ptrdiff_t size = steps.size(); 8 | for (ptrdiff_t i = 0; i < size; ++i) 9 | { 10 | r += CubeRotateMethodName[steps[i]] + delim; 11 | } 12 | return r; 13 | } 14 | 15 | void printError(CubeError err) 16 | { 17 | if (err.what == "") 18 | { 19 | fprintf(stderr, "CubeError\n"); 20 | } 21 | else 22 | { 23 | fprintf(stderr, "CubeError: %s\n", err.what.c_str()); 24 | } 25 | } 26 | 27 | void randomCube(Cube &cube) 28 | { 29 | for (int i = 0; i < rand() % 1000 + 1; ++i) 30 | { 31 | CubeRotateMethod method = (CubeRotateMethod)((rand() % 19) + 1); 32 | cube.DoMethod(method); 33 | } 34 | } 35 | 36 | string randomCube() 37 | { 38 | Cube cube; 39 | randomCube(cube); 40 | return cube.Serialize(); 41 | } 42 | 43 | CubeRotateMethod inverse(CubeRotateMethod m) 44 | { 45 | if (m < ROTATE_NONEi) 46 | { 47 | return (CubeRotateMethod)(m + (ROTATE_NONEi - ROTATE_NONE)); //inverse 48 | } 49 | else 50 | { 51 | return (CubeRotateMethod)(m - (ROTATE_NONEi - ROTATE_NONE)); //inverse 52 | } 53 | } 54 | 55 | void copySteps(CubeSteps &src, CubeSteps &dest) 56 | { 57 | size_t size = src.size(); 58 | for (ptrdiff_t i = 0; i < (ptrdiff_t)size; ++i) 59 | { 60 | if (src[i] != ROTATE_NONE && src[i] != ROTATE_NONEi) 61 | dest.push_back(src[i]); 62 | } 63 | } 64 | 65 | bool isWholeRotate(CubeRotateMethod m) 66 | { 67 | return (m >= ROTATE_WHOLEX && m <= ROTATE_WHOLEZ) || (m >= ROTATE_WHOLEXi && m <= ROTATE_WHOLEZi); 68 | } 69 | 70 | // This table was written by hand, so if you find any mistake, just let me know :) 71 | int format1ToFormat2Table[FORMAT1_LENGTH] = { 72 | -1, 17, 24, -1, -1, 51, -1, 16, -1, -1, -1, 52, -1, 15, -1, 35, -1, 53, //(0, 0, 0) ~ (2, 0, 0) 73 | -1, 14, 21, -1, -1, -1, -1, 13, -1, -1, -1, -1, -1, 12, -1, 32, -1, -1, //(0, 1, 0) ~ (2, 1, 0) 74 | -1, 11, 18, -1, 36, -1, -1, 10, -1, -1, 37, -1, -1, 9, -1, 29, 38, -1, //(0, 2, 0) ~ (2, 2, 0) 75 | -1, -1, 25, -1, -1, 48, -1, -1, -1, -1, -1, 49, -1, -1, -1, 34, -1, 50, //(0, 0, 1) ~ (2, 0, 1) 76 | -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 31, -1, -1, //(0, 1, 1) ~ (2, 1, 1) 77 | -1, -1, 19, -1, 39, -1, -1, -1, -1, -1, 40, -1, -1, -1, -1, 28, 41, -1, //(0, 2, 1) ~ (2, 2, 1) 78 | 6, -1, 26, -1, -1, 45, 7, -1, -1, -1, -1, 46, 8, -1, -1, 33, -1, 47, //(0, 0, 2) ~ (2, 0, 2) 79 | 3, -1, 23, -1, -1, -1, 4, -1, -1, -1, -1, -1, 5, -1, -1, 30, -1, -1, //(0, 1, 2) ~ (2, 1, 2) 80 | 0, -1, 20, -1, 42, -1, 1, -1, -1, -1, 43, -1, 2, -1, -1, 27, 44, -1 //(0, 2, 2) ~ (2, 2, 2) 81 | }; 82 | 83 | int format2ToFormat1Table[FORMAT2_LENGTH] = {-1}; 84 | 85 | void makeTable2() 86 | { 87 | for (int i = 0; i < FORMAT1_LENGTH; ++i) 88 | { 89 | if (format1ToFormat2Table[i] >= 0) format2ToFormat1Table[format1ToFormat2Table[i]] = i; 90 | } 91 | } 92 | 93 | string convertFromFormat2(char *f2) 94 | { 95 | string f1(FORMAT1_LENGTH, '-'); 96 | for (int i = 0; i < FORMAT1_LENGTH; ++i) 97 | { 98 | if (format1ToFormat2Table[i] >= 0) 99 | { 100 | f1[i] = f2[format1ToFormat2Table[i]]; 101 | } 102 | } 103 | return f1; 104 | } 105 | 106 | char *convertToFormat2(string f1) 107 | { 108 | if (format2ToFormat1Table[0] == -1) 109 | { 110 | makeTable2(); 111 | } 112 | 113 | char *f2 = new char[FORMAT2_LENGTH]; 114 | for (int i = 0; i < FORMAT2_LENGTH; ++i) 115 | { 116 | f2[i] = f1[format2ToFormat1Table[i]]; 117 | } 118 | return f2; 119 | } 120 | -------------------------------------------------------------------------------- /CubeCommon/utilities.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CubeError.h" 4 | #include "Cube.h" 5 | 6 | string stepsToString(CubeSteps&, char); 7 | void printError(CubeError); 8 | void randomCube(Cube&); 9 | string randomCube(); 10 | CubeRotateMethod inverse(CubeRotateMethod); 11 | 12 | // copy steps with deleting NONE steps 13 | void copySteps(CubeSteps&, CubeSteps&); 14 | 15 | bool isWholeRotate(CubeRotateMethod); 16 | 17 | // format2: see pair 1 18 | string convertFromFormat2(char*); 19 | char *convertToFormat2(string); 20 | -------------------------------------------------------------------------------- /Doc/FOP-Project-Guide @ Rubiks-solution-en_398409200.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/Doc/FOP-Project-Guide @ Rubiks-solution-en_398409200.pdf -------------------------------------------------------------------------------- /Doc/format2.txt: -------------------------------------------------------------------------------- 1 | G W G 2 | B B B 3 | O B Y 4 | W G B 5 | G G G 6 | G G W 7 | R R R 8 | O O Y 9 | O O G 10 | O O B 11 | R R R 12 | B R R 13 | Y W R 14 | Y Y Y 15 | Y O Y 16 | W W O 17 | B W W 18 | B Y W 19 | -------------------------------------------------------------------------------- /Doc/format2_oneline.txt: -------------------------------------------------------------------------------- 1 | GWGBBBOBYWGBGGGGGWRRROOYOOGOOBRRRBRRYWRYYYYOYWWOBWWBYW 2 | -------------------------------------------------------------------------------- /Doc/good.txt: -------------------------------------------------------------------------------- 1 | -BO--Y-B---Y-B-R-Y-BO----B-----B-R---BO-W--B--W--B-RW---O--Y-----Y---R-Y--O------------R----O-W-----W----RW-G-O--YG----YG--R-YG-O---G-----G--R--G-O-W-G---W-G--RW- 2 | -BR--W-B---W-B-O-W-BR----B-----B-O---BR-Y--B--Y--B-OY---R--W-----W---O-W--R------------O----R-Y-----Y----OY-G-R--WG----WG--O-WG-R---G-----G--O--G-R-Y-G---Y-G--OY- 3 | -BW--O-B---O-B-Y-O-BW----B-----B-Y---BW-R--B--R--B-YR---W--O-----O---Y-O--W------------Y----W-R-----R----YR-G-W--OG----OG--Y-OG-W---G-----G--Y--G-W-R-G---R-G--YR- 4 | -BY--R-B---R-B-W-R-BY----B-----B-W---BY-O--B--O--B-WO---Y--R-----R---W-R--Y------------W----Y-O-----O----WO-G-Y--RG----RG--W-RG-Y---G-----G--W--G-Y-O-G---O-G--WO- 5 | -GO--W-G---W-G-R-W-GO----G-----G-R---GO-Y--G--Y--G-RY---O--W-----W---R-W--O------------R----O-Y-----Y----RY-B-O--WB----WB--R-WB-O---B-----B--R--B-O-Y-B---Y-B--RY- 6 | -GR--Y-G---Y-G-O-Y-GR----G-----G-O---GR-W--G--W--G-OW---R--Y-----Y---O-Y--R------------O----R-W-----W----OW-B-R--YB----YB--O-YB-R---B-----B--O--B-R-W-B---W-B--OW- 7 | -GW--R-G---R-G-Y-R-GW----G-----G-Y---GW-O--G--O--G-YO---W--R-----R---Y-R--W------------Y----W-O-----O----YO-B-W--RB----RB--Y-RB-W---B-----B--Y--B-W-O-B---O-B--YO- 8 | -GY--O-G---O-G-W-O-GY----G-----G-W---GY-R--G--R--G-WR---Y--O-----O---W-O--Y------------W----Y-R-----R----WR-B-Y--OB----OB--W-OB-Y---B-----B--W--B-Y-R-B---R-B--WR- 9 | -OB--W-O---W-O-G-W-OB----O-----O-G---OB-Y--O--Y--O-GY---B--W-----W---G-W--B------------G----B-Y-----Y----GY-R-B--WR----WR--G-WR-B---R-----R--G--R-B-Y-R---Y-R--GY- 10 | -OG--Y-O---Y-O-B-Y-OG----O-----O-B---OG-W--O--W--O-BW---G--Y-----Y---B-Y--G------------B----G-W-----W----BW-R-G--YR----YR--B-YR-G---R-----R--B--R-G-W-R---W-R--BW- 11 | -OW--G-O---G-O-Y-G-OW----O-----O-Y---OW-B--O--B--O-YB---W--G-----G---Y-G--W------------Y----W-B-----B----YB-R-W--GR----GR--Y-GR-W---R-----R--Y--R-W-B-R---B-R--YB- 12 | -OY--B-O---B-O-W-B-OY----O-----O-W---OY-G--O--G--O-WG---Y--B-----B---W-B--Y------------W----Y-G-----G----WG-R-Y--BR----BR--W-BR-Y---R-----R--W--R-Y-G-R---G-R--WG- 13 | -RB--Y-R---Y-R-G-Y-RB----R-----R-G---RB-W--R--W--R-GW---B--Y-----Y---G-Y--B------------G----B-W-----W----GW-O-B--YO----YO--G-YO-B---O-----O--G--O-B-W-O---W-O--GW- 14 | -RG--W-R---W-R-B-W-RG----R-----R-B---RG-Y--R--Y--R-BY---G--W-----W---B-W--G------------B----G-Y-----Y----BY-O-G--WO----WO--B-WO-G---O-----O--B--O-G-Y-O---Y-O--BY- 15 | -RW--B-R---B-R-Y-B-RW----R-----R-Y---RW-G--R--G--R-YG---W--B-----B---Y-B--W------------Y----W-G-----G----YG-O-W--BO----BO--Y-BO-W---O-----O--Y--O-W-G-O---G-O--YG- 16 | -RY--G-R---G-R-W-G-RY----R-----R-W---RY-B--R--B--R-WB---Y--G-----G---W-G--Y------------W----Y-B-----B----WB-O-Y--GO----GO--W-GO-Y---O-----O--W--O-Y-B-O---B-O--WB- 17 | -WB--R-W---R-W-G-R-WB----W-----W-G---WB-O--W--O--W-GO---B--R-----R---G-R--B------------G----B-O-----O----GO-Y-B--RY----RY--G-RY-B---Y-----Y--G--Y-B-O-Y---O-Y--GO- 18 | -WG--O-W---O-W-B-O-WG----W-----W-B---WG-R--W--R--W-BR---G--O-----O---B-O--G------------B----G-R-----R----BR-Y-G--OY----OY--B-OY-G---Y-----Y--B--Y-G-R-Y---R-Y--BR- 19 | -WO--B-W---B-W-R-B-WO----W-----W-R---WO-G--W--G--W-RG---O--B-----B---R-B--O------------R----O-G-----G----RG-Y-O--BY----BY--R-BY-O---Y-----Y--R--Y-O-G-Y---G-Y--RG- 20 | -WR--G-W---G-W-O-G-WR----W-----W-O---WR-B--W--B--W-OB---R--G-----G---O-G--R------------O----R-B-----B----OB-Y-R--GY----GY--O-GY-R---Y-----Y--O--Y-R-B-Y---B-Y--OB- 21 | -YB--O-Y---O-Y-G-O-YB----Y-----Y-G---YB-R--Y--R--Y-GR---B--O-----O---G-O--B------------G----B-R-----R----GR-W-B--OW----OW--G-OW-B---W-----W--G--W-B-R-W---R-W--GR- 22 | -YG--R-Y---R-Y-B-R-YG----Y-----Y-B---YG-O--Y--O--Y-BO---G--R-----R---B-R--G------------B----G-O-----O----BO-W-G--RW----RW--B-RW-G---W-----W--B--W-G-O-W---O-W--BO- 23 | -YO--G-Y---G-Y-R-G-YO----Y-----Y-R---YO-B--Y--B--Y-RB---O--G-----G---R-G--O------------R----O-B-----B----RB-W-O--GW----GW--R-GW-O---W-----W--R--W-O-B-W---B-W--RB- 24 | -YR--B-Y---B-Y-O-B-YR----Y-----Y-O---YR-G--Y--G--Y-OG---R--B-----B---O-B--R------------O----R-G-----G----OG-W-R--BW----BW--O-BW-R---W-----W--O--W-R-G-W---G-W--OG- 25 | -------------------------------------------------------------------------------- /Doc/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/Doc/image1.png -------------------------------------------------------------------------------- /Doc/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/Doc/image2.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Wende Tan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /MagicCube.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MagicCube", "MagicCube\MagicCube.vcxproj", "{CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791} = {B70D9CC0-5E42-456B-B2BA-9B4344EAB791} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CubeCommon", "CubeCommon\CubeCommon.vcxproj", "{B70D9CC0-5E42-456B-B2BA-9B4344EAB791}" 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MagicCubeServer", "MagicCubeServer\MagicCubeServer.vcxproj", "{4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}" 14 | EndProject 15 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NetworkCommon", "NetworkCommon\NetworkCommon.vcxproj", "{E2535545-AF18-41E0-9505-3745E2C40D15}" 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Win32 = Debug|Win32 20 | Debug|x64 = Debug|x64 21 | NOGL_Static_Release|Win32 = NOGL_Static_Release|Win32 22 | NOGL_Static_Release|x64 = NOGL_Static_Release|x64 23 | Release|Win32 = Release|Win32 24 | Release|x64 = Release|x64 25 | EndGlobalSection 26 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 27 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Debug|Win32.ActiveCfg = Debug|Win32 28 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Debug|Win32.Build.0 = Debug|Win32 29 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Debug|x64.ActiveCfg = Debug|x64 30 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Debug|x64.Build.0 = Debug|x64 31 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Debug|x64.Deploy.0 = Debug|x64 32 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.NOGL_Static_Release|Win32.ActiveCfg = NOGL_Static_Release|Win32 33 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.NOGL_Static_Release|Win32.Build.0 = NOGL_Static_Release|Win32 34 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.NOGL_Static_Release|x64.ActiveCfg = NOGL_Static_Release|x64 35 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.NOGL_Static_Release|x64.Build.0 = NOGL_Static_Release|x64 36 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Release|Win32.ActiveCfg = Release|Win32 37 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Release|Win32.Build.0 = Release|Win32 38 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Release|x64.ActiveCfg = Release|x64 39 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Release|x64.Build.0 = Release|x64 40 | {CF6D7C4B-78BA-4D8F-AF53-86F915B6F761}.Release|x64.Deploy.0 = Release|x64 41 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.Debug|Win32.ActiveCfg = Debug|Win32 42 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.Debug|Win32.Build.0 = Debug|Win32 43 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.Debug|x64.ActiveCfg = Debug|x64 44 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.Debug|x64.Build.0 = Debug|x64 45 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.NOGL_Static_Release|Win32.ActiveCfg = Static_Release|Win32 46 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.NOGL_Static_Release|Win32.Build.0 = Static_Release|Win32 47 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.NOGL_Static_Release|x64.ActiveCfg = Static_Release|x64 48 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.NOGL_Static_Release|x64.Build.0 = Static_Release|x64 49 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.Release|Win32.ActiveCfg = Release|Win32 50 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.Release|Win32.Build.0 = Release|Win32 51 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.Release|x64.ActiveCfg = Release|x64 52 | {B70D9CC0-5E42-456B-B2BA-9B4344EAB791}.Release|x64.Build.0 = Release|x64 53 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.Debug|Win32.ActiveCfg = Debug|Win32 54 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.Debug|Win32.Build.0 = Debug|Win32 55 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.Debug|x64.ActiveCfg = Debug|x64 56 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.Debug|x64.Build.0 = Debug|x64 57 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.NOGL_Static_Release|Win32.ActiveCfg = Release|Win32 58 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.NOGL_Static_Release|x64.ActiveCfg = Release|x64 59 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.Release|Win32.ActiveCfg = Release|Win32 60 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.Release|Win32.Build.0 = Release|Win32 61 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.Release|x64.ActiveCfg = Release|x64 62 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A}.Release|x64.Build.0 = Release|x64 63 | {E2535545-AF18-41E0-9505-3745E2C40D15}.Debug|Win32.ActiveCfg = Debug|Win32 64 | {E2535545-AF18-41E0-9505-3745E2C40D15}.Debug|Win32.Build.0 = Debug|Win32 65 | {E2535545-AF18-41E0-9505-3745E2C40D15}.Debug|x64.ActiveCfg = Debug|x64 66 | {E2535545-AF18-41E0-9505-3745E2C40D15}.Debug|x64.Build.0 = Debug|x64 67 | {E2535545-AF18-41E0-9505-3745E2C40D15}.NOGL_Static_Release|Win32.ActiveCfg = Release|Win32 68 | {E2535545-AF18-41E0-9505-3745E2C40D15}.NOGL_Static_Release|x64.ActiveCfg = Release|x64 69 | {E2535545-AF18-41E0-9505-3745E2C40D15}.Release|Win32.ActiveCfg = Release|Win32 70 | {E2535545-AF18-41E0-9505-3745E2C40D15}.Release|Win32.Build.0 = Release|Win32 71 | {E2535545-AF18-41E0-9505-3745E2C40D15}.Release|x64.ActiveCfg = Release|x64 72 | {E2535545-AF18-41E0-9505-3745E2C40D15}.Release|x64.Build.0 = Release|x64 73 | EndGlobalSection 74 | GlobalSection(SolutionProperties) = preSolution 75 | HideSolutionNode = FALSE 76 | EndGlobalSection 77 | EndGlobal 78 | -------------------------------------------------------------------------------- /MagicCube/BruteForceSolver.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "BruteForceSolver.h" 3 | 4 | BruteForceSolver::~BruteForceSolver() 5 | { 6 | } 7 | 8 | void BruteForceSolver::Solve() 9 | { 10 | BruteTask task0; 11 | task0.cube = cube; 12 | Q.push(task0); 13 | 14 | while (!Q.empty()) 15 | { 16 | BruteTask task = Q.front(); 17 | Q.pop(); 18 | 19 | if (task.cube.Check()) 20 | { 21 | Steps = task.Steps; 22 | break; 23 | } 24 | 25 | if (task.Steps.size() >= BRUTEFORCE_MAXSTEPS) 26 | continue; 27 | 28 | for (CubeRotateMethod method = ROTATE_FRONT; method <= ROTATE_DOWNi; method = (CubeRotateMethod)((int)method + 1)) 29 | { 30 | if (isWholeRotate(method) || method == ROTATE_NONE) 31 | continue; 32 | 33 | BruteTask newTask; 34 | newTask.cube = task.cube; 35 | newTask.Steps = task.Steps; 36 | 37 | newTask.cube.DoMethod(method); 38 | newTask.Steps.push_back(method); 39 | 40 | if (!isCheckedOrInQueue[newTask.cube.Serialize()]) 41 | { 42 | Q.push(newTask); 43 | isCheckedOrInQueue[newTask.cube.Serialize()] = true; 44 | } 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /MagicCube/BruteForceSolver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utilities.h" 4 | #include "CubeSolver.h" 5 | #include 6 | #include 7 | 8 | #ifndef BRUTEFORCE_MAXSTEPS 9 | #define BRUTEFORCE_MAXSTEPS 20 10 | #endif 11 | 12 | class BruteTask 13 | { 14 | public: 15 | Cube cube; 16 | CubeSteps Steps; 17 | }; 18 | 19 | class BruteForceSolver : 20 | public CubeSolver 21 | { 22 | public: 23 | BruteForceSolver(Cube &cube) : CubeSolver(cube) 24 | {} 25 | ~BruteForceSolver(); 26 | 27 | void Solve(); 28 | 29 | private: 30 | 31 | queue Q; 32 | map isCheckedOrInQueue; 33 | }; 34 | 35 | -------------------------------------------------------------------------------- /MagicCube/CommandHandlers.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CommandHandlers.h" 3 | 4 | #ifdef USE_GL 5 | 6 | map commandHandler; 7 | 8 | void rotateHandler(string value) 9 | { 10 | string rotateCmd = toUpperString(value); 11 | if (rotateCmd.length() > 1) 12 | rotateCmd[1] = toLower(rotateCmd[1]); 13 | 14 | CubeRotateMethod method = NameToCubeRotateMethod[rotateCmd]; 15 | if (method != ROTATE_NONE) 16 | { 17 | startRotate(method); 18 | } 19 | else 20 | { 21 | printf("Unknown command %s\n", value.c_str()); 22 | } 23 | } 24 | 25 | void checkHandler(string value) 26 | { 27 | printf("U%d D%d L%d R%d F%d B%d: %d\n", cube.CheckU(), cube.CheckD(), cube.CheckL(), cube.CheckR(), cube.CheckF(), cube.CheckB(), cube.Check()); 28 | } 29 | 30 | void helpHandler(string value) 31 | { 32 | printf(":)\n"); 33 | } 34 | 35 | void aboutHandler(string value) 36 | { 37 | printf("Wandai :)\n"); 38 | } 39 | 40 | void resetHandler(string value) 41 | { 42 | cube = Cube(); 43 | } 44 | 45 | void solveHandler(string value) 46 | { 47 | solveAndPrint(cube); 48 | } 49 | 50 | void playHandler(string value) 51 | { 52 | CubeSteps steps = solveAndPrint(cube); 53 | play(steps); 54 | } 55 | 56 | void stopHandler(string value) 57 | { 58 | stopPlay(); 59 | } 60 | 61 | void randomHandler(string value) 62 | { 63 | randomCube(cube); 64 | } 65 | 66 | void fileHandler(string value) 67 | { 68 | try 69 | { 70 | ifstream file(value); 71 | if (file.is_open()) 72 | { 73 | string line; 74 | getline(file, line); 75 | printf("Loading: %s\n", line.c_str()); 76 | cube.Deserialize(line); 77 | file.close(); 78 | } 79 | else 80 | { 81 | printf("ERROR\n"); 82 | } 83 | } 84 | catch (const CubeError &err) 85 | { 86 | printf("CubeError: %s\n", err.what.c_str()); 87 | } 88 | } 89 | 90 | void loadHandler(string value) 91 | { 92 | try 93 | { 94 | if (toLowerString(value) == "") 95 | { 96 | printf("Format1>"); 97 | string line; 98 | getline(cin, line); 99 | printf("Loading: %s\n", line.c_str()); 100 | cube.Deserialize(line); 101 | } 102 | else if (toLowerString(value) == "format2") 103 | { 104 | printf("Format2>"); 105 | 106 | char f2[54]; 107 | for (int i = 0; i < 54; ++i) 108 | { 109 | cin >> f2[i]; 110 | } 111 | 112 | string data = convertFromFormat2(f2); 113 | printf("Loading: %s\n", data.c_str()); 114 | cube.Deserialize(data); 115 | } 116 | else 117 | { 118 | printf("Loading: %s\n", value.c_str()); 119 | cube.Deserialize(value); 120 | } 121 | } 122 | catch (const CubeError &err) 123 | { 124 | printf("CubeError: %s\n", err.what.c_str()); 125 | } 126 | } 127 | 128 | void saveHandler(string value) 129 | { 130 | string data = cube.Serialize(); 131 | if (toLowerString(value) != "format2") 132 | { 133 | printf("%s\n", data.c_str()); 134 | } 135 | else 136 | { 137 | char *f2 = convertToFormat2(data); 138 | for (int i = 0; i < 54; ++i) 139 | { 140 | printf("%c ", f2[i]); 141 | 142 | if ((i + 1) % 3 == 0) 143 | { 144 | printf("\n"); 145 | } 146 | } 147 | delete[] f2; 148 | } 149 | } 150 | 151 | void testHandler(string value) 152 | { 153 | unsigned long long count = 0; 154 | for (;;) 155 | { 156 | ++count; 157 | if (count % 10000 == 0) 158 | { 159 | printf("%llu\n", count); 160 | } 161 | 162 | Cube cube1, cube2; 163 | 164 | for (int i = 0; i < rand() % 1000 + 1; ++i) 165 | { 166 | CubeRotateMethod method = (CubeRotateMethod)((rand() % 12) + 1); 167 | cube1.DoMethod(method); 168 | } 169 | 170 | cube2 = cube1; 171 | 172 | CubeSolver *solver = (CubeSolver*)new GeneralSolver(cube1); 173 | try 174 | { 175 | solver->Solve(); 176 | CubeSteps steps = solver->Steps; 177 | steps = ReduceFilter::Filter(steps); 178 | steps = NoXYZFilter::Filter(steps); 179 | steps = ReduceFilter::Filter(steps); 180 | for (auto step : steps) 181 | { 182 | cube2.DoMethod(step); 183 | } 184 | } 185 | catch (const SolverError &err) 186 | { 187 | printf("ERROR %s %s\n", err.what.c_str(), cube1.Serialize().c_str()); 188 | } 189 | delete solver; 190 | 191 | if (!cube2.Check()) 192 | { 193 | printf("FAIL %s\n", cube1.Serialize().c_str()); 194 | } 195 | } 196 | } 197 | 198 | void tranHandler(string value) 199 | { 200 | isTransparent = !isTransparent; 201 | } 202 | 203 | void axisHandler(string value) 204 | { 205 | doRenderAxis = !doRenderAxis; 206 | } 207 | 208 | void echoHandler(string value) 209 | { 210 | printf("%s\n", value.c_str()); 211 | } 212 | 213 | void set_solverHandler(string value) 214 | { 215 | value = toLowerString(value); 216 | if (value == "" || value == "general") 217 | { 218 | currentSolver = "general"; 219 | } 220 | else if (value == "random" || value == "monkey") 221 | { 222 | currentSolver = "random"; 223 | } 224 | else if (value == "bruteforce" || value == "bf") 225 | { 226 | currentSolver = "bruteforce"; 227 | } 228 | } 229 | 230 | void get_solverHandler(string value) 231 | { 232 | printf("%s\n", currentSolver.c_str()); 233 | } 234 | 235 | 236 | void addCommandHandler(string cmd, CommandHandler handler) 237 | { 238 | commandHandler[cmd] = handler; 239 | } 240 | 241 | void execCommand(string cmd) 242 | { 243 | try 244 | { 245 | string value = ""; 246 | size_t index = cmd.find(' '); 247 | if (index != string::npos) 248 | { 249 | value = cmd.substr(index + 1); 250 | cmd = cmd.substr(0, index); 251 | } 252 | cmd = toLowerString(cmd); 253 | 254 | // other commands 255 | CommandHandler handler = commandHandler[cmd]; 256 | if (handler != NULL) 257 | { 258 | handler(value); 259 | } 260 | else 261 | { 262 | // rotate 263 | handler = commandHandler["rotate"]; 264 | if (handler != NULL) 265 | { 266 | handler(cmd); 267 | } 268 | else 269 | { 270 | printf("Unknown command %s\n", cmd.c_str()); 271 | } 272 | } 273 | } 274 | catch (const SolverError &err) 275 | { 276 | printError(err); 277 | } 278 | catch (const CubeError &err) 279 | { 280 | printError(err); 281 | } 282 | } 283 | 284 | void initCommandHandlers() 285 | { 286 | #define HAND(x) addCommandHandler(#x, x##Handler) 287 | HAND(rotate); 288 | HAND(check); 289 | HAND(help); 290 | HAND(about); 291 | HAND(reset); 292 | HAND(solve); 293 | HAND(play); 294 | HAND(stop); 295 | HAND(random); 296 | HAND(file); 297 | HAND(load); 298 | HAND(save); 299 | HAND(test); 300 | HAND(tran); 301 | HAND(axis); 302 | HAND(echo); 303 | HAND(set_solver); 304 | HAND(get_solver); 305 | #undef HAND 306 | } 307 | 308 | #endif -------------------------------------------------------------------------------- /MagicCube/CommandHandlers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../CubeCommon/CubeCommon.h" 4 | #include "utilities.h" 5 | #include "Input.h" 6 | #include "NoXYZFilter.h" 7 | #include "RandomSolver.h" 8 | #include "BruteForceSolver.h" 9 | 10 | #ifdef USE_GL 11 | 12 | typedef void(*CommandHandler)(string); 13 | 14 | void initCommandHandlers(); 15 | void addCommandHandler(string, CommandHandler); 16 | void execCommand(string); 17 | 18 | extern map commandHandler; 19 | 20 | #endif -------------------------------------------------------------------------------- /MagicCube/Config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MEM_DEBUG 4 | 5 | #define WIDTH 800 6 | #define HEIGHT 600 7 | 8 | #ifndef NOGL 9 | #define USE_GL 10 | #endif 11 | 12 | #define NO_VERTICES_BUFFER // TODO: fix vertices buffer 13 | 14 | #define BRUTEFORCE_MAXSTEPS 7 // ~ 2 minutes 15 | 16 | #ifndef NO_VERTICES_BUFFER 17 | #error TODO: fix vertices buffer 18 | #endif -------------------------------------------------------------------------------- /MagicCube/CubeClient.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CubeClient.h" 3 | 4 | CubeClient::CubeClient() 5 | : TcpClient() 6 | { 7 | initCommandHandlers(); 8 | } 9 | 10 | 11 | CubeClient::~CubeClient() 12 | { 13 | Close(); 14 | } 15 | 16 | void CubeClient::Start() 17 | { 18 | TcpClient::Start(); 19 | threadHeartbeat = new thread([this] {this->heartbeat(); }); 20 | } 21 | 22 | void CubeClient::Close() 23 | { 24 | IsAlive = false; 25 | 26 | if (threadHeartbeat) 27 | { 28 | if (threadHeartbeat->native_handle()) 29 | { 30 | threadHeartbeat->join(); 31 | } 32 | 33 | delete threadHeartbeat; 34 | threadHeartbeat = NULL; 35 | } 36 | 37 | TcpClient::Close(); 38 | } 39 | 40 | bool CubeClient::Auth(string key) 41 | { 42 | StringBuffer sb; 43 | 44 | rapidjson::Writer writer(sb); 45 | writer.StartObject(); 46 | 47 | writer.String("command"); 48 | writer.String("auth"); 49 | 50 | writer.String("key"); 51 | writer.String(key.c_str()); 52 | 53 | writer.EndObject(); 54 | 55 | responseEvent.Reset(); 56 | SendPackage(sb.GetString()); 57 | responseEvent.Wait(); 58 | 59 | return Succeeded; 60 | } 61 | 62 | void CubeClient::OnPackage(Package *&pack) 63 | { 64 | if (!pack || pack->Header.DataLength == 0) return; 65 | pack->Data[pack->Header.DataLength - 1] = '\0'; 66 | log_debug("on package (fd = %u): %s", static_cast(fd), pack->Data); 67 | 68 | Document doc; 69 | doc.Parse(pack->Data); 70 | // {"command": "cmd...", arg1: argv1, arg2: argv2, ...} 71 | // {"ack": "cmd...", arg1: argv1, arg2, argv2, ...} 72 | // {"error": 123, "message": "..."} 73 | // {"success": 0} 74 | do 75 | { 76 | if (!doc.IsObject()) 77 | { 78 | break; 79 | } 80 | 81 | if (doc.HasMember("command") || doc.HasMember("ack")) 82 | { 83 | handleCommandAndAck(doc); 84 | } 85 | else if (doc.HasMember("success")) 86 | { 87 | Succeeded = true; 88 | responseEvent.Set(); 89 | } 90 | else if (doc.HasMember("error")) 91 | { 92 | Succeeded = false; 93 | LastErrorCode = _SE(doc["error"].GetInt()); 94 | LastErrorMessage = doc["message"].GetString(); 95 | responseEvent.Set(); 96 | } 97 | } while (false); 98 | 99 | delete pack; 100 | pack = NULL; 101 | } 102 | 103 | void CubeClient::initCommandHandlers() 104 | { 105 | #define HAND(a) commandHandlers[#a] = &CubeClient::a##Handler 106 | /*HAND(auth_ack); 107 | HAND(list_rooms_ack); 108 | HAND(get_room_info_ack);*/ 109 | #undef HAND 110 | } 111 | 112 | void CubeClient::handleCommandAndAck(Document &doc) 113 | { 114 | string cmd; 115 | 116 | if (doc.HasMember("command")) 117 | { 118 | cmd = doc["command"].GetString(); 119 | } 120 | else if (doc.HasMember("ack")) 121 | { 122 | cmd = doc["command"].GetString() + string("_ack"); 123 | } 124 | 125 | CommandHandlerPtr hand = NULL; 126 | if ((hand = commandHandlers[cmd]) != NULL) 127 | { 128 | (this->*hand)(doc); 129 | } 130 | else 131 | { 132 | return; 133 | } 134 | } 135 | 136 | #undef reqArg 137 | 138 | void CubeClient::heartbeat() 139 | { 140 | string pack; 141 | 142 | StringBuffer sb; 143 | rapidjson::Writer writer(sb); 144 | 145 | writer.StartObject(); 146 | 147 | writer.String("command"); 148 | writer.String("heartbeat"); 149 | 150 | writer.EndObject(); 151 | 152 | pack = sb.GetString(); 153 | 154 | while (IsAlive) 155 | { 156 | SendPackage(pack); 157 | sleep(1); 158 | // sleep(TIMEOUT_S - 5); 159 | } 160 | } -------------------------------------------------------------------------------- /MagicCube/CubeClient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "TcpClient.h" 3 | 4 | class CubeClient : 5 | public TcpClient 6 | { 7 | public: 8 | 9 | typedef void (CubeClient::*CommandHandlerPtr)(Value&); 10 | 11 | bool Succeeded = false; 12 | SessionErrorType LastErrorCode = SESSIONERROR_UNKNOWN; 13 | string LastErrorMessage; 14 | 15 | CubeClient(); 16 | ~CubeClient(); 17 | 18 | void Start(); 19 | void Close(); 20 | bool Auth(string); 21 | 22 | void OnPackage(Package*&); 23 | 24 | private: 25 | 26 | map commandHandlers; 27 | void initCommandHandlers(); 28 | 29 | ManualEvent ackEvent, responseEvent; 30 | 31 | thread *threadHeartbeat = NULL; 32 | 33 | void handleCommandAndAck(Document&); 34 | 35 | void heartbeat(); 36 | }; 37 | 38 | -------------------------------------------------------------------------------- /MagicCube/CubeSolver.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CubeSolver.h" 3 | 4 | string currentSolver = "general"; 5 | 6 | CubeSolver::~CubeSolver() 7 | { 8 | } 9 | 10 | void CubeSolver::Do(CubeRotateMethod method) 11 | { 12 | cube.DoMethod(method); 13 | Steps.push_back(method); 14 | } 15 | -------------------------------------------------------------------------------- /MagicCube/CubeSolver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../CubeCommon/CubeCommon.h" 5 | #include "SolverError.h" 6 | 7 | class CubeSolver 8 | { 9 | public: 10 | 11 | Cube &cube; 12 | vector Steps; 13 | 14 | CubeSolver(Cube &cube): cube(cube) 15 | {} 16 | 17 | virtual ~CubeSolver() = 0; 18 | 19 | virtual void Solve() = 0; 20 | 21 | void Do(CubeRotateMethod); 22 | }; 23 | 24 | extern string currentSolver; -------------------------------------------------------------------------------- /MagicCube/GeneralSolver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "CubeSolver.h" 5 | 6 | class GeneralSolver : 7 | public CubeSolver 8 | { 9 | public: 10 | GeneralSolver(Cube &cube) : CubeSolver(cube) 11 | {} 12 | ~GeneralSolver(); 13 | 14 | void Solve(); 15 | 16 | void MoveToUp(CubeColor); 17 | void MoveToDown(CubeColor); 18 | void MoveToLeft(CubeColor); 19 | void MoveToRight(CubeColor); 20 | void MoveToFront(CubeColor); 21 | void MoveToBack(CubeColor); 22 | 23 | void Stage1(); //pdf stage2: solve the white cross 24 | void Stage2(); //pdf stage3: solve the white corners 25 | void Stage3(); //pdf stage4: solve the middle layer 26 | void Stage4(); //pdf stage5: solve the top layer: get yellow cross 27 | void Stage5(); //pdf stage5: solve the top layer: get all the yellow on top 28 | void Stage6(); //pdf stage6: position the yellow corners correctly 29 | void Stage7(); //pdf stage6: position yellow edges correctly 30 | 31 | private: 32 | bool CheckStage3(); 33 | bool CheckStage4State1(); // + 34 | bool CheckStage4State3(); 35 | bool CheckStage4State4(); // - 36 | bool CheckStage4State4i(); // | 37 | void CheckStage6ABCD(bool*, bool*, bool*, bool*); 38 | void CheckStage7EFGH(bool*, bool*, bool*, bool*); 39 | }; 40 | 41 | -------------------------------------------------------------------------------- /MagicCube/Graphics.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Graphics.h" 3 | 4 | #ifdef USE_GL 5 | 6 | Cube cube; 7 | GLFWwindow *window; 8 | thread *consoleHandlerThread = NULL; 9 | bool consoleRunning = true; 10 | 11 | #ifndef NO_VERTICES_BUFFER 12 | 13 | GLuint vertexArrayId; 14 | 15 | void initVertexArray() 16 | { 17 | glGenVertexArrays(1, &vertexArrayId); 18 | glBindVertexArray(vertexArrayId); 19 | } 20 | 21 | #endif 22 | 23 | void consoleHandler() 24 | { 25 | printf("Hello, you can type commands here!\n"); 26 | while (consoleRunning && cin) 27 | { 28 | string cmd; 29 | printf(">"); 30 | getline(cin, cmd); 31 | double start = glfwGetTime(); 32 | execCommand(cmd); 33 | printf("\nDone(%.4f ms).\n", (glfwGetTime() - start) * 1000); 34 | } 35 | } 36 | 37 | int graphicMode(int argc, char *argv[]) 38 | { 39 | initCommandHandlers(); 40 | consoleHandlerThread = new thread(consoleHandler); 41 | 42 | 43 | //Initialize the library 44 | if (!glfwInit()) 45 | throw string("error glfwInit"); 46 | 47 | 48 | //MSAA 49 | glfwWindowHint(GLFW_SAMPLES, 9); 50 | 51 | //Create a windowed mode window and its OpenGL context 52 | window = glfwCreateWindow(WIDTH, HEIGHT, "Magic Cube", NULL, NULL); 53 | if (!window) 54 | { 55 | glfwTerminate(); 56 | throw string("error glfwCreateWindow"); 57 | } 58 | 59 | //Make the window's context current 60 | glfwMakeContextCurrent(window); 61 | 62 | glfwSetMouseButtonCallback(window, mouseButtonCallback); 63 | 64 | // We process commands in console handler thread. 65 | //glfwSetKeyCallback(window, keyboardCallback); 66 | //glfwSetCharCallback(window, characterCallback); 67 | 68 | initGL(); 69 | 70 | #ifndef NO_VERTICES_BUFFER 71 | initVertexArray(); 72 | initAxisVertexBuffer(); 73 | initCubeVertexBuffer(); 74 | initCubeEdgeVertexBuffer(); 75 | #endif 76 | 77 | glfwSwapInterval(1); 78 | 79 | //Loop until the user closes the window 80 | while (!glfwWindowShouldClose(window)) 81 | { 82 | nextFrame(); 83 | 84 | render(); 85 | 86 | //Swap front and back buffers 87 | glfwSwapBuffers(window); 88 | 89 | //Poll for and process events 90 | glfwPollEvents(); 91 | 92 | keyboardScan(); 93 | mouseMove(); 94 | updateFPS(); 95 | } 96 | 97 | glfwTerminate(); 98 | 99 | consoleRunning = false; 100 | 101 | return 0; 102 | } 103 | 104 | void initGL() 105 | { 106 | // init OpenGL 107 | glEnable(GL_DEPTH_TEST); 108 | glDepthFunc(GL_LESS); 109 | glPointSize(8); 110 | glLineWidth(2); 111 | glEnable(GL_POINT_SMOOTH); 112 | glEnable(GL_LINE_SMOOTH); 113 | glEnable(GL_POLYGON_SMOOTH); 114 | glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // Make round points, not square points 115 | glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); // Antialias the lines 116 | glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); 117 | glEnable(GL_BLEND); 118 | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 119 | glViewport(0, 0, WIDTH, HEIGHT); 120 | glMatrixMode(GL_PROJECTION); 121 | glLoadIdentity(); 122 | gluPerspective(45.0f, (float)(WIDTH) / (float)(HEIGHT), 0.1f, 1000.0f); 123 | glMatrixMode(GL_MODELVIEW); 124 | glLoadIdentity(); 125 | gluLookAt(0.0f, 0.0f, 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); 126 | } 127 | 128 | void updateFPS() 129 | { 130 | static double lastTime = glfwGetTime(); 131 | static int lastFPS = 0; 132 | double currTime = glfwGetTime(); 133 | ++lastFPS; 134 | if (currTime - lastTime >= 1.0) 135 | { 136 | char str[256]; 137 | #ifdef _WIN32 138 | sprintf_s(str, "Magic Cube (FPS: %d)", lastFPS); 139 | #else 140 | snprintf(str, sizeof(str), "Magic Cube (FPS: %d)", lastFPS); 141 | #endif 142 | glfwSetWindowTitle(window, str); 143 | lastTime = glfwGetTime(); 144 | lastFPS = 0; 145 | } 146 | } 147 | 148 | #endif -------------------------------------------------------------------------------- /MagicCube/Graphics.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MagicCube.h" 4 | 5 | #ifdef USE_GL 6 | 7 | extern Cube cube; 8 | extern GLFWwindow *window; 9 | 10 | #ifndef NO_VERTICES_BUFFER 11 | extern GLuint vertexArrayId; 12 | void initVertexArray(); 13 | #endif 14 | 15 | int graphicMode(int, char*[]); 16 | void initGL(); 17 | void updateFPS(); 18 | 19 | #endif -------------------------------------------------------------------------------- /MagicCube/Input.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Input.h" 3 | 4 | #ifdef USE_GL 5 | 6 | double lastX = 0.0, lastY = 0.0; 7 | bool mouseDown = false; 8 | 9 | double lastAngleX, lastAngleY; 10 | 11 | void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods) 12 | { 13 | if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) 14 | { 15 | lastAngleX = viewRotationAngleX; 16 | lastAngleY = viewRotationAngleY; 17 | glfwGetCursorPos(window, &lastX, &lastY); 18 | mouseDown = true; 19 | } 20 | else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) 21 | { 22 | mouseDown = false; 23 | glfwGetCursorPos(window, &lastX, &lastX); 24 | } 25 | } 26 | 27 | void mouseMove() 28 | { 29 | if (!mouseDown) return; 30 | 31 | double currX, currY; 32 | glfwGetCursorPos(window, &currX, &currY); 33 | 34 | double deltaX = currX - lastX, 35 | deltaY = currY - lastY; 36 | 37 | viewRotationAngleY = (GLfloat)(lastAngleY + deltaX * 0.5); 38 | viewRotationAngleX = (GLfloat)(lastAngleX + deltaY * 0.5); 39 | } 40 | 41 | string commandBuffer = ""; 42 | 43 | void keyboardCallback(GLFWwindow *window, int key, int scancode, int action, int mods) 44 | { 45 | if (action == GLFW_PRESS || action == GLFW_REPEAT) 46 | { 47 | if (key == GLFW_KEY_BACKSPACE) 48 | { 49 | if (commandBuffer.length() > 0) 50 | { 51 | commandBuffer = commandBuffer.substr(0, commandBuffer.length() - 1); 52 | } 53 | printf("\r%s ", commandBuffer.c_str()); 54 | printf("\r%s", commandBuffer.c_str()); 55 | } 56 | else if (key == GLFW_KEY_ENTER || key == GLFW_KEY_KP_ENTER) 57 | { 58 | printf("\n"); 59 | double start = glfwGetTime(); 60 | execCommand(commandBuffer); 61 | printf("\nDone(%.4f ms).\n", (glfwGetTime() - start) * 1000); 62 | commandBuffer = ""; 63 | } 64 | } 65 | } 66 | 67 | void characterCallback(GLFWwindow *window, unsigned int codepoint) 68 | { 69 | if (codepoint < 256) 70 | { 71 | char ch = (char)codepoint; 72 | commandBuffer += ch; 73 | printf("%c", ch); 74 | } 75 | } 76 | 77 | void keyboardScan() 78 | { 79 | if (glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) 80 | { 81 | viewRotationAngleY -= 0.5f; 82 | } 83 | if (glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) 84 | { 85 | viewRotationAngleY += 0.5f; 86 | } 87 | if (glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) 88 | { 89 | viewRotationAngleX -= 0.5f; 90 | } 91 | if (glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) 92 | { 93 | viewRotationAngleX += 0.5f; 94 | } 95 | } 96 | 97 | #endif -------------------------------------------------------------------------------- /MagicCube/Input.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "utilities.h" 6 | #include "MagicCube.h" 7 | #include "Graphics.h" 8 | #include "Rendering.h" 9 | 10 | #ifdef USE_GL 11 | 12 | extern double lastX, lastY, lastAngleX, lastAngleY; 13 | extern bool mouseDown; 14 | 15 | void mouseButtonCallback(GLFWwindow*, int, int, int); 16 | void mouseMove(); 17 | void keyboardCallback(GLFWwindow*, int, int, int, int); 18 | void characterCallback(GLFWwindow*, unsigned int); 19 | void keyboardScan(); 20 | 21 | #endif -------------------------------------------------------------------------------- /MagicCube/MagicCube.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "MagicCube.h" 3 | 4 | #ifndef USE_GL 5 | int textMode(int argc, char *argv[]) 6 | { 7 | Cube cube; 8 | 9 | char f2[FORMAT2_LENGTH]; 10 | for (int i = 0; i < FORMAT2_LENGTH; ++i) 11 | { 12 | cin >> f2[i]; 13 | } 14 | 15 | string data = convertFromFormat2(f2); 16 | cube.Deserialize(data); 17 | 18 | CubeSolver *solver = newSolver(cube); 19 | solver->Solve(); 20 | 21 | auto steps = ReduceFilter::Filter(solver->Steps); 22 | steps = NoXYZFilter::Filter(steps); 23 | steps = ReduceFilter::Filter(steps); 24 | 25 | delete solver; 26 | 27 | if (steps.size() > 0) 28 | { 29 | printf("%s", stepsToString(steps, '\n').c_str()); 30 | } 31 | else 32 | { 33 | printf("Nothing to do.\n"); 34 | } 35 | return 0; 36 | } 37 | #else 38 | 39 | void libeventError(int errcode) 40 | { 41 | fprintf(stderr, "libevent fatal error occurred, error code: %d\n", errcode); 42 | exit(1); 43 | } 44 | 45 | void initLibraries() 46 | { 47 | #ifdef _DEBUG 48 | event_enable_debug_mode(); // may cause memory leak 49 | #endif 50 | 51 | event_set_fatal_callback(libeventError); 52 | 53 | #ifdef _WIN32 54 | 55 | #ifdef MEM_DEBUG 56 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 57 | #endif 58 | 59 | WSADATA data; 60 | int err = WSAStartup(0, &data); 61 | err = WSAStartup(data.wVersion, &data); 62 | assert(err == 0); 63 | #endif 64 | 65 | #ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED 66 | evthread_use_windows_threads(); // may cause memory leak 67 | #endif 68 | 69 | #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED 70 | evthread_use_pthreads(); 71 | #endif 72 | } 73 | 74 | void test() 75 | { 76 | CubeClient client; 77 | // while (true) 78 | { 79 | bool connected = false; 80 | for (int i = 0; i < 3; ++i) 81 | { 82 | if (client.Connect(string("127.0.0.1"), 2333)) 83 | { 84 | connected = true; 85 | break; 86 | } 87 | } 88 | if (!connected) 89 | { 90 | log_normal("cannot connect"); 91 | return; 92 | // continue; 93 | } 94 | 95 | client.Start(); 96 | 97 | bool succ = client.Auth("123456"); 98 | log_normal("auth: %d", succ); 99 | 100 | string s; 101 | while (getline(cin, s)) 102 | { 103 | client.SendPackage(s); 104 | 105 | if (!client.IsAlive) 106 | { 107 | break; 108 | } 109 | } 110 | 111 | client.Close(); 112 | } 113 | } 114 | #endif //USE_GL 115 | 116 | int main(int argc, char *argv[]) 117 | { 118 | int retcode = 0; 119 | 120 | #ifdef USE_GL 121 | try 122 | { 123 | initLibraries(); 124 | test(); 125 | 126 | retcode = graphicMode(argc, argv); 127 | } 128 | catch (const string &err) 129 | { 130 | log_warn("%s\n", err.c_str()); 131 | retcode = 1; 132 | } 133 | #else 134 | try 135 | { 136 | retcode = textMode(argc, argv); 137 | } 138 | catch (const SolverError &err) 139 | { 140 | printError(err); 141 | retcode = 1; 142 | } 143 | catch (const CubeError &err) 144 | { 145 | printError(err); 146 | retcode = 1; 147 | } 148 | #endif //USE_GL 149 | 150 | #ifdef MEM_DEBUG 151 | #ifdef _WIN32 152 | _CrtDumpMemoryLeaks(); 153 | #endif 154 | #endif 155 | 156 | return retcode; 157 | } 158 | 159 | -------------------------------------------------------------------------------- /MagicCube/MagicCube.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../CubeCommon/CubeCommon.h" 4 | #include "utilities.h" 5 | #include "CubeSolver.h" 6 | #include "GeneralSolver.h" 7 | #include "ReduceFilter.h" 8 | #include "NoXYZFilter.h" 9 | 10 | #ifdef USE_GL 11 | #include "CommandHandlers.h" 12 | #include "Input.h" 13 | #include "RotationAnimation.h" 14 | #include "Vertices.h" 15 | #include "Graphics.h" 16 | #include "Rendering.h" 17 | #include "TcpClient.h" 18 | #include "CubeClient.h" 19 | #endif 20 | 21 | #ifndef USE_GL 22 | int textMode(int, char *[]); 23 | #endif //USE_GL 24 | 25 | int main(int, char *[]); -------------------------------------------------------------------------------- /MagicCube/MagicCube.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 14 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | Headers 23 | 24 | 25 | Headers 26 | 27 | 28 | Headers 29 | 30 | 31 | Headers 32 | 33 | 34 | Headers 35 | 36 | 37 | Headers 38 | 39 | 40 | Headers 41 | 42 | 43 | Headers 44 | 45 | 46 | Headers 47 | 48 | 49 | Headers 50 | 51 | 52 | Headers 53 | 54 | 55 | Headers 56 | 57 | 58 | Headers 59 | 60 | 61 | Headers 62 | 63 | 64 | Headers 65 | 66 | 67 | Headers 68 | 69 | 70 | Headers 71 | 72 | 73 | Headers 74 | 75 | 76 | Headers 77 | 78 | 79 | Headers 80 | 81 | 82 | Headers 83 | 84 | 85 | Headers 86 | 87 | 88 | Headers 89 | 90 | 91 | 92 | 93 | Sources 94 | 95 | 96 | Sources 97 | 98 | 99 | Sources 100 | 101 | 102 | Sources 103 | 104 | 105 | Sources 106 | 107 | 108 | Sources 109 | 110 | 111 | Sources 112 | 113 | 114 | Sources 115 | 116 | 117 | Sources 118 | 119 | 120 | Sources 121 | 122 | 123 | Sources 124 | 125 | 126 | Sources 127 | 128 | 129 | Sources 130 | 131 | 132 | Sources 133 | 134 | 135 | Sources 136 | 137 | 138 | Sources 139 | 140 | 141 | Sources 142 | 143 | 144 | Sources 145 | 146 | 147 | Sources 148 | 149 | 150 | -------------------------------------------------------------------------------- /MagicCube/NoXYZFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "NoXYZFilter.h" 3 | 4 | map > XYZMapTables = 5 | { 6 | { ROTATE_NONE, { 7 | { ROTATE_NONE, ROTATE_NONE }, 8 | { ROTATE_FRONT, ROTATE_FRONT }, 9 | { ROTATE_BACK, ROTATE_BACK }, 10 | { ROTATE_LEFT, ROTATE_LEFT }, 11 | { ROTATE_RIGHT, ROTATE_RIGHT }, 12 | { ROTATE_UP, ROTATE_UP }, 13 | { ROTATE_DOWN, ROTATE_DOWN }, 14 | { ROTATE_WHOLEX, ROTATE_WHOLEX }, 15 | { ROTATE_WHOLEY, ROTATE_WHOLEY }, 16 | { ROTATE_WHOLEZ, ROTATE_WHOLEZ }, 17 | { ROTATE_NONEi, ROTATE_NONE }, 18 | { ROTATE_FRONTi, ROTATE_FRONTi }, 19 | { ROTATE_BACKi, ROTATE_BACKi }, 20 | { ROTATE_LEFTi, ROTATE_LEFTi }, 21 | { ROTATE_RIGHTi, ROTATE_RIGHTi }, 22 | { ROTATE_UPi, ROTATE_UPi }, 23 | { ROTATE_DOWNi, ROTATE_DOWNi }, 24 | { ROTATE_WHOLEXi, ROTATE_WHOLEXi }, 25 | { ROTATE_WHOLEYi, ROTATE_WHOLEYi }, 26 | { ROTATE_WHOLEZi, ROTATE_WHOLEZi } 27 | } }, 28 | { ROTATE_WHOLEX, { 29 | { ROTATE_NONE, ROTATE_NONE }, 30 | { ROTATE_FRONT, ROTATE_DOWN }, 31 | { ROTATE_BACK, ROTATE_UP }, 32 | { ROTATE_LEFT, ROTATE_LEFT }, 33 | { ROTATE_RIGHT, ROTATE_RIGHT }, 34 | { ROTATE_UP, ROTATE_FRONT }, 35 | { ROTATE_DOWN, ROTATE_BACK }, 36 | { ROTATE_WHOLEX, ROTATE_WHOLEX }, 37 | { ROTATE_WHOLEY, ROTATE_WHOLEZ }, 38 | { ROTATE_WHOLEZ, ROTATE_WHOLEYi }, 39 | { ROTATE_NONEi, ROTATE_NONE }, 40 | { ROTATE_FRONTi, ROTATE_DOWNi }, 41 | { ROTATE_BACKi, ROTATE_UPi }, 42 | { ROTATE_LEFTi, ROTATE_LEFTi }, 43 | { ROTATE_RIGHTi, ROTATE_RIGHTi }, 44 | { ROTATE_UPi, ROTATE_FRONTi }, 45 | { ROTATE_DOWNi, ROTATE_BACKi }, 46 | { ROTATE_WHOLEXi, ROTATE_WHOLEXi }, 47 | { ROTATE_WHOLEYi, ROTATE_WHOLEZi }, 48 | { ROTATE_WHOLEZi, ROTATE_WHOLEY } 49 | } }, 50 | { ROTATE_WHOLEY, { 51 | { ROTATE_NONE, ROTATE_NONE }, 52 | { ROTATE_FRONT, ROTATE_RIGHT }, 53 | { ROTATE_BACK, ROTATE_LEFT }, 54 | { ROTATE_LEFT, ROTATE_FRONT }, 55 | { ROTATE_RIGHT, ROTATE_BACK }, 56 | { ROTATE_UP, ROTATE_UP }, 57 | { ROTATE_DOWN, ROTATE_DOWN }, 58 | { ROTATE_WHOLEX, ROTATE_WHOLEZi }, 59 | { ROTATE_WHOLEY, ROTATE_WHOLEY }, 60 | { ROTATE_WHOLEZ, ROTATE_WHOLEX }, 61 | { ROTATE_NONEi, ROTATE_NONE }, 62 | { ROTATE_FRONTi, ROTATE_RIGHTi }, 63 | { ROTATE_BACKi, ROTATE_LEFTi }, 64 | { ROTATE_LEFTi, ROTATE_FRONTi }, 65 | { ROTATE_RIGHTi, ROTATE_BACKi }, 66 | { ROTATE_UPi, ROTATE_UPi }, 67 | { ROTATE_DOWNi, ROTATE_DOWNi }, 68 | { ROTATE_WHOLEXi, ROTATE_WHOLEZ }, 69 | { ROTATE_WHOLEYi, ROTATE_WHOLEYi }, 70 | { ROTATE_WHOLEZi, ROTATE_WHOLEXi } 71 | } }, 72 | { ROTATE_WHOLEZ, { 73 | { ROTATE_NONE, ROTATE_NONE }, 74 | { ROTATE_FRONT, ROTATE_FRONT }, 75 | { ROTATE_BACK, ROTATE_BACK }, 76 | { ROTATE_LEFT, ROTATE_DOWN }, 77 | { ROTATE_RIGHT, ROTATE_UP }, 78 | { ROTATE_UP, ROTATE_LEFT }, 79 | { ROTATE_DOWN, ROTATE_RIGHT }, 80 | { ROTATE_WHOLEX, ROTATE_WHOLEY }, 81 | { ROTATE_WHOLEY, ROTATE_WHOLEXi }, 82 | { ROTATE_WHOLEZ, ROTATE_WHOLEZ }, 83 | { ROTATE_NONEi, ROTATE_NONE }, 84 | { ROTATE_FRONTi, ROTATE_FRONTi }, 85 | { ROTATE_BACKi, ROTATE_BACKi }, 86 | { ROTATE_LEFTi, ROTATE_DOWNi }, 87 | { ROTATE_RIGHTi, ROTATE_UPi }, 88 | { ROTATE_UPi, ROTATE_LEFTi }, 89 | { ROTATE_DOWNi, ROTATE_RIGHTi }, 90 | { ROTATE_WHOLEXi, ROTATE_WHOLEYi }, 91 | { ROTATE_WHOLEYi, ROTATE_WHOLEX }, 92 | { ROTATE_WHOLEZi, ROTATE_WHOLEZi } 93 | } }, 94 | { ROTATE_WHOLEXi, { 95 | { ROTATE_NONE, ROTATE_NONE }, 96 | { ROTATE_FRONT, ROTATE_UP }, 97 | { ROTATE_BACK, ROTATE_DOWN }, 98 | { ROTATE_LEFT, ROTATE_LEFT }, 99 | { ROTATE_RIGHT, ROTATE_RIGHT }, 100 | { ROTATE_UP, ROTATE_BACK }, 101 | { ROTATE_DOWN, ROTATE_FRONT }, 102 | { ROTATE_WHOLEX, ROTATE_WHOLEX }, 103 | { ROTATE_WHOLEY, ROTATE_WHOLEZi }, 104 | { ROTATE_WHOLEZ, ROTATE_WHOLEY }, 105 | { ROTATE_NONEi, ROTATE_NONE }, 106 | { ROTATE_FRONTi, ROTATE_UPi }, 107 | { ROTATE_BACKi, ROTATE_DOWNi }, 108 | { ROTATE_LEFTi, ROTATE_LEFTi }, 109 | { ROTATE_RIGHTi, ROTATE_RIGHTi }, 110 | { ROTATE_UPi, ROTATE_BACKi }, 111 | { ROTATE_DOWNi, ROTATE_FRONTi }, 112 | { ROTATE_WHOLEXi, ROTATE_WHOLEXi }, 113 | { ROTATE_WHOLEYi, ROTATE_WHOLEZ }, 114 | { ROTATE_WHOLEZi, ROTATE_WHOLEYi } 115 | } }, 116 | { ROTATE_WHOLEYi, { 117 | { ROTATE_NONE, ROTATE_NONE }, 118 | { ROTATE_FRONT, ROTATE_LEFT }, 119 | { ROTATE_BACK, ROTATE_RIGHT }, 120 | { ROTATE_LEFT, ROTATE_BACK }, 121 | { ROTATE_RIGHT, ROTATE_FRONT }, 122 | { ROTATE_UP, ROTATE_UP }, 123 | { ROTATE_DOWN, ROTATE_DOWN }, 124 | { ROTATE_WHOLEX, ROTATE_WHOLEZ }, 125 | { ROTATE_WHOLEY, ROTATE_WHOLEY }, 126 | { ROTATE_WHOLEZ, ROTATE_WHOLEXi }, 127 | { ROTATE_NONEi, ROTATE_NONE }, 128 | { ROTATE_FRONTi, ROTATE_LEFTi }, 129 | { ROTATE_BACKi, ROTATE_RIGHTi }, 130 | { ROTATE_LEFTi, ROTATE_BACKi }, 131 | { ROTATE_RIGHTi, ROTATE_FRONTi }, 132 | { ROTATE_UPi, ROTATE_UPi }, 133 | { ROTATE_DOWNi, ROTATE_DOWNi }, 134 | { ROTATE_WHOLEXi, ROTATE_WHOLEZi }, 135 | { ROTATE_WHOLEYi, ROTATE_WHOLEYi }, 136 | { ROTATE_WHOLEZi, ROTATE_WHOLEX } 137 | } }, 138 | { ROTATE_WHOLEZi, { 139 | { ROTATE_NONE, ROTATE_NONE }, 140 | { ROTATE_FRONT, ROTATE_FRONT }, 141 | { ROTATE_BACK, ROTATE_BACK }, 142 | { ROTATE_LEFT, ROTATE_UP }, 143 | { ROTATE_RIGHT, ROTATE_DOWN }, 144 | { ROTATE_UP, ROTATE_RIGHT }, 145 | { ROTATE_DOWN, ROTATE_LEFT }, 146 | { ROTATE_WHOLEX, ROTATE_WHOLEYi }, 147 | { ROTATE_WHOLEY, ROTATE_WHOLEX }, 148 | { ROTATE_WHOLEZ, ROTATE_WHOLEZ }, 149 | { ROTATE_NONEi, ROTATE_NONE }, 150 | { ROTATE_FRONTi, ROTATE_FRONTi }, 151 | { ROTATE_BACKi, ROTATE_BACKi }, 152 | { ROTATE_LEFTi, ROTATE_UPi }, 153 | { ROTATE_RIGHTi, ROTATE_DOWNi }, 154 | { ROTATE_UPi, ROTATE_RIGHTi }, 155 | { ROTATE_DOWNi, ROTATE_LEFTi }, 156 | { ROTATE_WHOLEXi, ROTATE_WHOLEY }, 157 | { ROTATE_WHOLEYi, ROTATE_WHOLEXi }, 158 | { ROTATE_WHOLEZi, ROTATE_WHOLEZi } 159 | } } 160 | }; 161 | 162 | // above tables were generated by following code: 163 | /*for (CubeRotateMethod wholeMethod = ROTATE_NONE; wholeMethod <= ROTATE_WHOLEZi; wholeMethod = (CubeRotateMethod)((int)wholeMethod + 1)) 164 | { 165 | if (!(wholeMethod == ROTATE_NONE || isWholeRotate(wholeMethod))) 166 | { 167 | continue; 168 | } 169 | 170 | printf("{ %s, {\n", CubeRotateMethodEnumName[wholeMethod].c_str()); 171 | for (CubeRotateMethod src = ROTATE_NONE; src <= ROTATE_WHOLEZi; src = (CubeRotateMethod)((int)src + 1)) 172 | { 173 | for (CubeRotateMethod des = ROTATE_NONE; des <= ROTATE_WHOLEZi; des = (CubeRotateMethod)((int)des + 1)) 174 | { 175 | Cube a, b; 176 | a.DoMethod(wholeMethod); 177 | a.DoMethod(src); 178 | a.DoMethod(inverse(wholeMethod)); 179 | b.DoMethod(des); 180 | if (a == b) 181 | { 182 | // found 183 | printf("\t{%s, %s}", CubeRotateMethodEnumName[src].c_str(), CubeRotateMethodEnumName[des].c_str()); 184 | 185 | break; 186 | } 187 | } 188 | printf(",\n"); 189 | } 190 | printf("} },\n"); 191 | }*/ 192 | 193 | CubeSteps NoXYZFilter::Filter(CubeSteps &steps) 194 | { 195 | CubeSteps newSteps = steps; 196 | auto currentMap = XYZMapTables[ROTATE_NONE]; 197 | size_t size = newSteps.size(); 198 | for (ptrdiff_t i = 0; i < (ptrdiff_t)size; ++i) 199 | { 200 | auto step = currentMap[newSteps[i]]; 201 | if (isWholeRotate(step)) 202 | { 203 | CombineMapTable(currentMap, XYZMapTables[step]); 204 | newSteps[i] = ROTATE_NONE; 205 | } 206 | else 207 | { 208 | newSteps[i] = step; 209 | } 210 | } 211 | CubeSteps newNewSteps; 212 | copySteps(newSteps, newNewSteps); 213 | return newNewSteps; 214 | } 215 | 216 | NoXYZFilter::~NoXYZFilter() 217 | { 218 | } 219 | 220 | void NoXYZFilter::CombineMapTable(map &target, map &mapTable) 221 | { 222 | for (CubeRotateMethod m = ROTATE_NONE; m <= ROTATE_WHOLEZi; m = (CubeRotateMethod)((int)m + 1)) 223 | { 224 | target[m] = mapTable[target[m]]; 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /MagicCube/NoXYZFilter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "StepFilter.h" 6 | 7 | class NoXYZFilter : 8 | public StepFilter 9 | { 10 | public: 11 | virtual ~NoXYZFilter() = 0; 12 | 13 | static CubeSteps Filter(CubeSteps&); 14 | 15 | private: 16 | NoXYZFilter(); 17 | 18 | static void CombineMapTable(map&, map&); 19 | }; 20 | 21 | extern map > XYZMapTables; 22 | 23 | -------------------------------------------------------------------------------- /MagicCube/RandomSolver.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "RandomSolver.h" 3 | 4 | RandomSolver::~RandomSolver() 5 | { 6 | } 7 | 8 | void RandomSolver::Solve() 9 | { 10 | srand(clock()); 11 | while (!cube.Check()) 12 | { 13 | CubeRotateMethod method = (CubeRotateMethod)((rand() % 19) + 1); 14 | if (isWholeRotate(method) || method == ROTATE_NONE || method == ROTATE_NONEi) 15 | { 16 | continue; 17 | } 18 | Do(method); 19 | } 20 | } -------------------------------------------------------------------------------- /MagicCube/RandomSolver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utilities.h" 4 | #include "CubeSolver.h" 5 | 6 | class RandomSolver : 7 | public CubeSolver 8 | { 9 | public: 10 | RandomSolver(Cube &cube) : CubeSolver(cube) 11 | {} 12 | ~RandomSolver(); 13 | 14 | void Solve(); 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /MagicCube/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ======================================================================== 2 | 控制台应用程序:MagicCube 项目概述 3 | ======================================================================== 4 | 5 | 应用程序向导已为您创建了此 MagicCube 应用程序。 6 | 7 | 本文件概要介绍组成 MagicCube 应用程序的每个文件的内容。 8 | 9 | 10 | MagicCube.vcxproj 11 | 这是使用应用程序向导生成的 VC++ 项目的主项目文件,其中包含生成该文件的 Visual C++ 的版本信息,以及有关使用应用程序向导选择的平台、配置和项目功能的信息。 12 | 13 | MagicCube.vcxproj.filters 14 | 这是使用“应用程序向导”生成的 VC++ 项目筛选器文件。它包含有关项目文件与筛选器之间的关联信息。在 IDE 中,通过这种关联,在特定节点下以分组形式显示具有相似扩展名的文件。例如,“.cpp”文件与“源文件”筛选器关联。 15 | 16 | MagicCube.cpp 17 | 这是主应用程序源文件。 18 | 19 | ///////////////////////////////////////////////////////////////////////////// 20 | 其他标准文件: 21 | 22 | StdAfx.h, StdAfx.cpp 23 | 这些文件用于生成名为 MagicCube.pch 的预编译头 (PCH) 文件和名为 StdAfx.obj 的预编译类型文件。 24 | 25 | ///////////////////////////////////////////////////////////////////////////// 26 | 其他注释: 27 | 28 | 应用程序向导使用“TODO:”注释来指示应添加或自定义的源代码部分。 29 | 30 | ///////////////////////////////////////////////////////////////////////////// 31 | -------------------------------------------------------------------------------- /MagicCube/ReduceFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "ReduceFilter.h" 3 | 4 | 5 | ReduceFilter::~ReduceFilter() 6 | { 7 | } 8 | 9 | CubeSteps ReduceFilter::Filter(CubeSteps &steps) 10 | { 11 | CubeSteps newSteps = steps; 12 | while (ReduceContinuous(newSteps) || 13 | ReduceInverse(newSteps)) 14 | { 15 | CubeSteps newNewSteps; 16 | copySteps(newSteps, newNewSteps); 17 | newSteps = newNewSteps; 18 | } 19 | return newSteps; 20 | } 21 | 22 | bool ReduceFilter::ReduceContinuous(CubeSteps &steps) 23 | { 24 | size_t size = steps.size(); 25 | bool found = false; 26 | for (ptrdiff_t i = 0; i < (ptrdiff_t)size - 2; ++i) 27 | { 28 | if (steps[i] == steps[i + 1] && steps[i] == steps[i + 2]) 29 | { 30 | steps[i] = inverse(steps[i]); 31 | steps[i + 1] = steps[i + 2] = ROTATE_NONE; 32 | found = true; 33 | } 34 | } 35 | return found; 36 | } 37 | 38 | bool ReduceFilter::ReduceInverse(CubeSteps &steps) 39 | { 40 | size_t size = steps.size(); 41 | bool found = false; 42 | for (ptrdiff_t i = 0; i < (ptrdiff_t)size - 1; ++i) 43 | { 44 | if (steps[i] == inverse(steps[i + 1])) 45 | { 46 | steps[i] = steps[i + 1] = ROTATE_NONE; 47 | found = true; 48 | } 49 | } 50 | return found; 51 | } -------------------------------------------------------------------------------- /MagicCube/ReduceFilter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "StepFilter.h" 5 | 6 | class ReduceFilter : 7 | public StepFilter 8 | { 9 | public: 10 | virtual ~ReduceFilter() = 0; 11 | 12 | static CubeSteps Filter(CubeSteps&); 13 | 14 | private: 15 | 16 | ReduceFilter(); 17 | 18 | static bool ReduceContinuous(CubeSteps&); 19 | static bool ReduceInverse(CubeSteps&); 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /MagicCube/Rendering.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Rendering.h" 3 | 4 | #ifdef USE_GL 5 | 6 | GLfloat viewRotationAngleX = 45.0, viewRotationAngleY = -45.0; 7 | 8 | bool isTransparent = false; 9 | bool doRenderAxis = true; 10 | 11 | void setColor(CubeColor color) 12 | { 13 | GLfloat alpha = 1.0f; 14 | if (isTransparent) 15 | { 16 | alpha = 0.5f; 17 | } 18 | 19 | switch (color) 20 | { 21 | case COLOR_UNUSED: 22 | glColor4f(0.5f, 0.5f, 0.5f, alpha); 23 | break; 24 | case COLOR_BLUE: 25 | glColor4f(0.0f, 0.0f, 1.0f, alpha); 26 | break; 27 | case COLOR_GREEN: 28 | glColor4f(0.0f, 1.0f, 0.0f, alpha); 29 | break; 30 | case COLOR_ORANGE: 31 | glColor4f(1.0f, 0.5f, 0.0f, alpha); 32 | break; 33 | case COLOR_RED: 34 | glColor4f(1.0f, 0.0f, 0.0f, alpha); 35 | break; 36 | case COLOR_WHITE: 37 | glColor4f(1.0f, 1.0f, 1.0f, alpha); 38 | break; 39 | case COLOR_YELLOW: 40 | glColor4f(1.0f, 1.0f, 0.0f, alpha); 41 | break; 42 | default: 43 | break; 44 | } 45 | } 46 | 47 | void renderAxis() 48 | { 49 | #ifndef NO_VERTICES_BUFFER 50 | glEnableVertexAttribArray(0); 51 | glBindBuffer(GL_ARRAY_BUFFER, axisVertexBuffer); 52 | glVertexAttribPointer( 53 | 0, // index 54 | 3, // size 55 | GL_FLOAT, // type 56 | GL_FALSE, // normalized? 57 | 0, // stride 58 | (void*)0 // array buffer offset 59 | ); 60 | 61 | //x 62 | glColor4f(1.0f, 0.0f, 0.0f, 0.5f); 63 | glDrawArrays(GL_LINES, 0, 3 * 2); 64 | 65 | //y 66 | glColor4f(0.0f, 1.0f, 0.0f, 0.5f); 67 | glDrawArrays(GL_LINES, 3 * 2, 3 * 2); 68 | 69 | //z 70 | glColor4f(0.0f, 0.0f, 1.0f, 0.5f); 71 | glDrawArrays(GL_LINES, 6 * 2, 3 * 2); 72 | 73 | glDisableVertexAttribArray(0); 74 | #else 75 | 76 | //x 77 | glColor4f(1.0f, 0.0f, 0.0f, 0.5f); 78 | glBegin(GL_LINES); 79 | for (int i = 0; i < 6; ++i) 80 | { 81 | glVertex3f(axisVertexBufferData[i * 3 + 0], 82 | axisVertexBufferData[i * 3 + 1], 83 | axisVertexBufferData[i * 3 + 2]); 84 | } 85 | glEnd(); 86 | 87 | //y 88 | glColor4f(0.0f, 1.0f, 0.0f, 0.5f); 89 | glBegin(GL_LINES); 90 | for (int i = 6; i < 12; ++i) 91 | { 92 | glVertex3f(axisVertexBufferData[i * 3 + 0], 93 | axisVertexBufferData[i * 3 + 1], 94 | axisVertexBufferData[i * 3 + 2]); 95 | } 96 | glEnd(); 97 | 98 | //z 99 | glColor4f(0.0f, 0.0f, 1.0f, 0.5f); 100 | glBegin(GL_LINES); 101 | for (int i = 12; i < 18; ++i) 102 | { 103 | glVertex3f(axisVertexBufferData[i * 3 + 0], 104 | axisVertexBufferData[i * 3 + 1], 105 | axisVertexBufferData[i * 3 + 2]); 106 | } 107 | glEnd(); 108 | #endif 109 | } 110 | 111 | void renderSubCube(GLfloat x, GLfloat y, GLfloat z, cube_t colorInfo) 112 | { 113 | glPushMatrix(); 114 | glTranslatef(-1.6f, -1.6f, -1.6f); 115 | 116 | glPushMatrix(); 117 | glTranslatef(1.1f * x, 1.1f * y, 1.1f * z); 118 | 119 | #ifndef NO_VERTICES_BUFFER 120 | glEnableVertexAttribArray(0); 121 | glBindBuffer(GL_ARRAY_BUFFER, cubeVertexBuffer); 122 | glVertexAttribPointer( 123 | 0, // index 124 | 3, // size 125 | GL_FLOAT, // type 126 | GL_FALSE, // normalized? 127 | 0, // stride 128 | (void*)0 // array buffer offset 129 | ); 130 | 131 | setColor((CubeColor)GET_FRONT(colorInfo)); 132 | glDrawArrays(GL_TRIANGLES, 0, 2 * 3); 133 | 134 | setColor((CubeColor)GET_BACK(colorInfo)); 135 | glDrawArrays(GL_TRIANGLES, 2 * 3, 2 * 3); 136 | 137 | setColor((CubeColor)GET_LEFT(colorInfo)); 138 | glDrawArrays(GL_TRIANGLES, 2 * 2 * 3, 2 * 3); 139 | 140 | setColor((CubeColor)GET_RIGHT(colorInfo)); 141 | glDrawArrays(GL_TRIANGLES, 3 * 2 * 3, 2 * 3); 142 | 143 | setColor((CubeColor)GET_UP(colorInfo)); 144 | glDrawArrays(GL_TRIANGLES, 4 * 2 * 3, 2 * 3); 145 | 146 | setColor((CubeColor)GET_DOWN(colorInfo)); 147 | glDrawArrays(GL_TRIANGLES, 5 * 2 * 3, 2 * 3); 148 | 149 | glDisableVertexAttribArray(0); 150 | #else 151 | setColor((CubeColor)GET_FRONT(colorInfo)); 152 | glBegin(GL_TRIANGLES); 153 | for (int i = 0; i < 6; ++i) 154 | { 155 | glVertex3f(cubeVertexBufferData[i * 3 + 0], 156 | cubeVertexBufferData[i * 3 + 1], 157 | cubeVertexBufferData[i * 3 + 2]); 158 | } 159 | glEnd(); 160 | 161 | setColor((CubeColor)GET_BACK(colorInfo)); 162 | glBegin(GL_TRIANGLES); 163 | for (int i = 6; i < 12; ++i) 164 | { 165 | glVertex3f(cubeVertexBufferData[i * 3 + 0], 166 | cubeVertexBufferData[i * 3 + 1], 167 | cubeVertexBufferData[i * 3 + 2]); 168 | } 169 | glEnd(); 170 | 171 | setColor((CubeColor)GET_LEFT(colorInfo)); 172 | glBegin(GL_TRIANGLES); 173 | for (int i = 12; i < 18; ++i) 174 | { 175 | glVertex3f(cubeVertexBufferData[i * 3 + 0], 176 | cubeVertexBufferData[i * 3 + 1], 177 | cubeVertexBufferData[i * 3 + 2]); 178 | } 179 | glEnd(); 180 | 181 | setColor((CubeColor)GET_RIGHT(colorInfo)); 182 | glBegin(GL_TRIANGLES); 183 | for (int i = 18; i < 24; ++i) 184 | { 185 | glVertex3f(cubeVertexBufferData[i * 3 + 0], 186 | cubeVertexBufferData[i * 3 + 1], 187 | cubeVertexBufferData[i * 3 + 2]); 188 | } 189 | glEnd(); 190 | 191 | setColor((CubeColor)GET_UP(colorInfo)); 192 | glBegin(GL_TRIANGLES); 193 | for (int i = 24; i < 30; ++i) 194 | { 195 | glVertex3f(cubeVertexBufferData[i * 3 + 0], 196 | cubeVertexBufferData[i * 3 + 1], 197 | cubeVertexBufferData[i * 3 + 2]); 198 | } 199 | glEnd(); 200 | 201 | setColor((CubeColor)GET_DOWN(colorInfo)); 202 | glBegin(GL_TRIANGLES); 203 | for (int i = 30; i < 36; ++i) 204 | { 205 | glVertex3f(cubeVertexBufferData[i * 3 + 0], 206 | cubeVertexBufferData[i * 3 + 1], 207 | cubeVertexBufferData[i * 3 + 2]); 208 | } 209 | glEnd(); 210 | 211 | glColor4f(0.0f, 0.0f, 0.0f, 1.0f); 212 | glBegin(GL_LINES); 213 | for (int i = 0; i < 24; ++i) 214 | { 215 | glVertex3f(cubeEdgeVertexBufferData[i * 3 + 0], 216 | cubeEdgeVertexBufferData[i * 3 + 1], 217 | cubeEdgeVertexBufferData[i * 3 + 2]); 218 | } 219 | glEnd(); 220 | #endif 221 | 222 | glPopMatrix(); 223 | 224 | glPopMatrix(); 225 | } 226 | 227 | void renderCube(Cube &cube) 228 | { 229 | glPushMatrix(); 230 | glTranslatef(-1.6f, -1.6f, -1.6f); 231 | for (int x = 0; x <= 2; ++x) 232 | { 233 | for (int y = 0; y <= 2; ++y) 234 | { 235 | for (int z = 0; z <= 2; ++z) 236 | { 237 | renderSubCube((GLfloat)x, (GLfloat)y, (GLfloat)z, cube.subCubes[x][y][z]); 238 | } 239 | } 240 | } 241 | glPopMatrix(); 242 | } 243 | 244 | inline void renderCubeRange(Cube &cube, int x0, int x1, int y0, int y1, int z0, int z1) 245 | { 246 | for (int x = x0; x <= x1; ++x) 247 | { 248 | for (int y = y0; y <= y1; ++y) 249 | { 250 | for (int z = z0; z <= z1; ++z) 251 | { 252 | renderSubCube((GLfloat)x, (GLfloat)y, (GLfloat)z, cube.subCubes[x][y][z]); 253 | } 254 | } 255 | } 256 | } 257 | 258 | void renderCube(Cube &cube, float angle, CubeRotateMethod method) 259 | { 260 | switch (method) 261 | { 262 | case ROTATE_FRONT: 263 | glPushMatrix(); 264 | glRotatef(angle, 0.0, 0.0, -1.0); 265 | renderCubeRange(cube, 0, 2, 0, 2, 2, 2); 266 | glPopMatrix(); 267 | renderCubeRange(cube, 0, 2, 0, 2, 0, 1); 268 | break; 269 | case ROTATE_BACK: 270 | glPushMatrix(); 271 | glRotatef(angle, 0.0, 0.0, 1.0); 272 | renderCubeRange(cube, 0, 2, 0, 2, 0, 0); 273 | glPopMatrix(); 274 | renderCubeRange(cube, 0, 2, 0, 2, 1, 2); 275 | break; 276 | case ROTATE_LEFT: 277 | glPushMatrix(); 278 | glRotatef(angle, 1.0, 0.0, 0.0); 279 | renderCubeRange(cube, 0, 0, 0, 2, 0, 2); 280 | glPopMatrix(); 281 | renderCubeRange(cube, 1, 2, 0, 2, 0, 2); 282 | break; 283 | case ROTATE_RIGHT: 284 | glPushMatrix(); 285 | glRotatef(angle, -1.0, 0.0, 0.0); 286 | renderCubeRange(cube, 2, 2, 0, 2, 0, 2); 287 | glPopMatrix(); 288 | renderCubeRange(cube, 0, 1, 0, 2, 0, 2); 289 | break; 290 | case ROTATE_UP: 291 | glPushMatrix(); 292 | glRotatef(angle, 0.0, -1.0, 0.0); 293 | renderCubeRange(cube, 0, 2, 2, 2, 0, 2); 294 | glPopMatrix(); 295 | renderCubeRange(cube, 0, 2, 0, 1, 0, 2); 296 | break; 297 | case ROTATE_DOWN: 298 | glPushMatrix(); 299 | glRotatef(angle, 0.0, 1.0, 0.0); 300 | renderCubeRange(cube, 0, 2, 0, 0, 0, 2); 301 | glPopMatrix(); 302 | renderCubeRange(cube, 0, 2, 1, 2, 0, 2); 303 | break; 304 | case ROTATE_WHOLEX: 305 | glPushMatrix(); 306 | glRotatef(angle, -1.0, 0.0, 0.0); 307 | renderCubeRange(cube, 0, 2, 0, 2, 0, 2); 308 | glPopMatrix(); 309 | break; 310 | case ROTATE_WHOLEY: 311 | glPushMatrix(); 312 | glRotatef(angle, 0.0, -1.0, 0.0); 313 | renderCubeRange(cube, 0, 2, 0, 2, 0, 2); 314 | glPopMatrix(); 315 | break; 316 | case ROTATE_WHOLEZ: 317 | glPushMatrix(); 318 | glRotatef(angle, 0.0, 0.0, -1.0); 319 | renderCubeRange(cube, 0, 2, 0, 2, 0, 2); 320 | glPopMatrix(); 321 | break; 322 | case ROTATE_FRONTi: 323 | glPushMatrix(); 324 | glRotatef(angle, 0.0, 0.0, 1.0); 325 | renderCubeRange(cube, 0, 2, 0, 2, 2, 2); 326 | glPopMatrix(); 327 | renderCubeRange(cube, 0, 2, 0, 2, 0, 1); 328 | break; 329 | case ROTATE_BACKi: 330 | glPushMatrix(); 331 | glRotatef(angle, 0.0, 0.0, -1.0); 332 | renderCubeRange(cube, 0, 2, 0, 2, 0, 0); 333 | glPopMatrix(); 334 | renderCubeRange(cube, 0, 2, 0, 2, 1, 2); 335 | break; 336 | case ROTATE_LEFTi: 337 | glPushMatrix(); 338 | glRotatef(angle, -1.0, 0.0, 0.0); 339 | renderCubeRange(cube, 0, 0, 0, 2, 0, 2); 340 | glPopMatrix(); 341 | renderCubeRange(cube, 1, 2, 0, 2, 0, 2); 342 | break; 343 | case ROTATE_RIGHTi: 344 | glPushMatrix(); 345 | glRotatef(angle, 1.0, 0.0, 0.0); 346 | renderCubeRange(cube, 2, 2, 0, 2, 0, 2); 347 | glPopMatrix(); 348 | renderCubeRange(cube, 0, 1, 0, 2, 0, 2); 349 | break; 350 | case ROTATE_UPi: 351 | glPushMatrix(); 352 | glRotatef(angle, 0.0, 1.0, 0.0); 353 | renderCubeRange(cube, 0, 2, 2, 2, 0, 2); 354 | glPopMatrix(); 355 | renderCubeRange(cube, 0, 2, 0, 1, 0, 2); 356 | break; 357 | case ROTATE_DOWNi: 358 | glPushMatrix(); 359 | glRotatef(angle, 0.0, -1.0, 0.0); 360 | renderCubeRange(cube, 0, 2, 0, 0, 0, 2); 361 | glPopMatrix(); 362 | renderCubeRange(cube, 0, 2, 1, 2, 0, 2); 363 | break; 364 | case ROTATE_WHOLEXi: 365 | glPushMatrix(); 366 | glRotatef(angle, 1.0, 0.0, 0.0); 367 | renderCubeRange(cube, 0, 2, 0, 2, 0, 2); 368 | glPopMatrix(); 369 | break; 370 | case ROTATE_WHOLEYi: 371 | glPushMatrix(); 372 | glRotatef(angle, 0.0, 1.0, 0.0); 373 | renderCubeRange(cube, 0, 2, 0, 2, 0, 2); 374 | glPopMatrix(); 375 | break; 376 | case ROTATE_WHOLEZi: 377 | glPushMatrix(); 378 | glRotatef(angle, 0.0, 0.0, 1.0); 379 | renderCubeRange(cube, 0, 2, 0, 2, 0, 2); 380 | glPopMatrix(); 381 | break; 382 | default: 383 | renderCubeRange(cube, 0, 2, 0, 2, 0, 2); 384 | break; 385 | } 386 | } 387 | 388 | void render() 389 | { 390 | glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 391 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 392 | glFlush(); 393 | 394 | glPushMatrix(); 395 | glTranslatef(0.0f, 0.0f, -10.0f); 396 | 397 | glPushMatrix(); 398 | glRotatef(viewRotationAngleX, 1.0f, 0.0f, 0.0f); 399 | 400 | glPushMatrix(); 401 | glRotatef(viewRotationAngleY, 0.0f, 1.0f, 0.0f); 402 | 403 | glPushMatrix(); 404 | glScalef(3, 3, 3); 405 | 406 | if (doRenderAxis) 407 | { 408 | renderAxis(); 409 | } 410 | 411 | glPopMatrix(); 412 | 413 | renderCube(cube, (GLfloat)rotateAngle, rotateMethod); 414 | 415 | glPopMatrix(); 416 | glPopMatrix(); 417 | glPopMatrix(); 418 | 419 | glFlush(); 420 | } 421 | 422 | #endif -------------------------------------------------------------------------------- /MagicCube/Rendering.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MagicCube.h" 4 | #include "Graphics.h" 5 | #include "Vertices.h" 6 | #include "RotationAnimation.h" 7 | 8 | #ifdef USE_GL 9 | 10 | extern GLfloat viewRotationAngleX, viewRotationAngleY; 11 | extern bool isTransparent; 12 | extern bool doRenderAxis; 13 | 14 | void setColor(CubeColor); 15 | void renderAxis(); 16 | void renderSubCube(GLfloat, GLfloat, GLfloat, cube_t); 17 | void renderCube(Cube&); 18 | inline void renderCubeRange(Cube&, int, int, int, int, int, int); 19 | void renderCube(Cube&, float, CubeRotateMethod); 20 | void render(); 21 | 22 | #endif -------------------------------------------------------------------------------- /MagicCube/RotationAnimation.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "RotationAnimation.h" 3 | 4 | #ifdef USE_GL 5 | 6 | bool playing = false; 7 | vector stepsToPlay; 8 | ptrdiff_t playIndex = 0; 9 | 10 | double rotateAngle = 0.0; 11 | double finishAngle = 90.0; 12 | CubeRotateMethod rotateMethod = ROTATE_NONE; 13 | 14 | double lastPlayTime = glfwGetTime(); 15 | 16 | const double speed = 1.5; 17 | 18 | double easingDelta(double currentAngle) 19 | { 20 | currentAngle = abs(currentAngle); 21 | if (currentAngle == 0.0) 22 | { 23 | return speed * 180.0; 24 | } 25 | else 26 | { 27 | return speed * min(180.0, 8100.0 / currentAngle); 28 | } 29 | } 30 | 31 | void rotateFinishCallback() 32 | { 33 | if (rotateMethod == ROTATE_NONE) 34 | return; 35 | 36 | cube.DoMethod(rotateMethod); 37 | 38 | rotateAngle = 0.0; 39 | rotateMethod = ROTATE_NONE; 40 | 41 | if (playing) 42 | { 43 | playNext(); 44 | } 45 | } 46 | 47 | void nextFrame() 48 | { 49 | double currentTime = glfwGetTime(); 50 | 51 | if (rotateMethod != ROTATE_NONE) 52 | { 53 | double delta = easingDelta(rotateAngle) * (currentTime - lastPlayTime); 54 | rotateAngle += delta; 55 | if (rotateAngle >= finishAngle) 56 | { 57 | rotateFinishCallback(); 58 | } 59 | } 60 | 61 | lastPlayTime = currentTime; 62 | } 63 | 64 | void finishCurrentRotate() 65 | { 66 | rotateAngle = finishAngle; 67 | rotateFinishCallback(); 68 | } 69 | 70 | void startRotate(CubeRotateMethod method) 71 | { 72 | if (rotateMethod != ROTATE_NONE) 73 | finishCurrentRotate(); 74 | rotateMethod = method; 75 | lastPlayTime = glfwGetTime(); 76 | } 77 | 78 | void play(CubeSteps &steps) 79 | { 80 | if (steps.size() <= 0) return; 81 | stepsToPlay = steps; 82 | playIndex = 0; 83 | playing = true; 84 | startRotate(stepsToPlay[0]); 85 | } 86 | 87 | void playNext() 88 | { 89 | if (!playing) 90 | { 91 | return; 92 | } 93 | 94 | ++playIndex; 95 | if (playIndex < (ptrdiff_t)stepsToPlay.size()) 96 | { 97 | startRotate(stepsToPlay[playIndex]); 98 | } 99 | else 100 | { 101 | stopPlay(); 102 | } 103 | } 104 | 105 | void stopPlay() 106 | { 107 | playing = false; 108 | playIndex = 0; 109 | } 110 | #endif -------------------------------------------------------------------------------- /MagicCube/RotationAnimation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "MagicCube.h" 4 | 5 | #ifdef USE_GL 6 | 7 | extern bool playing; 8 | extern CubeSteps stepsToPlay; 9 | extern ptrdiff_t playIndex; 10 | 11 | extern double rotateAngle, finishAngle; 12 | extern CubeRotateMethod rotateMethod; 13 | 14 | extern const double speed; 15 | 16 | double easingDelta(double); 17 | void rotateFinishCallback(); 18 | void nextFrame(); 19 | void finishCurrentRotate(); 20 | void startRotate(CubeRotateMethod); 21 | void play(CubeSteps&); 22 | void playNext(); 23 | void stopPlay(); 24 | 25 | #endif -------------------------------------------------------------------------------- /MagicCube/SolverError.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "SolverError.h" 3 | 4 | 5 | SolverError::SolverError() 6 | { 7 | } 8 | 9 | 10 | SolverError::~SolverError() 11 | { 12 | } 13 | -------------------------------------------------------------------------------- /MagicCube/SolverError.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class SolverError 4 | { 5 | public: 6 | string what; 7 | 8 | SolverError(); 9 | SolverError(string what) : what(what) 10 | {} 11 | ~SolverError(); 12 | }; 13 | 14 | -------------------------------------------------------------------------------- /MagicCube/StepFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "StepFilter.h" 3 | 4 | 5 | StepFilter::StepFilter() 6 | { 7 | } 8 | 9 | 10 | CubeSteps StepFilter::Filter(CubeSteps &s) 11 | { 12 | throw "Not Implemented"; 13 | } 14 | 15 | StepFilter::~StepFilter() 16 | { 17 | } 18 | -------------------------------------------------------------------------------- /MagicCube/StepFilter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "utilities.h" 4 | #include "../CubeCommon/CubeCommon.h" 5 | 6 | class StepFilter 7 | { 8 | public: 9 | virtual ~StepFilter() = 0; 10 | 11 | static CubeSteps Filter(CubeSteps&); 12 | 13 | private: 14 | StepFilter(); 15 | }; 16 | 17 | -------------------------------------------------------------------------------- /MagicCube/TcpClient.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "TcpClient.h" 3 | 4 | #ifndef NONET 5 | 6 | TcpClient::TcpClient() 7 | : doQueueEvent(false, true) 8 | { 9 | } 10 | 11 | 12 | TcpClient::~TcpClient() 13 | { 14 | Close(); 15 | queueLock.lock(); 16 | queueLock.unlock(); 17 | } 18 | 19 | bool TcpClient::Connect(const string &address, short port) 20 | { 21 | #ifdef ENABLE_IPV6 22 | if (address.find(':') != string::npos) // ipv6 23 | { 24 | fd = socket(AF_INET6, SOCK_STREAM, 0); 25 | if (fd <= 0) 26 | { 27 | fd = static_cast(0); 28 | _perror("socket6"); 29 | return false; 30 | } 31 | 32 | sockaddr_in6 sin6; 33 | sin6.sin6_family = AF_INET6; 34 | evutil_inet_pton(AF_INET6, address.c_str(), &(sin6.sin6_addr.s6_addr)); 35 | sin6.sin6_port = htons(port); 36 | 37 | if (connect(fd, reinterpret_cast(&sin6), sizeof(sin6)) != 0) 38 | { 39 | _perror("connect6"); 40 | #ifdef _WIN32 41 | closesocket(fd); 42 | #else 43 | close(fd); 44 | #endif 45 | fd = static_cast(0); 46 | return false; 47 | } 48 | 49 | return true; 50 | } 51 | #else 52 | if (address.find(':') != string::npos) // ipv6 53 | { 54 | log_warn("IPv6 is not supported."); 55 | return false; 56 | } 57 | #endif 58 | 59 | #ifdef ENABLE_IPV4 60 | fd = socket(AF_INET, SOCK_STREAM, 0); 61 | if (fd <= 0) 62 | { 63 | fd = static_cast(0); 64 | _perror("socket"); 65 | return false; 66 | } 67 | 68 | sockaddr_in sin; 69 | sin.sin_family = AF_INET; 70 | evutil_inet_pton(AF_INET, address.c_str(), &(sin.sin_addr.s_addr)); 71 | sin.sin_port = htons(port); 72 | 73 | if (connect(fd, reinterpret_cast(&sin), sizeof(sin)) != 0) 74 | { 75 | _perror("connect"); 76 | #ifdef _WIN32 77 | closesocket(fd); 78 | #else 79 | close(fd); 80 | #endif 81 | fd = static_cast(0); 82 | return false; 83 | } 84 | 85 | return true; 86 | #endif 87 | } 88 | 89 | void TcpClient::Close() 90 | { 91 | IsAlive = false; 92 | 93 | if (fd) 94 | { 95 | #ifdef _WIN32 96 | closesocket(fd); 97 | #else 98 | close(fd); 99 | #endif 100 | fd = static_cast(0); 101 | } 102 | 103 | if (threadReader) 104 | { 105 | if (threadReader->native_handle()) 106 | { 107 | threadReader->join(); 108 | } 109 | delete threadReader; 110 | threadReader = NULL; 111 | } 112 | 113 | doQueueEvent.Set(); 114 | 115 | if (threadWriter) 116 | { 117 | if (threadWriter->native_handle()) 118 | { 119 | threadWriter->join(); 120 | } 121 | delete threadWriter; 122 | threadWriter = NULL; 123 | } 124 | 125 | while (!pendingPackages.empty()) 126 | { 127 | Package *&pack = pendingPackages.front(); 128 | if (pack) 129 | { 130 | delete pack; 131 | pack = NULL; 132 | } 133 | pendingPackages.pop(); 134 | } 135 | } 136 | 137 | void TcpClient::Wait() 138 | { 139 | if (threadWriter) 140 | { 141 | threadWriter->join(); 142 | } 143 | } 144 | 145 | void TcpClient::Start() 146 | { 147 | if (IsAlive) return; 148 | IsAlive = true; 149 | 150 | doQueueEvent.Reset(); 151 | 152 | threadReader = new thread([this] {this->Reader(); }); 153 | threadWriter = new thread([this] {this->Writer(); }); 154 | } 155 | 156 | void TcpClient::Reader() 157 | { 158 | while (IsAlive) 159 | { 160 | const size_t headerLength = sizeof(PackageHeader); 161 | 162 | // read header 163 | char headerBuffer[headerLength]; 164 | if (!bufferedRecv(headerBuffer, headerLength)) 165 | { 166 | log_debug("Read error, disconnected."); 167 | break; 168 | } 169 | 170 | PackageHeader header = *reinterpret_cast(headerBuffer); 171 | header.DataLength = ntohpacklen(header.DataLength); 172 | 173 | if (memcmp(headerBuffer, MAGIC_MARK, min(headerLength, sizeof(MAGIC_MARK) - 1)) != 0) 174 | { 175 | log_debug("Protocol mismatch."); 176 | break; 177 | } 178 | 179 | if (header.DataLength == 0 || header.DataLength > PACKAGE_MAXLENGTH) 180 | { 181 | log_debug("Package is empty or too long."); 182 | break; 183 | } 184 | 185 | Package *pack = new (header.DataLength) Package; 186 | if (!pack) 187 | { 188 | throw bad_alloc(); 189 | } 190 | pack->Header = header; // copy 191 | 192 | memset(pack->Data, 0x00, header.DataLength); // ensure 193 | 194 | if (!bufferedRecv(pack->Data, header.DataLength)) 195 | { 196 | log_debug("Read error, disconnected."); 197 | break; 198 | } 199 | 200 | OnPackage(pack); 201 | if (pack) 202 | { 203 | delete pack; 204 | pack = NULL; 205 | } 206 | } 207 | 208 | // error or disconnected. 209 | IsAlive = false; 210 | doQueueEvent.Set(); 211 | } 212 | 213 | void TcpClient::Writer() 214 | { 215 | while (IsAlive) 216 | { 217 | 218 | doQueueEvent.Wait(); 219 | 220 | { 221 | unique_lock lckQueue(queueLock); 222 | 223 | while (!pendingPackages.empty()) 224 | { 225 | Package *&pack = pendingPackages.front(); 226 | 227 | size_t dataLength = pack->Header.DataLength; 228 | pack->Header.DataLength = htonpacklen(pack->Header.DataLength); 229 | 230 | if (!bufferedSend(reinterpret_cast(pack), sizeof(PackageHeader) + dataLength)) 231 | { 232 | log_debug("Send error, disconnected."); 233 | break; 234 | } 235 | 236 | if (pack) 237 | { 238 | delete pack; 239 | pack = NULL; 240 | } 241 | pendingPackages.pop(); 242 | } 243 | } 244 | } 245 | 246 | // error or disconnected. 247 | IsAlive = false; 248 | doQueueEvent.Set(); 249 | } 250 | 251 | void TcpClient::OnPackage(Package *&pack) 252 | { 253 | if (!pack || pack->Header.DataLength == 0) return; 254 | pack->Data[pack->Header.DataLength - 1] = '\0'; 255 | log_debug("on package (fd = %u): %s\n", static_cast(fd), pack->Data); 256 | 257 | // TODO: process received package 258 | 259 | delete pack; 260 | pack = NULL; 261 | } 262 | 263 | void TcpClient::SendPackage(Package *&pack) 264 | { 265 | if (!pack || pack->Header.DataLength == 0) return; 266 | 267 | { 268 | unique_lock lckQueue(queueLock); 269 | pendingPackages.push(pack); 270 | } 271 | 272 | doQueueEvent.Set(); 273 | } 274 | 275 | void TcpClient::SendPackage(string str) 276 | { 277 | Package *pack = MakePackage(str); 278 | SendPackage(pack); 279 | } 280 | 281 | Package *TcpClient::MakePackage(string &strdata) 282 | { 283 | package_len_t len = static_cast((strdata.length() + 1) * sizeof(char)); 284 | Package *pack = new (len) Package; 285 | memcpy(pack->Header.Magic, MAGIC_MARK, sizeof(MAGIC_MARK) - 1); 286 | pack->Header.DataLength = len; 287 | memcpy(pack->Data, strdata.c_str(), len); 288 | return pack; 289 | } 290 | 291 | bool TcpClient::bufferedRecv(char *buffer, size_t size) 292 | { 293 | size_t readLength = 0; 294 | 295 | while (IsAlive && readLength < size) 296 | { 297 | size_t wantRead = min(BUFFER_SIZE, size - readLength); 298 | size_t currentRead = recv(fd, buffer + readLength, wantRead, 0); 299 | if (currentRead <= 0) // error or disconnected 300 | { 301 | break; 302 | } 303 | readLength += currentRead; 304 | } 305 | 306 | return readLength == size; 307 | } 308 | 309 | bool TcpClient::bufferedSend(char *buffer, size_t size) 310 | { 311 | size_t sentLength = 0; 312 | 313 | while (IsAlive && sentLength < size) 314 | { 315 | size_t wantSend = min(BUFFER_SIZE, size - sentLength); 316 | size_t currentSend = send(fd, buffer + sentLength, wantSend, 0); 317 | if (currentSend <= 0) // error or disconnected 318 | { 319 | break; 320 | } 321 | sentLength += currentSend; 322 | } 323 | 324 | return sentLength == size; 325 | } 326 | 327 | #endif -------------------------------------------------------------------------------- /MagicCube/TcpClient.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef NONET 4 | 5 | class TcpClient 6 | { 7 | public: 8 | bool IsAlive = false; 9 | 10 | TcpClient(); 11 | virtual ~TcpClient(); 12 | 13 | bool Connect(const string&, short); 14 | virtual void Close(); 15 | 16 | void Wait(); 17 | 18 | virtual void Start(); 19 | 20 | void Reader(); 21 | void Writer(); 22 | 23 | virtual void OnPackage(Package*&); 24 | 25 | void SendPackage(Package*&); 26 | void SendPackage(string); 27 | 28 | static Package *MakePackage(string&); 29 | 30 | protected: 31 | 32 | ManualEvent doQueueEvent; 33 | 34 | thread *threadReader = NULL, *threadWriter = NULL; 35 | 36 | evutil_socket_t fd = static_cast(0); 37 | 38 | queue pendingPackages; 39 | mutex writeLock, queueLock; 40 | 41 | bool bufferedRecv(char*, size_t); 42 | bool bufferedSend(char*, size_t); 43 | 44 | private: 45 | 46 | DISALLOW_COPY_AND_ASSIGN(TcpClient); 47 | }; 48 | 49 | #endif -------------------------------------------------------------------------------- /MagicCube/Vertices.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Vertices.h" 3 | 4 | #ifdef USE_GL 5 | 6 | const GLfloat axisVertexBufferData[] = { 7 | //x 8 | -1.0f, 0.0f, 0.0f, 9 | 1.0f, 0.0f, 0.0f, 10 | 0.975f, 0.025f, 0.0f, 11 | 1.0f, 0.0f, 0.0f, 12 | 0.975f, -0.025f, 0.0f, 13 | 1.0f, 0.0f, 0.0f, 14 | //y 15 | 0.0f, -1.0f, 0.0f, 16 | 0.0f, 1.0f, 0.0f, 17 | 0.025f, 0.975f, 0.0f, 18 | 0.0f, 1.0f, 0.0f, 19 | -0.025f, 0.975f, 0.0f, 20 | 0.0f, 1.0f, 0.0f, 21 | //z 22 | 0.0f, 0.0f, -1.0f, 23 | 0.0f, 0.0f, 1.0f, 24 | 0.0f, 0.025f, 0.975f, 25 | 0.0f, 0.0f, 1.0f, 26 | 0.0f, -0.025f, 0.975f, 27 | 0.0f, 0.0f, 1.0f 28 | }; 29 | 30 | const GLfloat cubeVertexBufferData[] = { 31 | //Front 32 | 0.0f, 0.0f, 1.0f, 33 | 0.0f, 1.0f, 1.0f, 34 | 1.0f, 0.0f, 1.0f, 35 | 1.0f, 1.0f, 1.0f, 36 | 0.0f, 1.0f, 1.0f, 37 | 1.0f, 0.0f, 1.0f, 38 | //Back 39 | 0.0f, 0.0f, 0.0f, 40 | 0.0f, 1.0f, 0.0f, 41 | 1.0f, 0.0f, 0.0f, 42 | 1.0f, 1.0f, 0.0f, 43 | 0.0f, 1.0f, 0.0f, 44 | 1.0f, 0.0f, 0.0f, 45 | //Left 46 | 0.0f, 0.0f, 0.0f, 47 | 0.0f, 1.0f, 0.0f, 48 | 0.0f, 0.0f, 1.0f, 49 | 0.0f, 1.0f, 1.0f, 50 | 0.0f, 1.0f, 0.0f, 51 | 0.0f, 0.0f, 1.0f, 52 | //Right 53 | 1.0f, 0.0f, 0.0f, 54 | 1.0f, 1.0f, 0.0f, 55 | 1.0f, 0.0f, 1.0f, 56 | 1.0f, 1.0f, 1.0f, 57 | 1.0f, 1.0f, 0.0f, 58 | 1.0f, 0.0f, 1.0f, 59 | //Up 60 | 0.0f, 1.0f, 0.0f, 61 | 1.0f, 1.0f, 0.0f, 62 | 0.0f, 1.0f, 1.0f, 63 | 1.0f, 1.0f, 1.0f, 64 | 1.0f, 1.0f, 0.0f, 65 | 0.0f, 1.0f, 1.0f, 66 | //Down 67 | 0.0f, 0.0f, 0.0f, 68 | 1.0f, 0.0f, 0.0f, 69 | 0.0f, 0.0f, 1.0f, 70 | 1.0f, 0.0f, 1.0f, 71 | 1.0f, 0.0f, 0.0f, 72 | 0.0f, 0.0f, 1.0f 73 | }; 74 | 75 | const GLfloat cubeEdgeVertexBufferData[] = { 76 | 0.0f, 1.0f, 0.0f, 77 | 0.0f, 1.0f, 1.0f, 78 | 0.0f, 1.0f, 1.0f, 79 | 1.0f, 1.0f, 1.0f, 80 | 1.0f, 1.0f, 1.0f, 81 | 1.0f, 1.0f, 0.0f, 82 | 0.0f, 1.0f, 0.0f, 83 | 1.0f, 1.0f, 0.0f, 84 | 0.0f, 0.0f, 0.0f, 85 | 0.0f, 0.0f, 1.0f, 86 | 0.0f, 0.0f, 1.0f, 87 | 1.0f, 0.0f, 1.0f, 88 | 1.0f, 0.0f, 1.0f, 89 | 1.0f, 0.0f, 0.0f, 90 | 0.0f, 0.0f, 0.0f, 91 | 1.0f, 0.0f, 0.0f, 92 | 0.0f, 0.0f, 0.0f, 93 | 0.0f, 1.0f, 0.0f, 94 | 1.0f, 0.0f, 0.0f, 95 | 1.0f, 1.0f, 0.0f, 96 | 0.0f, 0.0f, 1.0f, 97 | 0.0f, 1.0f, 1.0f, 98 | 1.0f, 0.0f, 1.0f, 99 | 1.0f, 1.0f, 1.0f 100 | }; 101 | 102 | #ifndef NO_VERTICES_BUFFER 103 | 104 | GLuint axisVertexBuffer, cubeVertexBuffer, cubeEdgeVertexBuffer; 105 | 106 | void initAxisVertexBuffer() 107 | { 108 | glGenBuffers(1, &axisVertexBuffer); 109 | glBindBuffer(GL_ARRAY_BUFFER, axisVertexBuffer); 110 | glBufferData(GL_ARRAY_BUFFER, sizeof(axisVertexBufferData), axisVertexBufferData, GL_STATIC_DRAW); 111 | } 112 | 113 | void initCubeVertexBuffer() 114 | { 115 | glGenBuffers(1, &cubeVertexBuffer); 116 | glBindBuffer(GL_ARRAY_BUFFER, cubeVertexBuffer); 117 | glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertexBufferData), cubeVertexBufferData, GL_STATIC_DRAW); 118 | } 119 | 120 | void initCubeEdgeVertexBuffer() 121 | { 122 | glGenBuffers(1, &cubeEdgeVertexBuffer); 123 | glBindBuffer(GL_ARRAY_BUFFER, cubeEdgeVertexBuffer); 124 | glBufferData(GL_ARRAY_BUFFER, sizeof(cubeEdgeVertexBufferData), cubeEdgeVertexBufferData, GL_STATIC_DRAW); 125 | } 126 | 127 | #endif 128 | 129 | #endif -------------------------------------------------------------------------------- /MagicCube/Vertices.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef USE_GL 4 | 5 | extern const GLfloat axisVertexBufferData[]; 6 | extern const GLfloat cubeVertexBufferData[]; 7 | extern const GLfloat cubeEdgeVertexBufferData[]; 8 | 9 | #ifndef NO_VERTICES_BUFFER 10 | extern GLuint axisVertexBuffer, cubeVertexBuffer, cubeEdgeVertexBuffer; 11 | void initAxisVertexBuffer(); 12 | void initCubeVertexBuffer(); 13 | void initCubeEdgeVertexBuffer(); 14 | #endif 15 | 16 | #endif -------------------------------------------------------------------------------- /MagicCube/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /MagicCube/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Config.h" 4 | 5 | #ifdef NDEBUG 6 | #undef MEM_DEBUG 7 | #endif 8 | 9 | #ifdef _WIN32 10 | #define __perror(s) fprintf(stderr, "%s: Win32 Error %d(0x%08x)\n", s, GetLastError(), GetLastError()) 11 | #ifdef MEM_DEBUG 12 | #define _CRTDBG_MAP_ALLOC 13 | #include 14 | #include 15 | #endif 16 | #endif 17 | 18 | #ifdef __linux 19 | #include 20 | #define __perror(s) perror(s) 21 | #endif 22 | 23 | #if defined(__APPLE__) && defined(__MACH__) 24 | #include 25 | #define __perror(s) perror(s) 26 | #endif 27 | 28 | #ifdef _DEBUG 29 | #define _perror(s) do {__perror(s); /*abort();*/} while (false) 30 | #else 31 | #define _perror(s) __perror(s) 32 | #endif 33 | 34 | #define _log(type, format, ...) do {FILE *__fd = stdout; printTime(__fd); fprintf(__fd, "[%s] ", type); fprintf(__fd, format, ##__VA_ARGS__); fprintf(__fd, "\n");} while (false) 35 | #define log_normal(format, ...) _log("normal", format, ##__VA_ARGS__) 36 | #define log_debug(format, ...) _log("debug", format, ##__VA_ARGS__) 37 | #define log_warn(format, ...) _log("WARN", format, ##__VA_ARGS__) 38 | #define log_error(format, ...) do {_log("ERROR", format, ##__VA_ARGS__); abort();} while (false) 39 | #define log_fatal(format, ...) do {_log("FATAL", format, ##__VA_ARGS__); abort();} while (false) 40 | 41 | #ifdef NDEBUG 42 | #undef log_debug 43 | #define log_debug(format, ...) (int)0 44 | #endif 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | using namespace std; 59 | 60 | #ifdef USE_GL 61 | 62 | #define GLFW_INCLUDE_GLU 63 | #include 64 | 65 | #include 66 | #include 67 | #include 68 | 69 | #include 70 | #include 71 | #include 72 | 73 | using rapidjson::Document; 74 | using rapidjson::Value; 75 | using rapidjson::Writer; 76 | using rapidjson::StringBuffer; 77 | 78 | #include "../NetworkCommon/NetworkCommon.h" 79 | 80 | #else 81 | #define NONET 82 | #endif 83 | 84 | #include "utilities.h" 85 | -------------------------------------------------------------------------------- /MagicCube/utilities.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "utilities.h" 3 | 4 | void printError(SolverError err) 5 | { 6 | if (err.what == "") 7 | { 8 | fprintf(stderr, "SolverError\n"); 9 | } 10 | else 11 | { 12 | fprintf(stderr, "SolverError: %s\n", err.what.c_str()); 13 | } 14 | } 15 | 16 | void printTime(FILE *fd) 17 | { 18 | time_t now = time(NULL); 19 | char tmpBuf[256]; 20 | tm t; 21 | #ifdef _WIN32 22 | localtime_s(&t, &now); 23 | #else 24 | t = *localtime(&now); 25 | #endif 26 | strftime(tmpBuf, sizeof(tmpBuf), "%Y-%m-%d %H:%M:%S", &t); 27 | fprintf(fd, "[%s]", tmpBuf); 28 | } 29 | 30 | CubeSolver *newSolver(Cube &cube) 31 | { 32 | if (currentSolver == "general") 33 | { 34 | return (CubeSolver*)new GeneralSolver(cube); 35 | } 36 | else if (currentSolver == "random") 37 | { 38 | return (CubeSolver*)new RandomSolver(cube); 39 | } 40 | else if (currentSolver == "bruteforce") 41 | { 42 | return (CubeSolver*)new BruteForceSolver(cube); 43 | } 44 | else 45 | { 46 | throw "Unknown solver"; 47 | } 48 | } 49 | 50 | CubeSteps solveAndPrint(Cube cube) 51 | { 52 | printf("Solving...\n"); 53 | 54 | CubeSolver *solver = newSolver(cube); 55 | solver->Solve(); 56 | CubeSteps steps = solver->Steps; 57 | delete solver; 58 | 59 | printf("Steps(%llu): %s\n", (unsigned long long)steps.size(), stepsToString(steps, ' ').c_str()); 60 | steps = ReduceFilter::Filter(steps); 61 | printf("Reduced steps(%llu): %s\n", (unsigned long long)steps.size(), stepsToString(steps, ' ').c_str()); 62 | steps = NoXYZFilter::Filter(steps); 63 | printf("No XYZ steps(%llu): %s\n", (unsigned long long)steps.size(), stepsToString(steps, ' ').c_str()); 64 | steps = ReduceFilter::Filter(steps); 65 | printf("Reduced again steps(%llu): %s\n", (unsigned long long)steps.size(), stepsToString(steps, ' ').c_str()); 66 | 67 | return steps; 68 | } -------------------------------------------------------------------------------- /MagicCube/utilities.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "../CubeCommon/CubeCommon.h" 9 | #include "CubeSolver.h" 10 | #include "GeneralSolver.h" 11 | #include "BruteForceSolver.h" 12 | #include "RandomSolver.h" 13 | #include "ReduceFilter.h" 14 | #include "NoXYZFilter.h" 15 | #include "SolverError.h" 16 | 17 | void printError(SolverError); 18 | void printTime(FILE*); 19 | CubeSolver *newSolver(Cube&); 20 | CubeSteps solveAndPrint(Cube); -------------------------------------------------------------------------------- /MagicCubeServer/CommandHandlers.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CommandHandlers.h" 3 | 4 | map handlers; 5 | 6 | void addHandler(string cmd, CommandHandler handler) 7 | { 8 | handlers[cmd] = handler; 9 | } 10 | 11 | CommandHandler delHandler(string cmd) 12 | { 13 | CommandHandler oldHandler = handlers[cmd]; 14 | handlers[cmd] = NULL; 15 | return oldHandler; 16 | } 17 | 18 | void handleCommand(TcpServer &server) 19 | { 20 | string cmd, args; 21 | 22 | printf("Server> "); 23 | while (server.IsRunning && getline(cin, cmd)) 24 | { 25 | size_t i = cmd.find(' '); 26 | args = ""; 27 | if (i != string::npos) 28 | { 29 | args = cmd.substr(i + 1); 30 | cmd = cmd.substr(0, i); 31 | } 32 | 33 | if (cmd != "") 34 | { 35 | cmd = toLowerString(cmd); 36 | 37 | if (handlers[cmd]) 38 | { 39 | handlers[cmd](server, args); 40 | } 41 | else 42 | { 43 | printf("Unhandled command %s\n", cmd.c_str()); 44 | } 45 | } 46 | 47 | printf("Server> "); 48 | } 49 | } 50 | 51 | void exitHandler(TcpServer &server, string &args) 52 | { 53 | for (auto &sess : server.Sessions) 54 | { 55 | sess->SendError(SESSIONERROR_SERVER_CLOSE); 56 | } 57 | while (server.Sessions.size() > 0) 58 | { 59 | usleep(100000); 60 | } 61 | server.Stop(); 62 | } 63 | 64 | void msgHandler(TcpServer &server, string &args) 65 | { 66 | for (auto &sess : server.Sessions) 67 | { 68 | sess->SendPackage(args); 69 | } 70 | } 71 | 72 | void initHandlers() 73 | { 74 | #define HAND(x) addHandler(#x, x##Handler) 75 | HAND(exit); 76 | HAND(msg); 77 | #undef HAND 78 | } -------------------------------------------------------------------------------- /MagicCubeServer/CommandHandlers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "TcpServer.h" 4 | 5 | typedef void(*CommandHandler)(TcpServer&, string&); 6 | 7 | void initHandlers(); 8 | void handleCommand(TcpServer&); -------------------------------------------------------------------------------- /MagicCubeServer/Config.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MEM_DEBUG 4 | -------------------------------------------------------------------------------- /MagicCubeServer/Config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Server": 3 | { 4 | "Auth": true, 5 | "ServerKey": "123456", 6 | "IPv4": 7 | { 8 | "Enable": true, 9 | "Address": "0.0.0.0", 10 | "Port": 2333, 11 | "Backlog": 1024 12 | }, 13 | "IPv6": 14 | { 15 | "Enable": true, 16 | "Address": "::", 17 | "Port": 2333, 18 | "Backlog": 1024 19 | }, 20 | "MaxConnections": -1 21 | }, 22 | "Rooms": 23 | [ 24 | { 25 | "Name": "test", 26 | "Auth": true, 27 | "Key": "123456", 28 | "Capacity": 2 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /MagicCubeServer/CubeServer.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CubeServer.h" 3 | 4 | CubeServer::CubeServer() 5 | : TcpServer() 6 | { 7 | 8 | } 9 | 10 | 11 | CubeServer::~CubeServer() 12 | { 13 | 14 | } 15 | 16 | #ifdef ENABLE_IPV4 17 | void CubeServer::OnNewSession(sockaddr_in sin, evutil_socket_t fd) 18 | { 19 | Session *sess = new CubeSession(*this, sin, fd); 20 | log_normal("accept fd = %u from %s:%d", static_cast(fd), sess->RemoteAddress.c_str(), sess->RemotePort); 21 | sess->SetCallbacks(); 22 | AddSession(sess); 23 | } 24 | #endif 25 | 26 | #ifdef ENABLE_IPV6 27 | void CubeServer::OnNewSession(sockaddr_in6 sin6, evutil_socket_t fd) 28 | { 29 | Session *sess = new CubeSession(*this, sin6, fd); 30 | log_normal("accept6 fd = %u from [%s]:%d", static_cast(fd), sess->RemoteAddress.c_str(), sess->RemotePort); 31 | sess->SetCallbacks(); 32 | AddSession(sess); 33 | } 34 | #endif -------------------------------------------------------------------------------- /MagicCubeServer/CubeServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CubeSession.h" 4 | #include "TcpServer.h" 5 | 6 | class CubeServer : 7 | public TcpServer 8 | { 9 | public: 10 | bool NeedAuth = false; 11 | string ServerKey; 12 | 13 | vector Rooms; 14 | map RoomIds; 15 | 16 | CubeServer(); 17 | ~CubeServer(); 18 | 19 | #ifdef ENABLE_IPV4 20 | void OnNewSession(sockaddr_in, evutil_socket_t); 21 | #endif 22 | 23 | #ifdef ENABLE_IPV6 24 | void OnNewSession(sockaddr_in6, evutil_socket_t); 25 | #endif 26 | 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /MagicCubeServer/CubeSession.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "CubeSession.h" 3 | 4 | #ifdef ENABLE_IPV4 5 | CubeSession::CubeSession(CubeServer &server, sockaddr_in addr, evutil_socket_t fd) 6 | : Session(server, addr, fd), Server(server) 7 | { 8 | initCommandHandlers(); 9 | } 10 | #endif 11 | 12 | #ifdef ENABLE_IPV6 13 | CubeSession::CubeSession(CubeServer &server, sockaddr_in6 addr, evutil_socket_t fd) 14 | : Session(server, addr, fd), server(server) 15 | { 16 | initCommandHandlers(); 17 | } 18 | #endif 19 | 20 | CubeSession::~CubeSession() 21 | { 22 | 23 | } 24 | 25 | void CubeSession::OnPackage(Package *&pack) 26 | { 27 | if (!pack || pack->Header.DataLength == 0) return; 28 | pack->Data[pack->Header.DataLength - 1] = '\0'; 29 | log_debug("on package (fd = %u): %s", static_cast(fd), pack->Data); 30 | 31 | Document doc; 32 | doc.Parse(pack->Data); 33 | // {"command": "cmd...", arg1: argv1, arg2: argv2, ...} 34 | do 35 | { 36 | if (!doc.IsObject()) 37 | { 38 | SendError(SESSIONERROR_PROTOCOL_MISMATCH); 39 | break; 40 | } 41 | 42 | if (checkObj(doc, 1, "command", "str")) 43 | { 44 | handleCommand(doc); 45 | } 46 | else 47 | { 48 | SendError(SESSIONERROR_PROTOCOL_MISMATCH); 49 | break; 50 | } 51 | } while (false); 52 | 53 | delete pack; 54 | pack = NULL; 55 | } 56 | 57 | void CubeSession::SendSuccess() 58 | { 59 | log_debug("sending success fd = %u", static_cast(fd)); 60 | 61 | StringBuffer sb; 62 | Writer writer(sb); 63 | 64 | writer.StartObject(); 65 | 66 | writer.String("success"); 67 | writer.Int(0); 68 | 69 | writer.EndObject(); 70 | 71 | SendPackage(sb.GetString()); 72 | } 73 | 74 | void CubeSession::SendError(SessionErrorType errorCode) 75 | { 76 | SendError(errorCode, false); 77 | } 78 | 79 | void CubeSession::SendError(SessionErrorType errorCode, bool close) 80 | { 81 | log_debug("sending error (fd = %u): %d", static_cast(fd), errorCode); 82 | 83 | int code = static_cast(errorCode); 84 | 85 | StringBuffer sb; 86 | Writer writer(sb); 87 | 88 | writer.StartObject(); 89 | 90 | writer.String("error"); 91 | writer.Int(errorCode); 92 | 93 | writer.String("message"); 94 | 95 | if (code > SESSIONERROR_UNKNOWN) // user facing error 96 | { 97 | writer.String(UserFacingErrorMessage[_UE(errorCode)].c_str()); 98 | } 99 | else 100 | { 101 | writer.String(SessionErrorMessage[errorCode].c_str()); 102 | } 103 | 104 | writer.EndObject(); 105 | 106 | SendPackage(sb.GetString()); 107 | 108 | // is SessionError 109 | if (close || static_cast(errorCode) <= static_cast(SESSIONERROR_UNKNOWN)) 110 | { 111 | FlushAndClose(); 112 | } 113 | } 114 | 115 | bool CubeSession::EnterRoom(string name) 116 | { 117 | return EnterRoom(Server.RoomIds[name]); 118 | } 119 | 120 | bool CubeSession::EnterRoom(size_t i) 121 | { 122 | /* 1. Put CubeSession into RoomInfo::Sessions 123 | * 2. set currentRoom 124 | */ 125 | 126 | RoomInfo &room = Server.Rooms[i]; 127 | bool v = room.Enter(this); 128 | 129 | if (v) 130 | { 131 | currentRoom = i; 132 | } 133 | 134 | return v; 135 | } 136 | 137 | void CubeSession::ExitRoom() 138 | { 139 | /* 1. Remove CubeSession from RoomInfo 140 | * 2. Clear currentRoom 141 | */ 142 | 143 | if (currentRoom >= 0) 144 | { 145 | Server.Rooms[currentRoom].Exit(this); 146 | currentRoom = -1; 147 | } 148 | } 149 | 150 | void CubeSession::initCommandHandlers() 151 | { 152 | #define HAND(a) commandHandlers[#a] = &CubeSession::a##Handler 153 | HAND(auth); 154 | HAND(list_rooms); 155 | HAND(get_room_info); 156 | HAND(heartbeat); 157 | #undef HAND 158 | } 159 | 160 | void CubeSession::handleCommand(Document &doc) 161 | { 162 | string cmd = doc["command"].GetString(); 163 | 164 | if (cmd != "auth" && !Authed) 165 | { 166 | SendError(_SE(ERROR_AUTH)); 167 | return; 168 | } 169 | 170 | CommandHandlerPtr hand = NULL; 171 | if ((hand = commandHandlers[cmd]) != NULL) 172 | { 173 | (this->*hand)(doc); 174 | } 175 | else 176 | { 177 | SendError(SESSIONERROR_PROTOCOL_MISMATCH); 178 | return; 179 | } 180 | } 181 | 182 | // require argument(s) 183 | #define reqArg(v, argc, ...) \ 184 | if (!checkObj((v), (argc), ##__VA_ARGS__)) \ 185 | { \ 186 | SendError(_SE(ERROR_BAD_ARGUMENT)); \ 187 | return; \ 188 | } \ 189 | 190 | void CubeSession::authHandler(Value &v) 191 | { 192 | reqArg(v, 1, "key", "str"); 193 | 194 | if (v["key"].GetString() == Server.ServerKey || !Server.NeedAuth) 195 | { 196 | Authed = true; 197 | SendSuccess(); 198 | } 199 | else 200 | { 201 | SendError(_SE(ERROR_AUTH_FAILED)); 202 | } 203 | } 204 | 205 | void CubeSession::list_roomsHandler(Value &v) 206 | { 207 | // TODO 208 | } 209 | 210 | void CubeSession::get_room_infoHandler(Value &v) 211 | { 212 | reqArg(v, 1, "id", "int"); 213 | // TODO 214 | } 215 | 216 | void CubeSession::heartbeatHandler(Value &v) 217 | { 218 | // nop 219 | } 220 | 221 | #undef reqArg 222 | -------------------------------------------------------------------------------- /MagicCubeServer/CubeSession.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Session.h" 4 | 5 | class CubeServer; 6 | 7 | class CubeSession : 8 | public Session 9 | { 10 | 11 | public: 12 | 13 | friend class RoomInfo; 14 | 15 | typedef void (CubeSession::*CommandHandlerPtr)(Value&); 16 | 17 | bool Authed = false; 18 | 19 | Cube cube; 20 | 21 | CubeServer &Server; 22 | 23 | #ifdef ENABLE_IPV4 24 | CubeSession(CubeServer&, sockaddr_in, evutil_socket_t); 25 | #endif 26 | #ifdef ENABLE_IPV6 27 | CubeSession(CubeServer&, sockaddr_in6, evutil_socket_t); 28 | #endif 29 | 30 | ~CubeSession(); 31 | 32 | void OnPackage(Package*&); 33 | 34 | void SendSuccess(); 35 | void SendError(SessionErrorType); 36 | void SendError(SessionErrorType, bool close); 37 | 38 | bool EnterRoom(string); 39 | bool EnterRoom(size_t); 40 | void ExitRoom(); 41 | 42 | private: 43 | 44 | map commandHandlers; 45 | void initCommandHandlers(); 46 | 47 | void handleCommand(Document&); 48 | 49 | ptrdiff_t currentRoom = -1; 50 | list::iterator iterInRoom; 51 | 52 | void authHandler(Value&); 53 | void list_roomsHandler(Value&); 54 | void get_room_infoHandler(Value&); 55 | void heartbeatHandler(Value&); 56 | }; 57 | -------------------------------------------------------------------------------- /MagicCubeServer/MagicCubeServer.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "MagicCubeServer.h" 3 | 4 | FILE *logFile = stdout; 5 | 6 | void libeventError(int errcode) 7 | { 8 | log_fatal("libevent fatal error occurred, error code: %d\n", errcode); 9 | exit(1); 10 | } 11 | 12 | void initLibraries() 13 | { 14 | #ifdef _DEBUG 15 | event_enable_debug_mode(); // may cause memory leak 16 | #endif 17 | 18 | event_set_fatal_callback(libeventError); 19 | 20 | #ifdef _WIN32 21 | 22 | #ifdef MEM_DEBUG 23 | _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 24 | #endif 25 | 26 | WSADATA data; 27 | int err = WSAStartup(0, &data); 28 | err = WSAStartup(data.wVersion, &data); 29 | assert(err == 0); 30 | #endif 31 | 32 | #ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED 33 | evthread_use_windows_threads(); // may cause memory leak 34 | #endif 35 | 36 | #ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED 37 | evthread_use_pthreads(); 38 | #endif 39 | 40 | srand(static_cast(time(NULL))); // stdlib :) 41 | } 42 | 43 | int main(int argc, char *argv[]) 44 | { 45 | string configFilename = "Config.json"; 46 | string logFilename = "-"; 47 | 48 | #ifndef _WIN32 49 | cmdline::parser arg; 50 | arg.add("config", 'c', "configuration file", false, "Config.json"); 51 | arg.add("log", 'l', "log file", false, "-"); 52 | arg.parse_check(argc, argv); 53 | configFilename = arg.get("config"); 54 | logFilename = arg.get("log"); 55 | #endif 56 | 57 | log_normal("Using configuration file: %s", configFilename.c_str()); 58 | log_normal("Log file: %s", logFilename.c_str()); 59 | 60 | setLogFile(logFilename); 61 | 62 | Document configDoc = loadConfigObj(configFilename); 63 | Value &roomsVal = configDoc["Rooms"]; 64 | assert(roomsVal.IsArray()); 65 | vector rooms(loadRooms(roomsVal)); 66 | 67 | initLibraries(); 68 | 69 | CubeServer server; 70 | configRooms(server, rooms); 71 | 72 | server.EnableTimer(CHECK_INTERVAL_uS); 73 | 74 | configServer(server, configDoc["Server"]); 75 | 76 | server.IsRunning = true; 77 | thread th(eventEntry, &server); 78 | 79 | initHandlers(); 80 | handleCommand(server); 81 | 82 | server.Stop(); 83 | th.join(); 84 | 85 | log_normal("%s", "Stopped."); 86 | 87 | #ifdef MEM_DEBUG 88 | #ifdef _WIN32 89 | _CrtDumpMemoryLeaks(); 90 | #endif 91 | #endif 92 | 93 | return 0; 94 | } 95 | 96 | void eventEntry(TcpServer *server) 97 | { 98 | server->Start(); 99 | } 100 | -------------------------------------------------------------------------------- /MagicCubeServer/MagicCubeServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "stdafx.h" 4 | #include 5 | 6 | #ifndef _WIN32 7 | #include 8 | #endif 9 | 10 | #include "Config.h" 11 | #include "CommandHandlers.h" 12 | #include "TcpServer.h" 13 | #include "CubeServer.h" 14 | #include "Session.h" 15 | #include "RoomInfo.h" 16 | 17 | void eventEntry(TcpServer*); -------------------------------------------------------------------------------- /MagicCubeServer/MagicCubeServer.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {4E6C5C7C-A8B6-4A3D-9478-FA64B58BFB7A} 23 | Win32Proj 24 | MagicCubeServer 25 | 8.1 26 | 27 | 28 | 29 | Application 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | Application 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | Application 43 | true 44 | v140 45 | Unicode 46 | 47 | 48 | Application 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | true 74 | ../include/win;../include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 75 | 76 | 77 | true 78 | ../include/win;../include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 79 | 80 | 81 | false 82 | ../include/win;../include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 83 | 84 | 85 | false 86 | ../include/win;../include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 87 | 88 | 89 | 90 | Use 91 | Level3 92 | Disabled 93 | WIN32;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) 94 | true 95 | 96 | 97 | Console 98 | true 99 | ../lib/win;%(AdditionalLibraryDirectories) 100 | ws2_32.lib;wsock32.lib;libevent_core.lib;libevent_extras.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 101 | 102 | 103 | 104 | 105 | Use 106 | Level3 107 | Disabled 108 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions) 109 | true 110 | 111 | 112 | Console 113 | true 114 | ../lib/winx64;%(AdditionalLibraryDirectories) 115 | ws2_32.lib;wsock32.lib;libevent_core.lib;libevent_extras.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 116 | 117 | 118 | 119 | 120 | Level3 121 | Use 122 | MaxSpeed 123 | true 124 | true 125 | WIN32;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 126 | true 127 | 128 | 129 | Console 130 | true 131 | true 132 | true 133 | ../lib/win;%(AdditionalLibraryDirectories) 134 | ws2_32.lib;wsock32.lib;libevent_core.lib;libevent_extras.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 135 | 136 | 137 | 138 | 139 | Level3 140 | Use 141 | MaxSpeed 142 | true 143 | true 144 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 145 | true 146 | 147 | 148 | Console 149 | true 150 | true 151 | true 152 | ../lib/winx64;%(AdditionalLibraryDirectories) 153 | ws2_32.lib;wsock32.lib;libevent_core.lib;libevent_extras.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | Create 178 | Create 179 | Create 180 | Create 181 | 182 | 183 | 184 | 185 | 186 | {b70d9cc0-5e42-456b-b2ba-9b4344eab791} 187 | 188 | 189 | {e2535545-af18-41e0-9505-3745e2c40d15} 190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /MagicCubeServer/MagicCubeServer.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 14 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 15 | 16 | 17 | 18 | 19 | Headers 20 | 21 | 22 | Headers 23 | 24 | 25 | Headers 26 | 27 | 28 | Headers 29 | 30 | 31 | Headers 32 | 33 | 34 | Headers 35 | 36 | 37 | Headers 38 | 39 | 40 | Headers 41 | 42 | 43 | Headers 44 | 45 | 46 | Headers 47 | 48 | 49 | 50 | 51 | Sources 52 | 53 | 54 | Sources 55 | 56 | 57 | Sources 58 | 59 | 60 | Sources 61 | 62 | 63 | Sources 64 | 65 | 66 | Sources 67 | 68 | 69 | Sources 70 | 71 | 72 | Sources 73 | 74 | 75 | Sources 76 | 77 | 78 | -------------------------------------------------------------------------------- /MagicCubeServer/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = MagicCubeServer 2 | 3 | SOURCES := $(shell ls *.cpp) 4 | OBJECTS := $(patsubst %.cpp, build/%.o, $(SOURCES)) 5 | ifeq ($(shell uname),Linux) 6 | # compiler 7 | CC = g++ 8 | INC_DIR = ../include/osx 9 | CC_FLAGS = -O2 -Wall -fno-strict-aliasing -std=c++11 -I $(INC_DIR) -I ../include 10 | 11 | # linker 12 | LD = g++ 13 | LIB_DIR = ../lib/linux 14 | LIBS = -lCubeCommon -lNetworkCommon -levent -lm -ldl -lpthread -lstdc++ -lc 15 | LINKER_FLAGS = -L $(LIB_DIR) -L ../CubeCommon/build -L ../NetworkCommon/build 16 | else 17 | 18 | ifeq ($(shell uname),Darwin) 19 | # compiler 20 | INC_DIR = ../include/osx 21 | CC_FLAGS = -O2 -Wall -fno-strict-aliasing -std=c++11 -I $(INC_DIR) -I ../include 22 | 23 | # linker 24 | LIB_DIR = ../lib/osx 25 | LIBS = -lCubeCommon -lNetworkCommon -levent -lc++ -lm -lSystem 26 | LINKER_FLAGS = -L $(LIB_DIR) -L ../CubeCommon/build -L ../NetworkCommon/build 27 | else 28 | # Unsupported operating system. 29 | CC = echo && echo "******** Unsupported operating system! ********" && echo && exit 1 || 30 | endif 31 | 32 | endif 33 | 34 | .PHONY: all 35 | all: 36 | -mkdir build 37 | make $(PROJECT) 38 | 39 | build/%.o: %.cpp %.h Config.h ../NetworkCommon/NetworkConfig.h 40 | $(CC) -c $(CC_FLAGS) -o $@ $< 41 | 42 | $(PROJECT): $(OBJECTS) 43 | $(CC) $(LINKER_FLAGS) -o build/$(PROJECT) $(OBJECTS) $(LIBS) 44 | 45 | .PHONY: clean 46 | clean: 47 | -rm build/* 48 | -rm -rf build 49 | -------------------------------------------------------------------------------- /MagicCubeServer/RoomInfo.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "RoomInfo.h" 3 | 4 | RoomInfo::RoomInfo(const RoomInfo &&ri) 5 | : Name(move(ri.Name)), NeedAuth(ri.NeedAuth), Key(move(ri.Key)), Capacity(ri.Capacity), 6 | Sessions(move(ri.Sessions)), ptrMutex(move(ri.ptrMutex)) 7 | { 8 | 9 | } 10 | 11 | RoomInfo::RoomInfo() 12 | : ptrMutex(new mutex) 13 | { 14 | 15 | } 16 | 17 | 18 | RoomInfo::~RoomInfo() 19 | { 20 | 21 | } 22 | 23 | bool RoomInfo::Enter(CubeSession *sess) 24 | { 25 | unique_lock lck(*ptrMutex); 26 | 27 | if (Sessions.size() >= Capacity) 28 | { 29 | return false; 30 | } 31 | 32 | Sessions.push_back(sess); 33 | sess->iterInRoom = Sessions.end(); 34 | --sess->iterInRoom; 35 | 36 | return true; 37 | } 38 | 39 | void RoomInfo::Exit(CubeSession *sess) 40 | { 41 | unique_lock lck(*ptrMutex); 42 | Sessions.erase(sess->iterInRoom); 43 | } 44 | -------------------------------------------------------------------------------- /MagicCubeServer/RoomInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CubeSession.h" 4 | 5 | class RoomInfo 6 | { 7 | public: 8 | bool NeedAuth = false; 9 | string Name, Key; 10 | size_t Capacity; 11 | list Sessions; 12 | 13 | RoomInfo(const RoomInfo&&); 14 | 15 | RoomInfo(); 16 | ~RoomInfo(); 17 | 18 | bool Enter(CubeSession*); 19 | void Exit(CubeSession*); 20 | 21 | private: 22 | 23 | // prevent copying 24 | DISALLOW_COPY_AND_ASSIGN(RoomInfo); 25 | 26 | shared_ptr ptrMutex; 27 | 28 | }; 29 | 30 | -------------------------------------------------------------------------------- /MagicCubeServer/Session.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Session.h" 3 | 4 | #ifdef ENABLE_IPV4 5 | Session::Session(TcpServer &server, sockaddr_in addr, evutil_socket_t fd) 6 | : Server(server), fd(fd), sAddr(addr) 7 | { 8 | char buffer[INET6_ADDRSTRLEN + 1] = { 0 }; 9 | evutil_inet_ntop(addr.sin_family, &(addr.sin_addr), buffer, sizeof(buffer)); 10 | RemoteAddress = buffer; 11 | RemotePort = ntohs(addr.sin_port); 12 | 13 | evutil_make_socket_nonblocking(fd); 14 | buffev = bufferevent_socket_new(server.Base, fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE | BEV_OPT_DEFER_CALLBACKS); 15 | } 16 | #endif 17 | 18 | #ifdef ENABLE_IPV6 19 | Session::Session(TcpServer &server, sockaddr_in6 addr, evutil_socket_t fd) 20 | : IsIPv6(true), server(server), fd(fd), sAddr6(addr) 21 | { 22 | char buffer[INET6_ADDRSTRLEN + 1] = { 0 }; 23 | evutil_inet_ntop(addr.sin6_family, &(addr.sin6_addr), buffer, sizeof(buffer)); 24 | RemoteAddress = buffer; 25 | RemotePort = ntohs(addr.sin6_port); 26 | 27 | evutil_make_socket_nonblocking(fd); 28 | buffev = bufferevent_socket_new(server.Base, fd, BEV_OPT_CLOSE_ON_FREE); 29 | } 30 | #endif 31 | 32 | Session::~Session() 33 | { 34 | Close(); 35 | readLock.lock(); 36 | readLock.unlock(); 37 | writeLock.lock(); 38 | writeLock.unlock(); 39 | queueLock.lock(); 40 | queueLock.unlock(); 41 | } 42 | 43 | void Session::KeepAlive() 44 | { 45 | LastAlive = time(NULL); 46 | } 47 | 48 | void Session::SetCallbacks() 49 | { 50 | SetCallbacks(true, true, true); 51 | } 52 | 53 | void Session::SetCallbacks(bool read, bool write, bool event) 54 | { 55 | bufferevent_data_cb readCB = NULL, writeCB = NULL; 56 | bufferevent_event_cb eventCB = NULL; 57 | short eventsEN = EV_PERSIST; 58 | if (read) 59 | { 60 | readCB = readCallbackDispatcher; 61 | eventsEN |= EV_READ; 62 | } 63 | if (write) 64 | { 65 | writeCB = writeCallbackDispatcher; 66 | eventsEN |= EV_WRITE; 67 | } 68 | if (event) 69 | { 70 | eventCB = errorCallbackDispatcher; 71 | } 72 | 73 | bufferevent_setcb(buffev, 74 | readCB, 75 | writeCB, 76 | eventCB, (void*)this); 77 | 78 | if (read || write || event) 79 | { 80 | bufferevent_enable(buffev, eventsEN); 81 | } 82 | else 83 | { 84 | bufferevent_disable(buffev, EV_READ | EV_WRITE); 85 | } 86 | } 87 | 88 | void Session::ClearCallbacks() 89 | { 90 | SetCallbacks(false, false, false); 91 | } 92 | 93 | void Session::ReadCallback() 94 | { 95 | if (!IsAlive) return; 96 | 97 | unique_lock lck(readLock); 98 | log_debug("fd = %u, entering read", static_cast(fd)); 99 | while (IsAlive) 100 | { 101 | KeepAlive(); 102 | switch (readState) 103 | { 104 | case READSTATE_NONE: 105 | readLength = 0; 106 | readState = READSTATE_READING_HEADER; 107 | continue; 108 | break; 109 | case READSTATE_READING_HEADER: 110 | { 111 | const size_t headerLength = sizeof(PackageHeader); 112 | 113 | while (readLength < headerLength) 114 | { 115 | size_t currentLength = bufferevent_read(buffev, headerBuffer + readLength, headerLength - readLength); 116 | if (currentLength <= 0) break; 117 | 118 | readLength += currentLength; 119 | } 120 | 121 | if (readLength == headerLength) 122 | { 123 | PackageHeader header = *reinterpret_cast(headerBuffer); 124 | header.DataLength = ntohpacklen(header.DataLength); 125 | 126 | if (memcmp(headerBuffer, "GET ", min(headerLength, (size_t)4)) == 0) 127 | { 128 | // http request! 129 | char buff[sizeof(PackageHeader) + 1]; 130 | memcpy(buff, headerBuffer, sizeof(PackageHeader)); 131 | buff[sizeof(PackageHeader)] = '\0'; 132 | 133 | lineBuffer = buff; 134 | 135 | readState = READSTATE_READING_LINE; 136 | continue; 137 | } 138 | else if (memcmp(headerBuffer, MAGIC_MARK, min(headerLength, sizeof(MAGIC_MARK) - 1)) != 0) 139 | { 140 | readErrorCode = SESSIONERROR_PROTOCOL_MISMATCH; 141 | readState = READSTATE_ERROR; 142 | continue; 143 | } 144 | 145 | if (header.DataLength == 0 || header.DataLength > PACKAGE_MAXLENGTH) 146 | { 147 | // package is empty or too long 148 | log_debug("fd = %u, data length: %d == 0 || too long", static_cast(fd), header.DataLength); 149 | 150 | if (header.DataLength == 0) 151 | readErrorCode = SESSIONERROR_PACKAGE_EMPTY; 152 | else 153 | readErrorCode = SESSIONERROR_PACKAGE_TOO_LONG; 154 | 155 | readState = READSTATE_ERROR; 156 | continue; 157 | } 158 | 159 | currentPackage = new (header.DataLength) Package; 160 | if (!currentPackage) 161 | { 162 | throw bad_alloc(); 163 | } 164 | currentPackage->Header = header; // copy 165 | 166 | memset(currentPackage->Data, 0x00, header.DataLength); // ensure 167 | 168 | readLength = 0; 169 | readState = READSTATE_READING_DATA; 170 | continue; 171 | } 172 | break; 173 | } 174 | case READSTATE_READING_DATA: 175 | { 176 | while (readLength < currentPackage->Header.DataLength) 177 | { 178 | size_t currentLength = bufferevent_read(buffev, currentPackage->Data + readLength, currentPackage->Header.DataLength - readLength); 179 | log_debug("fd = %u, recv %u", static_cast(fd), currentLength); 180 | if (currentLength <= 0) break; 181 | 182 | readLength += currentLength; 183 | } 184 | 185 | if (readLength == currentPackage->Header.DataLength) 186 | { 187 | OnPackage(currentPackage); // TODO: sync or async? 188 | if (currentPackage) 189 | { 190 | delete currentPackage; 191 | currentPackage = NULL; 192 | } 193 | readLength = 0; 194 | readState = READSTATE_NONE; 195 | continue; 196 | } 197 | break; 198 | } 199 | case READSTATE_READING_LINE: 200 | { 201 | char ch; 202 | bool cont = false; 203 | 204 | while (bufferevent_read(buffev, &ch, sizeof(ch)) > 0) 205 | { 206 | lineBuffer += ch; 207 | if (lineBuffer.length() > HTTP_HEADER_MAXLENGTH) 208 | { 209 | // header is too long 210 | readErrorCode = SESSIONERROR_PACKAGE_TOO_LONG; 211 | readState = READSTATE_ERROR; 212 | cont = true; 213 | break; 214 | } 215 | if (endsWith(lineBuffer,LINE_ENDDING)) 216 | { 217 | OnLine(lineBuffer); 218 | lineBuffer = ""; 219 | } 220 | } 221 | 222 | if (cont) 223 | { 224 | continue; 225 | } 226 | break; 227 | } 228 | case READSTATE_ERROR: 229 | { 230 | SendError(readErrorCode); 231 | readErrorCode = SESSIONERROR_UNKNOWN; 232 | break; 233 | } 234 | } 235 | 236 | break; 237 | } 238 | log_debug("fd = %u, exitting read", static_cast(fd)); 239 | } 240 | 241 | void Session::WriteCallback() 242 | { 243 | if (!IsAlive) return; 244 | 245 | { 246 | unique_lock lck(writeLock); 247 | if (isFirstCall) 248 | { 249 | log_debug("fd = %u, dropping first write callback calling", static_cast(fd)); 250 | // drop first write callback calling 251 | isFirstCall = false; 252 | return; 253 | } 254 | } 255 | 256 | log_debug("fd = %u, write callback called", static_cast(fd)); 257 | 258 | if (closeAfterWritten) 259 | { 260 | log_debug("fd = %u, closeAfterWritten is set, closing", static_cast(fd)); 261 | Close(); 262 | } 263 | 264 | KeepAlive(); 265 | } 266 | 267 | void Session::ErrorCallback(short event) 268 | { 269 | if (!IsAlive) return; 270 | 271 | const char *msg = ""; 272 | if (event & BEV_EVENT_TIMEOUT) 273 | { 274 | msg = "timed out"; // if bufferevent_set_timeouts() called 275 | } 276 | else if (event & BEV_EVENT_EOF) 277 | { 278 | msg = "connection closed"; 279 | } 280 | else if (event & BEV_EVENT_ERROR) 281 | { 282 | msg = "some other error"; 283 | __perror("error"); 284 | } 285 | 286 | log_debug("fd = %u, %s", static_cast(fd), msg); 287 | 288 | Close(); 289 | } 290 | 291 | void Session::DoQueue() 292 | { 293 | if (!IsAlive) return; 294 | 295 | unique_lock lck(writeLock), lckQueue(queueLock); 296 | log_debug("fd = %u, dequeuing", static_cast(fd)); 297 | 298 | while (!pendingPackages.empty()) 299 | { 300 | Package *&pack = pendingPackages.front(); 301 | package_len_t packLen = pack->Header.DataLength; 302 | pack->Header.DataLength = htonpacklen(pack->Header.DataLength); 303 | 304 | if (packLen > 0) 305 | { 306 | size_t toSendLength = sizeof(PackageHeader) + packLen; 307 | char *packData = reinterpret_cast(pack); 308 | 309 | bufferevent_write(buffev, packData, toSendLength); 310 | } 311 | delete pack; 312 | pack = NULL; 313 | 314 | pendingPackages.pop(); 315 | } 316 | 317 | log_debug("fd = %u, dequeued", static_cast(fd)); 318 | } 319 | 320 | void Session::OnLine(const string &line) 321 | { 322 | if (line == LINE_ENDDING) 323 | { 324 | OnHTTPRequest(line); 325 | } 326 | } 327 | 328 | void Session::OnHTTPRequest(const string &req) 329 | { 330 | log_debug("regarded as HTTP request (fd = %u)", static_cast(fd)); 331 | 332 | unique_lock lck(writeLock); 333 | 334 | string content = "

It really works!

\n

But... this isn't a HTTP service.

"; 335 | string header = "HTTP/1.0 200 OK\r\nServer: Wandai/0.1\r\nConnection: close\r\nContent-Type: text/html\r\nContent-Length: " + to_string(content.length()) + "\r\n\r\n"; 336 | string data = header + content; 337 | 338 | bufferevent_write(buffev, data.c_str(), data.length()); 339 | FlushAndClose(); 340 | } 341 | 342 | void Session::OnPackage(Package *&pack) 343 | { 344 | if (!pack || pack->Header.DataLength == 0) return; 345 | pack->Data[pack->Header.DataLength - 1] = '\0'; 346 | log_debug("on package (fd = %u): %s", static_cast(fd), pack->Data); 347 | 348 | // TODO: process received package 349 | 350 | delete pack; 351 | pack = NULL; 352 | } 353 | 354 | void Session::SendPackage(Package *&pack) 355 | { 356 | if (!pack || pack->Header.DataLength == 0) return; 357 | 358 | { 359 | unique_lock lckQueue(queueLock); 360 | pendingPackages.push(pack); 361 | } 362 | 363 | DoQueue(); 364 | } 365 | 366 | void Session::SendPackage(string str) 367 | { 368 | Package *pack = MakePackage(str); 369 | SendPackage(pack); 370 | } 371 | 372 | void Session::SendError(SessionErrorType errorCode) 373 | { 374 | SendPackage(SessionErrorMessage[errorCode]); 375 | FlushAndClose(); 376 | } 377 | 378 | void Session::FlushAndClose() 379 | { 380 | closeAfterWritten = true; 381 | } 382 | 383 | void Session::Close() 384 | { 385 | if (!IsAlive) return; 386 | IsAlive = false; 387 | 388 | log_debug("fd = %u, closing", static_cast(fd)); 389 | 390 | if (buffev) 391 | { 392 | ClearCallbacks(); // need clear callbacks BEFORE shutdown. 393 | } 394 | 395 | if (fd) 396 | { 397 | shutdown(fd, SHUT_RDWR); 398 | #ifdef _WIN32 399 | closesocket(fd); 400 | #else 401 | close(fd); 402 | #endif 403 | fd = static_cast(0); 404 | } 405 | 406 | if (buffev) 407 | { 408 | bufferevent_free(buffev); 409 | buffev = NULL; 410 | } 411 | 412 | if (currentPackage) 413 | { 414 | delete currentPackage; 415 | currentPackage = NULL; 416 | } 417 | 418 | while (!pendingPackages.empty()) 419 | { 420 | Package *&pack = pendingPackages.front(); 421 | if (pack) 422 | { 423 | delete pack; 424 | pack = NULL; 425 | } 426 | pendingPackages.pop(); 427 | } 428 | } 429 | 430 | Package *Session::MakePackage(string &strdata) 431 | { 432 | package_len_t len = static_cast((strdata.length() + 1) * sizeof(char)); 433 | Package *pack = new (len) Package; 434 | memcpy(pack->Header.Magic, MAGIC_MARK, sizeof(MAGIC_MARK) - 1); 435 | pack->Header.DataLength = len; 436 | memcpy(pack->Data, strdata.c_str(), len); 437 | return pack; 438 | } 439 | 440 | void readCallbackDispatcher(bufferevent *buffev, void *arg) 441 | { 442 | Session *sess = reinterpret_cast(arg); 443 | 444 | sess->ReadCallback(); 445 | sess->Server.CleanSession((Session*)arg); 446 | } 447 | 448 | void writeCallbackDispatcher(bufferevent *buffev, void *arg) 449 | { 450 | Session *sess = reinterpret_cast(arg); 451 | 452 | sess->WriteCallback(); 453 | sess->Server.CleanSession(sess); 454 | } 455 | 456 | void errorCallbackDispatcher(bufferevent *buffev, short event, void *arg) 457 | { 458 | Session *sess = reinterpret_cast(arg); 459 | 460 | sess->ErrorCallback(event); 461 | sess->Server.CleanSession(sess); 462 | } 463 | -------------------------------------------------------------------------------- /MagicCubeServer/Session.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class TcpServer; 8 | 9 | enum ReadStateType 10 | { 11 | READSTATE_NONE, 12 | READSTATE_READING_HEADER, 13 | READSTATE_READING_DATA, 14 | READSTATE_READING_LINE, 15 | READSTATE_ERROR 16 | }; 17 | 18 | class Session 19 | { 20 | public: 21 | list::iterator Iter; 22 | 23 | bool IsAlive = true; 24 | bool IsIPv6 = false; 25 | time_t LastAlive = time(NULL); 26 | 27 | string RemoteAddress; 28 | unsigned short RemotePort; 29 | 30 | TcpServer &Server; 31 | 32 | #ifdef ENABLE_IPV4 33 | Session(TcpServer&, sockaddr_in, evutil_socket_t); 34 | #endif 35 | #ifdef ENABLE_IPV6 36 | Session(TcpServer&, sockaddr_in6, evutil_socket_t); 37 | #endif 38 | virtual ~Session(); 39 | 40 | // invoked again and again when doing complex calculation to avoid being cleaned 41 | void KeepAlive(); 42 | 43 | void SetCallbacks(); 44 | void SetCallbacks(bool, bool, bool); 45 | void ClearCallbacks(); 46 | 47 | virtual void ReadCallback(); 48 | virtual void WriteCallback(); 49 | virtual void ErrorCallback(short); 50 | 51 | void DoQueue(); 52 | 53 | virtual void OnLine(const string&); 54 | virtual void OnHTTPRequest(const string&); 55 | virtual void OnPackage(Package*&); 56 | 57 | void SendPackage(Package*&); 58 | void SendPackage(string); 59 | virtual void SendError(SessionErrorType); 60 | 61 | void FlushAndClose(); 62 | void Close(); 63 | 64 | static Package *MakePackage(string&); 65 | 66 | protected: 67 | 68 | bufferevent *buffev; 69 | evutil_socket_t fd; 70 | 71 | #ifdef ENABLE_IPV4 72 | sockaddr_in sAddr; 73 | #endif 74 | 75 | #ifdef ENABLE_IPV6 76 | sockaddr_in6 sAddr6; 77 | #endif 78 | 79 | mutex readLock; 80 | ReadStateType readState = READSTATE_NONE; 81 | SessionErrorType readErrorCode = SESSIONERROR_UNKNOWN; 82 | size_t readLength; 83 | char headerBuffer[sizeof(PackageHeader)]; 84 | string lineBuffer; 85 | Package *currentPackage = NULL; 86 | 87 | bool isFirstCall = true; 88 | queue pendingPackages; 89 | mutex writeLock, queueLock; 90 | bool closeAfterWritten = false; 91 | 92 | private: 93 | 94 | // prevent copying 95 | DISALLOW_COPY_AND_ASSIGN(Session); 96 | }; 97 | 98 | void readCallbackDispatcher(bufferevent*, void*); 99 | void writeCallbackDispatcher(bufferevent*, void*); 100 | void errorCallbackDispatcher(bufferevent*, short, void*); 101 | -------------------------------------------------------------------------------- /MagicCubeServer/TcpServer.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "TcpServer.h" 3 | 4 | TcpServer::TcpServer() 5 | { 6 | Base = event_base_new(); 7 | if (!Base) 8 | { 9 | _perror("event_base_new"); 10 | } 11 | } 12 | 13 | #ifdef ENABLE_IPV4 14 | bool TcpServer::Listen(string address, unsigned short port, int backlog) 15 | { 16 | listener = socket(AF_INET, SOCK_STREAM, 0); 17 | if (listener <= 0) 18 | { 19 | listener = static_cast(0); 20 | _perror("socket"); 21 | return false; 22 | } 23 | evutil_make_listen_socket_reuseable(listener); 24 | 25 | sockaddr_in sin; 26 | sin.sin_family = AF_INET; 27 | evutil_inet_pton(AF_INET, address.c_str(), &(sin.sin_addr.s_addr)); 28 | sin.sin_port = htons(port); 29 | 30 | if (::bind(listener, (sockaddr *)&sin, sizeof(sin)) < 0) 31 | { 32 | listener = static_cast(0); 33 | _perror("bind"); 34 | return false; 35 | } 36 | 37 | if (listen(listener, backlog) < 0) 38 | { 39 | listener = static_cast(0); 40 | _perror("listen"); 41 | return false; 42 | } 43 | 44 | evutil_make_socket_nonblocking(listener); 45 | return true; 46 | } 47 | 48 | void TcpServer::AcceptCallback(short event) 49 | { 50 | evutil_socket_t fd; 51 | sockaddr_in sin; 52 | socklen_t slen = (socklen_t)sizeof(sin); 53 | fd = accept(listener, (sockaddr *)&sin, &slen); 54 | if (fd < 0) 55 | { 56 | _perror("accept"); 57 | return; 58 | } 59 | 60 | OnNewSession(sin, fd); 61 | } 62 | 63 | void TcpServer::OnNewSession(sockaddr_in sin, evutil_socket_t fd) 64 | { 65 | Session *sess = new Session(*this, sin, fd); 66 | log_normal("accept fd = %u from %s:%d", static_cast(fd), sess->RemoteAddress.c_str(), sess->RemotePort); 67 | sess->SetCallbacks(); 68 | AddSession(sess); 69 | } 70 | #endif 71 | 72 | #ifdef ENABLE_IPV6 73 | bool TcpServer::Listen6(string address, unsigned short port, int backlog) 74 | { 75 | listener6 = socket(AF_INET6, SOCK_STREAM, 0); 76 | if (listener6 <= 0) 77 | { 78 | listener6 = static_cast(0); 79 | _perror("socket6"); 80 | return false; 81 | } 82 | evutil_make_listen_socket_reuseable(listener6); 83 | 84 | #ifndef _WIN32 85 | int yes = 1; 86 | setsockopt(listener6, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&yes, sizeof(yes)); 87 | #endif 88 | 89 | sockaddr_in6 sin6; 90 | sin6.sin6_family = AF_INET6; 91 | evutil_inet_pton(AF_INET6, address.c_str(), sin6.sin6_addr.s6_addr); 92 | sin6.sin6_port = htons(port); 93 | 94 | if (::bind(listener6, (sockaddr *)&sin6, sizeof(sin6)) < 0) 95 | { 96 | listener6 = static_cast(0); 97 | _perror("bind6"); 98 | return false; 99 | } 100 | 101 | if (listen(listener6, backlog) < 0) 102 | { 103 | listener6 = static_cast(0); 104 | _perror("listen6"); 105 | return false; 106 | } 107 | 108 | evutil_make_socket_nonblocking(listener6); 109 | return true; 110 | } 111 | 112 | void TcpServer::Accept6Callback(short event) 113 | { 114 | evutil_socket_t fd; 115 | sockaddr_in6 sin6; 116 | socklen_t slen = (socklen_t)sizeof(sin6); 117 | fd = accept(listener6, (sockaddr *)&sin6, &slen); 118 | if (fd < 0) 119 | { 120 | _perror("accept6"); 121 | return; 122 | } 123 | 124 | OnNewSession(sin6, fd); 125 | } 126 | 127 | void TcpServer::OnNewSession(sockaddr_in6 sin6, evutil_socket_t fd) 128 | { 129 | Session *sess = new Session(*this, sin6, fd); 130 | log_normal("accept6 fd = %u from [%s]:%d", static_cast(fd), sess->RemoteAddress.c_str(), sess->RemotePort); 131 | sess->SetCallbacks(); 132 | AddSession(sess); 133 | } 134 | #endif 135 | 136 | void TcpServer::Start() 137 | { 138 | #ifdef ENABLE_IPV4 139 | if (listener) 140 | { 141 | listener_event = event_new(Base, listener, EV_READ | EV_PERSIST, acceptCallbackDispatcher, (void*)this); 142 | event_add(listener_event, NULL); 143 | } 144 | #endif 145 | 146 | #ifdef ENABLE_IPV6 147 | if (listener6) 148 | { 149 | listener6_event = event_new(Base, listener6, EV_READ | EV_PERSIST, accept6CallbackDispatcher, (void*)this); 150 | event_add(listener6_event, NULL); 151 | } 152 | #endif 153 | 154 | IsRunning = true; 155 | event_base_dispatch(Base); 156 | } 157 | 158 | void TcpServer::Stop() 159 | { 160 | #ifdef ENABLE_IPV4 161 | if (listener) 162 | { 163 | shutdown(listener, SHUT_RDWR); 164 | #ifdef _WIN32 165 | closesocket(listener); 166 | #else 167 | close(listener); 168 | #endif 169 | listener = static_cast(0); 170 | } 171 | 172 | if (listener_event) 173 | { 174 | event_del(listener_event); 175 | event_free(listener_event); 176 | listener_event = NULL; 177 | } 178 | #endif 179 | 180 | #ifdef ENABLE_IPV6 181 | if (listener6) 182 | { 183 | shutdown(listener6, SHUT_RDWR); 184 | #ifdef _WIN32 185 | closesocket(listener6); 186 | #else 187 | close(listener6); 188 | #endif 189 | listener6 = static_cast(0); 190 | } 191 | 192 | if (listener6_event) 193 | { 194 | event_del(listener6_event); 195 | event_free(listener6_event); 196 | listener6_event = NULL; 197 | } 198 | #endif 199 | 200 | event_base_loopbreak(Base); 201 | IsRunning = false; 202 | } 203 | 204 | void TcpServer::SetTimer(event *&timer, long interval) 205 | { 206 | ClearTimer(timer); 207 | 208 | timeval *timerInterval = new timeval; 209 | evutil_timerclear(timerInterval); 210 | timerInterval->tv_usec = interval; 211 | 212 | timer = event_new(Base, -1, EV_PERSIST, timerCallbackDispatcher, (void *)this); 213 | evtimer_add(timer, timerInterval); 214 | 215 | delete timerInterval; 216 | timerInterval = NULL; 217 | } 218 | 219 | void TcpServer::ClearTimer(event *&timer) 220 | { 221 | if (timer) 222 | { 223 | event_del(timer); 224 | event_free(timer); 225 | timer = NULL; 226 | } 227 | } 228 | 229 | void TcpServer::EnableTimer(long interval) 230 | { 231 | SetTimer(defaultTimer, interval); 232 | } 233 | 234 | void TcpServer::TimerCallback(short event) 235 | { 236 | log_debug("%s", "Timer tick."); 237 | 238 | time_t now = time(NULL); 239 | 240 | for (auto &sess : Sessions) 241 | { 242 | if (difftime(now, sess->LastAlive) > TIMEOUT_S) 243 | { 244 | sess->SendError(SESSIONERROR_TIMEOUT); 245 | log_debug("Cleaning %p", sess); 246 | } 247 | } 248 | 249 | CleanSessions(); 250 | } 251 | 252 | void TcpServer::CleanSession(Session *sess) 253 | { 254 | if (!sess) return; 255 | 256 | log_debug("Checking %p", sess); 257 | 258 | if (!sess->IsAlive) 259 | { 260 | list::iterator iter = sess->Iter; 261 | delete sess; 262 | 263 | Sessions.erase(iter); 264 | } 265 | } 266 | 267 | void TcpServer::CleanSessions() 268 | { 269 | for (list::iterator iter = Sessions.begin(); iter != Sessions.end(); ++iter) 270 | { 271 | Session *&sess = *iter; 272 | log_debug("Checking %p", sess); 273 | if (sess) 274 | { 275 | if (!sess->IsAlive) 276 | { 277 | delete sess; 278 | sess = NULL; 279 | } 280 | } 281 | if (!sess) 282 | { 283 | Sessions.erase(iter); 284 | } 285 | } 286 | } 287 | 288 | TcpServer::~TcpServer() 289 | { 290 | Stop(); 291 | 292 | ClearTimer(defaultTimer); 293 | 294 | for (auto &sess : Sessions) 295 | { 296 | delete sess; 297 | sess = NULL; 298 | } 299 | Sessions.clear(); 300 | 301 | if (Base) 302 | { 303 | event_base_free(Base); 304 | Base = NULL; 305 | } 306 | } 307 | 308 | void TcpServer::AddSession(Session *sess) 309 | { 310 | Sessions.push_back(sess); 311 | sess->Iter = Sessions.end(); 312 | --sess->Iter; 313 | } 314 | 315 | #ifdef ENABLE_IPV4 316 | void acceptCallbackDispatcher(evutil_socket_t listener, short event, void *arg) 317 | { 318 | (reinterpret_cast(arg))->AcceptCallback(event); 319 | } 320 | #endif 321 | 322 | #ifdef ENABLE_IPV6 323 | void accept6CallbackDispatcher(evutil_socket_t listener, short event, void *arg) 324 | { 325 | (reinterpret_cast(arg))->Accept6Callback(event); 326 | } 327 | #endif 328 | 329 | void timerCallbackDispatcher(evutil_socket_t listener, short event, void *arg) 330 | { 331 | (reinterpret_cast(arg))->TimerCallback(event); 332 | } 333 | -------------------------------------------------------------------------------- /MagicCubeServer/TcpServer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "Session.h" 6 | 7 | class TcpServer 8 | { 9 | public: 10 | bool IsRunning = false; 11 | 12 | event_base *Base; 13 | 14 | size_t MaxConnections = static_cast(-1); 15 | list Sessions; 16 | 17 | TcpServer(); 18 | 19 | #ifdef ENABLE_IPV4 20 | bool Listen(string, unsigned short, int); 21 | virtual void AcceptCallback(short); 22 | virtual void OnNewSession(sockaddr_in, evutil_socket_t); 23 | #endif 24 | 25 | #ifdef ENABLE_IPV6 26 | bool Listen6(string, unsigned short, int); 27 | virtual void Accept6Callback(short); 28 | virtual void OnNewSession(sockaddr_in6, evutil_socket_t); 29 | #endif 30 | 31 | // sync, block 32 | void Start(); 33 | void Stop(); 34 | 35 | void SetTimer(event*&, long); 36 | void ClearTimer(event*&); 37 | void EnableTimer(long); 38 | 39 | virtual void TimerCallback(short); 40 | virtual void CleanSession(Session*); 41 | virtual void CleanSessions(); 42 | 43 | virtual ~TcpServer(); 44 | 45 | protected: 46 | 47 | #ifdef ENABLE_IPV4 48 | event *listener_event = NULL; 49 | evutil_socket_t listener = static_cast(0); 50 | #endif 51 | 52 | #ifdef ENABLE_IPV6 53 | event *listener6_event = NULL; 54 | evutil_socket_t listener6 = static_cast(0); 55 | #endif 56 | 57 | event *defaultTimer = NULL; 58 | 59 | void AddSession(Session*); 60 | 61 | private: 62 | 63 | // prevent copy 64 | DISALLOW_COPY_AND_ASSIGN(TcpServer); 65 | }; 66 | 67 | #ifdef ENABLE_IPV4 68 | void acceptCallbackDispatcher(evutil_socket_t, short, void*); 69 | #endif 70 | 71 | #ifdef ENABLE_IPV6 72 | void accept6CallbackDispatcher(evutil_socket_t, short, void*); 73 | #endif 74 | 75 | void timerCallbackDispatcher(evutil_socket_t, short, void*); 76 | -------------------------------------------------------------------------------- /MagicCubeServer/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /MagicCubeServer/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Config.h" 4 | #include "../NetworkCommon/NetworkCommon.h" 5 | 6 | #if !defined(_DEBUG) && !defined(NDEBUG) 7 | #define NDEBUG 8 | #endif 9 | 10 | #ifdef NDEBUG 11 | #undef MEM_DEBUG 12 | #endif 13 | 14 | #ifdef _WIN32 15 | #define __perror(s) fprintf(stderr, "%s: Win32 Error %d(0x%08x)\n", s, GetLastError(), GetLastError()) 16 | #ifdef MEM_DEBUG 17 | #define _CRTDBG_MAP_ALLOC 18 | #include 19 | #include 20 | #endif 21 | #endif 22 | 23 | #ifdef __linux 24 | #include 25 | #define __perror(s) perror(s) 26 | #endif 27 | 28 | #if defined(__APPLE__) && defined(__MACH__) 29 | #include 30 | #define __perror(s) perror(s) 31 | #endif 32 | 33 | #ifdef _DEBUG 34 | #define _perror(s) do {__perror(s); /*abort();*/} while (false) 35 | #else 36 | #define _perror(s) __perror(s) 37 | #endif 38 | 39 | #define _log(type, format, ...) do {FILE *__fd = logFile; printTime(__fd); fprintf(__fd, "[%s] ", type); fprintf(__fd, format, ##__VA_ARGS__); fprintf(__fd, "\n");} while (false) 40 | #define log_normal(format, ...) _log("normal", format, ##__VA_ARGS__) 41 | #define log_debug(format, ...) _log("debug", format, ##__VA_ARGS__) 42 | #define log_warn(format, ...) _log("WARN", format, ##__VA_ARGS__) 43 | #define log_error(format, ...) do {_log("ERROR", format, ##__VA_ARGS__); abort();} while (false) 44 | #define log_fatal(format, ...) do {_log("FATAL", format, ##__VA_ARGS__); abort();} while (false) 45 | 46 | #ifdef NDEBUG 47 | #undef log_debug 48 | #define log_debug(format, ...) (int)0 49 | #endif 50 | 51 | #include 52 | #include 53 | #include 54 | 55 | #include 56 | #include 57 | #include 58 | 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | 68 | using namespace std; 69 | using rapidjson::Document; 70 | using rapidjson::Value; 71 | using rapidjson::Writer; 72 | using rapidjson::StringBuffer; 73 | 74 | extern FILE *logFile; // defined in MagicCubeServer.cpp 75 | 76 | #include "../CubeCommon/CubeCommon.h" 77 | 78 | #include "utilities.h" 79 | #include "MagicCubeServer.h" 80 | -------------------------------------------------------------------------------- /MagicCubeServer/utilities.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "utilities.h" 3 | 4 | void printTime(FILE *fd) 5 | { 6 | time_t now = time(NULL); 7 | char tmpBuf[256]; 8 | tm t; 9 | #ifdef _WIN32 10 | localtime_s(&t, &now); 11 | #else 12 | t = *localtime(&now); 13 | #endif 14 | strftime(tmpBuf, sizeof(tmpBuf), "%Y-%m-%d %H:%M:%S", &t); 15 | fprintf(fd, "[%s]", tmpBuf); 16 | } 17 | 18 | void setLogFile(string filename) 19 | { 20 | if (filename != "-") 21 | { 22 | logFile = NULL; 23 | #ifdef _WIN32 24 | fopen_s(&logFile, filename.c_str(), "w+"); 25 | #else 26 | logFile = fopen(filename.c_str(), "w+"); 27 | #endif 28 | if (!logFile) 29 | { 30 | logFile = stdout; 31 | _perror("fopen"); 32 | log_warn("%s", "open log file error"); 33 | } 34 | } 35 | } 36 | 37 | Document loadConfigObj(string filename) 38 | { 39 | string configJson = "", line; 40 | ifstream configFile(filename); 41 | while (getline(configFile, line)) 42 | { 43 | configJson += line + "\n"; 44 | } 45 | configFile.close(); 46 | 47 | if (configJson == "") 48 | { 49 | log_error("config file is not found or empty"); 50 | } 51 | 52 | Document configDoc; 53 | configDoc.Parse(configJson.c_str()); 54 | assert(configDoc.IsObject()); 55 | 56 | return move(configDoc); 57 | } 58 | 59 | size_t getSizeT(Value &v) 60 | { 61 | if (sizeof(size_t) == sizeof(unsigned int)) 62 | { 63 | return static_cast(v.GetInt()); 64 | } 65 | else if (sizeof(size_t) == sizeof(unsigned long long)) 66 | { 67 | return static_cast(v.GetInt64()); 68 | } 69 | } 70 | 71 | void configServer(CubeServer &server, Value &config) 72 | { 73 | server.MaxConnections = getSizeT(config["MaxConnections"]); 74 | 75 | #ifdef ENABLE_IPV4 76 | { 77 | Value &IPVal = config["IPv4"]; 78 | if (IPVal["Enable"].GetBool()) 79 | { 80 | log_normal("Listening %s:%d...", IPVal["Address"].GetString(), IPVal["Port"].GetUint()); 81 | server.Listen(IPVal["Address"].GetString(), IPVal["Port"].GetUint(), IPVal["Backlog"].GetInt()); 82 | } 83 | } 84 | #endif 85 | 86 | #ifdef ENABLE_IPV6 87 | { 88 | Value &IPVal = config["IPv6"]; 89 | if (IPVal["Enable"].GetBool()) 90 | { 91 | log_normal("Listening [%s]:%d...", IPVal["Address"].GetString(), IPVal["Port"].GetUint()); 92 | server.Listen6(IPVal["Address"].GetString(), IPVal["Port"].GetUint(), IPVal["Backlog"].GetInt()); 93 | } 94 | } 95 | #endif 96 | 97 | server.NeedAuth = config["Auth"].GetBool(); 98 | server.ServerKey = config["ServerKey"].GetString(); 99 | } 100 | 101 | vector loadRooms(Value &rooms) 102 | { 103 | log_normal("%s", "Loading rooms..."); 104 | 105 | size_t count = rooms.Size(); 106 | vector ris; 107 | 108 | for (size_t i = 0; i < count; ++i) 109 | { 110 | Value &room = rooms[i]; 111 | 112 | RoomInfo ri; 113 | ri.Name = room["Name"].GetString(); 114 | ri.NeedAuth = room["Auth"].GetBool(); 115 | ri.Key = room["Key"].GetString(); 116 | ri.Capacity = getSizeT(room["Capacity"]); 117 | ris.push_back(move(ri)); 118 | log_normal("%s...", room["Name"].GetString()); 119 | } 120 | 121 | return ris; 122 | } 123 | 124 | void configRooms(CubeServer &server, vector &rooms) 125 | { 126 | server.Rooms = move(rooms); 127 | server.RoomIds.clear(); 128 | for (size_t i = 0; i < server.Rooms.size(); ++i) 129 | { 130 | server.RoomIds[server.Rooms[i].Name] = i; 131 | } 132 | } 133 | 134 | bool checkObj(Value &doc, size_t argc, ...) 135 | { 136 | va_list ap = NULL; 137 | va_start(ap, argc); 138 | 139 | bool succeeded = true; 140 | 141 | for (size_t i = 0; i < argc; ++i) 142 | { 143 | const char *name = va_arg(ap, const char*); 144 | const char *type = va_arg(ap, const char*); 145 | 146 | if (!doc.HasMember(name)) 147 | { 148 | succeeded = false; 149 | break; 150 | } 151 | 152 | if (type == string("str")) 153 | { 154 | if (!doc[name].IsString()) 155 | { 156 | succeeded = false; 157 | break; 158 | } 159 | } 160 | else if (type == string("int")) 161 | { 162 | if (!doc[name].IsInt()) 163 | { 164 | succeeded = false; 165 | break; 166 | } 167 | } 168 | else if (type == string("uint")) 169 | { 170 | if (!doc[name].IsUint()) 171 | { 172 | succeeded = false; 173 | break; 174 | } 175 | } 176 | else if (type == string("int64")) 177 | { 178 | if (!doc[name].IsInt64()) 179 | { 180 | succeeded = false; 181 | break; 182 | } 183 | } 184 | else if (type == string("uint64")) 185 | { 186 | if (!doc[name].IsUint64()) 187 | { 188 | succeeded = false; 189 | break; 190 | } 191 | } 192 | else if (type == string("float")) 193 | { 194 | if (!doc[name].IsDouble()) 195 | { 196 | succeeded = false; 197 | break; 198 | } 199 | } 200 | else if (type == string("bool")) 201 | { 202 | if (!doc[name].IsBool()) 203 | { 204 | succeeded = false; 205 | break; 206 | } 207 | } 208 | else if (type == string("null")) 209 | { 210 | if (!doc[name].IsNull()) 211 | { 212 | succeeded = false; 213 | break; 214 | } 215 | } 216 | else if (type == string("array")) 217 | { 218 | if (!doc[name].IsArray()) 219 | { 220 | succeeded = false; 221 | break; 222 | } 223 | } 224 | else if (type == string("obj")) 225 | { 226 | if (!doc[name].IsObject()) 227 | { 228 | succeeded = false; 229 | break; 230 | } 231 | } 232 | } 233 | 234 | va_end(ap); 235 | 236 | return succeeded; 237 | } -------------------------------------------------------------------------------- /MagicCubeServer/utilities.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "RoomInfo.h" 4 | #include "TcpServer.h" 5 | #include "CubeServer.h" 6 | 7 | void printTime(FILE*); 8 | void setLogFile(string); 9 | Document loadConfigObj(string); 10 | size_t getSizeT(Value&); 11 | void configServer(CubeServer&, Value&); 12 | vector loadRooms(Value&); 13 | void configRooms(CubeServer&, vector&); 14 | 15 | template 16 | V getWithDefault(const map &m, const K &key, const V &defval) 17 | { 18 | typename map::const_iterator it = m.find(key); 19 | if (it == m.end()) 20 | { 21 | return defval; 22 | } 23 | else 24 | { 25 | return it->second; 26 | } 27 | } 28 | 29 | template 30 | bool contains(const map &m, const K &key) 31 | { 32 | typename map::const_iterator it = m.find(key); 33 | return it != m.end(); 34 | } 35 | 36 | // check document's props and type. string: str, int: int, uint: uint, int64: int64, uint64: uint64, float: float, bool: bool, null: null, array: array, object, obj 37 | bool checkObj(Value&, size_t, ...); -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = MagicCube 2 | 3 | SOURCES := $(shell ls $(PROJECT)/*.cpp) 4 | OBJECTS := $(patsubst $(PROJECT)/%.cpp, build/%.o, $(SOURCES)) 5 | 6 | ifeq ($(shell uname),Linux) 7 | # compiler 8 | CC = g++ 9 | INC_DIR = include/osx 10 | CC_FLAGS = -O2 -Wall -fno-strict-aliasing -std=c++11 -I $(INC_DIR) -I include 11 | 12 | # linker 13 | LD = g++ 14 | LIB_DIR = lib/linux 15 | LIBS = -lCubeCommon -lNetworkCommon -levent -lglfw3 -lstdc++ -lc -lm -ldl -lX11 -lpthread -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor -lGL -lGLU 16 | LINKER_FLAGS = -L $(LIB_DIR) -L CubeCommon/build -L NetworkCommon/build 17 | else 18 | 19 | ifeq ($(shell uname),Darwin) 20 | # compiler 21 | INC_DIR = include/osx 22 | CC_FLAGS = -O2 -Wall -fno-strict-aliasing -std=c++11 -I $(INC_DIR) -I include 23 | 24 | # linker 25 | LD = cc 26 | LIB_DIR = lib/osx 27 | LIBS = -lCubeCommon -lNetworkCommon -levent -lc++ -lm -lSystem -lglfw3 -framework Cocoa -framework OpenGL -framework IOKit -framework CoreVideo 28 | LINKER_FLAGS = -L $(LIB_DIR) -L CubeCommon/build -L NetworkCommon/build 29 | else 30 | # Unsupported operating system. 31 | CC = echo && echo "******** Unsupported operating system! ********" && echo && exit 1 || 32 | endif 33 | 34 | endif 35 | 36 | .PHONY: client 37 | client: 38 | -mkdir build 39 | make common 40 | make network 41 | make $(PROJECT) 42 | 43 | .PHONY: all 44 | all: 45 | -mkdir build 46 | make common 47 | make network 48 | make $(PROJECT) 49 | make server 50 | 51 | .PHONY: common 52 | common: 53 | cd CubeCommon && make 54 | 55 | .PHONY: network 56 | network: 57 | cd NetworkCommon && make 58 | 59 | .PHONY: server 60 | server: 61 | -mkdir build 62 | make common 63 | make network 64 | cd MagicCubeServer && make 65 | 66 | $(PROJECT): $(OBJECTS) 67 | $(LD) $(LINKER_FLAGS) -o build/$(PROJECT) $(OBJECTS) $(LIBS) 68 | 69 | build/%.o: $(PROJECT)/%.cpp $(PROJECT)/%.h $(PROJECT)/Config.h $(PROJECT)/utilities.h NetworkCommon/NetworkConfig.h 70 | $(CC) -c $(CC_FLAGS) -o $@ $< 71 | 72 | .PHONY: release 73 | release: client 74 | cd build && tar czvf $(PROJECT)_$(shell uname).tar.gz $(PROJECT) 75 | 76 | .PHONY: clean 77 | clean: 78 | -rm build/* 79 | -rm -rf build 80 | cd CubeCommon && make clean 81 | cd NetworkCommon && make clean 82 | cd MagicCubeServer && make clean 83 | -------------------------------------------------------------------------------- /NetworkCommon/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = NetworkCommon 2 | 3 | SOURCES := $(shell ls *.cpp) 4 | OBJECTS := $(patsubst %.cpp, build/%.o, $(SOURCES)) 5 | 6 | # compiler 7 | INC_DIR = ../include/osx 8 | CC_FLAGS = -O2 -Wall -fno-strict-aliasing -std=c++11 -I $(INC_DIR) -I ../include 9 | 10 | .PHONY: all 11 | all: 12 | -mkdir build 13 | make lib$(PROJECT).a 14 | 15 | build/%.o: %.cpp %.h NetworkConfig.h 16 | $(CC) -c $(CC_FLAGS) -o $@ $< 17 | 18 | lib$(PROJECT).a: $(OBJECTS) 19 | $(AR) rcs build/lib$(PROJECT).a $(OBJECTS) 20 | 21 | .PHONY: clean 22 | clean: 23 | -rm build/* 24 | -rm -rf build 25 | -------------------------------------------------------------------------------- /NetworkCommon/ManualEvent.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "ManualEvent.h" 3 | 4 | 5 | ManualEvent::ManualEvent() 6 | { 7 | 8 | } 9 | 10 | ManualEvent::ManualEvent(bool set) : set(set) 11 | { 12 | 13 | } 14 | 15 | ManualEvent::ManualEvent(bool set, bool autoReset) : AutoReset(autoReset), set(set) 16 | { 17 | 18 | } 19 | 20 | ManualEvent::~ManualEvent() 21 | { 22 | if (!mtx.try_lock()) 23 | { 24 | fprintf(stderr, "%s", "cannot destory while someone is waiting"); 25 | abort(); 26 | } 27 | else 28 | { 29 | mtx.unlock(); 30 | } 31 | 32 | //AutoReset = false; 33 | //Set(); 34 | //mtx.lock(); 35 | //mtx.unlock(); 36 | } 37 | 38 | void ManualEvent::Set() 39 | { 40 | unique_lock lck(mtx); 41 | set = true; 42 | condvar.notify_all(); 43 | } 44 | 45 | void ManualEvent::Reset() 46 | { 47 | unique_lock lck(mtx); 48 | set = false; 49 | } 50 | 51 | void ManualEvent::Wait() 52 | { 53 | unique_lock lck(mtx); 54 | while (!set) condvar.wait(lck); 55 | if (AutoReset) set = false; 56 | } 57 | -------------------------------------------------------------------------------- /NetworkCommon/ManualEvent.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | class ManualEvent 7 | { 8 | public: 9 | 10 | bool AutoReset = false; 11 | 12 | ManualEvent(); 13 | ManualEvent(bool); 14 | ManualEvent(bool, bool); 15 | ~ManualEvent(); 16 | 17 | void Set(); 18 | void Reset(); 19 | void Wait(); 20 | 21 | private: 22 | 23 | DISALLOW_COPY_AND_ASSIGN(ManualEvent); 24 | 25 | mutex mtx; 26 | condition_variable condvar; 27 | bool set = false; 28 | 29 | }; 30 | 31 | -------------------------------------------------------------------------------- /NetworkCommon/NetworkCommon.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NetworkConfig.h" 4 | #include "NetworkTypes.h" 5 | #include "Package.h" 6 | #include "ManualEvent.h" -------------------------------------------------------------------------------- /NetworkCommon/NetworkCommon.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {E2535545-AF18-41E0-9505-3745E2C40D15} 23 | Win32Proj 24 | NetworkCommon 25 | 8.1 26 | 27 | 28 | 29 | StaticLibrary 30 | true 31 | v140 32 | Unicode 33 | 34 | 35 | StaticLibrary 36 | false 37 | v140 38 | true 39 | Unicode 40 | 41 | 42 | StaticLibrary 43 | true 44 | v140 45 | Unicode 46 | 47 | 48 | StaticLibrary 49 | false 50 | v140 51 | true 52 | Unicode 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | ../include/win;../include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 74 | 75 | 76 | ../include/win;../include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 77 | 78 | 79 | ../include/win;../include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 80 | 81 | 82 | ../include/win;../include;$(VC_IncludePath);$(WindowsSDK_IncludePath); 83 | 84 | 85 | 86 | Use 87 | Level3 88 | Disabled 89 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 90 | true 91 | 92 | 93 | Windows 94 | true 95 | 96 | 97 | 98 | 99 | Use 100 | Level3 101 | Disabled 102 | _DEBUG;_LIB;%(PreprocessorDefinitions) 103 | true 104 | 105 | 106 | Windows 107 | true 108 | 109 | 110 | 111 | 112 | Level3 113 | Use 114 | MaxSpeed 115 | true 116 | true 117 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 118 | true 119 | 120 | 121 | Windows 122 | true 123 | true 124 | true 125 | 126 | 127 | 128 | 129 | Level3 130 | Use 131 | MaxSpeed 132 | true 133 | true 134 | NDEBUG;_LIB;%(PreprocessorDefinitions) 135 | true 136 | 137 | 138 | Windows 139 | true 140 | true 141 | true 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | Create 158 | Create 159 | Create 160 | Create 161 | 162 | 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /NetworkCommon/NetworkCommon.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 6 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 14 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 15 | 16 | 17 | 18 | 19 | Headers 20 | 21 | 22 | Headers 23 | 24 | 25 | Headers 26 | 27 | 28 | Headers 29 | 30 | 31 | Headers 32 | 33 | 34 | Headers 35 | 36 | 37 | 38 | 39 | Sources 40 | 41 | 42 | Sources 43 | 44 | 45 | Sources 46 | 47 | 48 | Sources 49 | 50 | 51 | -------------------------------------------------------------------------------- /NetworkCommon/NetworkConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef unsigned int package_len_t; 4 | 5 | #define MAGIC_MARK "MCP/0.0" 6 | #define LINE_ENDDING "\r\n" 7 | 8 | #define ENABLE_IPV4 9 | #define ENABLE_IPV6 10 | 11 | // CHECK_INTERVAL should be less than TIMEOUT_S 12 | #define CHECK_INTERVAL (1) // 10 13 | #define CHECK_INTERVAL_uS (CHECK_INTERVAL * 1000000) 14 | #define TIMEOUT_S 30 15 | 16 | #define PACKAGE_MAXLENGTH (static_cast(-1)) //(1024) 17 | #define HTTP_HEADER_MAXLENGTH (static_cast(16384)) 18 | #define LINE_MAXLENGTH (static_cast(16384)) 19 | #define BUFFER_SIZE (static_cast(4096)) -------------------------------------------------------------------------------- /NetworkCommon/NetworkTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "NetworkTypes.h" 3 | 4 | map SessionErrorMessage = 5 | { 6 | { SESSIONERROR_PROTOCOL_MISMATCH, "protocol mismatch" }, 7 | { SESSIONERROR_PACKAGE_EMPTY, "package is empty" }, 8 | { SESSIONERROR_PACKAGE_TOO_LONG, "package is too long" }, 9 | { SESSIONERROR_SERVER_CLOSE, "server is closing" }, 10 | { SESSIONERROR_TIMEOUT, "timed out" }, 11 | { SESSIONERROR_UNKNOWN, "unknown" } 12 | }; 13 | 14 | map UserFacingErrorMessage = 15 | { 16 | { ERROR_BAD_ARGUMENT, "bad argument(s)" }, 17 | { ERROR_AUTH_FAILED, "authorization failed" }, 18 | { ERROR_AUTH, "authorization needed" }, 19 | { ERROR_KICKED, "kicked by server" } 20 | }; -------------------------------------------------------------------------------- /NetworkCommon/NetworkTypes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NetworkConfig.h" 4 | #include "stdafx.h" 5 | 6 | #ifdef _WIN32 7 | #ifndef WIN32 8 | #define WIN32 // for libevent 9 | #endif 10 | typedef int socklen_t; 11 | #define INET6_ADDRSTRLEN 46 12 | #define SHUT_RD SD_RECEIVE 13 | #define SHUT_WR SD_SEND 14 | #define SHUT_RDWR SD_BOTH 15 | #ifdef ENABLE_IPV6 16 | // undefining ENABLE_IPV6 17 | #undef ENABLE_IPV6 18 | #endif 19 | #define sleep(t) Sleep((t) * 1000) 20 | #define usleep(t) Sleep((t) / 1000) 21 | #endif 22 | 23 | #ifdef __linux 24 | #include 25 | #endif 26 | 27 | #if defined(__APPLE__) && defined(__MACH__) 28 | #include 29 | #endif 30 | 31 | #if (!defined(ENABLE_IPV4) && !defined(ENABLE_IPV6)) 32 | #error Cannot disable ipv4 and ipv6 at the same time. 33 | #endif 34 | 35 | #define _SE(x) (static_cast(static_cast(x))) 36 | #define _UE(x) (static_cast(static_cast(x))) 37 | 38 | enum SessionErrorType 39 | { 40 | SESSIONERROR_PROTOCOL_MISMATCH, 41 | SESSIONERROR_PACKAGE_EMPTY, 42 | SESSIONERROR_PACKAGE_TOO_LONG, 43 | SESSIONERROR_SERVER_CLOSE, 44 | SESSIONERROR_TIMEOUT, 45 | SESSIONERROR_UNKNOWN 46 | }; 47 | extern map SessionErrorMessage; 48 | 49 | enum UserFacingError 50 | { 51 | ERROR_BAD_ARGUMENT = SESSIONERROR_UNKNOWN + 1, 52 | ERROR_AUTH_FAILED, 53 | ERROR_AUTH, 54 | ERROR_KICKED 55 | }; 56 | extern map UserFacingErrorMessage; 57 | -------------------------------------------------------------------------------- /NetworkCommon/Package.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Package.h" 3 | 4 | void *Package::operator new(size_t size, package_len_t dataLen) 5 | { 6 | size_t dataSize = static_cast(dataLen); 7 | return ::operator new(sizeof(PackageHeader) + dataSize); 8 | } 9 | 10 | void Package::operator delete(void *ptr) 11 | { 12 | ::operator delete(ptr); 13 | } 14 | 15 | package_len_t htonpacklen(package_len_t len) 16 | { 17 | if (sizeof(package_len_t) == 2) 18 | { 19 | return static_cast(htons(len)); 20 | } 21 | else if (sizeof(package_len_t) == 4) 22 | { 23 | return static_cast(htonl(len)); 24 | } 25 | } 26 | 27 | package_len_t ntohpacklen(package_len_t len) 28 | { 29 | if (sizeof(package_len_t) == 2) 30 | { 31 | return static_cast(ntohs(len)); 32 | } 33 | else if (sizeof(package_len_t) == 4) 34 | { 35 | return static_cast(ntohl(len)); 36 | } 37 | } -------------------------------------------------------------------------------- /NetworkCommon/Package.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NetworkConfig.h" 4 | #include "NetworkTypes.h" 5 | #include 6 | 7 | #pragma pack(push, 1) 8 | struct PackageHeader 9 | { 10 | char Magic[sizeof(MAGIC_MARK) - 1]; // always MAGIC_MARK without '\0' 11 | package_len_t DataLength; 12 | }; 13 | 14 | struct Package 15 | { 16 | PackageHeader Header; 17 | char Data[0]; 18 | 19 | void *operator new(size_t, void*) = delete; 20 | 21 | // suger for variable data size 22 | void *operator new(size_t, package_len_t); 23 | void operator delete(void*); 24 | }; 25 | #pragma pack(pop) 26 | 27 | package_len_t htonpacklen(package_len_t); 28 | package_len_t ntohpacklen(package_len_t); -------------------------------------------------------------------------------- /NetworkCommon/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /NetworkCommon/stdafx.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/NetworkCommon/stdafx.h -------------------------------------------------------------------------------- /PROBLEM.md: -------------------------------------------------------------------------------- 1 | # 解魔方 - SPJ 2 | ## (MagicCube.c/cpp/exe) 3 | 4 | ## 题目描述 5 | 6 | 王小二是一名大学新生,进入大学后,出于对魔方的兴趣,加入了魔方社。 7 | 8 | 小二想为社团做贡献,所以,他学习程序设计基础这门课程的过程中,想到这样一个问题:能否使用计算机计算出把魔方恢复为每个面中九个小方块颜色相同的步骤。 9 | 10 | 所以他想使用这门课程的知识,利用计算机,尝试编程来解魔方。 11 | 12 | 然而,小二所在的学校不允许新生在任何时间在宿舍使用自己的计算机,更不幸的是他在军训中骨折了,现在还不能够下床。所以,他想请求你帮助他完成这项任务。 13 | 14 | 聪明的你,能完成这项伟大而艰巨的任务吗? 15 | 16 | 他通过1寸小屏手机浏览的参考资料都在 `Doc` 目录中,现在提供给你。 17 | 18 | ## 输入格式 19 | 20 | 输入只有一行,这行有162个字符,为魔方的表示。 21 | 22 | 魔方的表示如下。 23 | 24 | 举起魔方,魔方离你最近的一面与目光垂直。以 `后左下` 顶角为原点O,水平向右为x轴,竖直向上为y轴,z轴与目光平行指向你,建立空间直角坐标系。 25 | 26 | 那么,魔方的27个小方块的坐标为(a, b, c) (a=0,1,2; b=0,1,2; c=0,1,2)。 27 | 28 | 其中,小方块(1, 1, 1)是完全看不见的。 29 | 30 | 对于每个小方块,前、后、左、右、上、下六个面的颜色分别使用一个字符来表示,组成一个六个字符的字符串。 31 | 32 | W: 白色 33 | O: 橙色 34 | Y: 黄色 35 | R: 红色 36 | G: 绿色 37 | B: 蓝色 38 | -: 看不见 39 | 40 | 例如,小方块(1, 1, 1)一定表示为 `------`;一个 `前左上` 角(0,2,2)的小方块可以表示为 `G-O-W-`;一个中央的小方块(1,1,2)可以表示为 `G-----`或(2,1,1)可以表示为 `---R--` 。 41 | 42 | 依次将魔方的27个小方块,以坐标 `(0,0,0)` `(1,0,0)` `(2,0,0)` `(0,1,0)` `(1,1,0)` `(2,1,0)` `(0,2,0)` `(1,2,0)` `(2,2,0)` `(0,0,1)` `(1,0,1)` `(2,0,1)` `(0,1,1)` `(1,1,1)` `(2,1,1)` `(0,2,1)` `(1,2,1)` `(2,2,1)` `(0,0,2)` `(1,0,2)` `(2,0,2)` `(0,1,2)` `(1,1,2)` `(2,1,2)` `(0,2,2)` `(1,2,2)` `(2,2,2)` 的顺序表示成六个字符的字符串,再拼合起来变成162个字符的字符串。 这就是魔方的表示方式。 43 | 44 | 例如,一个每个面中九个小方块颜色相同的魔方可能的表示为 `-GY--O-G---O-G-W-O-GY----G-----G-W---GY-R--G--R--G-WR---Y--O-----O---W-O--Y------------W----Y-R-----R----WR-B-Y--OB----OB--W-OB-Y---B-----B--W--B-Y-R-B---R-B--` 。 45 | 46 | 将这串字符串,六个一行写出来: 47 | 48 | -OB--W 49 | -O---W 50 | -O-G-W 51 | -OB--- 52 | -O---- 53 | -O-G-- 54 | -OB-Y- 55 | -O--Y- 56 | -O-GY- 57 | --B--W 58 | -----W 59 | ---G-W 60 | --B--- 61 | ------ 62 | ---G-- 63 | --B-Y- 64 | ----Y- 65 | ---GY- 66 | R-B--W 67 | R----W 68 | R--G-W 69 | R-B--- 70 | R----- 71 | R--G-- 72 | R-B-Y- 73 | R---Y- 74 | R--GY- 75 | 76 | 可以发现对于任意一列,除了为 `-` 的字符,其余字符相同、数量为9并且间距(隔过的 `-` 字符的个数)相同。 77 | 78 | 另外,每个面中九个小方块颜色相同的魔方,根据“前面”的选择不同,可能表示为如下,共24种。 79 | 80 | -BO--Y-B---Y-B-R-Y-BO----B-----B-R---BO-W--B--W--B-RW---O--Y-----Y---R-Y--O------------R----O-W-----W----RW-G-O--YG----YG--R-YG-O---G-----G--R--G-O-W-G---W-G--RW- 81 | -BR--W-B---W-B-O-W-BR----B-----B-O---BR-Y--B--Y--B-OY---R--W-----W---O-W--R------------O----R-Y-----Y----OY-G-R--WG----WG--O-WG-R---G-----G--O--G-R-Y-G---Y-G--OY- 82 | -BW--O-B---O-B-Y-O-BW----B-----B-Y---BW-R--B--R--B-YR---W--O-----O---Y-O--W------------Y----W-R-----R----YR-G-W--OG----OG--Y-OG-W---G-----G--Y--G-W-R-G---R-G--YR- 83 | -BY--R-B---R-B-W-R-BY----B-----B-W---BY-O--B--O--B-WO---Y--R-----R---W-R--Y------------W----Y-O-----O----WO-G-Y--RG----RG--W-RG-Y---G-----G--W--G-Y-O-G---O-G--WO- 84 | -GO--W-G---W-G-R-W-GO----G-----G-R---GO-Y--G--Y--G-RY---O--W-----W---R-W--O------------R----O-Y-----Y----RY-B-O--WB----WB--R-WB-O---B-----B--R--B-O-Y-B---Y-B--RY- 85 | -GR--Y-G---Y-G-O-Y-GR----G-----G-O---GR-W--G--W--G-OW---R--Y-----Y---O-Y--R------------O----R-W-----W----OW-B-R--YB----YB--O-YB-R---B-----B--O--B-R-W-B---W-B--OW- 86 | -GW--R-G---R-G-Y-R-GW----G-----G-Y---GW-O--G--O--G-YO---W--R-----R---Y-R--W------------Y----W-O-----O----YO-B-W--RB----RB--Y-RB-W---B-----B--Y--B-W-O-B---O-B--YO- 87 | -GY--O-G---O-G-W-O-GY----G-----G-W---GY-R--G--R--G-WR---Y--O-----O---W-O--Y------------W----Y-R-----R----WR-B-Y--OB----OB--W-OB-Y---B-----B--W--B-Y-R-B---R-B--WR- 88 | -OB--W-O---W-O-G-W-OB----O-----O-G---OB-Y--O--Y--O-GY---B--W-----W---G-W--B------------G----B-Y-----Y----GY-R-B--WR----WR--G-WR-B---R-----R--G--R-B-Y-R---Y-R--GY- 89 | -OG--Y-O---Y-O-B-Y-OG----O-----O-B---OG-W--O--W--O-BW---G--Y-----Y---B-Y--G------------B----G-W-----W----BW-R-G--YR----YR--B-YR-G---R-----R--B--R-G-W-R---W-R--BW- 90 | -OW--G-O---G-O-Y-G-OW----O-----O-Y---OW-B--O--B--O-YB---W--G-----G---Y-G--W------------Y----W-B-----B----YB-R-W--GR----GR--Y-GR-W---R-----R--Y--R-W-B-R---B-R--YB- 91 | -OY--B-O---B-O-W-B-OY----O-----O-W---OY-G--O--G--O-WG---Y--B-----B---W-B--Y------------W----Y-G-----G----WG-R-Y--BR----BR--W-BR-Y---R-----R--W--R-Y-G-R---G-R--WG- 92 | -RB--Y-R---Y-R-G-Y-RB----R-----R-G---RB-W--R--W--R-GW---B--Y-----Y---G-Y--B------------G----B-W-----W----GW-O-B--YO----YO--G-YO-B---O-----O--G--O-B-W-O---W-O--GW- 93 | -RG--W-R---W-R-B-W-RG----R-----R-B---RG-Y--R--Y--R-BY---G--W-----W---B-W--G------------B----G-Y-----Y----BY-O-G--WO----WO--B-WO-G---O-----O--B--O-G-Y-O---Y-O--BY- 94 | -RW--B-R---B-R-Y-B-RW----R-----R-Y---RW-G--R--G--R-YG---W--B-----B---Y-B--W------------Y----W-G-----G----YG-O-W--BO----BO--Y-BO-W---O-----O--Y--O-W-G-O---G-O--YG- 95 | -RY--G-R---G-R-W-G-RY----R-----R-W---RY-B--R--B--R-WB---Y--G-----G---W-G--Y------------W----Y-B-----B----WB-O-Y--GO----GO--W-GO-Y---O-----O--W--O-Y-B-O---B-O--WB- 96 | -WB--R-W---R-W-G-R-WB----W-----W-G---WB-O--W--O--W-GO---B--R-----R---G-R--B------------G----B-O-----O----GO-Y-B--RY----RY--G-RY-B---Y-----Y--G--Y-B-O-Y---O-Y--GO- 97 | -WG--O-W---O-W-B-O-WG----W-----W-B---WG-R--W--R--W-BR---G--O-----O---B-O--G------------B----G-R-----R----BR-Y-G--OY----OY--B-OY-G---Y-----Y--B--Y-G-R-Y---R-Y--BR- 98 | -WO--B-W---B-W-R-B-WO----W-----W-R---WO-G--W--G--W-RG---O--B-----B---R-B--O------------R----O-G-----G----RG-Y-O--BY----BY--R-BY-O---Y-----Y--R--Y-O-G-Y---G-Y--RG- 99 | -WR--G-W---G-W-O-G-WR----W-----W-O---WR-B--W--B--W-OB---R--G-----G---O-G--R------------O----R-B-----B----OB-Y-R--GY----GY--O-GY-R---Y-----Y--O--Y-R-B-Y---B-Y--OB- 100 | -YB--O-Y---O-Y-G-O-YB----Y-----Y-G---YB-R--Y--R--Y-GR---B--O-----O---G-O--B------------G----B-R-----R----GR-W-B--OW----OW--G-OW-B---W-----W--G--W-B-R-W---R-W--GR- 101 | -YG--R-Y---R-Y-B-R-YG----Y-----Y-B---YG-O--Y--O--Y-BO---G--R-----R---B-R--G------------B----G-O-----O----BO-W-G--RW----RW--B-RW-G---W-----W--B--W-G-O-W---O-W--BO- 102 | -YO--G-Y---G-Y-R-G-YO----Y-----Y-R---YO-B--Y--B--Y-RB---O--G-----G---R-G--O------------R----O-B-----B----RB-W-O--GW----GW--R-GW-O---W-----W--R--W-O-B-W---B-W--RB- 103 | -YR--B-Y---B-Y-O-B-YR----Y-----Y-O---YR-G--Y--G--Y-OG---R--B-----B---O-B--R------------O----R-G-----G----OG-W-R--BW----BW--O-BW-R---W-----W--O--W-R-G-W---G-W--OG- 104 | 105 | 106 | ## 输出格式 107 | 108 | 输出只有一行,输出用空格分开的旋转步骤。行末空格对于评测没有影响。 109 | 110 | 旋转步骤如下: 111 | 112 | U: 正对魔方,将“上面”旋转90°,角速度方向竖直向下。 113 | Ui: 正对魔方,将“上面”旋转90°,角速度方向竖直向上。 114 | D: 正对魔方,将“下面”旋转90°,角速度方向竖直向上。 115 | Di: 正对魔方,将“下面”旋转90°,角速度方向竖直向下。 116 | L: 正对魔方,将“左面”旋转90°,角速度方向水平向右。 117 | Li: 正对魔方,将“左面”旋转90°,角速度方向水平向左。 118 | R: 正对魔方,将“右面”旋转90°,角速度方向水平向左。 119 | Ri: 正对魔方,将“右面”旋转90°,角速度方向水平向右。 120 | F: 正对魔方,将“前面”旋转90°,角速度方向水平向后。 121 | Fi: 正对魔方,将“前面”旋转90°,角速度方向水平向前。 122 | B: 正对魔方,将“后面”旋转90°,角速度方向水平向前。 123 | Bi: 正对魔方,将“后面”旋转90°,角速度方向水平向后。 124 | X: 正对魔方,将整个魔方旋转90°,角速度方向水平向左。 125 | Xi: 正对魔方,将整个魔方旋转90°,角速度方向水平向右。 126 | Y: 正对魔方,将整个魔方旋转90°,角速度方向竖直向下。 127 | Yi: 正对魔方,将整个魔方旋转90°,角速度方向竖直向上。 128 | Z: 正对魔方,将整个魔方旋转90°,角速度方向水平向后。 129 | Zi: 正对魔方,将整个魔方旋转90°,角速度方向水平向前。 130 | 131 | 对于不需要操作的魔方,输出空行或者只含有空格和换行的字符串。 132 | 133 | ## 样例输入 1 134 | 135 | -GY--O-G---O-G-W-O-GY----G-----G-W---GY-R--G--R--G-WR---Y--O-----O---W-O--Y------------W----Y-R-----R----WR-B-Y--OB----OB--W-OB-Y---B-----B--W--B-Y-R-B---R-B-- 136 | 137 | ## 样例输出 1 138 | 139 | (空) 140 | 141 | ## 样例输入 2 142 | 143 | -BO--Y-B---O-G-R-W-RB----O-----Y-O---WR-B--W--G--R-BY---O--G-----Y---R-Y--G------------B----G-Y-----W----RG-W-O--GR----WY--G-RY-B---R-----B--W--G-Y-O-O---W-W--BO- 144 | 145 | ## 样例输入 2 可能的输出 146 | 147 | U Fi Ui Y L Fi D F Li R U Fi Ui Y R Y Ri U Fi Ui Y Li D D L Ri Di R D Ri Di R D Ri Di R D Ri Di R D Ri Di R D Y D D Ri Di R D Ri Di R D Ri Di R D Y X X U Li U L U F Ui Fi Yi Li U L U F Ui Fi Y F U R Ui Ri Fi Y R U Ri U R U U Ri Y Y R U Ri U R U U Ri Ui Y Ri F Ri B B R Fi Ri B B R R Ui F F U L Ri F F Li R U F F Yi F F U L Ri F F Li R U F F 148 | 149 | ## 限制 150 | 151 | 所有输入保证为合法的魔方。 152 | 153 | 时间1s。 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MagicCube 2 | ### Great homework for Fundamentals of Programming course. 3 | 4 | ![](https://raw.githubusercontent.com/twd2/MagicCube/master/Doc/image1.png) 5 | 6 | ![](https://raw.githubusercontent.com/twd2/MagicCube/master/Doc/image2.png) 7 | 8 | # Dependencies 9 | 10 | 1. Your interest. 11 | 2. [GLFW](http://www.glfw.org/) if compile without NOGL option. 12 | 3. [libevent](https://github.com/libevent/libevent) 2.0+ 13 | 4. [RapidJSON](https://github.com/miloyip/rapidjson) 14 | 5. [cmdline](https://github.com/tanakh/cmdline) (for server) 15 | 16 | ## Head Files And Precompiled Libraries 17 | 18 | TODO 19 | 20 | # Solvers 21 | 22 | 1. General solver(general): Fast, ~130 steps. 23 | 2. Random solver(random, monkey): Very very slow, infinite steps. 24 | 3. Brute force solver(bruteforce, bf): Very slow, less than 21 steps. 25 | 26 | # Building 27 | 28 | ## Windows - Visual Studio 29 | 30 | 0. Put downloaded head files directory (`include`) and precompiled libraries directory (`lib`) into the root of the project directory. 31 | 1. Open `MagicCube.sln`. 32 | 2. Build! 33 | 34 | ## OS X & Linux 35 | 36 | 0. If you are using Linux, install `xorg-dev`, `libgl1-mesa-dev` and `libglu1-mesa-dev` packages. 37 | 1. Build glfw and libevent, and make static libraries. 38 | 2. Put `libglfw3.a` and `libevent.a` into `lib/osx` or `lib/linux` (you may need create this directory before). 39 | 3. Execute `make -j8` and `build/MagicCube` is the binary. 40 | 41 | # Building - Server 42 | 43 | ## Windows - Visual Studio 44 | 45 | See #Building. 46 | 47 | ## OS X & Linux 48 | 49 | 1. Build libevent, and make a static library. 50 | 2. Put `libevent.a` into `lib/osx/` or `lib/linux/` (you may need create this directory before). 51 | 3. Execute `make -j8 server` and `MagicCubeServer/build/MagicCubeServer` is the binary. 52 | 53 | # Data Format 54 | 55 | ## Format1 56 | 57 | see: PROBLEM.md 58 | 59 | ## Format2 60 | 61 | 按“前、后、左、右、上、下”的次序来输入魔方的各面状态,其中“后左右”三面是“前”面保持上下面在同一水平面上分别旋转180度、90度、270度得到的,“上下”两面分别是“前”面向下和向上翻转90度(保持左右面在同一垂直平面上)得到的。 62 | 63 | 每面9个字符,代表颜色。 64 | 65 | # Usage - GUI 66 | 67 | 打开程序之后,会显示一个窗口,窗口里面有一个大方块,上面有27个小方块,其中一个基本看不见。 68 | 69 | 用鼠标在窗口内拖动可以以不同视角观看魔方。 70 | 71 | 焦点在窗口上,输入文字,会回显在控制台中。 72 | 73 | 现在支持如下命令: 74 | 75 | U, Ui, D, Di, L, Li, R, Ri, F, Fi, B, Bi, X, Xi, Y, Yi, Z, Zi: 参考PROBLEM.md中说明,其中“正对魔方”操作应将视角调整为程序打开时视角的初始位置。 76 | CHECK: 检查上下左右前后六个面每个小方块的颜色相等情况。 77 | ABOUT: 输出“Wandai :)”,没有实际用处,但拥有超级牛力。 78 | RESET: 新魔方。 79 | SOLVE: 解当前状态的魔方,输出参考步骤,窗口表现为魔方颜色复原。 80 | PLAY: 解当前状态的魔方,输出参考步骤,窗口表现为魔方颜色复原每一步的动画。 81 | SET_SOLVER : 设置求解算法(general/bruteforce/random)。 82 | RANDOM: 随机转动魔方,“打乱”。 83 | FILE : 从文件加载魔方表示。 84 | LOAD CMD: 从控制台输入魔方表示并加载。 85 | LOAD : 加载魔方表示数据。 86 | LOAD FORMAT2: 从控制台输入format2表示的魔方。 87 | SAVE: 保存当前魔方装态为魔方表示。 88 | TEST: 测试(不好玩)。 89 | 90 | # Usage - Text mode 91 | 92 | 1. Input cube data in format2. 93 | 2. Press `Enter`. 94 | 3. See the steps. 95 | 96 | # Homework? 97 | 98 | Need to compile with NOGL defined. -------------------------------------------------------------------------------- /lib/linux/libevent.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/linux/libevent.a -------------------------------------------------------------------------------- /lib/linux/libglfw3.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/linux/libglfw3.a -------------------------------------------------------------------------------- /lib/osx/libevent.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/osx/libevent.a -------------------------------------------------------------------------------- /lib/osx/libglfw3.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/osx/libglfw3.a -------------------------------------------------------------------------------- /lib/win/glfw3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/win/glfw3.dll -------------------------------------------------------------------------------- /lib/win/glfw3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/win/glfw3.lib -------------------------------------------------------------------------------- /lib/win/glfw3dll.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/win/glfw3dll.lib -------------------------------------------------------------------------------- /lib/win/libevent.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/win/libevent.lib -------------------------------------------------------------------------------- /lib/win/libevent_core.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/win/libevent_core.lib -------------------------------------------------------------------------------- /lib/win/libevent_extras.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/win/libevent_extras.lib -------------------------------------------------------------------------------- /lib/winx64/glfw3.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/winx64/glfw3.dll -------------------------------------------------------------------------------- /lib/winx64/glfw3.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/winx64/glfw3.lib -------------------------------------------------------------------------------- /lib/winx64/glfw3dll.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/winx64/glfw3dll.lib -------------------------------------------------------------------------------- /lib/winx64/libevent.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/winx64/libevent.lib -------------------------------------------------------------------------------- /lib/winx64/libevent_core.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/winx64/libevent_core.lib -------------------------------------------------------------------------------- /lib/winx64/libevent_extras.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/twd2/MagicCube/d7201b15424b8d06e124199054a7e315cf2de14c/lib/winx64/libevent_extras.lib --------------------------------------------------------------------------------