LevelGenerate.cpp 58 KB

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