LevelGenerate.cpp 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188
  1. //
  2. // LevelGenerate.cpp
  3. // auto_fill_jewel_v3
  4. //
  5. // Created by Red on 2024/11/23.
  6. //
  7. #include "LevelGenerate.hpp"
  8. #include <iostream>
  9. #include <cassert>
  10. #include <unordered_map>
  11. #include "FillGlobalConfig.hpp"
  12. #include <tuple>
  13. #include "BoxPositionTool.hpp"
  14. #include "GridPositionTool.hpp"
  15. //#include "LevelThumbTool.hpp"
  16. #define MOVEID_NO_MOVE 0
  17. #define MOVEID_1ST_LINE 1
  18. #define MOVEID_2ND_LINE 2
  19. using namespace std;
  20. void LevelGenerate::generateAll(FillGlobalConfig::LevelData levelData, string outname)
  21. {
  22. cout<<"debug level "<<levelData._id<<" subid "<<levelData._subId<<endl;
  23. auto fgc = FillGlobalConfig::getInstance() ;
  24. fgc->clearGridBoxFilledStatus() ;//每次填充盘子前必须清空盘子占位情况
  25. vector<PlateFillResult> resultPlateFRs ;
  26. vector<ContourData::Point> resultPlateCenterPosiArr ;
  27. generate(levelData, false, nullptr , resultPlateFRs, resultPlateCenterPosiArr) ;
  28. //输出结果
  29. string pngName0 = outname + "_000000.png" ;
  30. //LevelThumbTool ltt ;
  31. //ltt.makeThumb3(pngName0, resultPlateFRs, resultPlateCenterPosiArr) ;
  32. //对于所有移动的配置
  33. vector<FillGlobalConfig::MultiMoveConfig> mmcArr = fgc->getAllMoveConfigByJewels(levelData) ;
  34. for(int im=0;im < mmcArr.size();++ im ) {
  35. string moveName = mmcArr[im]._first->_type ;
  36. if( mmcArr[im]._second ) moveName += mmcArr[im]._second->_type ;
  37. else moveName += "00" ;
  38. cout<<"debug moveName "<<moveName<<endl;
  39. fgc->clearGridBoxFilledStatus() ;//每次填充盘子前必须清空盘子占位情况
  40. vector<PlateFillResult> resultPlateFRs1 ;
  41. vector<ContourData::Point> resultPlateCenterPosiArr1 ;
  42. generate(levelData, true, &mmcArr[im] , resultPlateFRs1, resultPlateCenterPosiArr1) ;
  43. //输出结果
  44. string pngName1 = outname + "_" + moveName;
  45. pngName1 += ".png" ;
  46. //ltt.makeThumb3(pngName1, resultPlateFRs1, resultPlateCenterPosiArr1) ;
  47. }
  48. }
  49. bool LevelGenerate::generate( FillGlobalConfig::LevelData levelData,
  50. const bool isMovable,
  51. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig , //移动盘子配置,如果isMovable为false,这个参数忽略,可以传入nullptr
  52. vector<PlateFillResult>& resultPlateFillResults,
  53. vector<ContourData::Point>& resultPlateCenterPointArr
  54. )
  55. {
  56. resultPlateFillResults.clear() ;
  57. resultPlateCenterPointArr.clear() ;
  58. auto ms0 = std::chrono::system_clock::now().time_since_epoch() ;
  59. uint64_t ms00 = std::chrono::duration_cast<chrono::milliseconds>(ms0).count() ;
  60. srand(_seed);
  61. unordered_map<int,tuple<int,int> > jewIdSzCntStorageMap ;// unordered_map<宝石ID,tuple<尺寸,库存数量> >
  62. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  63. int bigJewelCnt = 0 ;
  64. int midJewelCnt = 0;
  65. int smlJewelCnt = 0 ;
  66. for(int ij = 0 ; ij < levelData._jewelIds.size();++ ij ) {
  67. int jewId = levelData._jewelIds[ij] ;
  68. int cnt = levelData._cnts[ij] ;
  69. FillGlobalConfig::JewelItem* jewItem = fgc->getJewelItemById(jewId) ;
  70. jewIdSzCntStorageMap[jewId] = {jewItem->_size,cnt} ;
  71. if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_SM ) {
  72. smlJewelCnt+=cnt ;
  73. }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_MD ) {
  74. midJewelCnt += cnt ;
  75. }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_LG ) {
  76. bigJewelCnt += cnt ;
  77. }
  78. }
  79. //每个盘子类型小号宝石承载量
  80. //按顺序分别为大和中
  81. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  82. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  83. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  84. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  85. //FillGlobalConfig::PlateItem* smlPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_SM, 0) ;
  86. vector<FillGlobalConfig::PlateItem*> usedPlates = {bigPlateH,midPlateH,bigPlateV,midPlateV} ;//{bigPlate,midPlate,smlPlate} ;
  87. int maxSmlJewCapPerPlate = 0;
  88. int minSmlJewCapPerPlate = 99999 ;
  89. for(int ip=0;ip<usedPlates.size();++ip ) {
  90. maxSmlJewCapPerPlate = fmax( usedPlates[ip]->_bigJewCap*4 , maxSmlJewCapPerPlate) ;
  91. minSmlJewCapPerPlate = fmin( usedPlates[ip]->_bigJewCap*4 , minSmlJewCapPerPlate) ;
  92. }
  93. //等效小宝石数量
  94. int effSmallJewelsCount = bigJewelCnt*4 + midJewelCnt*2 + smlJewelCnt ;
  95. //cout<<"bigJewelCnt "<<bigJewelCnt<<endl;
  96. //cout<<"midJewelCnt "<<midJewelCnt<<endl;
  97. //cout<<"smlJewelCnt "<<smlJewelCnt<<endl;
  98. //cout<<"effSmallJewelsCount "<<effSmallJewelsCount<<endl;
  99. //构建符合难度条件的盘子和层数组合(包括可移动的盘子)
  100. vector<PlateIdAndLayerCnt> resPlateNLyrCnt = generatePlateTypeAndLayerCnts2(isMovable, mulMoveConfig, levelData._difficulty,effSmallJewelsCount);
  101. if( resPlateNLyrCnt.size()==0 ) {
  102. //cout<<"failed at generatePlateTypeAndLayerCnts"<<endl;
  103. return false ;
  104. }
  105. //计算盘子的最大层数
  106. int maxLyrCnt = 0;
  107. for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it ) maxLyrCnt=fmax(maxLyrCnt,it->_layerCnt) ;
  108. //对每个盘子组合进行填充宝石
  109. RandomGridFiller filler ;
  110. filler._seed = this->_seed ;
  111. srand(filler._seed);
  112. //构建每个盘子每个层的填充结果容器
  113. vector< tuple<int,int,vector<FillResult>,int> > plateIdLyrFillResultsMoveIdArray ;// tuple<plateId, layerIndex, fillresults_array ,moveId>
  114. //从顶到底部,逐层进行填充
  115. int residues = 0 ;
  116. for(int nlayer = maxLyrCnt; nlayer > 0 ; nlayer-- ) {
  117. //cout<<"for layer "<<nlayer<<endl;
  118. //满足该层数的所有盘子ID
  119. vector<int> plateIdArr ;//临时符合当前层次的盘子类型ID
  120. vector<int> moveIdArr ;//临时保存对应盘子是否是可移动的,0-不可移动,1-第一移动行,2-第二移动行
  121. for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it )
  122. {
  123. if(it->_layerCnt>=nlayer) {
  124. plateIdArr.push_back(it->_plateId) ;
  125. moveIdArr.push_back( it->_moveId ) ;
  126. }
  127. }
  128. //该层总计需要填充多少小宝石
  129. int currLyrNeedEquvSmlCnt = 0 ;
  130. for(int ip=0;ip<plateIdArr.size();++ip ) {
  131. currLyrNeedEquvSmlCnt += fgc->getPlateItemById(plateIdArr[ip])->_bigJewCap*4 ;
  132. }
  133. //cout<<"layer need eqsmCnt "<<currLyrNeedEquvSmlCnt<<endl;
  134. //根据所需数量和所需求解百分比,计算从库存取出每类宝石多少个。
  135. float solPercent = 0.7 ;//根据需求文档,每层可解百分比都是70%.
  136. unordered_map<int, int> chosenJewIdNCnt = randPickJewels(currLyrNeedEquvSmlCnt, solPercent, jewIdSzCntStorageMap) ;
  137. int choseEqSmCnt=0;
  138. for(auto itp=chosenJewIdNCnt.begin();itp!=chosenJewIdNCnt.end();++itp) {
  139. choseEqSmCnt += jewSz2SmlCnt( fgc->getJewelItemById(itp->first)->_size) * itp->second ;
  140. }
  141. //cout<<"layer choose eqsmCnt "<<choseEqSmCnt<<endl;
  142. //逐个盘子填充
  143. for(int ipid = 0 ; ipid !=plateIdArr.size();++ipid) {
  144. int plateId1 = plateIdArr[ipid] ;
  145. int moveId1 = moveIdArr[ipid] ;
  146. vector<FillResult> fr = fillPlateOneLayer(filler, plateId1 , chosenJewIdNCnt) ;
  147. tuple<int,int,vector<FillResult>,int> plateLyrFillResult={plateId1 , nlayer , fr , moveId1 } ;
  148. plateIdLyrFillResultsMoveIdArray.push_back(plateLyrFillResult);
  149. }
  150. //检查为该层挑选的宝石是不是全部填完了,如果没有填完还要还给库存,给下一轮填充用
  151. residues = 0 ;
  152. for(auto itjn = chosenJewIdNCnt.begin();itjn!=chosenJewIdNCnt.end();++itjn){
  153. if( itjn->second>0 ) {
  154. residues+=itjn->second;
  155. std::get<1>(jewIdSzCntStorageMap[itjn->first]) += itjn->second ;//剩余的加回到库存里
  156. }
  157. }
  158. //cout<<"layer chosen jewels residues "<<residues<<endl;
  159. }
  160. //查看库存是否全部用掉了
  161. if( residues>0 ) {
  162. int extraPlateCnt = 0 ;
  163. //剩了,添加一个小盘子和层,仍然剩了再继续加盘子加层
  164. unordered_map<int, int> residueJewIdAndCnts = findUnfilledInStorages(jewIdSzCntStorageMap) ;
  165. while( residueJewIdAndCnts.size()>0 ) {
  166. //新建一个中盘子
  167. extraPlateCnt++;
  168. //cout<<"add extra plate "<< extraPlateCnt <<endl;
  169. int plateId = midPlateH->_id ;
  170. for(int ilyr = 1 ; ilyr <= maxLyrCnt; ++ ilyr ) {
  171. vector<FillResult> frs = fillPlateOneLayer(filler, plateId, residueJewIdAndCnts) ;
  172. plateIdLyrFillResultsMoveIdArray.push_back( {plateId,ilyr,frs, MOVEID_NO_MOVE } );
  173. //cout<<"add extra lyr "<<endl;
  174. if( residueJewIdAndCnts.size()==0 ) break ;
  175. }
  176. if( residueJewIdAndCnts.size()==0 ) break ;
  177. }
  178. }
  179. //整理数据
  180. regroupPlateLyrFillResults(plateIdLyrFillResultsMoveIdArray, resultPlateFillResults);
  181. //摆放盘子
  182. {
  183. placePlates(isMovable,mulMoveConfig, resultPlateFillResults, resultPlateCenterPointArr) ;
  184. }
  185. auto ms1 = std::chrono::system_clock::now().time_since_epoch() ;
  186. uint64_t ms11 = std::chrono::duration_cast<chrono::milliseconds>(ms1).count() ;
  187. //cout<<"duration "<<ms11-ms00<<endl;
  188. return true ;
  189. }
  190. bool LevelGenerate::generate_v2(
  191. const LevelInputData& indata,
  192. const LevelExtInputData& extdata,
  193. vector<PlateFillResult>& resultPlateFillResults,
  194. vector<ContourData::Point>& resultPlateCenterPointArr,
  195. string& error )
  196. {
  197. FillGlobalConfig::getInstance()->clearGridBoxFilledStatus() ;
  198. resultPlateFillResults.clear() ;
  199. resultPlateCenterPointArr.clear() ;
  200. auto ms0 = std::chrono::system_clock::now().time_since_epoch() ;
  201. uint64_t ms00 = std::chrono::duration_cast<chrono::milliseconds>(ms0).count() ;
  202. srand( extdata._seed );
  203. unordered_map<int,tuple<int,int> > jewIdSzCntStorageMap ;// unordered_map<宝石ID,tuple<尺寸,库存数量> >
  204. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  205. int bigJewelCnt = 0 ;
  206. int midJewelCnt = 0;
  207. int smlJewelCnt = 0 ;
  208. for(int ij = 0 ; ij < indata._jewels.size() ;++ ij ) {
  209. int jewId = indata._jewels[ij]._jewelId ;
  210. int cnt = indata._jewels[ij]._count ;
  211. FillGlobalConfig::JewelItem* jewItem = fgc->getJewelItemById(jewId) ;
  212. jewIdSzCntStorageMap[jewId] = {jewItem->_size,cnt} ;
  213. if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_SM ) {
  214. smlJewelCnt+=cnt ;
  215. }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_MD ) {
  216. midJewelCnt += cnt ;
  217. }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_LG ) {
  218. bigJewelCnt += cnt ;
  219. }
  220. }
  221. //每个盘子类型小号宝石承载量
  222. //按顺序分别为大和中
  223. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  224. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  225. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  226. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  227. //FillGlobalConfig::PlateItem* smlPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_SM, 0) ;
  228. vector<FillGlobalConfig::PlateItem*> usedPlates = {bigPlateH,midPlateH,bigPlateV,midPlateV} ;//{bigPlate,midPlate,smlPlate} ;
  229. int maxSmlJewCapPerPlate = 0;
  230. int minSmlJewCapPerPlate = 99999 ;
  231. for(int ip=0;ip<usedPlates.size();++ip ) {
  232. maxSmlJewCapPerPlate = fmax( usedPlates[ip]->_bigJewCap*4 , maxSmlJewCapPerPlate) ;
  233. minSmlJewCapPerPlate = fmin( usedPlates[ip]->_bigJewCap*4 , minSmlJewCapPerPlate) ;
  234. }
  235. //等效小宝石数量
  236. int effSmallJewelsCount = bigJewelCnt*4 + midJewelCnt*2 + smlJewelCnt ;
  237. if( effSmallJewelsCount==0 ) {
  238. error = "equv small jewel count is zero." ;
  239. return false ;
  240. }
  241. //构建符合难度条件的盘子和层数组合(包括可移动的盘子)
  242. bool isMovable = (extdata._hasMovement==1)?true:false ;
  243. FillGlobalConfig::MultiMoveConfig* mulMoveConfigPtr = nullptr ;
  244. FillGlobalConfig::MultiMoveConfig mulMoveConfig;
  245. if( isMovable ) {
  246. vector<FillGlobalConfig::MoveConfig*> mc1arr = FillGlobalConfig::getInstance()->getMoveConfigDatasByTypeAndNLayers(extdata._firstMoveType, extdata._firstMoveLyrCnt) ;
  247. if( mc1arr.size()==0 ) {
  248. error = string("failed to get first move config data by move type '")+extdata._firstMoveType+"'." ;
  249. return false ;
  250. }
  251. mulMoveConfig._first = mc1arr[0] ;
  252. if( extdata._secondMoveType.compare("") != 0 ) {
  253. vector<FillGlobalConfig::MoveConfig*> mc2arr = FillGlobalConfig::getInstance()->getMoveConfigDatasByTypeAndNLayers(extdata._secondMoveType, extdata._secondMoveLyrCnt) ;
  254. if( mc2arr.size()==0 ) {
  255. error = string("failed to get second move config data by move type '")+extdata._secondMoveType+"'." ;
  256. return false ;
  257. }
  258. mulMoveConfig._second = mc2arr[0] ;
  259. }else{
  260. mulMoveConfig._second = nullptr ;
  261. }
  262. mulMoveConfigPtr = &mulMoveConfig;
  263. }
  264. vector<PlateIdAndLayerCnt> resPlateNLyrCnt = generatePlateTypeAndLayerCnts3(
  265. isMovable,
  266. mulMoveConfigPtr,
  267. indata._difficulty,
  268. effSmallJewelsCount,
  269. extdata
  270. );
  271. if( resPlateNLyrCnt.size()==0 ) {
  272. error = string("failed on generatePlateTypeAndLayerCnts3.") ;
  273. return false ;
  274. }
  275. //计算盘子的最大层数
  276. int maxLyrCnt = 0;
  277. for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it ) maxLyrCnt=fmax(maxLyrCnt,it->_layerCnt) ;
  278. //对每个盘子组合进行填充宝石
  279. RandomGridFiller filler ;
  280. filler._seed = extdata._seed ;
  281. srand(filler._seed);
  282. //构建每个盘子每个层的填充结果容器
  283. vector< tuple<int,int,vector<FillResult>,int> > plateIdLyrFillResultsMoveIdArray ;// tuple<plateId, layerIndex, fillresults_array ,moveId>
  284. //从顶到底部,逐层进行填充
  285. int residues = 0 ;
  286. for(int nlayer = maxLyrCnt; nlayer > 0 ; nlayer-- ) {
  287. //cout<<"for layer "<<nlayer<<endl;
  288. //满足该层数的所有盘子ID
  289. vector<int> plateIdArr ;//临时符合当前层次的盘子类型ID
  290. vector<int> moveIdArr ;//临时保存对应盘子是否是可移动的,0-不可移动,1-第一移动行,2-第二移动行
  291. for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it )
  292. {
  293. if(it->_layerCnt>=nlayer) {
  294. plateIdArr.push_back(it->_plateId) ;
  295. moveIdArr.push_back( it->_moveId ) ;
  296. }
  297. }
  298. //该层总计需要填充多少小宝石
  299. int currLyrNeedEquvSmlCnt = 0 ;
  300. for(int ip=0;ip<plateIdArr.size();++ip ) {
  301. currLyrNeedEquvSmlCnt += fgc->getPlateItemById(plateIdArr[ip])->_bigJewCap*4 ;
  302. }
  303. //cout<<"layer need eqsmCnt "<<currLyrNeedEquvSmlCnt<<endl;
  304. //根据所需数量和所需求解百分比,计算从库存取出每类宝石多少个。
  305. float solPercent = 0.7 ;//根据需求文档,每层可解百分比都是70%.
  306. unordered_map<int, int> chosenJewIdNCnt = randPickJewels(currLyrNeedEquvSmlCnt, solPercent, jewIdSzCntStorageMap) ;
  307. int choseEqSmCnt=0;
  308. for(auto itp=chosenJewIdNCnt.begin();itp!=chosenJewIdNCnt.end();++itp) {
  309. choseEqSmCnt += jewSz2SmlCnt( fgc->getJewelItemById(itp->first)->_size) * itp->second ;
  310. }
  311. //cout<<"layer choose eqsmCnt "<<choseEqSmCnt<<endl;
  312. //逐个盘子填充
  313. for(int ipid = 0 ; ipid !=plateIdArr.size();++ipid) {
  314. int plateId1 = plateIdArr[ipid] ;
  315. int moveId1 = moveIdArr[ipid] ;
  316. vector<FillResult> fr = fillPlateOneLayer(filler, plateId1 , chosenJewIdNCnt) ;
  317. tuple<int,int,vector<FillResult>,int> plateLyrFillResult={plateId1 , nlayer , fr , moveId1 } ;
  318. plateIdLyrFillResultsMoveIdArray.push_back(plateLyrFillResult);
  319. }
  320. //检查为该层挑选的宝石是不是全部填完了,如果没有填完还要还给库存,给下一轮填充用
  321. residues = 0 ;
  322. for(auto itjn = chosenJewIdNCnt.begin();itjn!=chosenJewIdNCnt.end();++itjn){
  323. if( itjn->second>0 ) {
  324. residues+=itjn->second;
  325. std::get<1>(jewIdSzCntStorageMap[itjn->first]) += itjn->second ;//剩余的加回到库存里
  326. }
  327. }
  328. //cout<<"layer chosen jewels residues "<<residues<<endl;
  329. }
  330. //查看库存是否全部用掉了
  331. if( residues>0 ) {
  332. int extraPlateCnt = 0 ;
  333. //剩了,添加一个小盘子和层,仍然剩了再继续加盘子加层
  334. unordered_map<int, int> residueJewIdAndCnts = findUnfilledInStorages(jewIdSzCntStorageMap) ;
  335. while( residueJewIdAndCnts.size()>0 ) {
  336. //新建一个中盘子
  337. extraPlateCnt++;
  338. //cout<<"add extra plate "<< extraPlateCnt <<endl;
  339. int plateId = midPlateH->_id ;
  340. for(int ilyr = 1 ; ilyr <= maxLyrCnt; ++ ilyr ) {
  341. vector<FillResult> frs = fillPlateOneLayer(filler, plateId, residueJewIdAndCnts) ;
  342. plateIdLyrFillResultsMoveIdArray.push_back( {plateId,ilyr,frs, MOVEID_NO_MOVE } );
  343. //cout<<"add extra lyr "<<endl;
  344. if( residueJewIdAndCnts.size()==0 ) break ;
  345. }
  346. if( residueJewIdAndCnts.size()==0 ) break ;
  347. }
  348. }
  349. //整理数据
  350. regroupPlateLyrFillResults(plateIdLyrFillResultsMoveIdArray, resultPlateFillResults);
  351. //摆放盘子
  352. {
  353. placePlates(isMovable,mulMoveConfigPtr, resultPlateFillResults, resultPlateCenterPointArr) ;
  354. }
  355. auto ms1 = std::chrono::system_clock::now().time_since_epoch() ;
  356. uint64_t ms11 = std::chrono::duration_cast<chrono::milliseconds>(ms1).count() ;
  357. cout<<"duration(ms): "<<ms11-ms00<<endl;
  358. return true ;
  359. }
  360. // this method is deprecated, use generatePlateTypeAndLayerCnts2()
  361. [[deprecated]]
  362. vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts(const int difficulty,const int totEquvSmallJewelCnt)
  363. {
  364. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  365. //...
  366. //...
  367. return results ;
  368. }
  369. //考虑可移动关卡的条件
  370. vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts2(
  371. const bool isMovable,
  372. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  373. const int difficulty,
  374. const int totEquvSmallJewelCnt
  375. )
  376. {
  377. //如果是移动关卡,那么至少需要保证如下等价小盘子数量,如果减少层数仍然不能满足那么就有几个盘子输出几个
  378. //const int MAX_LG_PLATE_CNT = 9 ;// + (isMovable?1:0) ;
  379. // const int MAX_SM_PLATE_CNT = MAX_LG_PLATE_CNT*4 ;
  380. //const int MAX_SM_JEWEL_CNT_PER_LAYER = MAX_LG_PLATE_CNT * 24 ;
  381. const int MID_PLATE_CAP = 12 ;//中盘子对小宝石的容量
  382. //const int minEquaSmPlateCntForMovable = 16 ; //
  383. //const int smPlateEquaSmJewelCnt = 6 ;// 小盘子装1.5个大,3个中,6个小
  384. //一个关卡最多出现大、中、小盘子个数
  385. int tempBigPlateCnt1 = 9 ;// 1个大盘子=2两个中盘子
  386. int tempMidPlateCnt1 = 0 ;
  387. computePlateCount(mulMoveConfig, tempBigPlateCnt1, tempMidPlateCnt1) ;
  388. int midPlateMaxCnt = tempBigPlateCnt1 * 2 + tempMidPlateCnt1 ;//大盘子数量换算成中盘子
  389. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  390. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  391. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  392. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  393. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  394. //如果是移动关卡,先构建移动盘子
  395. int totEquvSmallJewelCnt2 = totEquvSmallJewelCnt ;
  396. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  397. //剩余可以用的中盘子个数
  398. if( isMovable ) {
  399. int residueEquvSmlJewelCnt = 0 ;
  400. results = generatePlateTypeAndLayerCntsForMovablePlates(mulMoveConfig, totEquvSmallJewelCnt2, residueEquvSmlJewelCnt) ;
  401. totEquvSmallJewelCnt2 = residueEquvSmlJewelCnt ;
  402. //减去移动的盘子
  403. for(int ir = 0 ; ir < results.size(); ++ ir ){
  404. if( fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_LG ) {
  405. midPlateMaxCnt-=2 ;//减去移动的盘子
  406. }else if(fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_MD) {
  407. midPlateMaxCnt-=1 ;//减去移动的盘子
  408. }
  409. }
  410. }
  411. int equvMidPlateCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / MID_PLATE_CAP) ; // 本关需要多少个一层中盘子的总数量
  412. int layerCnt0 = 1 ;//盘子层数下限
  413. int layerCnt1 = 1 ;//盘子层数上限
  414. //计算可能的层取值范围
  415. {
  416. layerCnt0 = fmax(1 , totEquvSmallJewelCnt2 / (midPlateMaxCnt*MID_PLATE_CAP) ) ;
  417. if( layerCnt0<3 ) layerCnt1 = 3 ;
  418. else layerCnt1 = layerCnt0 + 1 ;
  419. }
  420. int bigPlateCnt0 = totEquvSmallJewelCnt2 * 1.0 / layerCnt1 / 24 ; //大盘子最少需要数量
  421. int bigPlateCnt1 = totEquvSmallJewelCnt2 * 1.0 / layerCnt0 / 24 + 1; //大盘子最多需要数量
  422. int midPlateCnt0 = bigPlateCnt0*2 ;
  423. int midPlateCnt1 = bigPlateCnt1*2 ;
  424. bigPlateCnt1 = fmin( midPlateMaxCnt/2 ,bigPlateCnt1 ) ;
  425. midPlateCnt1 = fmin( midPlateMaxCnt ,midPlateCnt1 ) ;
  426. bool findFirstAvailableComb = false ;//第一个完全放入宝石的组合,用于当不满足任何条件时,至少返回一个可装入全部宝石的默认方案
  427. vector<vector<LevelGenerate::PlateIdAndLayerCnt>> possibleResults ;//满足全部百分比要求的组合
  428. vector<LevelGenerate::PlateIdAndLayerCnt> firstAvailablePlateComb ;//第一个满足全部宝石填充的组合,如果需要移动还要考虑最小移动盘子个数的条件
  429. int firstAvailableLyrCnt = 0 ;
  430. //难度对盘子数量的限制 普通 难 极难
  431. vector< vector<float> > hardPlateCntPercent0 = { {0.3,0.3}, {0.2,0.4}, {0.1,0.5} } ;
  432. vector< vector<float> > hardPlateCntPercent1 = { {0.7,0.7}, {0.6,0.8}, {0.5,0.9} } ;
  433. //穷举全部盘子和层的组合找到符合条件的组合
  434. for(int ibig = 0; ibig <= bigPlateCnt1; ++ ibig ) {
  435. for(int imid = 0; imid <= midPlateCnt1 ; ++ imid ) {
  436. int currEquvMidPlateCnt = imid+ibig*2 ;
  437. if( currEquvMidPlateCnt==0 || currEquvMidPlateCnt > midPlateMaxCnt ) continue ;
  438. float bigPlateCntPercent = ibig*2.0 / currEquvMidPlateCnt ;
  439. float midPlateCntPercent = imid*1.0 / currEquvMidPlateCnt ;
  440. vector<float> percentArr = {bigPlateCntPercent,midPlateCntPercent} ;
  441. //判断每个盘子百分比是否满足难度要求
  442. bool percentOk = true ;
  443. for(int iplatetype=0;iplatetype<percentArr.size();++iplatetype) {
  444. if( hardPlateCntPercent0[difficulty][iplatetype]>percentArr[iplatetype] || hardPlateCntPercent1[difficulty][iplatetype]<percentArr[iplatetype] )
  445. percentOk=false;
  446. }
  447. if( findFirstAvailableComb == true ){
  448. //至少有一个装下宝石的方案了
  449. if( !percentOk ) continue ;//盘子百分比不符合要求,跳过
  450. }
  451. if( findFirstAvailableComb==false || (findFirstAvailableComb && firstAvailableLyrCnt>3 ) ) {
  452. //保证至少有一个可以满足宝石的盘子组合,优先保存总层数大于3的情况
  453. //当前盘子组合下最小满足的层数
  454. int upperLyrCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / (currEquvMidPlateCnt*MID_PLATE_CAP) ) ;
  455. bool upperLyrCntOk = true ;
  456. if( findFirstAvailableComb ) {
  457. if( upperLyrCnt >= firstAvailableLyrCnt ) {
  458. upperLyrCntOk = false ;
  459. }
  460. }
  461. vector<int> pidArr ;
  462. vector<int> capArr ;
  463. vector<int> lyrArr ;
  464. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  465. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
  466. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
  467. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  468. if( lyrOk==false && upperLyrCnt>1 ) {
  469. for(int it=0;it<lyrArr.size();++it ) {
  470. lyrArr[it] -= 1 ;
  471. lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  472. if( lyrOk ) break ;
  473. }
  474. }
  475. if( lyrOk && upperLyrCntOk ){
  476. findFirstAvailableComb = true ;
  477. firstAvailableLyrCnt = upperLyrCnt ;
  478. //保存结果
  479. firstAvailablePlateComb.resize(capArr.size());
  480. for(int it = 0 ; it < capArr.size(); ++ it ) {
  481. firstAvailablePlateComb[it]._plateId = pidArr[it] ;
  482. firstAvailablePlateComb[it]._layerCnt = lyrArr[it] ;
  483. firstAvailablePlateComb[it]._moveId = MOVEID_NO_MOVE ;
  484. }
  485. }
  486. }
  487. //计算每个类型的层数
  488. if( difficulty== FILLGLOBALCONFIG_DIFFCULTY_NORM ) {
  489. //全部两层
  490. vector<int> pidArr ;
  491. vector<int> capArr ;
  492. vector<int> lyrArr ;
  493. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  494. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(2); }
  495. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(2); }
  496. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  497. if(!lyrOk) continue;
  498. //保存结果
  499. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  500. for(int it = 0 ; it < capArr.size(); ++ it ) {
  501. tres[it]._plateId = pidArr[it] ;
  502. tres[it]._layerCnt = lyrArr[it] ;
  503. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  504. }
  505. possibleResults.push_back(tres) ;
  506. }else if( difficulty==FILLGLOBALCONFIG_DIFFCULTY_HARD2 ) {
  507. //全部3层
  508. vector<int> pidArr ;
  509. vector<int> capArr ;
  510. vector<int> lyrArr ;
  511. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  512. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(3); }
  513. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(3); }
  514. //cout<<"debug big "<<ibig<<" mid "<<imid<<" sml "<<isml<<endl;
  515. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  516. if(!lyrOk) continue;
  517. //保存结果
  518. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  519. for(int it = 0 ; it < capArr.size(); ++ it ) {
  520. tres[it]._plateId = pidArr[it] ;
  521. tres[it]._layerCnt = lyrArr[it] ;
  522. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  523. }
  524. possibleResults.push_back(tres) ;
  525. }else{
  526. //50% 2层, 50% 3层
  527. vector<int> pidArr ;
  528. vector<int> capArr ;
  529. vector<int> lyrArr ;
  530. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  531. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back((rand()%2==0)?2:3); }
  532. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back((rand()%2==0)?2:3); }
  533. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  534. if(!lyrOk) continue;
  535. //保存结果
  536. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  537. for(int it = 0 ; it < capArr.size(); ++ it ) {
  538. tres[it]._plateId = pidArr[it] ;
  539. tres[it]._layerCnt = lyrArr[it] ;
  540. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  541. }
  542. possibleResults.push_back(tres) ;
  543. }
  544. }
  545. }
  546. //随机挑选一个结果返回
  547. if( possibleResults.size()> 0 ) {
  548. int randindex = rand() % possibleResults.size();
  549. for(int ip = 0 ; ip < possibleResults[randindex].size();++ ip ) {
  550. results.push_back(possibleResults[randindex][ip]) ;
  551. }
  552. }else {
  553. for(int ip = 0 ; ip < firstAvailablePlateComb.size();++ ip ) {
  554. results.push_back(firstAvailablePlateComb[ip]) ;
  555. }
  556. }
  557. return results ;//
  558. }
  559. vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts3(
  560. const bool isMovable,
  561. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  562. const int difficulty,
  563. const int totEquvSmallJewelCnt,
  564. const LevelExtInputData& extdata )
  565. {
  566. const int MID_PLATE_CAP = 12 ;//中盘子对小宝石的容量
  567. //一个关卡最多出现大、中个数
  568. int tempBigPlateCnt1 = 9 ;// 1个大盘子=2两个中盘子
  569. int tempMidPlateCnt1 = 0 ;
  570. computePlateCount(mulMoveConfig, tempBigPlateCnt1, tempMidPlateCnt1) ;
  571. int equvMidPlateMaxCnt = tempBigPlateCnt1 * 2 + tempMidPlateCnt1 ;//大盘子数量换算成中盘子
  572. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  573. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  574. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  575. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  576. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  577. //如果是移动关卡,先构建移动盘子
  578. int totEquvSmallJewelCnt2 = totEquvSmallJewelCnt ;
  579. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  580. //剩余可以用的中盘子个数
  581. if( isMovable ) {
  582. int residueEquvSmlJewelCnt = 0 ;
  583. results = generatePlateTypeAndLayerCntsForMovablePlates(mulMoveConfig, totEquvSmallJewelCnt2, residueEquvSmlJewelCnt) ;
  584. totEquvSmallJewelCnt2 = residueEquvSmlJewelCnt ;
  585. //减去移动的盘子
  586. for(int ir = 0 ; ir < results.size(); ++ ir ){
  587. if( fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_LG ) {
  588. equvMidPlateMaxCnt-=2 ;//减去移动的盘子
  589. }else if(fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_MD) {
  590. equvMidPlateMaxCnt-=1 ;//减去移动的盘子
  591. }
  592. }
  593. }
  594. // 本关需要多少个一层中盘子的总数量,
  595. // 已经去掉了移动盘子所用的宝石(如果有移动盘子的话)
  596. int equvMidPlateCntOneLyr = ceil( totEquvSmallJewelCnt2 * 1.0 / MID_PLATE_CAP) ;
  597. int bigPlateCntL1 = 0 ;
  598. int midPlateCntL1 = equvMidPlateCntOneLyr ;
  599. if( extdata._bigPlatePercent > 0 ) {
  600. float bigPercent = extdata._bigPlatePercent*1.0/(extdata._bigPlatePercent+extdata._midPlatePercent) ;
  601. float midPercent = 1.0 - bigPercent ;
  602. bigPlateCntL1 = ceil( equvMidPlateCntOneLyr * 1.0 / (2.0+midPercent/bigPercent) ) ;
  603. midPlateCntL1 = fmax(0, equvMidPlateCntOneLyr - bigPlateCntL1*2 ) ;
  604. }
  605. int layerCnt0 = 1 ;//盘子层数下限
  606. int layerCnt1 = 3 ;//盘子层数上限
  607. //计算可能的层取值范围
  608. {
  609. layerCnt0 = fmax(1 , totEquvSmallJewelCnt2 / (equvMidPlateCntOneLyr*MID_PLATE_CAP) ) ;
  610. if( layerCnt0<3 ) layerCnt1 = 3 ;
  611. else layerCnt1 = layerCnt0 + 1 ;
  612. }
  613. int bigPlateCnt0 = bigPlateCntL1 * 1.0 / layerCnt1 ; //大盘子最少需要数量
  614. int bigPlateCnt1 = bigPlateCntL1 * 1.0 / layerCnt0 + 1; //大盘子最多需要数量
  615. int midPlateCnt0 = midPlateCntL1*1.0/layerCnt1 ;
  616. int midPlateCnt1 = midPlateCntL1*1.0/layerCnt0 + 1 ;
  617. bool findFirstAvailableComb = false ;//第一个完全放入宝石的组合,用于当不满足任何条件时,至少返回一个可装入全部宝石的默认方案
  618. vector<vector<LevelGenerate::PlateIdAndLayerCnt>> possibleResults ;//满足全部百分比要求的组合
  619. vector<LevelGenerate::PlateIdAndLayerCnt> firstAvailablePlateComb ;//第一个满足全部宝石填充的组合,如果需要移动还要考虑最小移动盘子个数的条件
  620. int firstAvailableLyrCnt = 0 ;
  621. //难度对盘子数量的限制 普通 难 极难
  622. //vector< vector<float> > hardPlateCntPercent0 = { {0.3,0.3}, {0.2,0.4}, {0.1,0.5} } ;
  623. //vector< vector<float> > hardPlateCntPercent1 = { {0.7,0.7}, {0.6,0.8}, {0.5,0.9} } ;
  624. //这个数据不需要了,通过extdata中直接获取这个数据。
  625. //穷举全部盘子和层的组合找到符合条件的组合
  626. for(int ibig = bigPlateCnt0; ibig <= bigPlateCnt1; ++ ibig ) {
  627. for(int imid = midPlateCnt0; imid <= midPlateCnt1 ; ++ imid ) {
  628. int currEquvMidPlateCnt = imid+ibig*2 ;
  629. if( currEquvMidPlateCnt==0 ) continue ;
  630. if( findFirstAvailableComb==false || (findFirstAvailableComb && firstAvailableLyrCnt>3 ) ) {
  631. //保证至少有一个可以满足宝石的盘子组合,优先保存总层数大于3的情况
  632. //当前盘子组合下最小满足的层数
  633. int upperLyrCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / (currEquvMidPlateCnt*MID_PLATE_CAP) ) ;
  634. bool upperLyrCntOk = true ;
  635. if( findFirstAvailableComb ) {
  636. if( upperLyrCnt >= firstAvailableLyrCnt ) {
  637. upperLyrCntOk = false ;
  638. }
  639. }
  640. vector<int> pidArr ;
  641. vector<int> capArr ;
  642. vector<int> lyrArr ;
  643. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  644. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
  645. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
  646. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  647. if( lyrOk==false && upperLyrCnt>1 ) {
  648. for(int it=0;it<lyrArr.size();++it ) {
  649. lyrArr[it] -= 1 ;
  650. lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  651. if( lyrOk ) break ;
  652. }
  653. }
  654. if( lyrOk && upperLyrCntOk ){
  655. findFirstAvailableComb = true ;
  656. firstAvailableLyrCnt = upperLyrCnt ;
  657. //保存结果
  658. firstAvailablePlateComb.resize(capArr.size());
  659. for(int it = 0 ; it < capArr.size(); ++ it ) {
  660. firstAvailablePlateComb[it]._plateId = pidArr[it] ;
  661. firstAvailablePlateComb[it]._layerCnt = lyrArr[it] ;
  662. firstAvailablePlateComb[it]._moveId = MOVEID_NO_MOVE ;
  663. }
  664. }
  665. }
  666. //计算每个类型的层数
  667. if( difficulty== FILLGLOBALCONFIG_DIFFCULTY_NORM ) {
  668. //全部两层
  669. vector<int> pidArr ;
  670. vector<int> capArr ;
  671. vector<int> lyrArr ;
  672. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  673. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(2); }
  674. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(2); }
  675. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  676. if(!lyrOk) continue;
  677. //保存结果
  678. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  679. for(int it = 0 ; it < capArr.size(); ++ it ) {
  680. tres[it]._plateId = pidArr[it] ;
  681. tres[it]._layerCnt = lyrArr[it] ;
  682. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  683. }
  684. possibleResults.push_back(tres) ;
  685. }else if( difficulty==FILLGLOBALCONFIG_DIFFCULTY_HARD2 ) {
  686. //全部3层
  687. vector<int> pidArr ;
  688. vector<int> capArr ;
  689. vector<int> lyrArr ;
  690. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  691. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(3); }
  692. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(3); }
  693. //cout<<"debug big "<<ibig<<" mid "<<imid<<" sml "<<isml<<endl;
  694. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  695. if(!lyrOk) continue;
  696. //保存结果
  697. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  698. for(int it = 0 ; it < capArr.size(); ++ it ) {
  699. tres[it]._plateId = pidArr[it] ;
  700. tres[it]._layerCnt = lyrArr[it] ;
  701. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  702. }
  703. possibleResults.push_back(tres) ;
  704. }else{
  705. //50% 2层, 50% 3层
  706. vector<int> pidArr ;
  707. vector<int> capArr ;
  708. vector<int> lyrArr ;
  709. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  710. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back((rand()%2==0)?2:3); }
  711. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back((rand()%2==0)?2:3); }
  712. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  713. if(!lyrOk) continue;
  714. //保存结果
  715. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  716. for(int it = 0 ; it < capArr.size(); ++ it ) {
  717. tres[it]._plateId = pidArr[it] ;
  718. tres[it]._layerCnt = lyrArr[it] ;
  719. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  720. }
  721. possibleResults.push_back(tres) ;
  722. }
  723. }
  724. }
  725. //随机挑选一个结果返回
  726. if( possibleResults.size()> 0 ) {
  727. int randindex = rand() % possibleResults.size();
  728. for(int ip = 0 ; ip < possibleResults[randindex].size();++ ip ) {
  729. results.push_back(possibleResults[randindex][ip]) ;
  730. }
  731. }else {
  732. for(int ip = 0 ; ip < firstAvailablePlateComb.size();++ ip ) {
  733. results.push_back(firstAvailablePlateComb[ip]) ;
  734. }
  735. }
  736. return results ;//
  737. }
  738. //随机排序数组索引值
  739. vector<int> LevelGenerate::randIndices(const int count0 ) {
  740. int count = count0 ;
  741. vector<int> indices ;
  742. unordered_map<int, bool> dict ;
  743. while( count > 0 ) {
  744. int r = rand()%count0;
  745. if( dict.find(r) == dict.end() ) {
  746. dict[r] = true ;
  747. indices.push_back(r) ;
  748. count-- ;
  749. }
  750. }
  751. return indices;
  752. }
  753. bool LevelGenerate::isJustFilledAll2(
  754. const vector<int>& plateCaps,//每个盘子的容量
  755. const vector<int> eachPlateLyrCnt,//对应盘子的层数
  756. const int totSmlJewCnt )
  757. {
  758. assert(plateCaps.size()>0);
  759. assert(plateCaps.size()==eachPlateLyrCnt.size());
  760. int fillcnt1 = 0;
  761. for(int ip = 0 ;ip<plateCaps.size();++ip ) {
  762. fillcnt1 += plateCaps[ip] * eachPlateLyrCnt[ip] ;
  763. }
  764. if( fillcnt1 < totSmlJewCnt ) return false ;
  765. if( fillcnt1 == totSmlJewCnt ) return true ;
  766. for(int ip = 0 ; ip < plateCaps.size();++ip ) {
  767. int fillcnt2 = fillcnt1 - plateCaps[ip] ;
  768. if( fillcnt2 < totSmlJewCnt ) {
  769. return true ;
  770. }
  771. }
  772. return false ;
  773. }
  774. unordered_map<int, int> LevelGenerate::randPickJewels( const int needEquvSmlCnt,const float solvedPercent, unordered_map<int,tuple<int,int>>& jewStorages )
  775. {
  776. int needEquvSmlCnt2 = needEquvSmlCnt ;
  777. int storageEquvSmlCnt = 0 ;
  778. int storageJewTypeCnt = jewStorages.size() ;
  779. for(auto it=jewStorages.begin();it!=jewStorages.end();++it) storageEquvSmlCnt+= std::get<1>(it->second)*jewSz2SmlCnt(std::get<0>(it->second)) ;
  780. unordered_map<int, int> res ;
  781. const float solPer = fmax(0.0,fmin(solvedPercent,1.0f)) ;
  782. //首先尝试可解的百分比部分
  783. int solEqSmGrpCnt = needEquvSmlCnt*solPer/3 ;
  784. // 随机尝试solEqSmGrpCnt*2 次取宝石,每次取一组。
  785. int loopCnt=solEqSmGrpCnt*storageJewTypeCnt*10;//随机迭代数量加大10倍,避免有始终选不到的情况
  786. while( solEqSmGrpCnt> 0 && storageEquvSmlCnt>0 && loopCnt>0) {
  787. int randJewI = rand()%storageJewTypeCnt ;
  788. auto itjew = jewStorages.begin() ;
  789. std::advance(itjew, randJewI) ;
  790. int jid = itjew->first ;
  791. int storage1 = std::get<1>( itjew->second ) ;
  792. int oneGrpEqSmGrpCnt = jewSz2SmlCnt( std::get<0>(itjew->second) ) ;
  793. if( storage1>=3 && oneGrpEqSmGrpCnt<=solEqSmGrpCnt ) {
  794. //库存有,且满足所需可解组数
  795. std::get<1>(itjew->second)-=3 ;
  796. solEqSmGrpCnt -= oneGrpEqSmGrpCnt ;
  797. storageEquvSmlCnt -= oneGrpEqSmGrpCnt*3 ;
  798. needEquvSmlCnt2 -= oneGrpEqSmGrpCnt*3 ; //本次所需的剩余等效小宝石个数
  799. res[jid] += 3 ;
  800. }
  801. --loopCnt ;
  802. }
  803. //尝试剩余百分比和上一步剩余没有符合条件的个数
  804. loopCnt = needEquvSmlCnt2*storageJewTypeCnt ;
  805. int jindex = 0 ;
  806. while( loopCnt>0 && needEquvSmlCnt2> 0 && storageEquvSmlCnt>0 ) {
  807. auto itjew = jewStorages.begin() ;
  808. std::advance(itjew, jindex) ;
  809. int jid = itjew->first;
  810. int sz = std::get<0>(itjew->second) ;
  811. int stor = std::get<1>(itjew->second) ;
  812. int eqsmCnt = jewSz2SmlCnt(sz) ;
  813. if( stor>0 && eqsmCnt <= needEquvSmlCnt2 ) {
  814. std::get<1>(itjew->second)-=1 ;
  815. needEquvSmlCnt2-=eqsmCnt ;
  816. storageEquvSmlCnt-=eqsmCnt ;
  817. res[jid] += 1 ;
  818. }
  819. ++jindex ; if(jindex>=storageJewTypeCnt) jindex=0;//循环取之,直到本层所需全部取完
  820. --loopCnt;
  821. }
  822. return res ;
  823. }
  824. int LevelGenerate::jewSz2SmlCnt(int sz)
  825. {
  826. switch (sz) {
  827. case FILLGLOBALCONFIG_JEWELSIZE_LG:
  828. return 4;break;
  829. case FILLGLOBALCONFIG_JEWELSIZE_MD:
  830. return 2;break;
  831. default:
  832. return 1;break;
  833. }
  834. return 1;
  835. }
  836. vector<FillResult> LevelGenerate::fillPlateOneLayer(RandomGridFiller& filler,const int plateId, unordered_map<int,int>& jewStoragesForUse )
  837. {
  838. auto fgc = FillGlobalConfig::getInstance() ;
  839. vector<RandomGridFiller::JewelBox> jewBoxArray ;
  840. FillGlobalConfig::PlateItem* pl = FillGlobalConfig::getInstance()->getPlateItemById(plateId) ;
  841. int plateEqSmCap = pl->_bigJewCap*4 ;
  842. int jewTypeCnt = jewStoragesForUse.size() ;
  843. int eqSmStorageCnt = 0 ;
  844. for(auto it = jewStoragesForUse.begin();it!=jewStoragesForUse.end();++it) {
  845. int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
  846. eqSmStorageCnt+=it->second*jewEqSmCnt ;
  847. }
  848. static int s_debug_cnt = 0;
  849. //cout<<"debug "<< s_debug_cnt << " storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
  850. unordered_map<int, int> jewForPlateMap ;// <jewId,Cnt>
  851. int loopCnt = plateEqSmCap*jewTypeCnt*4;// 随机数量多给4倍
  852. while(plateEqSmCap>0 && eqSmStorageCnt>0 && loopCnt>0 ) {
  853. int radv = rand() % jewTypeCnt ;
  854. auto it = jewStoragesForUse.begin() ;
  855. std::advance(it, radv) ;
  856. int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
  857. if( it->second>0 ) {
  858. if( jewEqSmCnt <= plateEqSmCap ) {
  859. plateEqSmCap -= jewEqSmCnt ;
  860. it->second -=1 ;
  861. eqSmStorageCnt -= jewEqSmCnt ;
  862. jewForPlateMap[it->first] += 1 ;
  863. if( it->second== 0 ) {
  864. jewStoragesForUse.erase(it) ;
  865. jewTypeCnt-- ;
  866. }
  867. }
  868. }else{
  869. jewStoragesForUse.erase(it) ;
  870. jewTypeCnt-- ;
  871. }
  872. --loopCnt ;
  873. }
  874. //cout<<"debug "<< s_debug_cnt ++ <<" storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
  875. for(auto it = jewForPlateMap.begin();it!=jewForPlateMap.end();++it) {
  876. RandomGridFiller::JewelBox jbox ;
  877. jbox._cnt = it->second ;
  878. jbox._jewelTypeId = it->first ;
  879. jbox._width = fgc->getJewelItemById(it->first)->_bbWidth ;
  880. jbox._height = fgc->getJewelItemById(it->first)->_bbHeight ;
  881. jewBoxArray.push_back(jbox) ;
  882. }
  883. vector<FillResult> fillresults ;
  884. filler.fill(jewBoxArray, pl->_blx, pl->_bly, pl->_trx, pl->_try, fillresults) ;
  885. return fillresults ;
  886. }
  887. unordered_map<int, int> LevelGenerate::findUnfilledInStorages( unordered_map<int,tuple<int,int>>& jewStorages)
  888. {
  889. unordered_map<int, int> res ;
  890. for(auto itj = jewStorages.begin();itj!=jewStorages.end();++itj) {
  891. int stor = std::get<1>(itj->second) ;
  892. int jid = itj->first ;
  893. if( stor>0 ) {
  894. res[jid] = stor ;
  895. std::get<1>(itj->second) = 0 ;
  896. }
  897. }
  898. return res ;
  899. }
  900. void LevelGenerate::regroupPlateLyrFillResults(
  901. vector<tuple<int,int,vector<FillResult>,int>>& pidlyrFillMvidArray,
  902. vector<PlateFillResult>& results)
  903. {
  904. int currLayer = 1 ;//从底层到顶层构建结果数据结构
  905. int num = pidlyrFillMvidArray.size() ;
  906. int nloop = num ;
  907. while( nloop > 0 ) {
  908. //cout<<"regroup for layer "<<currLayer<<endl;
  909. for( auto itlyr = pidlyrFillMvidArray.begin(); itlyr!=pidlyrFillMvidArray.end(); ++ itlyr ) {
  910. int pid = std::get<0>( *itlyr ) ;
  911. int lyr = std::get<1>( *itlyr ) ;
  912. vector<FillResult>& frs = std::get<2>(*itlyr) ;
  913. int moveId = std::get<3>(*itlyr) ;
  914. if(pid>=0) {
  915. if( lyr==currLayer ) {
  916. if( lyr==1 ) {
  917. vector<vector<FillResult>> frArr = {frs} ;
  918. PlateFillResult pfr ;
  919. pfr._layersFillResults = frArr ;
  920. pfr._moveId = moveId ;
  921. pfr._plateTypeId = pid ;
  922. results.push_back( pfr ) ;
  923. num-- ;
  924. std::get<0>( *itlyr ) = -1 ;
  925. }else {
  926. for(auto itPfr = results.begin();itPfr!=results.end();++itPfr ) {
  927. int pidr = itPfr->_plateTypeId ;
  928. int mvid = itPfr->_moveId ;
  929. vector<vector<FillResult>>& frArr = itPfr->_layersFillResults ;
  930. if( pidr == pid && mvid == moveId && frArr.size()==currLayer-1 ) {
  931. frArr.push_back(frs);
  932. num-- ;
  933. std::get<0>( *itlyr ) = -1 ;
  934. break ;
  935. }
  936. }
  937. }
  938. }
  939. }
  940. }
  941. currLayer++ ;
  942. if( num==0 ) break ;
  943. nloop--;
  944. }
  945. //cout<<"last plate lyr num "<<num<<endl;
  946. }
  947. void LevelGenerate::placePlates(const bool movable,
  948. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  949. const vector<PlateFillResult>& plateFRArr,
  950. vector<ContourData::Point>& resultPlateCenterPointArr )
  951. {
  952. GridPositionTool gpt ;
  953. vector<int> plateIdArr ;
  954. vector<int> moveIdArr ;
  955. for(int ip = 0 ; ip < plateFRArr.size(); ++ ip ) {
  956. plateIdArr.push_back( plateFRArr[ip]._plateTypeId ) ;
  957. moveIdArr.push_back( plateFRArr[ip]._moveId ) ;
  958. }
  959. vector<vector<int>> resPosis ;
  960. string firstMoveTypeCode = "" ;
  961. string secondMoveTypeCode = "" ;
  962. if( movable ) {
  963. firstMoveTypeCode = mulMoveConfig->_first->_type[0] ;
  964. if( mulMoveConfig->_second ) secondMoveTypeCode = mulMoveConfig->_second->_type[0] ;
  965. }
  966. gpt.solve(movable,
  967. firstMoveTypeCode ,
  968. secondMoveTypeCode,
  969. plateIdArr,
  970. moveIdArr,
  971. resPosis //这里结果是盘子左下角坐标,下面需要转换成中心坐标。
  972. ) ;
  973. for(int ip=0;ip<resPosis.size();++ip ) {
  974. FillGlobalConfig::PlateItem* platePtr = FillGlobalConfig::getInstance()->getPlateItemById(plateIdArr[ip]) ;
  975. resultPlateCenterPointArr.push_back( { (float)resPosis[ip][0]+platePtr->_bbwid/2 , (float)resPosis[ip][1]+platePtr->_bbhei/2} ) ;
  976. }
  977. }
  978. vector<LevelGenerate::PlateIdAndLayerCnt>
  979. LevelGenerate::generatePlateTypeAndLayerCntsForMovablePlates(
  980. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  981. const int totEquvSmallJewelCnt,
  982. int& retResidueEquvSmlJewelCnt )
  983. {
  984. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  985. retResidueEquvSmlJewelCnt = totEquvSmallJewelCnt ;
  986. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  987. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  988. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  989. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  990. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  991. const int MAX_MOVE_CONFIG_CNT = 2;
  992. FillGlobalConfig::MoveConfig* arr[MAX_MOVE_CONFIG_CNT] = { mulMoveConfig->_first , mulMoveConfig->_second } ;
  993. for(int ii = 0 ; ii < MAX_MOVE_CONFIG_CNT ; ++ ii ) {
  994. FillGlobalConfig::MoveConfig* moveConfig = arr[ii] ;
  995. if( moveConfig==nullptr ) continue ;
  996. //中盘子横
  997. for(int imid = 0 ; imid < moveConfig->_midPlateCntH ; ++ imid ) {
  998. PlateIdAndLayerCnt palc ;
  999. palc._layerCnt = moveConfig->_nLayer ;
  1000. palc._plateId = midPlateH->_id ;
  1001. palc._moveId = ii+1 ;//第一行为1,第二行为2
  1002. results.push_back(palc) ;
  1003. retResidueEquvSmlJewelCnt -= midPlateH->_bigJewCap*4*palc._layerCnt ;
  1004. }
  1005. //中盘子竖
  1006. for(int imid = 0 ; imid < moveConfig->_midPlateCntV ; ++ imid ) {
  1007. PlateIdAndLayerCnt palc ;
  1008. palc._layerCnt = moveConfig->_nLayer ;
  1009. palc._plateId = midPlateV->_id ;
  1010. palc._moveId = ii+1 ;
  1011. results.push_back(palc) ;
  1012. retResidueEquvSmlJewelCnt -= midPlateV->_bigJewCap*4*palc._layerCnt ;
  1013. }
  1014. //大盘子横
  1015. for(int ibig = 0 ; ibig < moveConfig->_bigPlateCntH ; ++ ibig ) {
  1016. PlateIdAndLayerCnt palc ;
  1017. palc._layerCnt = moveConfig->_nLayer ;
  1018. palc._plateId = bigPlateH->_id ;
  1019. palc._moveId = ii+1 ;
  1020. results.push_back(palc) ;
  1021. retResidueEquvSmlJewelCnt -= bigPlateH->_bigJewCap*4*palc._layerCnt ;
  1022. }
  1023. //大盘子竖
  1024. for(int ibig = 0 ; ibig < moveConfig->_bigPlateCntV ; ++ ibig ) {
  1025. PlateIdAndLayerCnt palc ;
  1026. palc._layerCnt = moveConfig->_nLayer ;
  1027. palc._plateId = bigPlateV->_id ;
  1028. palc._moveId = ii+1 ;
  1029. results.push_back(palc) ;
  1030. retResidueEquvSmlJewelCnt -= bigPlateV->_bigJewCap*4*palc._layerCnt ;
  1031. }
  1032. }
  1033. return results ;
  1034. }
  1035. void LevelGenerate::computePlateCount(const FillGlobalConfig::MultiMoveConfig* mmc ,int& retBigPlateCnt, int& retMidPlateCnt )
  1036. {
  1037. if( mmc==nullptr ) {
  1038. retBigPlateCnt = 9 ;
  1039. retMidPlateCnt = 0 ;
  1040. }else
  1041. if( mmc->_first && mmc->_second ) {
  1042. if( mmc->_first->_type.find("A") != string::npos && mmc->_second->_type.find("A") != string::npos ) {
  1043. retBigPlateCnt = 6 ;
  1044. retMidPlateCnt = 8 ;
  1045. }else if( mmc->_first->_type.find("B") != string::npos && mmc->_second->_type.find("B") != string::npos ) {
  1046. retBigPlateCnt = 9 ;
  1047. retMidPlateCnt = 0 ;
  1048. }else if( mmc->_first->_type.find("C") != string::npos && mmc->_second->_type.find("C") != string::npos ) {
  1049. retBigPlateCnt = 11 ;
  1050. retMidPlateCnt = 0 ;
  1051. }else if( mmc->_first->_type.find("B") != string::npos && mmc->_second->_type.find("A") != string::npos) {
  1052. retBigPlateCnt = 6 ;
  1053. retMidPlateCnt = 7 ;
  1054. }else if( mmc->_first->_type.find("C") != string::npos && mmc->_second->_type.find("B") != string::npos ) {
  1055. retBigPlateCnt = 10 ;
  1056. retMidPlateCnt = 0 ;
  1057. }else if( mmc->_first->_type.find("C") != string::npos && mmc->_second->_type.find("A") != string::npos ) {
  1058. retBigPlateCnt = 7 ;
  1059. retMidPlateCnt = 7 ;
  1060. }
  1061. }else if( mmc->_first && mmc->_second==nullptr ) {
  1062. if( mmc->_first->_type.find("A") != string::npos ) {
  1063. retBigPlateCnt = 6 ;
  1064. retMidPlateCnt = 7 ;
  1065. }else if( mmc->_first->_type.find("B") != string::npos ) {
  1066. retBigPlateCnt = 9 ;
  1067. retMidPlateCnt = 0 ;
  1068. }else if( mmc->_first->_type.find("C") != string::npos ) {
  1069. retBigPlateCnt = 10 ;
  1070. retMidPlateCnt = 0 ;
  1071. }
  1072. }else {
  1073. retBigPlateCnt = 9 ;
  1074. retMidPlateCnt = 0 ;
  1075. }
  1076. }