LevelGenerate.cpp 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  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. // this method is deprecated, use generatePlateTypeAndLayerCnts2()
  191. [[deprecated]]
  192. vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts(const int difficulty,const int totEquvSmallJewelCnt)
  193. {
  194. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  195. //...
  196. //...
  197. return results ;
  198. }
  199. //考虑可移动关卡的条件
  200. vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts2(
  201. const bool isMovable,
  202. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  203. const int difficulty,
  204. const int totEquvSmallJewelCnt
  205. )
  206. {
  207. //如果是移动关卡,那么至少需要保证如下等价小盘子数量,如果减少层数仍然不能满足那么就有几个盘子输出几个
  208. //const int MAX_LG_PLATE_CNT = 9 ;// + (isMovable?1:0) ;
  209. // const int MAX_SM_PLATE_CNT = MAX_LG_PLATE_CNT*4 ;
  210. //const int MAX_SM_JEWEL_CNT_PER_LAYER = MAX_LG_PLATE_CNT * 24 ;
  211. const int MID_PLATE_CAP = 12 ;//中盘子对小宝石的容量
  212. //const int minEquaSmPlateCntForMovable = 16 ; //
  213. //const int smPlateEquaSmJewelCnt = 6 ;// 小盘子装1.5个大,3个中,6个小
  214. //一个关卡最多出现大、中、小盘子个数
  215. int tempBigPlateCnt1 = 9 ;// 1个大盘子=2两个中盘子
  216. int tempMidPlateCnt1 = 0 ;
  217. computePlateCount(mulMoveConfig, tempBigPlateCnt1, tempMidPlateCnt1) ;
  218. int midPlateMaxCnt = tempBigPlateCnt1 * 2 + tempMidPlateCnt1 ;//大盘子数量换算成中盘子
  219. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  220. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  221. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  222. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  223. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  224. //如果是移动关卡,先构建移动盘子
  225. int totEquvSmallJewelCnt2 = totEquvSmallJewelCnt ;
  226. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  227. //剩余可以用的中盘子个数
  228. if( isMovable ) {
  229. int residueEquvSmlJewelCnt = 0 ;
  230. results = generatePlateTypeAndLayerCntsForMovablePlates(mulMoveConfig, totEquvSmallJewelCnt2, residueEquvSmlJewelCnt) ;
  231. totEquvSmallJewelCnt2 = residueEquvSmlJewelCnt ;
  232. //减去移动的盘子
  233. for(int ir = 0 ; ir < results.size(); ++ ir ){
  234. if( fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_LG ) {
  235. midPlateMaxCnt-=2 ;//减去移动的盘子
  236. }else if(fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_MD) {
  237. midPlateMaxCnt-=1 ;//减去移动的盘子
  238. }
  239. }
  240. }
  241. int equvMidPlateCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / MID_PLATE_CAP) ; // 本关需要多少个一层中盘子的总数量
  242. int layerCnt0 = 1 ;//盘子层数下限
  243. int layerCnt1 = 1 ;//盘子层数上限
  244. //计算可能的层取值范围
  245. {
  246. layerCnt0 = fmax(1 , totEquvSmallJewelCnt2 / (midPlateMaxCnt*MID_PLATE_CAP) ) ;
  247. if( layerCnt0<3 ) layerCnt1 = 3 ;
  248. else layerCnt1 = layerCnt0 + 1 ;
  249. }
  250. int bigPlateCnt0 = totEquvSmallJewelCnt2 * 1.0 / layerCnt1 / 24 ; //大盘子最少需要数量
  251. int bigPlateCnt1 = totEquvSmallJewelCnt2 * 1.0 / layerCnt0 / 24 + 1; //大盘子最多需要数量
  252. int midPlateCnt0 = bigPlateCnt0*2 ;
  253. int midPlateCnt1 = bigPlateCnt1*2 ;
  254. bigPlateCnt1 = fmin( midPlateMaxCnt/2 ,bigPlateCnt1 ) ;
  255. midPlateCnt1 = fmin( midPlateMaxCnt ,midPlateCnt1 ) ;
  256. bool findFirstAvailableComb = false ;//第一个完全放入宝石的组合,用于当不满足任何条件时,至少返回一个可装入全部宝石的默认方案
  257. vector<vector<LevelGenerate::PlateIdAndLayerCnt>> possibleResults ;//满足全部百分比要求的组合
  258. vector<LevelGenerate::PlateIdAndLayerCnt> firstAvailablePlateComb ;//第一个满足全部宝石填充的组合,如果需要移动还要考虑最小移动盘子个数的条件
  259. int firstAvailableLyrCnt = 0 ;
  260. //难度对盘子数量的限制 普通 难 极难
  261. vector< vector<float> > hardPlateCntPercent0 = { {0.3,0.3}, {0.2,0.4}, {0.1,0.5} } ;
  262. vector< vector<float> > hardPlateCntPercent1 = { {0.7,0.7}, {0.6,0.8}, {0.5,0.9} } ;
  263. //穷举全部盘子和层的组合找到符合条件的组合
  264. for(int ibig = 0; ibig <= bigPlateCnt1; ++ ibig ) {
  265. for(int imid = 0; imid <= midPlateCnt1 ; ++ imid ) {
  266. int currEquvMidPlateCnt = imid+ibig*2 ;
  267. if( currEquvMidPlateCnt==0 || currEquvMidPlateCnt > midPlateMaxCnt ) continue ;
  268. float bigPlateCntPercent = ibig*2.0 / currEquvMidPlateCnt ;
  269. float midPlateCntPercent = imid*1.0 / currEquvMidPlateCnt ;
  270. vector<float> percentArr = {bigPlateCntPercent,midPlateCntPercent} ;
  271. //判断每个盘子百分比是否满足难度要求
  272. bool percentOk = true ;
  273. for(int iplatetype=0;iplatetype<percentArr.size();++iplatetype) {
  274. if( hardPlateCntPercent0[difficulty][iplatetype]>percentArr[iplatetype] || hardPlateCntPercent1[difficulty][iplatetype]<percentArr[iplatetype] )
  275. percentOk=false;
  276. }
  277. if( findFirstAvailableComb == true ){
  278. //至少有一个装下宝石的方案了
  279. if( !percentOk ) continue ;//盘子百分比不符合要求,跳过
  280. }
  281. if( findFirstAvailableComb==false || (findFirstAvailableComb && firstAvailableLyrCnt>3 ) ) {
  282. //保证至少有一个可以满足宝石的盘子组合,优先保存总层数大于3的情况
  283. //当前盘子组合下最小满足的层数
  284. int upperLyrCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / (currEquvMidPlateCnt*MID_PLATE_CAP) ) ;
  285. bool upperLyrCntOk = true ;
  286. if( findFirstAvailableComb ) {
  287. if( upperLyrCnt >= firstAvailableLyrCnt ) {
  288. upperLyrCntOk = false ;
  289. }
  290. }
  291. vector<int> pidArr ;
  292. vector<int> capArr ;
  293. vector<int> lyrArr ;
  294. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  295. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
  296. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
  297. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  298. if( lyrOk==false && upperLyrCnt>1 ) {
  299. for(int it=0;it<lyrArr.size();++it ) {
  300. lyrArr[it] -= 1 ;
  301. lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  302. if( lyrOk ) break ;
  303. }
  304. }
  305. if( lyrOk && upperLyrCntOk ){
  306. findFirstAvailableComb = true ;
  307. firstAvailableLyrCnt = upperLyrCnt ;
  308. //保存结果
  309. firstAvailablePlateComb.resize(capArr.size());
  310. for(int it = 0 ; it < capArr.size(); ++ it ) {
  311. firstAvailablePlateComb[it]._plateId = pidArr[it] ;
  312. firstAvailablePlateComb[it]._layerCnt = lyrArr[it] ;
  313. firstAvailablePlateComb[it]._moveId = MOVEID_NO_MOVE ;
  314. }
  315. }
  316. }
  317. //计算每个类型的层数
  318. if( difficulty== FILLGLOBALCONFIG_DIFFCULTY_NORM ) {
  319. //全部两层
  320. vector<int> pidArr ;
  321. vector<int> capArr ;
  322. vector<int> lyrArr ;
  323. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  324. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(2); }
  325. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(2); }
  326. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  327. if(!lyrOk) continue;
  328. //保存结果
  329. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  330. for(int it = 0 ; it < capArr.size(); ++ it ) {
  331. tres[it]._plateId = pidArr[it] ;
  332. tres[it]._layerCnt = lyrArr[it] ;
  333. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  334. }
  335. possibleResults.push_back(tres) ;
  336. }else if( difficulty==FILLGLOBALCONFIG_DIFFCULTY_HARD2 ) {
  337. //全部3层
  338. vector<int> pidArr ;
  339. vector<int> capArr ;
  340. vector<int> lyrArr ;
  341. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  342. for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(3); }
  343. for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(3); }
  344. //cout<<"debug big "<<ibig<<" mid "<<imid<<" sml "<<isml<<endl;
  345. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  346. if(!lyrOk) continue;
  347. //保存结果
  348. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  349. for(int it = 0 ; it < capArr.size(); ++ it ) {
  350. tres[it]._plateId = pidArr[it] ;
  351. tres[it]._layerCnt = lyrArr[it] ;
  352. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  353. }
  354. possibleResults.push_back(tres) ;
  355. }else{
  356. //50% 2层, 50% 3层
  357. vector<int> pidArr ;
  358. vector<int> capArr ;
  359. vector<int> lyrArr ;
  360. //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
  361. 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); }
  362. 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); }
  363. bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
  364. if(!lyrOk) continue;
  365. //保存结果
  366. vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
  367. for(int it = 0 ; it < capArr.size(); ++ it ) {
  368. tres[it]._plateId = pidArr[it] ;
  369. tres[it]._layerCnt = lyrArr[it] ;
  370. tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
  371. }
  372. possibleResults.push_back(tres) ;
  373. }
  374. }
  375. }
  376. //随机挑选一个结果返回
  377. if( possibleResults.size()> 0 ) {
  378. int randindex = rand() % possibleResults.size();
  379. for(int ip = 0 ; ip < possibleResults[randindex].size();++ ip ) {
  380. results.push_back(possibleResults[randindex][ip]) ;
  381. }
  382. }else {
  383. for(int ip = 0 ; ip < firstAvailablePlateComb.size();++ ip ) {
  384. results.push_back(firstAvailablePlateComb[ip]) ;
  385. }
  386. }
  387. return results ;//
  388. }
  389. //随机排序数组索引值
  390. vector<int> LevelGenerate::randIndices(const int count0 ) {
  391. int count = count0 ;
  392. vector<int> indices ;
  393. unordered_map<int, bool> dict ;
  394. while( count > 0 ) {
  395. int r = rand()%count0;
  396. if( dict.find(r) == dict.end() ) {
  397. dict[r] = true ;
  398. indices.push_back(r) ;
  399. count-- ;
  400. }
  401. }
  402. return indices;
  403. }
  404. bool LevelGenerate::isJustFilledAll2(
  405. const vector<int>& plateCaps,//每个盘子的容量
  406. const vector<int> eachPlateLyrCnt,//对应盘子的层数
  407. const int totSmlJewCnt )
  408. {
  409. assert(plateCaps.size()>0);
  410. assert(plateCaps.size()==eachPlateLyrCnt.size());
  411. int fillcnt1 = 0;
  412. for(int ip = 0 ;ip<plateCaps.size();++ip ) {
  413. fillcnt1 += plateCaps[ip] * eachPlateLyrCnt[ip] ;
  414. }
  415. if( fillcnt1 < totSmlJewCnt ) return false ;
  416. if( fillcnt1 == totSmlJewCnt ) return true ;
  417. for(int ip = 0 ; ip < plateCaps.size();++ip ) {
  418. int fillcnt2 = fillcnt1 - plateCaps[ip] ;
  419. if( fillcnt2 < totSmlJewCnt ) {
  420. return true ;
  421. }
  422. }
  423. return false ;
  424. }
  425. unordered_map<int, int> LevelGenerate::randPickJewels( const int needEquvSmlCnt,const float solvedPercent, unordered_map<int,tuple<int,int>>& jewStorages )
  426. {
  427. int needEquvSmlCnt2 = needEquvSmlCnt ;
  428. int storageEquvSmlCnt = 0 ;
  429. int storageJewTypeCnt = jewStorages.size() ;
  430. for(auto it=jewStorages.begin();it!=jewStorages.end();++it) storageEquvSmlCnt+= std::get<1>(it->second)*jewSz2SmlCnt(std::get<0>(it->second)) ;
  431. unordered_map<int, int> res ;
  432. const float solPer = fmax(0.0,fmin(solvedPercent,1.0f)) ;
  433. //首先尝试可解的百分比部分
  434. int solEqSmGrpCnt = needEquvSmlCnt*solPer/3 ;
  435. // 随机尝试solEqSmGrpCnt*2 次取宝石,每次取一组。
  436. int loopCnt=solEqSmGrpCnt*storageJewTypeCnt*10;//随机迭代数量加大10倍,避免有始终选不到的情况
  437. while( solEqSmGrpCnt> 0 && storageEquvSmlCnt>0 && loopCnt>0) {
  438. int randJewI = rand()%storageJewTypeCnt ;
  439. auto itjew = jewStorages.begin() ;
  440. std::advance(itjew, randJewI) ;
  441. int jid = itjew->first ;
  442. int storage1 = std::get<1>( itjew->second ) ;
  443. int oneGrpEqSmGrpCnt = jewSz2SmlCnt( std::get<0>(itjew->second) ) ;
  444. if( storage1>=3 && oneGrpEqSmGrpCnt<=solEqSmGrpCnt ) {
  445. //库存有,且满足所需可解组数
  446. std::get<1>(itjew->second)-=3 ;
  447. solEqSmGrpCnt -= oneGrpEqSmGrpCnt ;
  448. storageEquvSmlCnt -= oneGrpEqSmGrpCnt*3 ;
  449. needEquvSmlCnt2 -= oneGrpEqSmGrpCnt*3 ; //本次所需的剩余等效小宝石个数
  450. res[jid] += 3 ;
  451. }
  452. --loopCnt ;
  453. }
  454. //尝试剩余百分比和上一步剩余没有符合条件的个数
  455. loopCnt = needEquvSmlCnt2*storageJewTypeCnt ;
  456. int jindex = 0 ;
  457. while( loopCnt>0 && needEquvSmlCnt2> 0 && storageEquvSmlCnt>0 ) {
  458. auto itjew = jewStorages.begin() ;
  459. std::advance(itjew, jindex) ;
  460. int jid = itjew->first;
  461. int sz = std::get<0>(itjew->second) ;
  462. int stor = std::get<1>(itjew->second) ;
  463. int eqsmCnt = jewSz2SmlCnt(sz) ;
  464. if( stor>0 && eqsmCnt <= needEquvSmlCnt2 ) {
  465. std::get<1>(itjew->second)-=1 ;
  466. needEquvSmlCnt2-=eqsmCnt ;
  467. storageEquvSmlCnt-=eqsmCnt ;
  468. res[jid] += 1 ;
  469. }
  470. ++jindex ; if(jindex>=storageJewTypeCnt) jindex=0;//循环取之,直到本层所需全部取完
  471. --loopCnt;
  472. }
  473. return res ;
  474. }
  475. int LevelGenerate::jewSz2SmlCnt(int sz)
  476. {
  477. switch (sz) {
  478. case FILLGLOBALCONFIG_JEWELSIZE_LG:
  479. return 4;break;
  480. case FILLGLOBALCONFIG_JEWELSIZE_MD:
  481. return 2;break;
  482. default:
  483. return 1;break;
  484. }
  485. return 1;
  486. }
  487. vector<FillResult> LevelGenerate::fillPlateOneLayer(RandomGridFiller& filler,const int plateId, unordered_map<int,int>& jewStoragesForUse )
  488. {
  489. auto fgc = FillGlobalConfig::getInstance() ;
  490. vector<RandomGridFiller::JewelBox> jewBoxArray ;
  491. FillGlobalConfig::PlateItem* pl = FillGlobalConfig::getInstance()->getPlateItemById(plateId) ;
  492. int plateEqSmCap = pl->_bigJewCap*4 ;
  493. int jewTypeCnt = jewStoragesForUse.size() ;
  494. int eqSmStorageCnt = 0 ;
  495. for(auto it = jewStoragesForUse.begin();it!=jewStoragesForUse.end();++it) {
  496. int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
  497. eqSmStorageCnt+=it->second*jewEqSmCnt ;
  498. }
  499. static int s_debug_cnt = 0;
  500. //cout<<"debug "<< s_debug_cnt << " storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
  501. unordered_map<int, int> jewForPlateMap ;// <jewId,Cnt>
  502. int loopCnt = plateEqSmCap*jewTypeCnt*4;// 随机数量多给4倍
  503. while(plateEqSmCap>0 && eqSmStorageCnt>0 && loopCnt>0 ) {
  504. int radv = rand() % jewTypeCnt ;
  505. auto it = jewStoragesForUse.begin() ;
  506. std::advance(it, radv) ;
  507. int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
  508. if( it->second>0 ) {
  509. if( jewEqSmCnt <= plateEqSmCap ) {
  510. plateEqSmCap -= jewEqSmCnt ;
  511. it->second -=1 ;
  512. eqSmStorageCnt -= jewEqSmCnt ;
  513. jewForPlateMap[it->first] += 1 ;
  514. if( it->second== 0 ) {
  515. jewStoragesForUse.erase(it) ;
  516. jewTypeCnt-- ;
  517. }
  518. }
  519. }else{
  520. jewStoragesForUse.erase(it) ;
  521. jewTypeCnt-- ;
  522. }
  523. --loopCnt ;
  524. }
  525. //cout<<"debug "<< s_debug_cnt ++ <<" storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
  526. for(auto it = jewForPlateMap.begin();it!=jewForPlateMap.end();++it) {
  527. RandomGridFiller::JewelBox jbox ;
  528. jbox._cnt = it->second ;
  529. jbox._jewelTypeId = it->first ;
  530. jbox._width = fgc->getJewelItemById(it->first)->_bbWidth ;
  531. jbox._height = fgc->getJewelItemById(it->first)->_bbHeight ;
  532. jewBoxArray.push_back(jbox) ;
  533. }
  534. vector<FillResult> fillresults ;
  535. filler.fill(jewBoxArray, pl->_blx, pl->_bly, pl->_trx, pl->_try, fillresults) ;
  536. return fillresults ;
  537. }
  538. unordered_map<int, int> LevelGenerate::findUnfilledInStorages( unordered_map<int,tuple<int,int>>& jewStorages)
  539. {
  540. unordered_map<int, int> res ;
  541. for(auto itj = jewStorages.begin();itj!=jewStorages.end();++itj) {
  542. int stor = std::get<1>(itj->second) ;
  543. int jid = itj->first ;
  544. if( stor>0 ) {
  545. res[jid] = stor ;
  546. std::get<1>(itj->second) = 0 ;
  547. }
  548. }
  549. return res ;
  550. }
  551. void LevelGenerate::regroupPlateLyrFillResults(
  552. vector<tuple<int,int,vector<FillResult>,int>>& pidlyrFillMvidArray,
  553. vector<PlateFillResult>& results)
  554. {
  555. int currLayer = 1 ;//从底层到顶层构建结果数据结构
  556. int num = pidlyrFillMvidArray.size() ;
  557. int nloop = num ;
  558. while( nloop > 0 ) {
  559. //cout<<"regroup for layer "<<currLayer<<endl;
  560. for( auto itlyr = pidlyrFillMvidArray.begin(); itlyr!=pidlyrFillMvidArray.end(); ++ itlyr ) {
  561. int pid = std::get<0>( *itlyr ) ;
  562. int lyr = std::get<1>( *itlyr ) ;
  563. vector<FillResult>& frs = std::get<2>(*itlyr) ;
  564. int moveId = std::get<3>(*itlyr) ;
  565. if(pid>=0) {
  566. if( lyr==currLayer ) {
  567. if( lyr==1 ) {
  568. vector<vector<FillResult>> frArr = {frs} ;
  569. PlateFillResult pfr ;
  570. pfr._layersFillResults = frArr ;
  571. pfr._moveId = moveId ;
  572. pfr._plateTypeId = pid ;
  573. results.push_back( pfr ) ;
  574. num-- ;
  575. std::get<0>( *itlyr ) = -1 ;
  576. }else {
  577. for(auto itPfr = results.begin();itPfr!=results.end();++itPfr ) {
  578. int pidr = itPfr->_plateTypeId ;
  579. int mvid = itPfr->_moveId ;
  580. vector<vector<FillResult>>& frArr = itPfr->_layersFillResults ;
  581. if( pidr == pid && mvid == moveId && frArr.size()==currLayer-1 ) {
  582. frArr.push_back(frs);
  583. num-- ;
  584. std::get<0>( *itlyr ) = -1 ;
  585. break ;
  586. }
  587. }
  588. }
  589. }
  590. }
  591. }
  592. currLayer++ ;
  593. if( num==0 ) break ;
  594. nloop--;
  595. }
  596. //cout<<"last plate lyr num "<<num<<endl;
  597. }
  598. void LevelGenerate::placePlates(const bool movable,
  599. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  600. const vector<PlateFillResult>& plateFRArr,
  601. vector<ContourData::Point>& resultPlateCenterPointArr )
  602. {
  603. GridPositionTool gpt ;
  604. vector<int> plateIdArr ;
  605. vector<int> moveIdArr ;
  606. for(int ip = 0 ; ip < plateFRArr.size(); ++ ip ) {
  607. plateIdArr.push_back( plateFRArr[ip]._plateTypeId ) ;
  608. moveIdArr.push_back( plateFRArr[ip]._moveId ) ;
  609. }
  610. vector<vector<int>> resPosis ;
  611. string firstMoveTypeCode = "" ;
  612. string secondMoveTypeCode = "" ;
  613. if( movable ) {
  614. firstMoveTypeCode = mulMoveConfig->_first->_type[0] ;
  615. if( mulMoveConfig->_second ) secondMoveTypeCode = mulMoveConfig->_second->_type[0] ;
  616. }
  617. gpt.solve(movable,
  618. firstMoveTypeCode ,
  619. secondMoveTypeCode,
  620. plateIdArr,
  621. moveIdArr,
  622. resPosis //这里结果是盘子左下角坐标,下面需要转换成中心坐标。
  623. ) ;
  624. for(int ip=0;ip<resPosis.size();++ip ) {
  625. FillGlobalConfig::PlateItem* platePtr = FillGlobalConfig::getInstance()->getPlateItemById(plateIdArr[ip]) ;
  626. resultPlateCenterPointArr.push_back( { (float)resPosis[ip][0]+platePtr->_bbwid/2 , (float)resPosis[ip][1]+platePtr->_bbhei/2} ) ;
  627. }
  628. }
  629. vector<LevelGenerate::PlateIdAndLayerCnt>
  630. LevelGenerate::generatePlateTypeAndLayerCntsForMovablePlates(
  631. const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
  632. const int totEquvSmallJewelCnt,
  633. int& retResidueEquvSmlJewelCnt )
  634. {
  635. vector<LevelGenerate::PlateIdAndLayerCnt> results ;
  636. retResidueEquvSmlJewelCnt = totEquvSmallJewelCnt ;
  637. FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
  638. FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
  639. FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
  640. FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
  641. FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
  642. const int MAX_MOVE_CONFIG_CNT = 2;
  643. FillGlobalConfig::MoveConfig* arr[MAX_MOVE_CONFIG_CNT] = { mulMoveConfig->_first , mulMoveConfig->_second } ;
  644. for(int ii = 0 ; ii < MAX_MOVE_CONFIG_CNT ; ++ ii ) {
  645. FillGlobalConfig::MoveConfig* moveConfig = arr[ii] ;
  646. if( moveConfig==nullptr ) continue ;
  647. //中盘子横
  648. for(int imid = 0 ; imid < moveConfig->_midPlateCntH ; ++ imid ) {
  649. PlateIdAndLayerCnt palc ;
  650. palc._layerCnt = moveConfig->_nLayer ;
  651. palc._plateId = midPlateH->_id ;
  652. palc._moveId = ii+1 ;//第一行为1,第二行为2
  653. results.push_back(palc) ;
  654. retResidueEquvSmlJewelCnt -= midPlateH->_bigJewCap*4*palc._layerCnt ;
  655. }
  656. //中盘子竖
  657. for(int imid = 0 ; imid < moveConfig->_midPlateCntV ; ++ imid ) {
  658. PlateIdAndLayerCnt palc ;
  659. palc._layerCnt = moveConfig->_nLayer ;
  660. palc._plateId = midPlateV->_id ;
  661. palc._moveId = ii+1 ;
  662. results.push_back(palc) ;
  663. retResidueEquvSmlJewelCnt -= midPlateV->_bigJewCap*4*palc._layerCnt ;
  664. }
  665. //大盘子横
  666. for(int ibig = 0 ; ibig < moveConfig->_bigPlateCntH ; ++ ibig ) {
  667. PlateIdAndLayerCnt palc ;
  668. palc._layerCnt = moveConfig->_nLayer ;
  669. palc._plateId = bigPlateH->_id ;
  670. palc._moveId = ii+1 ;
  671. results.push_back(palc) ;
  672. retResidueEquvSmlJewelCnt -= bigPlateH->_bigJewCap*4*palc._layerCnt ;
  673. }
  674. //大盘子竖
  675. for(int ibig = 0 ; ibig < moveConfig->_bigPlateCntV ; ++ ibig ) {
  676. PlateIdAndLayerCnt palc ;
  677. palc._layerCnt = moveConfig->_nLayer ;
  678. palc._plateId = bigPlateV->_id ;
  679. palc._moveId = ii+1 ;
  680. results.push_back(palc) ;
  681. retResidueEquvSmlJewelCnt -= bigPlateV->_bigJewCap*4*palc._layerCnt ;
  682. }
  683. }
  684. return results ;
  685. }
  686. void LevelGenerate::computePlateCount(const FillGlobalConfig::MultiMoveConfig* mmc ,int& retBigPlateCnt, int& retMidPlateCnt )
  687. {
  688. if( mmc==nullptr ) {
  689. retBigPlateCnt = 9 ;
  690. retMidPlateCnt = 0 ;
  691. }else
  692. if( mmc->_first && mmc->_second ) {
  693. if( mmc->_first->_type.find("A") != string::npos && mmc->_second->_type.find("A") != string::npos ) {
  694. retBigPlateCnt = 6 ;
  695. retMidPlateCnt = 8 ;
  696. }else if( mmc->_first->_type.find("B") != string::npos && mmc->_second->_type.find("B") != string::npos ) {
  697. retBigPlateCnt = 9 ;
  698. retMidPlateCnt = 0 ;
  699. }else if( mmc->_first->_type.find("C") != string::npos && mmc->_second->_type.find("C") != string::npos ) {
  700. retBigPlateCnt = 11 ;
  701. retMidPlateCnt = 0 ;
  702. }else if( mmc->_first->_type.find("B") != string::npos && mmc->_second->_type.find("A") != string::npos) {
  703. retBigPlateCnt = 6 ;
  704. retMidPlateCnt = 7 ;
  705. }else if( mmc->_first->_type.find("C") != string::npos && mmc->_second->_type.find("B") != string::npos ) {
  706. retBigPlateCnt = 10 ;
  707. retMidPlateCnt = 0 ;
  708. }else if( mmc->_first->_type.find("C") != string::npos && mmc->_second->_type.find("A") != string::npos ) {
  709. retBigPlateCnt = 7 ;
  710. retMidPlateCnt = 7 ;
  711. }
  712. }else if( mmc->_first && mmc->_second==nullptr ) {
  713. if( mmc->_first->_type.find("A") != string::npos ) {
  714. retBigPlateCnt = 6 ;
  715. retMidPlateCnt = 7 ;
  716. }else if( mmc->_first->_type.find("B") != string::npos ) {
  717. retBigPlateCnt = 9 ;
  718. retMidPlateCnt = 0 ;
  719. }else if( mmc->_first->_type.find("C") != string::npos ) {
  720. retBigPlateCnt = 10 ;
  721. retMidPlateCnt = 0 ;
  722. }
  723. }else {
  724. retBigPlateCnt = 9 ;
  725. retMidPlateCnt = 0 ;
  726. }
  727. }