LevelGenerate.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  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. #include "LevelOutputWriter.hpp"
  17. #define MOVEID_NO_MOVE 0
  18. #define MOVEID_1ST_LINE 1
  19. #define MOVEID_2ND_LINE 2
  20. using namespace std;
  21. void LevelGenerate::generateAll(FillGlobalConfig::LevelData levelData, string outname)
  22. {
  23. cout<<"debug level "<<levelData._id<<" subid "<<levelData._subId<<endl;
  24. auto fgc = FillGlobalConfig::getInstance() ;
  25. fgc->clearGridBoxFilledStatus() ;//每次填充盘子前必须清空盘子占位情况
  26. vector<PlateFillResult> resultPlateFRs ;
  27. vector<ContourData::Point> resultPlateCenterPosiArr ;
  28. generate(levelData, false, nullptr , resultPlateFRs, resultPlateCenterPosiArr) ;
  29. //输出结果
  30. // string pngName0 = outname + "_000000.png" ;
  31. // LevelThumbTool ltt ;
  32. // ltt.makeThumb3(pngName0, resultPlateFRs, resultPlateCenterPosiArr) ;
  33. string jsonName = outname + "_000000.json" ;
  34. LevelOutputWriter out ;
  35. out.writeLevelJson(resultPlateFRs, resultPlateCenterPosiArr, jsonName) ;
  36. //对于所有移动的配置
  37. vector<FillGlobalConfig::MultiMoveConfig> mmcArr = fgc->getAllMoveConfigByJewels(levelData) ;
  38. for(int im=0;im < mmcArr.size();++ im ) {
  39. string moveName = mmcArr[im]._first->_type ;
  40. if( mmcArr[im]._second ) moveName += mmcArr[im]._second->_type ;
  41. else moveName += "00" ;
  42. cout<<"debug moveName "<<moveName<<endl;
  43. fgc->clearGridBoxFilledStatus() ;//每次填充盘子前必须清空盘子占位情况
  44. vector<PlateFillResult> resultPlateFRs1 ;
  45. vector<ContourData::Point> resultPlateCenterPosiArr1 ;
  46. generate(levelData, true, &mmcArr[im] , resultPlateFRs1, resultPlateCenterPosiArr1) ;
  47. //输出结果
  48. // string pngName1 = outname + "_" + moveName;
  49. // pngName1 += ".png" ;
  50. // ltt.makeThumb3(pngName1, resultPlateFRs1, resultPlateCenterPosiArr1) ;
  51. string jsonName1 = outname + "_" + moveName + ".json" ;
  52. LevelOutputWriter out1 ;
  53. out1.writeLevelJson(resultPlateFRs1, resultPlateCenterPosiArr1, jsonName1) ;
  54. }
  55. }
  56. bool LevelGenerate::generate( FillGlobalConfig::LevelData levelData,
  57. const bool isMovable,
  58. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig , //移动盘子配置,如果isMovable为false,这个参数忽略,可以传入nullptr
  59. vector<PlateFillResult>& resultPlateFillResults,
  60. vector<ContourData::Point>& resultPlateCenterPointArr
  61. )
  62. {
  63. resultPlateFillResults.clear() ;
  64. resultPlateCenterPointArr.clear() ;
  65. auto ms0 = std::chrono::system_clock::now().time_since_epoch() ;
  66. uint64_t ms00 = std::chrono::duration_cast<chrono::milliseconds>(ms0).count() ;
  67. srand(_seed);
  68. unordered_map<int,tuple<int,int> > jewIdSzCntStorageMap ;// unordered_map<宝石ID,tuple<尺寸,库存数量> >
  69. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  70. int bigJewelCnt = 0 ;
  71. int midJewelCnt = 0;
  72. int smlJewelCnt = 0 ;
  73. for(int ij = 0 ; ij < levelData._jewelIds.size();++ ij ) {
  74. int jewId = levelData._jewelIds[ij] ;
  75. int cnt = levelData._cnts[ij] ;
  76. FillGlobalConfig::JewelItem* jewItem = fgc->getJewelItemById(jewId) ;
  77. jewIdSzCntStorageMap[jewId] = {jewItem->_size,cnt} ;
  78. if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_SM ) {
  79. smlJewelCnt+=cnt ;
  80. }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_MD ) {
  81. midJewelCnt += cnt ;
  82. }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_LG ) {
  83. bigJewelCnt += cnt ;
  84. }
  85. }
  86. //每个盘子类型小号宝石承载量
  87. //按顺序分别为大和中
  88. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  89. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  90. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  91. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  92. //FillGlobalConfig::PlateItem* smlPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_SM, 0) ;
  93. vector<FillGlobalConfig::PlateItem*> usedPlates = {bigPlateH,midPlateH,bigPlateV,midPlateV} ;//{bigPlate,midPlate,smlPlate} ;
  94. int maxSmlJewCapPerPlate = 0;
  95. int minSmlJewCapPerPlate = 99999 ;
  96. for(int ip=0;ip<usedPlates.size();++ip ) {
  97. maxSmlJewCapPerPlate = fmax( usedPlates[ip]->_bigJewCap*4 , maxSmlJewCapPerPlate) ;
  98. minSmlJewCapPerPlate = fmin( usedPlates[ip]->_bigJewCap*4 , minSmlJewCapPerPlate) ;
  99. }
  100. //等效小宝石数量
  101. int effSmallJewelsCount = bigJewelCnt*4 + midJewelCnt*2 + smlJewelCnt ;
  102. //cout<<"bigJewelCnt "<<bigJewelCnt<<endl;
  103. //cout<<"midJewelCnt "<<midJewelCnt<<endl;
  104. //cout<<"smlJewelCnt "<<smlJewelCnt<<endl;
  105. //cout<<"effSmallJewelsCount "<<effSmallJewelsCount<<endl;
  106. //构建符合难度条件的盘子和层数组合(包括可移动的盘子)
  107. vector<PlateIdAndLayerCnt> resPlateNLyrCnt = generatePlateTypeAndLayerCnts2(isMovable, mulMoveConfig, levelData._difficulty,effSmallJewelsCount);
  108. if( resPlateNLyrCnt.size()==0 ) {
  109. //cout<<"failed at generatePlateTypeAndLayerCnts"<<endl;
  110. return false ;
  111. }
  112. //计算盘子的最大层数
  113. int maxLyrCnt = 0;
  114. for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it ) maxLyrCnt=fmax(maxLyrCnt,it->_layerCnt) ;
  115. //对每个盘子组合进行填充宝石
  116. RandomGridFiller filler ;
  117. filler._seed = this->_seed ;
  118. srand(filler._seed);
  119. //构建每个盘子每个层的填充结果容器
  120. vector< tuple<int,int,vector<FillResult>,int> > plateIdLyrFillResultsMoveIdArray ;// tuple<plateId, layerIndex, fillresults_array ,moveId>
  121. //从顶到底部,逐层进行填充
  122. int residues = 0 ;
  123. for(int nlayer = maxLyrCnt; nlayer > 0 ; nlayer-- ) {
  124. //cout<<"for layer "<<nlayer<<endl;
  125. //满足该层数的所有盘子ID
  126. vector<int> plateIdArr ;//临时符合当前层次的盘子类型ID
  127. vector<int> moveIdArr ;//临时保存对应盘子是否是可移动的,0-不可移动,1-第一移动行,2-第二移动行
  128. for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it )
  129. {
  130. if(it->_layerCnt>=nlayer) {
  131. plateIdArr.push_back(it->_plateId) ;
  132. moveIdArr.push_back( it->_moveId ) ;
  133. }
  134. }
  135. //该层总计需要填充多少小宝石
  136. int currLyrNeedEquvSmlCnt = 0 ;
  137. for(int ip=0;ip<plateIdArr.size();++ip ) {
  138. currLyrNeedEquvSmlCnt += fgc->getPlateItemById(plateIdArr[ip])->_bigJewCap*4 ;
  139. }
  140. //cout<<"layer need eqsmCnt "<<currLyrNeedEquvSmlCnt<<endl;
  141. //根据所需数量和所需求解百分比,计算从库存取出每类宝石多少个。
  142. float solPercent = 0.7 ;//根据需求文档,每层可解百分比都是70%.
  143. unordered_map<int, int> chosenJewIdNCnt = randPickJewels(currLyrNeedEquvSmlCnt, solPercent, jewIdSzCntStorageMap) ;
  144. int choseEqSmCnt=0;
  145. for(auto itp=chosenJewIdNCnt.begin();itp!=chosenJewIdNCnt.end();++itp) {
  146. choseEqSmCnt += jewSz2SmlCnt( fgc->getJewelItemById(itp->first)->_size) * itp->second ;
  147. }
  148. //cout<<"layer choose eqsmCnt "<<choseEqSmCnt<<endl;
  149. //逐个盘子填充
  150. for(int ipid = 0 ; ipid !=plateIdArr.size();++ipid) {
  151. int plateId1 = plateIdArr[ipid] ;
  152. int moveId1 = moveIdArr[ipid] ;
  153. vector<FillResult> fr = fillPlateOneLayer(filler, plateId1 , chosenJewIdNCnt) ;
  154. tuple<int,int,vector<FillResult>,int> plateLyrFillResult={plateId1 , nlayer , fr , moveId1 } ;
  155. plateIdLyrFillResultsMoveIdArray.push_back(plateLyrFillResult);
  156. }
  157. //检查为该层挑选的宝石是不是全部填完了,如果没有填完还要还给库存,给下一轮填充用
  158. residues = 0 ;
  159. for(auto itjn = chosenJewIdNCnt.begin();itjn!=chosenJewIdNCnt.end();++itjn){
  160. if( itjn->second>0 ) {
  161. residues+=itjn->second;
  162. std::get<1>(jewIdSzCntStorageMap[itjn->first]) += itjn->second ;//剩余的加回到库存里
  163. }
  164. }
  165. //cout<<"layer chosen jewels residues "<<residues<<endl;
  166. }
  167. //查看库存是否全部用掉了
  168. if( residues>0 ) {
  169. int extraPlateCnt = 0 ;
  170. //剩了,添加一个小盘子和层,仍然剩了再继续加盘子加层
  171. unordered_map<int, int> residueJewIdAndCnts = findUnfilledInStorages(jewIdSzCntStorageMap) ;
  172. while( residueJewIdAndCnts.size()>0 ) {
  173. //新建一个中盘子
  174. extraPlateCnt++;
  175. //cout<<"add extra plate "<< extraPlateCnt <<endl;
  176. int plateId = midPlateH->_id ;
  177. for(int ilyr = 1 ; ilyr <= maxLyrCnt; ++ ilyr ) {
  178. vector<FillResult> frs = fillPlateOneLayer(filler, plateId, residueJewIdAndCnts) ;
  179. plateIdLyrFillResultsMoveIdArray.push_back( {plateId,ilyr,frs, MOVEID_NO_MOVE } );
  180. //cout<<"add extra lyr "<<endl;
  181. if( residueJewIdAndCnts.size()==0 ) break ;
  182. }
  183. if( residueJewIdAndCnts.size()==0 ) break ;
  184. }
  185. }
  186. //整理数据
  187. regroupPlateLyrFillResults(plateIdLyrFillResultsMoveIdArray, resultPlateFillResults);
  188. //摆放盘子
  189. {
  190. placePlates(isMovable,mulMoveConfig, resultPlateFillResults, resultPlateCenterPointArr) ;
  191. }
  192. auto ms1 = std::chrono::system_clock::now().time_since_epoch() ;
  193. uint64_t ms11 = std::chrono::duration_cast<chrono::milliseconds>(ms1).count() ;
  194. //cout<<"duration "<<ms11-ms00<<endl;
  195. return true ;
  196. }
  197. // this method is deprecated, use generatePlateTypeAndLayerCnts2()
  198. [[deprecated]]
  199. vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts(const int difficulty,const int totEquvSmallJewelCnt)
  200. {
  201. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  202. //...
  203. //...
  204. return results ;
  205. }
  206. //考虑可移动关卡的条件
  207. vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts2(
  208. const bool isMovable,
  209. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  210. const int difficulty,
  211. const int totEquvSmallJewelCnt
  212. )
  213. {
  214. //如果是移动关卡,那么至少需要保证如下等价小盘子数量,如果减少层数仍然不能满足那么就有几个盘子输出几个
  215. //const int MAX_LG_PLATE_CNT = 9 ;// + (isMovable?1:0) ;
  216. // const int MAX_SM_PLATE_CNT = MAX_LG_PLATE_CNT*4 ;
  217. //const int MAX_SM_JEWEL_CNT_PER_LAYER = MAX_LG_PLATE_CNT * 24 ;
  218. const int MID_PLATE_CAP = 12 ;//中盘子对小宝石的容量
  219. //const int minEquaSmPlateCntForMovable = 16 ; //
  220. //const int smPlateEquaSmJewelCnt = 6 ;// 小盘子装1.5个大,3个中,6个小
  221. //一个关卡最多出现大、中、小盘子个数
  222. int tempBigPlateCnt1 = 9 ;// 1个大盘子=2两个中盘子
  223. int tempMidPlateCnt1 = 0 ;
  224. computePlateCount(mulMoveConfig, tempBigPlateCnt1, tempMidPlateCnt1) ;
  225. int midPlateMaxCnt = tempBigPlateCnt1 * 2 + tempMidPlateCnt1 ;//大盘子数量换算成中盘子
  226. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  227. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  228. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  229. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  230. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  231. //如果是移动关卡,先构建移动盘子
  232. int totEquvSmallJewelCnt2 = totEquvSmallJewelCnt ;
  233. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  234. //剩余可以用的中盘子个数
  235. if( isMovable ) {
  236. int residueEquvSmlJewelCnt = 0 ;
  237. results = generatePlateTypeAndLayerCntsForMovablePlates(mulMoveConfig, totEquvSmallJewelCnt2, residueEquvSmlJewelCnt) ;
  238. totEquvSmallJewelCnt2 = residueEquvSmlJewelCnt ;
  239. //减去移动的盘子
  240. for(int ir = 0 ; ir < results.size(); ++ ir ){
  241. if( fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_LG ) {
  242. midPlateMaxCnt-=2 ;//减去移动的盘子
  243. }else if(fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_MD) {
  244. midPlateMaxCnt-=1 ;//减去移动的盘子
  245. }
  246. }
  247. }
  248. int equvMidPlateCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / MID_PLATE_CAP) ; // 本关需要多少个一层中盘子的总数量
  249. int layerCnt0 = 1 ;//盘子层数下限
  250. int layerCnt1 = 1 ;//盘子层数上限
  251. //计算可能的层取值范围
  252. {
  253. layerCnt0 = fmax(1 , totEquvSmallJewelCnt2 / (midPlateMaxCnt*MID_PLATE_CAP) ) ;
  254. if( layerCnt0<3 ) layerCnt1 = 3 ;
  255. else layerCnt1 = layerCnt0 + 1 ;
  256. }
  257. int bigPlateCnt0 = totEquvSmallJewelCnt2 * 1.0 / layerCnt1 / 24 ; //大盘子最少需要数量
  258. int bigPlateCnt1 = totEquvSmallJewelCnt2 * 1.0 / layerCnt0 / 24 + 1; //大盘子最多需要数量
  259. int midPlateCnt0 = bigPlateCnt0*2 ;
  260. int midPlateCnt1 = bigPlateCnt1*2 ;
  261. bigPlateCnt1 = fmin( midPlateMaxCnt/2 ,bigPlateCnt1 ) ;
  262. midPlateCnt1 = fmin( midPlateMaxCnt ,midPlateCnt1 ) ;
  263. bool findFirstAvailableComb = false ;//第一个完全放入宝石的组合,用于当不满足任何条件时,至少返回一个可装入全部宝石的默认方案
  264. vector<vector<LevelGenerate::PlateIdAndLayerCnt>> possibleResults ;//满足全部百分比要求的组合
  265. vector<LevelGenerate::PlateIdAndLayerCnt> firstAvailablePlateComb ;//第一个满足全部宝石填充的组合,如果需要移动还要考虑最小移动盘子个数的条件
  266. int firstAvailableLyrCnt = 0 ;
  267. //难度对盘子数量的限制 普通 难 极难
  268. vector< vector<float> > hardPlateCntPercent0 = { {0.3,0.3}, {0.2,0.4}, {0.1,0.5} } ;
  269. vector< vector<float> > hardPlateCntPercent1 = { {0.7,0.7}, {0.6,0.8}, {0.5,0.9} } ;
  270. //穷举全部盘子和层的组合找到符合条件的组合
  271. for(int ibig = 0; ibig <= bigPlateCnt1; ++ ibig ) {
  272. for(int imid = 0; imid <= midPlateCnt1 ; ++ imid ) {
  273. int currEquvMidPlateCnt = imid+ibig*2 ;
  274. if( currEquvMidPlateCnt==0 || currEquvMidPlateCnt > midPlateMaxCnt ) continue ;
  275. float bigPlateCntPercent = ibig*2.0 / currEquvMidPlateCnt ;
  276. float midPlateCntPercent = imid*1.0 / currEquvMidPlateCnt ;
  277. vector<float> percentArr = {bigPlateCntPercent,midPlateCntPercent} ;
  278. //判断每个盘子百分比是否满足难度要求
  279. bool percentOk = true ;
  280. for(int iplatetype=0;iplatetype<percentArr.size();++iplatetype) {
  281. if( hardPlateCntPercent0[difficulty][iplatetype]>percentArr[iplatetype] || hardPlateCntPercent1[difficulty][iplatetype]<percentArr[iplatetype] )
  282. percentOk=false;
  283. }
  284. if( findFirstAvailableComb == true ){
  285. //至少有一个装下宝石的方案了
  286. if( !percentOk ) continue ;//盘子百分比不符合要求,跳过
  287. }
  288. if( findFirstAvailableComb==false || (findFirstAvailableComb && firstAvailableLyrCnt>3 ) ) {
  289. //保证至少有一个可以满足宝石的盘子组合,优先保存总层数大于3的情况
  290. //当前盘子组合下最小满足的层数
  291. int upperLyrCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / (currEquvMidPlateCnt*MID_PLATE_CAP) ) ;
  292. bool upperLyrCntOk = true ;
  293. if( findFirstAvailableComb ) {
  294. if( upperLyrCnt >= firstAvailableLyrCnt ) {
  295. upperLyrCntOk = false ;
  296. }
  297. }
  298. vector<int> pidArr ;
  299. vector<int> capArr ;
  300. vector<int> lyrArr ;
  301. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  302. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
  303. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
  304. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  305. if( lyrOk==false && upperLyrCnt>1 ) {
  306. for(int it=0;it<lyrArr.size();++it ) {
  307. lyrArr[it] -= 1 ;
  308. lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  309. if( lyrOk ) break ;
  310. }
  311. }
  312. if( lyrOk && upperLyrCntOk ){
  313. findFirstAvailableComb = true ;
  314. firstAvailableLyrCnt = upperLyrCnt ;
  315. //保存结果
  316. firstAvailablePlateComb.resize(capArr.size());
  317. for(int it = 0 ; it < capArr.size(); ++ it ) {
  318. firstAvailablePlateComb[it]._plateId = pidArr[it] ;
  319. firstAvailablePlateComb[it]._layerCnt = lyrArr[it] ;
  320. firstAvailablePlateComb[it]._moveId = MOVEID_NO_MOVE ;
  321. }
  322. }
  323. }
  324. //计算每个类型的层数
  325. if( difficulty== FILLGLOBALCONFIG_DIFFCULTY_NORM ) {
  326. //全部两层
  327. vector<int> pidArr ;
  328. vector<int> capArr ;
  329. vector<int> lyrArr ;
  330. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  331. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(2); }
  332. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(2); }
  333. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  334. if(!lyrOk) continue;
  335. //保存结果
  336. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  337. for(int it = 0 ; it < capArr.size(); ++ it ) {
  338. tres[it]._plateId = pidArr[it] ;
  339. tres[it]._layerCnt = lyrArr[it] ;
  340. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  341. }
  342. possibleResults.push_back(tres) ;
  343. }else if( difficulty==FILLGLOBALCONFIG_DIFFCULTY_HARD2 ) {
  344. //全部3层
  345. vector<int> pidArr ;
  346. vector<int> capArr ;
  347. vector<int> lyrArr ;
  348. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  349. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(3); }
  350. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(3); }
  351. //cout<<"debug big "<<ibig<<" mid "<<imid<<" sml "<<isml<<endl;
  352. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  353. if(!lyrOk) continue;
  354. //保存结果
  355. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  356. for(int it = 0 ; it < capArr.size(); ++ it ) {
  357. tres[it]._plateId = pidArr[it] ;
  358. tres[it]._layerCnt = lyrArr[it] ;
  359. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  360. }
  361. possibleResults.push_back(tres) ;
  362. }else{
  363. //50% 2层, 50% 3层
  364. vector<int> pidArr ;
  365. vector<int> capArr ;
  366. vector<int> lyrArr ;
  367. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  368. 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); }
  369. 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); }
  370. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  371. if(!lyrOk) continue;
  372. //保存结果
  373. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  374. for(int it = 0 ; it < capArr.size(); ++ it ) {
  375. tres[it]._plateId = pidArr[it] ;
  376. tres[it]._layerCnt = lyrArr[it] ;
  377. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  378. }
  379. possibleResults.push_back(tres) ;
  380. }
  381. }
  382. }
  383. //随机挑选一个结果返回
  384. if( possibleResults.size()> 0 ) {
  385. int randindex = rand() % possibleResults.size();
  386. for(int ip = 0 ; ip < possibleResults[randindex].size();++ ip ) {
  387. results.push_back(possibleResults[randindex][ip]) ;
  388. }
  389. }else {
  390. for(int ip = 0 ; ip < firstAvailablePlateComb.size();++ ip ) {
  391. results.push_back(firstAvailablePlateComb[ip]) ;
  392. }
  393. }
  394. return results ;//
  395. }
  396. //随机排序数组索引值
  397. vector<int> LevelGenerate::randIndices(const int count0 ) {
  398. int count = count0 ;
  399. vector<int> indices ;
  400. unordered_map<int, bool> dict ;
  401. while( count > 0 ) {
  402. int r = rand()%count0;
  403. if( dict.find(r) == dict.end() ) {
  404. dict[r] = true ;
  405. indices.push_back(r) ;
  406. count-- ;
  407. }
  408. }
  409. return indices;
  410. }
  411. bool LevelGenerate::isJustFilledAll2(
  412. const vector<int>& plateCaps,//每个盘子的容量
  413. const vector<int> eachPlateLyrCnt,//对应盘子的层数
  414. const int totSmlJewCnt )
  415. {
  416. assert(plateCaps.size()>0);
  417. assert(plateCaps.size()==eachPlateLyrCnt.size());
  418. int fillcnt1 = 0;
  419. for(int ip = 0 ;ip<plateCaps.size();++ip ) {
  420. fillcnt1 += plateCaps[ip] * eachPlateLyrCnt[ip] ;
  421. }
  422. if( fillcnt1 < totSmlJewCnt ) return false ;
  423. if( fillcnt1 == totSmlJewCnt ) return true ;
  424. for(int ip = 0 ; ip < plateCaps.size();++ip ) {
  425. int fillcnt2 = fillcnt1 - plateCaps[ip] ;
  426. if( fillcnt2 < totSmlJewCnt ) {
  427. return true ;
  428. }
  429. }
  430. return false ;
  431. }
  432. unordered_map<int, int> LevelGenerate::randPickJewels( const int needEquvSmlCnt,const float solvedPercent, unordered_map<int,tuple<int,int>>& jewStorages )
  433. {
  434. int needEquvSmlCnt2 = needEquvSmlCnt ;
  435. int storageEquvSmlCnt = 0 ;
  436. int storageJewTypeCnt = jewStorages.size() ;
  437. for(auto it=jewStorages.begin();it!=jewStorages.end();++it) storageEquvSmlCnt+= std::get<1>(it->second)*jewSz2SmlCnt(std::get<0>(it->second)) ;
  438. unordered_map<int, int> res ;
  439. const float solPer = fmax(0.0,fmin(solvedPercent,1.0f)) ;
  440. //首先尝试可解的百分比部分
  441. int solEqSmGrpCnt = needEquvSmlCnt*solPer/3 ;
  442. // 随机尝试solEqSmGrpCnt*2 次取宝石,每次取一组。
  443. int loopCnt=solEqSmGrpCnt*storageJewTypeCnt*10;//随机迭代数量加大10倍,避免有始终选不到的情况
  444. while( solEqSmGrpCnt> 0 && storageEquvSmlCnt>0 && loopCnt>0) {
  445. int randJewI = rand()%storageJewTypeCnt ;
  446. auto itjew = jewStorages.begin() ;
  447. std::advance(itjew, randJewI) ;
  448. int jid = itjew->first ;
  449. int storage1 = std::get<1>( itjew->second ) ;
  450. int oneGrpEqSmGrpCnt = jewSz2SmlCnt( std::get<0>(itjew->second) ) ;
  451. if( storage1>=3 && oneGrpEqSmGrpCnt<=solEqSmGrpCnt ) {
  452. //库存有,且满足所需可解组数
  453. std::get<1>(itjew->second)-=3 ;
  454. solEqSmGrpCnt -= oneGrpEqSmGrpCnt ;
  455. storageEquvSmlCnt -= oneGrpEqSmGrpCnt*3 ;
  456. needEquvSmlCnt2 -= oneGrpEqSmGrpCnt*3 ; //本次所需的剩余等效小宝石个数
  457. res[jid] += 3 ;
  458. }
  459. --loopCnt ;
  460. }
  461. //尝试剩余百分比和上一步剩余没有符合条件的个数
  462. loopCnt = needEquvSmlCnt2*storageJewTypeCnt ;
  463. int jindex = 0 ;
  464. while( loopCnt>0 && needEquvSmlCnt2> 0 && storageEquvSmlCnt>0 ) {
  465. auto itjew = jewStorages.begin() ;
  466. std::advance(itjew, jindex) ;
  467. int jid = itjew->first;
  468. int sz = std::get<0>(itjew->second) ;
  469. int stor = std::get<1>(itjew->second) ;
  470. int eqsmCnt = jewSz2SmlCnt(sz) ;
  471. if( stor>0 && eqsmCnt <= needEquvSmlCnt2 ) {
  472. std::get<1>(itjew->second)-=1 ;
  473. needEquvSmlCnt2-=eqsmCnt ;
  474. storageEquvSmlCnt-=eqsmCnt ;
  475. res[jid] += 1 ;
  476. }
  477. ++jindex ; if(jindex>=storageJewTypeCnt) jindex=0;//循环取之,直到本层所需全部取完
  478. --loopCnt;
  479. }
  480. return res ;
  481. }
  482. int LevelGenerate::jewSz2SmlCnt(int sz)
  483. {
  484. switch (sz) {
  485. case FILLGLOBALCONFIG_JEWELSIZE_LG:
  486. return 4;break;
  487. case FILLGLOBALCONFIG_JEWELSIZE_MD:
  488. return 2;break;
  489. default:
  490. return 1;break;
  491. }
  492. return 1;
  493. }
  494. vector<FillResult> LevelGenerate::fillPlateOneLayer(RandomGridFiller& filler,const int plateId, unordered_map<int,int>& jewStoragesForUse )
  495. {
  496. auto fgc = FillGlobalConfig::getInstance() ;
  497. vector<RandomGridFiller::JewelBox> jewBoxArray ;
  498. FillGlobalConfig::PlateItem* pl = FillGlobalConfig::getInstance()->getPlateItemById(plateId) ;
  499. int plateEqSmCap = pl->_bigJewCap*4 ;
  500. int jewTypeCnt = jewStoragesForUse.size() ;
  501. int eqSmStorageCnt = 0 ;
  502. for(auto it = jewStoragesForUse.begin();it!=jewStoragesForUse.end();++it) {
  503. int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
  504. eqSmStorageCnt+=it->second*jewEqSmCnt ;
  505. }
  506. static int s_debug_cnt = 0;
  507. //cout<<"debug "<< s_debug_cnt << " storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
  508. unordered_map<int, int> jewForPlateMap ;// <jewId,Cnt>
  509. int loopCnt = plateEqSmCap*jewTypeCnt*4;// 随机数量多给4倍
  510. while(plateEqSmCap>0 && eqSmStorageCnt>0 && loopCnt>0 ) {
  511. int radv = rand() % jewTypeCnt ;
  512. auto it = jewStoragesForUse.begin() ;
  513. std::advance(it, radv) ;
  514. int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
  515. if( it->second>0 ) {
  516. if( jewEqSmCnt <= plateEqSmCap ) {
  517. plateEqSmCap -= jewEqSmCnt ;
  518. it->second -=1 ;
  519. eqSmStorageCnt -= jewEqSmCnt ;
  520. jewForPlateMap[it->first] += 1 ;
  521. if( it->second== 0 ) {
  522. jewStoragesForUse.erase(it) ;
  523. jewTypeCnt-- ;
  524. }
  525. }
  526. }else{
  527. jewStoragesForUse.erase(it) ;
  528. jewTypeCnt-- ;
  529. }
  530. --loopCnt ;
  531. }
  532. //cout<<"debug "<< s_debug_cnt ++ <<" storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
  533. for(auto it = jewForPlateMap.begin();it!=jewForPlateMap.end();++it) {
  534. RandomGridFiller::JewelBox jbox ;
  535. jbox._cnt = it->second ;
  536. jbox._jewelTypeId = it->first ;
  537. jbox._width = fgc->getJewelItemById(it->first)->_bbWidth ;
  538. jbox._height = fgc->getJewelItemById(it->first)->_bbHeight ;
  539. jewBoxArray.push_back(jbox) ;
  540. }
  541. vector<FillResult> fillresults ;
  542. filler.fill(jewBoxArray, pl->_blx, pl->_bly, pl->_trx, pl->_try, fillresults) ;
  543. return fillresults ;
  544. }
  545. unordered_map<int, int> LevelGenerate::findUnfilledInStorages( unordered_map<int,tuple<int,int>>& jewStorages)
  546. {
  547. unordered_map<int, int> res ;
  548. for(auto itj = jewStorages.begin();itj!=jewStorages.end();++itj) {
  549. int stor = std::get<1>(itj->second) ;
  550. int jid = itj->first ;
  551. if( stor>0 ) {
  552. res[jid] = stor ;
  553. std::get<1>(itj->second) = 0 ;
  554. }
  555. }
  556. return res ;
  557. }
  558. void LevelGenerate::regroupPlateLyrFillResults(
  559. vector<tuple<int,int,vector<FillResult>,int>>& pidlyrFillMvidArray,
  560. vector<PlateFillResult>& results)
  561. {
  562. int currLayer = 1 ;//从底层到顶层构建结果数据结构
  563. int num = pidlyrFillMvidArray.size() ;
  564. int nloop = num ;
  565. while( nloop > 0 ) {
  566. //cout<<"regroup for layer "<<currLayer<<endl;
  567. for( auto itlyr = pidlyrFillMvidArray.begin(); itlyr!=pidlyrFillMvidArray.end(); ++ itlyr ) {
  568. int pid = std::get<0>( *itlyr ) ;
  569. int lyr = std::get<1>( *itlyr ) ;
  570. vector<FillResult>& frs = std::get<2>(*itlyr) ;
  571. int moveId = std::get<3>(*itlyr) ;
  572. if(pid>=0) {
  573. if( lyr==currLayer ) {
  574. if( lyr==1 ) {
  575. vector<vector<FillResult>> frArr = {frs} ;
  576. PlateFillResult pfr ;
  577. pfr._layersFillResults = frArr ;
  578. pfr._moveId = moveId ;
  579. pfr._plateTypeId = pid ;
  580. results.push_back( pfr ) ;
  581. num-- ;
  582. std::get<0>( *itlyr ) = -1 ;
  583. }else {
  584. for(auto itPfr = results.begin();itPfr!=results.end();++itPfr ) {
  585. int pidr = itPfr->_plateTypeId ;
  586. int mvid = itPfr->_moveId ;
  587. vector<vector<FillResult>>& frArr = itPfr->_layersFillResults ;
  588. if( pidr == pid && mvid == moveId && frArr.size()==currLayer-1 ) {
  589. frArr.push_back(frs);
  590. num-- ;
  591. std::get<0>( *itlyr ) = -1 ;
  592. break ;
  593. }
  594. }
  595. }
  596. }
  597. }
  598. }
  599. currLayer++ ;
  600. if( num==0 ) break ;
  601. nloop--;
  602. }
  603. //cout<<"last plate lyr num "<<num<<endl;
  604. }
  605. void LevelGenerate::placePlates(const bool movable,
  606. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  607. const vector<PlateFillResult>& plateFRArr,
  608. vector<ContourData::Point>& resultPlateCenterPointArr )
  609. {
  610. GridPositionTool gpt ;
  611. vector<int> plateIdArr ;
  612. vector<int> moveIdArr ;
  613. for(int ip = 0 ; ip < plateFRArr.size(); ++ ip ) {
  614. plateIdArr.push_back( plateFRArr[ip]._plateTypeId ) ;
  615. moveIdArr.push_back( plateFRArr[ip]._moveId ) ;
  616. }
  617. vector<vector<int>> resPosis ;
  618. string firstMoveTypeCode = "" ;
  619. string secondMoveTypeCode = "" ;
  620. if( movable ) {
  621. firstMoveTypeCode = mulMoveConfig->_first->_type[0] ;
  622. if( mulMoveConfig->_second ) secondMoveTypeCode = mulMoveConfig->_second->_type[0] ;
  623. }
  624. gpt.solve(movable,
  625. firstMoveTypeCode ,
  626. secondMoveTypeCode,
  627. plateIdArr,
  628. moveIdArr,
  629. resPosis //这里结果是盘子左下角坐标,下面需要转换成中心坐标。
  630. ) ;
  631. for(int ip=0;ip<resPosis.size();++ip ) {
  632. FillGlobalConfig::PlateItem* platePtr = FillGlobalConfig::getInstance()->getPlateItemById(plateIdArr[ip]) ;
  633. resultPlateCenterPointArr.push_back( { (float)resPosis[ip][0]+platePtr->_bbwid/2 , (float)resPosis[ip][1]+platePtr->_bbhei/2} ) ;
  634. }
  635. }
  636. vector<LevelGenerate::PlateIdAndLayerCnt>
  637. LevelGenerate::generatePlateTypeAndLayerCntsForMovablePlates(
  638. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  639. const int totEquvSmallJewelCnt,
  640. int& retResidueEquvSmlJewelCnt )
  641. {
  642. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  643. retResidueEquvSmlJewelCnt = totEquvSmallJewelCnt ;
  644. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  645. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  646. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  647. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  648. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  649. const int MAX_MOVE_CONFIG_CNT = 2;
  650. FillGlobalConfig::MoveConfig* arr[MAX_MOVE_CONFIG_CNT] = { mulMoveConfig->_first , mulMoveConfig->_second } ;
  651. for(int ii = 0 ; ii < MAX_MOVE_CONFIG_CNT ; ++ ii ) {
  652. FillGlobalConfig::MoveConfig* moveConfig = arr[ii] ;
  653. if( moveConfig==nullptr ) continue ;
  654. //中盘子横
  655. for(int imid = 0 ; imid < moveConfig->_midPlateCntH ; ++ imid ) {
  656. PlateIdAndLayerCnt palc ;
  657. palc._layerCnt = moveConfig->_nLayer ;
  658. palc._plateId = midPlateH->_id ;
  659. palc._moveId = ii+1 ;//第一行为1,第二行为2
  660. results.push_back(palc) ;
  661. retResidueEquvSmlJewelCnt -= midPlateH->_bigJewCap*4*palc._layerCnt ;
  662. }
  663. //中盘子竖
  664. for(int imid = 0 ; imid < moveConfig->_midPlateCntV ; ++ imid ) {
  665. PlateIdAndLayerCnt palc ;
  666. palc._layerCnt = moveConfig->_nLayer ;
  667. palc._plateId = midPlateV->_id ;
  668. palc._moveId = ii+1 ;
  669. results.push_back(palc) ;
  670. retResidueEquvSmlJewelCnt -= midPlateV->_bigJewCap*4*palc._layerCnt ;
  671. }
  672. //大盘子横
  673. for(int ibig = 0 ; ibig < moveConfig->_bigPlateCntH ; ++ ibig ) {
  674. PlateIdAndLayerCnt palc ;
  675. palc._layerCnt = moveConfig->_nLayer ;
  676. palc._plateId = bigPlateH->_id ;
  677. palc._moveId = ii+1 ;
  678. results.push_back(palc) ;
  679. retResidueEquvSmlJewelCnt -= bigPlateH->_bigJewCap*4*palc._layerCnt ;
  680. }
  681. //大盘子竖
  682. for(int ibig = 0 ; ibig < moveConfig->_bigPlateCntV ; ++ ibig ) {
  683. PlateIdAndLayerCnt palc ;
  684. palc._layerCnt = moveConfig->_nLayer ;
  685. palc._plateId = bigPlateV->_id ;
  686. palc._moveId = ii+1 ;
  687. results.push_back(palc) ;
  688. retResidueEquvSmlJewelCnt -= bigPlateV->_bigJewCap*4*palc._layerCnt ;
  689. }
  690. }
  691. return results ;
  692. }
  693. void LevelGenerate::computePlateCount(const FillGlobalConfig::MultiMoveConfig* mmc ,int& retBigPlateCnt, int& retMidPlateCnt )
  694. {
  695. if( mmc==nullptr ) {
  696. retBigPlateCnt = 9 ;
  697. retMidPlateCnt = 0 ;
  698. }else
  699. if( mmc->_first && mmc->_second ) {
  700. if( mmc->_first->_type.find("A") != string::npos && mmc->_second->_type.compare("A") != string::npos ) {
  701. retBigPlateCnt = 6 ;
  702. retMidPlateCnt = 8 ;
  703. }else if( mmc->_first->_type.compare("B") != string::npos && mmc->_second->_type.compare("B") != string::npos ) {
  704. retBigPlateCnt = 9 ;
  705. retMidPlateCnt = 0 ;
  706. }else if( mmc->_first->_type.compare("C") != string::npos && mmc->_second->_type.compare("C") != string::npos ) {
  707. retBigPlateCnt = 11 ;
  708. retMidPlateCnt = 0 ;
  709. }else if( mmc->_first->_type.compare("B") != string::npos && mmc->_second->_type.compare("A") != string::npos) {
  710. retBigPlateCnt = 6 ;
  711. retMidPlateCnt = 7 ;
  712. }else if( mmc->_first->_type.compare("C") != string::npos && mmc->_second->_type.compare("B") != string::npos ) {
  713. retBigPlateCnt = 10 ;
  714. retMidPlateCnt = 0 ;
  715. }else if( mmc->_first->_type.compare("C") != string::npos && mmc->_second->_type.compare("A") != string::npos ) {
  716. retBigPlateCnt = 7 ;
  717. retMidPlateCnt = 7 ;
  718. }
  719. }else if( mmc->_first && mmc->_second==nullptr ) {
  720. if( mmc->_first->_type.compare("A") != string::npos ) {
  721. retBigPlateCnt = 6 ;
  722. retMidPlateCnt = 7 ;
  723. }else if( mmc->_first->_type.compare("B") != string::npos ) {
  724. retBigPlateCnt = 9 ;
  725. retMidPlateCnt = 0 ;
  726. }else if( mmc->_first->_type.compare("C") != string::npos ) {
  727. retBigPlateCnt = 10 ;
  728. retMidPlateCnt = 0 ;
  729. }
  730. }else {
  731. retBigPlateCnt = 9 ;
  732. retMidPlateCnt = 0 ;
  733. }
  734. }