main.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. //
  2. // main.cpp
  3. // auto_fill_jewel_v3
  4. //
  5. // Created by Red on 2024/11/22.
  6. //
  7. /*
  8. 需求:
  9. 1.给定宝石种类和每类数量
  10. 2.程序随机给出5种盘子组合
  11. 3.关卡由多个盘子组成,每个盘子包含若干不同层,每层上面包含宝石。
  12. 4.宝石有大、中、小三个尺度,按面积算: 1大=2中=4小
  13. 5.盘子有大、小、迷你3种,其容量分别对应 6个大宝石,3个大宝石,1个大宝石。(确认没有中盘子)
  14. 6.每个关卡最大有9个大盘子。
  15. 7.盘子之间的层数差异在0-1个。迷你盘子数量可以很多,这个是不是需要人工控制后面再问吧。
  16. 8.盘子会移动,但是盘子间不会重叠。
  17. 9.大中小号盘子有横的有竖着的。
  18. 10.重叠区百分比可以从0.05到0.2,程序自行判断最优值。
  19. 11.宝石只提供 80x80的资源,对应大。如果有中和小,需要程序缩放(0.75,0.50)。大、中、小是不同的宝石各消各的。
  20. */
  21. #include <iostream>
  22. #include <string>
  23. #include <vector>
  24. #include "SpriteData.hpp"
  25. #include "ajson5.hpp"
  26. #include "contourdata.h"
  27. #include "LevelGenerate.hpp"
  28. #include "FillGlobalConfig.hpp"
  29. #include "RandomGridFiller.hpp"
  30. #include "BoostGeometryTools.hpp"
  31. #include <opencv2/core.hpp>
  32. #include <opencv2/imgproc.hpp>
  33. #include <opencv2/highgui.hpp>
  34. #include <sstream>
  35. #include <ctime>
  36. #include <chrono>
  37. #include <tuple>
  38. #include <sstream>
  39. //#include "LevelThumbTool.hpp"
  40. using namespace ArduinoJson;
  41. using namespace std;
  42. #include "levelinputdata.h"
  43. #include "levelextinputdata.h"
  44. #include "LevelOutputWriter.hpp"
  45. int main(int argc, const char * argv[]) {
  46. cout<<"A program to generate level. 2024-11-23"<<endl;
  47. cout<<"usage:auto_fill_jewel_v3 level0001_01.json level0001_01_ext.json output.json"<<endl;
  48. cout<<"version v3.3"<<endl ;
  49. if( argc!=4 ) {
  50. cout<<"缺少参数"<<endl;
  51. return 11 ;
  52. }
  53. string levelinFilename = argv[1] ;
  54. string levelextFilename = argv[2] ;
  55. string outputFilename = argv[3] ;
  56. LevelInputData levelInputData ;
  57. LevelExtInputData levelExtData ;
  58. bool ok1 = levelInputData.readFromFile(levelinFilename);
  59. bool ok2 = levelExtData.readFromFile(levelextFilename) ;
  60. if( ok1==false ) {
  61. cout<<"加载关卡输入参数失败 "<<levelinFilename <<endl;
  62. return 12 ;
  63. }
  64. if( ok2==false ) {
  65. cout<<"加载关卡扩展参数失败 "<<levelextFilename <<endl;
  66. return 13 ;
  67. }
  68. FillGlobalConfig::getInstance() ; //初始化单例
  69. LevelGenerate genv3 ;
  70. vector<PlateFillResult> resultPlateFillResults ;
  71. vector<ContourData::Point> resultPlateCenterPointArr ;
  72. string errorStr ;
  73. bool genok = genv3.generate_v2(levelInputData, levelExtData, resultPlateFillResults, resultPlateCenterPointArr,errorStr);
  74. if( genok==false ) {
  75. cout<<"Error: "<<errorStr<<endl;
  76. return 14 ;
  77. }
  78. cout<<"write results"<<endl;
  79. LevelOutputWriter writer ;
  80. writer.writeLevelJson(levelInputData, levelExtData, resultPlateFillResults, resultPlateCenterPointArr, outputFilename) ;
  81. cout<<"done"<<endl;
  82. return 0;
  83. }
  84. /*
  85. void plateInfo(vector<tuple<int,vector<vector<FillResult>>>>& result1,string& info ) {
  86. auto fgc = FillGlobalConfig::getInstance() ;
  87. int nbig=0;
  88. int nmid = 0 ;
  89. int nsml = 0 ;
  90. stringstream ss ;
  91. for(auto it = result1.begin(); it!= result1.end(); ++ it ) {
  92. int plateId = std::get<0>( *it ) ;
  93. vector<vector<FillResult>>& layers = std::get<1>(*it);
  94. FillGlobalConfig::PlateItem* plate = fgc->getPlateItemById(plateId) ;
  95. if( plate->_size == FILLGLOBALCONFIG_PLATESIZE_LG ){
  96. nbig++;
  97. ss<<"LG:"<<layers.size()<<";" ;
  98. }
  99. else if( plate->_size==FILLGLOBALCONFIG_PLATESIZE_MD ){
  100. nmid++;
  101. ss<<"MD:"<<layers.size()<<";" ;
  102. }
  103. else{
  104. nsml++ ;
  105. ss<<"SM:"<<layers.size()<<";" ;
  106. }
  107. }
  108. stringstream ss2 ;
  109. ss2<<"N-LG:"<<nbig<<"; N-MD:"<<nmid<<"; N-SM:"<<nsml<<" "<<ss.str() ;
  110. info = ss2.str() ;
  111. }
  112. */
  113. /*
  114. bool writeLevelJson(vector<tuple<int,vector<vector<FillResult>>>>& resultPlateFillResults,
  115. vector<ContourData::Point>& resultPlateCenterPointArr,
  116. string outfilename)
  117. {
  118. auto fgc = FillGlobalConfig::getInstance() ;
  119. int totalJewelCnt = 0 ;
  120. for(auto itp = resultPlateFillResults.begin();itp!=resultPlateFillResults.end();++itp) {
  121. int plateId = std::get<0>( *itp ) ;
  122. vector<vector<FillResult>>& frArr = std::get<1>( *itp );
  123. for(auto itfr = frArr.begin(); itfr!=frArr.end();++itfr ) {
  124. totalJewelCnt+=itfr->size() ;
  125. }
  126. }
  127. DynamicJsonBuffer jsonBuffer;
  128. JsonObject& root = jsonBuffer.createObject() ;
  129. root.createNestedObject("target");//not used.
  130. root["bgtem"] = "no"; //背景redream文件
  131. root["jewel_count"] = totalJewelCnt ;
  132. JsonArray& jplatesArr = root.createNestedArray("plates") ;
  133. int ids = 1 ;
  134. for(int ip = 0 ; ip < resultPlateFillResults.size() ; ++ ip ) {
  135. JsonObject& plateObj = jplatesArr.createNestedObject() ;
  136. auto itp = resultPlateFillResults.begin() ;
  137. std::advance(itp, ip) ;
  138. int plateId = std::get<0>( *itp ) ;
  139. vector<vector<FillResult>>& frArr = std::get<1>( *itp );
  140. float platex = resultPlateCenterPointArr[ip].x ;
  141. float platey = resultPlateCenterPointArr[ip].y ;
  142. plateObj["typeId"] = plateId ;
  143. plateObj["plateId"] = ids++ ;
  144. // plateObj[""] =
  145. plateObj["x"] = platex ; //这里是盘子中心在游戏区域的坐标(原点左下角)
  146. plateObj["y"] = platey ;
  147. plateObj["sprite_frame_name"] = fgc->getPlateItemById(plateId)->_pngName ;
  148. JsonArray& layerArr = plateObj.createNestedArray("layers") ;
  149. for(int il = 0 ; il < frArr.size() ; ++il ) {
  150. vector<FillResult>& frs = frArr[il] ;
  151. JsonObject& lyrObj = layerArr.createNestedObject() ;
  152. lyrObj["rotate"] = 0.0 ;
  153. lyrObj["scale_x"] = 1.0 ;
  154. lyrObj["scale_y"] = 1.0 ;
  155. lyrObj["scale"] = 1.0 ;
  156. lyrObj["sprite_frame_name"] = fgc->getPlateItemById(plateId)->_pngName ;
  157. lyrObj["lyrId"] = ids++ ;
  158. lyrObj["zorder"] = il+1 ;
  159. JsonArray& posArr = lyrObj.createNestedArray("position") ;
  160. posArr.add(platex) ;
  161. posArr.add(platey) ;
  162. JsonArray& screwArr = lyrObj.createNestedArray("screws") ;
  163. for(int ij = 0 ;ij < frs.size();++ ij ) {
  164. FillResult& fr = frs[ij] ;
  165. FillGlobalConfig::JewelItem* jewPtr = fgc->getJewelItemById(fr._jewelTypeId);
  166. if( fr._jewelTypeId>=0 ) { // -1 is removed.
  167. JsonObject& jobj = screwArr.createNestedObject();
  168. jobj["rotate"] = fr._rotdeg ;
  169. jobj["scale_x"] = jewPtr->_scale ;
  170. jobj["scale_y"] = jewPtr->_scale ;
  171. jobj["csx"] = 0;
  172. jobj["csy"] = 0;
  173. jobj["scale"] = jewPtr->_scale ;
  174. jobj["sprite_frame_name"] = jewPtr->_pngName ;
  175. jobj["screwId"] = ids++ ;
  176. jobj["typeId"] = fr._jewelTypeId ;
  177. JsonArray& posArr2 = jobj.createNestedArray("position") ;
  178. posArr2.add( fr._x) ; // 钉子中心在盘子内部的坐标(原点左下角)
  179. posArr2.add( fr._y) ;
  180. }
  181. }
  182. }
  183. }
  184. string jsonText ;
  185. root.printTo(jsonText);
  186. ofstream ofs( outfilename.c_str() );
  187. if( ofs.good()==false ) return false;
  188. ofs<<jsonText;
  189. return true ;
  190. }
  191. */
  192. //测试输出结果到屏幕
  193. /*
  194. void testPrintPlateToScreenByOpenCV () {
  195. if(false)
  196. {//测试
  197. int iplate = 5 ;
  198. int ilayer = 2 ;
  199. auto itPlate = resultPlateFillResults.begin() ;
  200. std::advance(itPlate, iplate) ;
  201. FillGlobalConfig::PlateItem* platePtr = FillGlobalConfig::getInstance()->getPlateItemById( std::get<0>(*itPlate) ) ;
  202. vector<vector<FillResult>>& layersArr = std::get<1>(*itPlate);
  203. cv::Mat plateimage = cv::Mat::zeros( platePtr->_bbwid, platePtr->_bbhei , CV_8UC3 );
  204. for(int ibox = 0 ; ibox < layersArr[ilayer].size() ; ++ ibox ) {
  205. FillResult& fr = layersArr[ilayer][ibox] ;
  206. BoostGeometryTools::BoostPolygon poly1 = BoostGeometryTools::makeRotateNTranslateBox(-fr._width/2, -fr._height/2, fr._width, fr._height, fr._rotdeg, fr._x, fr._y) ;
  207. vector<cv::Point> cvpoints ;
  208. for(int ipt = 0 ;ipt < poly1.outer().size();++ ipt ) {
  209. cv::Point p2 ;
  210. p2.x = poly1.outer()[ipt].get<0>();
  211. p2.y = poly1.outer()[ipt].get<1>() ;
  212. cvpoints.push_back(p2) ;
  213. }
  214. cv::polylines(plateimage, cvpoints, true, cv::Scalar(rand()%255,rand()%255,rand()%255));
  215. }
  216. //
  217. stringstream ss ;
  218. ss<<"win"<<iplate<<"-"<<ilayer ;
  219. cv::imshow( ss.str().c_str() , plateimage );
  220. cv::waitKey();
  221. }
  222. }
  223. */