12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196 |
- //
- // LevelGenerate.cpp
- // auto_fill_jewel_v3
- //
- // Created by Red on 2024/11/23.
- //
- #include "LevelGenerate.hpp"
- #include <iostream>
- #include <cassert>
- #include <unordered_map>
- #include "FillGlobalConfig.hpp"
- #include <tuple>
- #include "BoxPositionTool.hpp"
- #include "GridPositionTool.hpp"
- //#include "LevelThumbTool.hpp"
- #include "LevelOutputWriter.hpp"
- #define MOVEID_NO_MOVE 0
- #define MOVEID_1ST_LINE 1
- #define MOVEID_2ND_LINE 2
- using namespace std;
- void LevelGenerate::generateAll(FillGlobalConfig::LevelData levelData, string outname)
- {
- cout<<"debug level "<<levelData._id<<" subid "<<levelData._subId<<endl;
- auto fgc = FillGlobalConfig::getInstance() ;
- fgc->clearGridBoxFilledStatus() ;//每次填充盘子前必须清空盘子占位情况
- vector<PlateFillResult> resultPlateFRs ;
- vector<ContourData::Point> resultPlateCenterPosiArr ;
- generate(levelData, false, nullptr , resultPlateFRs, resultPlateCenterPosiArr) ;
- //输出结果
- string pngName0 = outname + "_000000.png" ;
- // LevelThumbTool ltt ;
- // ltt.makeThumb3(pngName0, resultPlateFRs, resultPlateCenterPosiArr) ;
- string jsonName = outname + "_000000.json" ;
- LevelOutputWriter out ;
- out.writeLevelJson(resultPlateFRs, resultPlateCenterPosiArr, jsonName) ;
-
- //对于所有移动的配置
- vector<FillGlobalConfig::MultiMoveConfig> mmcArr = fgc->getAllMoveConfigByJewels(levelData) ;
- for(int im=0;im < mmcArr.size();++ im ) {
- string moveName = mmcArr[im]._first->_type ;
- if( mmcArr[im]._second ) moveName += mmcArr[im]._second->_type ;
- else moveName += "00" ;
- cout<<"debug moveName "<<moveName<<endl;
- fgc->clearGridBoxFilledStatus() ;//每次填充盘子前必须清空盘子占位情况
- vector<PlateFillResult> resultPlateFRs1 ;
- vector<ContourData::Point> resultPlateCenterPosiArr1 ;
- generate(levelData, true, &mmcArr[im] , resultPlateFRs1, resultPlateCenterPosiArr1) ;
- //输出结果
- string pngName1 = outname + "_" + moveName;
- pngName1 += ".png" ;
- // ltt.makeThumb3(pngName1, resultPlateFRs1, resultPlateCenterPosiArr1) ;
-
- string jsonName1 = outname + "_" + moveName + ".json" ;
- LevelOutputWriter out1 ;
- out1.writeLevelJson(resultPlateFRs1, resultPlateCenterPosiArr1, jsonName1);
- }
-
-
- }
- bool LevelGenerate::generate( FillGlobalConfig::LevelData levelData,
- const bool isMovable,
- const FillGlobalConfig::MultiMoveConfig* mulMoveConfig , //移动盘子配置,如果isMovable为false,这个参数忽略,可以传入nullptr
- vector<PlateFillResult>& resultPlateFillResults,
- vector<ContourData::Point>& resultPlateCenterPointArr
- )
- {
- resultPlateFillResults.clear() ;
- resultPlateCenterPointArr.clear() ;
-
- auto ms0 = std::chrono::system_clock::now().time_since_epoch() ;
- uint64_t ms00 = std::chrono::duration_cast<chrono::milliseconds>(ms0).count() ;
-
- srand(_seed);
- unordered_map<int,tuple<int,int> > jewIdSzCntStorageMap ;// unordered_map<宝石ID,tuple<尺寸,库存数量> >
- FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
- int bigJewelCnt = 0 ;
- int midJewelCnt = 0;
- int smlJewelCnt = 0 ;
- for(int ij = 0 ; ij < levelData._jewelIds.size();++ ij ) {
- int jewId = levelData._jewelIds[ij] ;
- int cnt = levelData._cnts[ij] ;
- FillGlobalConfig::JewelItem* jewItem = fgc->getJewelItemById(jewId) ;
- jewIdSzCntStorageMap[jewId] = {jewItem->_size,cnt} ;
- if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_SM ) {
- smlJewelCnt+=cnt ;
- }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_MD ) {
- midJewelCnt += cnt ;
- }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_LG ) {
- bigJewelCnt += cnt ;
- }
- }
- //每个盘子类型小号宝石承载量
- //按顺序分别为大和中
- FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
- FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
- FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
- FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
-
- //FillGlobalConfig::PlateItem* smlPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_SM, 0) ;
- vector<FillGlobalConfig::PlateItem*> usedPlates = {bigPlateH,midPlateH,bigPlateV,midPlateV} ;//{bigPlate,midPlate,smlPlate} ;
- int maxSmlJewCapPerPlate = 0;
- int minSmlJewCapPerPlate = 99999 ;
- for(int ip=0;ip<usedPlates.size();++ip ) {
- maxSmlJewCapPerPlate = fmax( usedPlates[ip]->_bigJewCap*4 , maxSmlJewCapPerPlate) ;
- minSmlJewCapPerPlate = fmin( usedPlates[ip]->_bigJewCap*4 , minSmlJewCapPerPlate) ;
- }
- //等效小宝石数量
- int effSmallJewelsCount = bigJewelCnt*4 + midJewelCnt*2 + smlJewelCnt ;
- //cout<<"bigJewelCnt "<<bigJewelCnt<<endl;
- //cout<<"midJewelCnt "<<midJewelCnt<<endl;
- //cout<<"smlJewelCnt "<<smlJewelCnt<<endl;
- //cout<<"effSmallJewelsCount "<<effSmallJewelsCount<<endl;
-
- //构建符合难度条件的盘子和层数组合(包括可移动的盘子)
- vector<PlateIdAndLayerCnt> resPlateNLyrCnt = generatePlateTypeAndLayerCnts2(isMovable, mulMoveConfig, levelData._difficulty,effSmallJewelsCount);
- if( resPlateNLyrCnt.size()==0 ) {
- //cout<<"failed at generatePlateTypeAndLayerCnts"<<endl;
- return false ;
- }
-
- //计算盘子的最大层数
- int maxLyrCnt = 0;
- for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it ) maxLyrCnt=fmax(maxLyrCnt,it->_layerCnt) ;
-
- //对每个盘子组合进行填充宝石
- RandomGridFiller filler ;
- filler._seed = this->_seed ;
- srand(filler._seed);
-
- //构建每个盘子每个层的填充结果容器
- vector< tuple<int,int,vector<FillResult>,int> > plateIdLyrFillResultsMoveIdArray ;// tuple<plateId, layerIndex, fillresults_array ,moveId>
-
-
- //从顶到底部,逐层进行填充
- int residues = 0 ;
- for(int nlayer = maxLyrCnt; nlayer > 0 ; nlayer-- ) {
- //cout<<"for layer "<<nlayer<<endl;
-
- //满足该层数的所有盘子ID
- vector<int> plateIdArr ;//临时符合当前层次的盘子类型ID
- vector<int> moveIdArr ;//临时保存对应盘子是否是可移动的,0-不可移动,1-第一移动行,2-第二移动行
- for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it )
- {
- if(it->_layerCnt>=nlayer) {
- plateIdArr.push_back(it->_plateId) ;
- moveIdArr.push_back( it->_moveId ) ;
- }
- }
-
- //该层总计需要填充多少小宝石
- int currLyrNeedEquvSmlCnt = 0 ;
- for(int ip=0;ip<plateIdArr.size();++ip ) {
- currLyrNeedEquvSmlCnt += fgc->getPlateItemById(plateIdArr[ip])->_bigJewCap*4 ;
- }
- //cout<<"layer need eqsmCnt "<<currLyrNeedEquvSmlCnt<<endl;
-
- //根据所需数量和所需求解百分比,计算从库存取出每类宝石多少个。
- float solPercent = 0.7 ;//根据需求文档,每层可解百分比都是70%.
- unordered_map<int, int> chosenJewIdNCnt = randPickJewels(currLyrNeedEquvSmlCnt, solPercent, jewIdSzCntStorageMap) ;
- int choseEqSmCnt=0;
- for(auto itp=chosenJewIdNCnt.begin();itp!=chosenJewIdNCnt.end();++itp) {
- choseEqSmCnt += jewSz2SmlCnt( fgc->getJewelItemById(itp->first)->_size) * itp->second ;
- }
- //cout<<"layer choose eqsmCnt "<<choseEqSmCnt<<endl;
-
- //逐个盘子填充
- for(int ipid = 0 ; ipid !=plateIdArr.size();++ipid) {
- int plateId1 = plateIdArr[ipid] ;
- int moveId1 = moveIdArr[ipid] ;
- vector<FillResult> fr = fillPlateOneLayer(filler, plateId1 , chosenJewIdNCnt) ;
- tuple<int,int,vector<FillResult>,int> plateLyrFillResult={plateId1 , nlayer , fr , moveId1 } ;
- plateIdLyrFillResultsMoveIdArray.push_back(plateLyrFillResult);
- }
-
- //检查为该层挑选的宝石是不是全部填完了,如果没有填完还要还给库存,给下一轮填充用
- residues = 0 ;
- for(auto itjn = chosenJewIdNCnt.begin();itjn!=chosenJewIdNCnt.end();++itjn){
- if( itjn->second>0 ) {
- residues+=itjn->second;
- std::get<1>(jewIdSzCntStorageMap[itjn->first]) += itjn->second ;//剩余的加回到库存里
- }
- }
- //cout<<"layer chosen jewels residues "<<residues<<endl;
- }
-
- //查看库存是否全部用掉了
- if( residues>0 ) {
- int extraPlateCnt = 0 ;
- //剩了,添加一个小盘子和层,仍然剩了再继续加盘子加层
- unordered_map<int, int> residueJewIdAndCnts = findUnfilledInStorages(jewIdSzCntStorageMap) ;
- while( residueJewIdAndCnts.size()>0 ) {
- //新建一个中盘子
- extraPlateCnt++;
- //cout<<"add extra plate "<< extraPlateCnt <<endl;
- int plateId = midPlateH->_id ;
- for(int ilyr = 1 ; ilyr <= maxLyrCnt; ++ ilyr ) {
- vector<FillResult> frs = fillPlateOneLayer(filler, plateId, residueJewIdAndCnts) ;
- plateIdLyrFillResultsMoveIdArray.push_back( {plateId,ilyr,frs, MOVEID_NO_MOVE } );
- //cout<<"add extra lyr "<<endl;
- if( residueJewIdAndCnts.size()==0 ) break ;
- }
- if( residueJewIdAndCnts.size()==0 ) break ;
- }
- }
-
- //整理数据
- regroupPlateLyrFillResults(plateIdLyrFillResultsMoveIdArray, resultPlateFillResults);
-
- //摆放盘子
- {
- placePlates(isMovable,mulMoveConfig, resultPlateFillResults, resultPlateCenterPointArr) ;
- }
-
-
- auto ms1 = std::chrono::system_clock::now().time_since_epoch() ;
- uint64_t ms11 = std::chrono::duration_cast<chrono::milliseconds>(ms1).count() ;
- //cout<<"duration "<<ms11-ms00<<endl;
- return true ;
- }
- bool LevelGenerate::generate_v2(
- const LevelInputData& indata,
- const LevelExtInputData& extdata,
- vector<PlateFillResult>& resultPlateFillResults,
- vector<ContourData::Point>& resultPlateCenterPointArr,
- string& error )
- {
- FillGlobalConfig::getInstance()->clearGridBoxFilledStatus() ;
- resultPlateFillResults.clear() ;
- resultPlateCenterPointArr.clear() ;
-
- auto ms0 = std::chrono::system_clock::now().time_since_epoch() ;
- uint64_t ms00 = std::chrono::duration_cast<chrono::milliseconds>(ms0).count() ;
-
- srand( extdata._seed );
- unordered_map<int,tuple<int,int> > jewIdSzCntStorageMap ;// unordered_map<宝石ID,tuple<尺寸,库存数量> >
- FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
- int bigJewelCnt = 0 ;
- int midJewelCnt = 0;
- int smlJewelCnt = 0 ;
- for(int ij = 0 ; ij < indata._jewels.size() ;++ ij ) {
- int jewId = indata._jewels[ij]._jewelId ;
- int cnt = indata._jewels[ij]._count ;
- FillGlobalConfig::JewelItem* jewItem = fgc->getJewelItemById(jewId) ;
- jewIdSzCntStorageMap[jewId] = {jewItem->_size,cnt} ;
- if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_SM ) {
- smlJewelCnt+=cnt ;
- }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_MD ) {
- midJewelCnt += cnt ;
- }else if( jewItem->_size == FILLGLOBALCONFIG_JEWELSIZE_LG ) {
- bigJewelCnt += cnt ;
- }
- }
- //每个盘子类型小号宝石承载量
- //按顺序分别为大和中
- FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
- FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
- FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
- FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
-
- //FillGlobalConfig::PlateItem* smlPlate = fgc->getPlateItemBySzNIndex(FILLGLOBALCONFIG_PLATESIZE_SM, 0) ;
- vector<FillGlobalConfig::PlateItem*> usedPlates = {bigPlateH,midPlateH,bigPlateV,midPlateV} ;//{bigPlate,midPlate,smlPlate} ;
- int maxSmlJewCapPerPlate = 0;
- int minSmlJewCapPerPlate = 99999 ;
- for(int ip=0;ip<usedPlates.size();++ip ) {
- maxSmlJewCapPerPlate = fmax( usedPlates[ip]->_bigJewCap*4 , maxSmlJewCapPerPlate) ;
- minSmlJewCapPerPlate = fmin( usedPlates[ip]->_bigJewCap*4 , minSmlJewCapPerPlate) ;
- }
- //等效小宝石数量
- int effSmallJewelsCount = bigJewelCnt*4 + midJewelCnt*2 + smlJewelCnt ;
- if( effSmallJewelsCount==0 ) {
- error = "equv small jewel count is zero." ;
- return false ;
- }
-
- //构建符合难度条件的盘子和层数组合(包括可移动的盘子)
- bool isMovable = (extdata._hasMovement==1)?true:false ;
- FillGlobalConfig::MultiMoveConfig* mulMoveConfigPtr = nullptr ;
- FillGlobalConfig::MultiMoveConfig mulMoveConfig;
- if( isMovable ) {
- vector<FillGlobalConfig::MoveConfig*> mc1arr = FillGlobalConfig::getInstance()->getMoveConfigDatasByTypeAndNLayers(extdata._firstMoveType, extdata._firstMoveLyrCnt) ;
- if( mc1arr.size()==0 ) {
- error = string("failed to get first move config data by move type '")+extdata._firstMoveType+"'." ;
- return false ;
- }
- mulMoveConfig._first = mc1arr[0] ;
- if( extdata._secondMoveType.compare("") != 0 ) {
- vector<FillGlobalConfig::MoveConfig*> mc2arr = FillGlobalConfig::getInstance()->getMoveConfigDatasByTypeAndNLayers(extdata._secondMoveType, extdata._secondMoveLyrCnt) ;
- if( mc2arr.size()==0 ) {
- error = string("failed to get second move config data by move type '")+extdata._secondMoveType+"'." ;
- return false ;
- }
- mulMoveConfig._second = mc2arr[0] ;
- }else{
- mulMoveConfig._second = nullptr ;
- }
- mulMoveConfigPtr = &mulMoveConfig;
- }
-
- vector<PlateIdAndLayerCnt> resPlateNLyrCnt = generatePlateTypeAndLayerCnts3(
- isMovable,
- mulMoveConfigPtr,
- indata._difficulty,
- effSmallJewelsCount,
- extdata
- );
- if( resPlateNLyrCnt.size()==0 ) {
- error = string("failed on generatePlateTypeAndLayerCnts3.") ;
- return false ;
- }
-
- //计算盘子的最大层数
- int maxLyrCnt = 0;
- for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it ) maxLyrCnt=fmax(maxLyrCnt,it->_layerCnt) ;
-
- //对每个盘子组合进行填充宝石
- RandomGridFiller filler ;
- filler._seed = extdata._seed ;
- srand(filler._seed);
-
- //构建每个盘子每个层的填充结果容器
- vector< tuple<int,int,vector<FillResult>,int> > plateIdLyrFillResultsMoveIdArray ;// tuple<plateId, layerIndex, fillresults_array ,moveId>
-
-
- //从顶到底部,逐层进行填充
- int residues = 0 ;
- for(int nlayer = maxLyrCnt; nlayer > 0 ; nlayer-- ) {
- //cout<<"for layer "<<nlayer<<endl;
-
- //满足该层数的所有盘子ID
- vector<int> plateIdArr ;//临时符合当前层次的盘子类型ID
- vector<int> moveIdArr ;//临时保存对应盘子是否是可移动的,0-不可移动,1-第一移动行,2-第二移动行
- for(auto it = resPlateNLyrCnt.begin();it!=resPlateNLyrCnt.end();++it )
- {
- if(it->_layerCnt>=nlayer) {
- plateIdArr.push_back(it->_plateId) ;
- moveIdArr.push_back( it->_moveId ) ;
- }
- }
-
- //该层总计需要填充多少小宝石
- int currLyrNeedEquvSmlCnt = 0 ;
- for(int ip=0;ip<plateIdArr.size();++ip ) {
- currLyrNeedEquvSmlCnt += fgc->getPlateItemById(plateIdArr[ip])->_bigJewCap*4 ;
- }
- //cout<<"layer need eqsmCnt "<<currLyrNeedEquvSmlCnt<<endl;
-
- //根据所需数量和所需求解百分比,计算从库存取出每类宝石多少个。
- float solPercent = 0.7 ;//根据需求文档,每层可解百分比都是70%.
- unordered_map<int, int> chosenJewIdNCnt = randPickJewels(currLyrNeedEquvSmlCnt, solPercent, jewIdSzCntStorageMap) ;
- int choseEqSmCnt=0;
- for(auto itp=chosenJewIdNCnt.begin();itp!=chosenJewIdNCnt.end();++itp) {
- choseEqSmCnt += jewSz2SmlCnt( fgc->getJewelItemById(itp->first)->_size) * itp->second ;
- }
- //cout<<"layer choose eqsmCnt "<<choseEqSmCnt<<endl;
-
- //逐个盘子填充
- for(int ipid = 0 ; ipid !=plateIdArr.size();++ipid) {
- int plateId1 = plateIdArr[ipid] ;
- int moveId1 = moveIdArr[ipid] ;
- vector<FillResult> fr = fillPlateOneLayer(filler, plateId1 , chosenJewIdNCnt) ;
- tuple<int,int,vector<FillResult>,int> plateLyrFillResult={plateId1 , nlayer , fr , moveId1 } ;
- plateIdLyrFillResultsMoveIdArray.push_back(plateLyrFillResult);
- }
-
- //检查为该层挑选的宝石是不是全部填完了,如果没有填完还要还给库存,给下一轮填充用
- residues = 0 ;
- for(auto itjn = chosenJewIdNCnt.begin();itjn!=chosenJewIdNCnt.end();++itjn){
- if( itjn->second>0 ) {
- residues+=itjn->second;
- std::get<1>(jewIdSzCntStorageMap[itjn->first]) += itjn->second ;//剩余的加回到库存里
- }
- }
- //cout<<"layer chosen jewels residues "<<residues<<endl;
- }
-
- //查看库存是否全部用掉了
- if( residues>0 ) {
- int extraPlateCnt = 0 ;
- //剩了,添加一个小盘子和层,仍然剩了再继续加盘子加层
- unordered_map<int, int> residueJewIdAndCnts = findUnfilledInStorages(jewIdSzCntStorageMap) ;
- while( residueJewIdAndCnts.size()>0 ) {
- //新建一个中盘子
- extraPlateCnt++;
- //cout<<"add extra plate "<< extraPlateCnt <<endl;
- int plateId = midPlateH->_id ;
- for(int ilyr = 1 ; ilyr <= maxLyrCnt; ++ ilyr ) {
- vector<FillResult> frs = fillPlateOneLayer(filler, plateId, residueJewIdAndCnts) ;
- plateIdLyrFillResultsMoveIdArray.push_back( {plateId,ilyr,frs, MOVEID_NO_MOVE } );
- //cout<<"add extra lyr "<<endl;
- if( residueJewIdAndCnts.size()==0 ) break ;
- }
- if( residueJewIdAndCnts.size()==0 ) break ;
- }
- }
- //整理数据
- regroupPlateLyrFillResults(plateIdLyrFillResultsMoveIdArray, resultPlateFillResults);
- //摆放盘子
- {
- placePlates(isMovable,mulMoveConfigPtr, resultPlateFillResults, resultPlateCenterPointArr) ;
- }
- auto ms1 = std::chrono::system_clock::now().time_since_epoch() ;
- uint64_t ms11 = std::chrono::duration_cast<chrono::milliseconds>(ms1).count() ;
- cout<<"duration(ms): "<<ms11-ms00<<endl;
- return true ;
- }
- // this method is deprecated, use generatePlateTypeAndLayerCnts2()
- [[deprecated]]
- vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts(const int difficulty,const int totEquvSmallJewelCnt)
- {
- vector<LevelGenerate::PlateIdAndLayerCnt> results ;
- //...
- //...
- return results ;
- }
- //考虑可移动关卡的条件
- vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts2(
- const bool isMovable,
- const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
- const int difficulty,
- const int totEquvSmallJewelCnt
- )
- {
- //如果是移动关卡,那么至少需要保证如下等价小盘子数量,如果减少层数仍然不能满足那么就有几个盘子输出几个
- //const int MAX_LG_PLATE_CNT = 9 ;// + (isMovable?1:0) ;
- // const int MAX_SM_PLATE_CNT = MAX_LG_PLATE_CNT*4 ;
- //const int MAX_SM_JEWEL_CNT_PER_LAYER = MAX_LG_PLATE_CNT * 24 ;
- const int MID_PLATE_CAP = 12 ;//中盘子对小宝石的容量
-
- //const int minEquaSmPlateCntForMovable = 16 ; //
- //const int smPlateEquaSmJewelCnt = 6 ;// 小盘子装1.5个大,3个中,6个小
-
- //一个关卡最多出现大、中、小盘子个数
- int tempBigPlateCnt1 = 9 ;// 1个大盘子=2两个中盘子
- int tempMidPlateCnt1 = 0 ;
- computePlateCount(mulMoveConfig, tempBigPlateCnt1, tempMidPlateCnt1) ;
- int midPlateMaxCnt = tempBigPlateCnt1 * 2 + tempMidPlateCnt1 ;//大盘子数量换算成中盘子
-
-
- FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
- FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
- FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
- FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
- FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
-
- //如果是移动关卡,先构建移动盘子
- int totEquvSmallJewelCnt2 = totEquvSmallJewelCnt ;
- vector<LevelGenerate::PlateIdAndLayerCnt> results ;
- //剩余可以用的中盘子个数
- if( isMovable ) {
- int residueEquvSmlJewelCnt = 0 ;
- results = generatePlateTypeAndLayerCntsForMovablePlates(mulMoveConfig, totEquvSmallJewelCnt2, residueEquvSmlJewelCnt) ;
- totEquvSmallJewelCnt2 = residueEquvSmlJewelCnt ;
- //减去移动的盘子
- for(int ir = 0 ; ir < results.size(); ++ ir ){
- if( fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_LG ) {
- midPlateMaxCnt-=2 ;//减去移动的盘子
- }else if(fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_MD) {
- midPlateMaxCnt-=1 ;//减去移动的盘子
- }
- }
- }
-
- int equvMidPlateCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / MID_PLATE_CAP) ; // 本关需要多少个一层中盘子的总数量
- int layerCnt0 = 1 ;//盘子层数下限
- int layerCnt1 = 1 ;//盘子层数上限
-
- //计算可能的层取值范围
- {
- layerCnt0 = fmax(1 , totEquvSmallJewelCnt2 / (midPlateMaxCnt*MID_PLATE_CAP) ) ;
- if( layerCnt0<3 ) layerCnt1 = 3 ;
- else layerCnt1 = layerCnt0 + 1 ;
- }
-
- int bigPlateCnt0 = totEquvSmallJewelCnt2 * 1.0 / layerCnt1 / 24 ; //大盘子最少需要数量
- int bigPlateCnt1 = totEquvSmallJewelCnt2 * 1.0 / layerCnt0 / 24 + 1; //大盘子最多需要数量
- int midPlateCnt0 = bigPlateCnt0*2 ;
- int midPlateCnt1 = bigPlateCnt1*2 ;
-
- bigPlateCnt1 = fmin( midPlateMaxCnt/2 ,bigPlateCnt1 ) ;
- midPlateCnt1 = fmin( midPlateMaxCnt ,midPlateCnt1 ) ;
-
- bool findFirstAvailableComb = false ;//第一个完全放入宝石的组合,用于当不满足任何条件时,至少返回一个可装入全部宝石的默认方案
- vector<vector<LevelGenerate::PlateIdAndLayerCnt>> possibleResults ;//满足全部百分比要求的组合
- vector<LevelGenerate::PlateIdAndLayerCnt> firstAvailablePlateComb ;//第一个满足全部宝石填充的组合,如果需要移动还要考虑最小移动盘子个数的条件
- int firstAvailableLyrCnt = 0 ;
-
- //难度对盘子数量的限制 普通 难 极难
- vector< vector<float> > hardPlateCntPercent0 = { {0.3,0.3}, {0.2,0.4}, {0.1,0.5} } ;
- vector< vector<float> > hardPlateCntPercent1 = { {0.7,0.7}, {0.6,0.8}, {0.5,0.9} } ;
-
- //穷举全部盘子和层的组合找到符合条件的组合
- for(int ibig = 0; ibig <= bigPlateCnt1; ++ ibig ) {
- for(int imid = 0; imid <= midPlateCnt1 ; ++ imid ) {
- int currEquvMidPlateCnt = imid+ibig*2 ;
- if( currEquvMidPlateCnt==0 || currEquvMidPlateCnt > midPlateMaxCnt ) continue ;
-
- float bigPlateCntPercent = ibig*2.0 / currEquvMidPlateCnt ;
- float midPlateCntPercent = imid*1.0 / currEquvMidPlateCnt ;
- vector<float> percentArr = {bigPlateCntPercent,midPlateCntPercent} ;
- //判断每个盘子百分比是否满足难度要求
- bool percentOk = true ;
- for(int iplatetype=0;iplatetype<percentArr.size();++iplatetype) {
- if( hardPlateCntPercent0[difficulty][iplatetype]>percentArr[iplatetype] || hardPlateCntPercent1[difficulty][iplatetype]<percentArr[iplatetype] )
- percentOk=false;
- }
- if( findFirstAvailableComb == true ){
- //至少有一个装下宝石的方案了
- if( !percentOk ) continue ;//盘子百分比不符合要求,跳过
- }
-
- if( findFirstAvailableComb==false || (findFirstAvailableComb && firstAvailableLyrCnt>3 ) ) {
- //保证至少有一个可以满足宝石的盘子组合,优先保存总层数大于3的情况
- //当前盘子组合下最小满足的层数
- int upperLyrCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / (currEquvMidPlateCnt*MID_PLATE_CAP) ) ;
- bool upperLyrCntOk = true ;
- if( findFirstAvailableComb ) {
- if( upperLyrCnt >= firstAvailableLyrCnt ) {
- upperLyrCntOk = false ;
- }
- }
- vector<int> pidArr ;
- vector<int> capArr ;
- vector<int> lyrArr ;
- //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
- for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
- for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
- bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if( lyrOk==false && upperLyrCnt>1 ) {
- for(int it=0;it<lyrArr.size();++it ) {
- lyrArr[it] -= 1 ;
- lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if( lyrOk ) break ;
- }
- }
- if( lyrOk && upperLyrCntOk ){
- findFirstAvailableComb = true ;
- firstAvailableLyrCnt = upperLyrCnt ;
- //保存结果
- firstAvailablePlateComb.resize(capArr.size());
- for(int it = 0 ; it < capArr.size(); ++ it ) {
- firstAvailablePlateComb[it]._plateId = pidArr[it] ;
- firstAvailablePlateComb[it]._layerCnt = lyrArr[it] ;
- firstAvailablePlateComb[it]._moveId = MOVEID_NO_MOVE ;
- }
- }
- }
- //计算每个类型的层数
- if( difficulty== FILLGLOBALCONFIG_DIFFCULTY_NORM ) {
- //全部两层
- vector<int> pidArr ;
- vector<int> capArr ;
- vector<int> lyrArr ;
- //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
- for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(2); }
- for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(2); }
- bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if(!lyrOk) continue;
-
- //保存结果
- vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
- for(int it = 0 ; it < capArr.size(); ++ it ) {
- tres[it]._plateId = pidArr[it] ;
- tres[it]._layerCnt = lyrArr[it] ;
- tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
- }
- possibleResults.push_back(tres) ;
-
- }else if( difficulty==FILLGLOBALCONFIG_DIFFCULTY_HARD2 ) {
- //全部3层
- vector<int> pidArr ;
- vector<int> capArr ;
- vector<int> lyrArr ;
- //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
- for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(3); }
- for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(3); }
- //cout<<"debug big "<<ibig<<" mid "<<imid<<" sml "<<isml<<endl;
- bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if(!lyrOk) continue;
- //保存结果
- vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
- for(int it = 0 ; it < capArr.size(); ++ it ) {
- tres[it]._plateId = pidArr[it] ;
- tres[it]._layerCnt = lyrArr[it] ;
- tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
- }
- possibleResults.push_back(tres) ;
- }else{
- //50% 2层, 50% 3层
- vector<int> pidArr ;
- vector<int> capArr ;
- vector<int> lyrArr ;
- //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
- 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); }
- 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); }
- bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if(!lyrOk) continue;
- //保存结果
- vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
- for(int it = 0 ; it < capArr.size(); ++ it ) {
- tres[it]._plateId = pidArr[it] ;
- tres[it]._layerCnt = lyrArr[it] ;
- tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
- }
- possibleResults.push_back(tres) ;
- }
- }
- }
- //随机挑选一个结果返回
- if( possibleResults.size()> 0 ) {
- int randindex = rand() % possibleResults.size();
- for(int ip = 0 ; ip < possibleResults[randindex].size();++ ip ) {
- results.push_back(possibleResults[randindex][ip]) ;
- }
- }else {
- for(int ip = 0 ; ip < firstAvailablePlateComb.size();++ ip ) {
- results.push_back(firstAvailablePlateComb[ip]) ;
- }
- }
- return results ;//
-
- }
- vector<LevelGenerate::PlateIdAndLayerCnt> LevelGenerate::generatePlateTypeAndLayerCnts3(
- const bool isMovable,
- const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
- const int difficulty,
- const int totEquvSmallJewelCnt,
- const LevelExtInputData& extdata )
- {
- const int MID_PLATE_CAP = 12 ;//中盘子对小宝石的容量
- //一个关卡最多出现大、中个数
- int tempBigPlateCnt1 = 9 ;// 1个大盘子=2两个中盘子
- int tempMidPlateCnt1 = 0 ;
- computePlateCount(mulMoveConfig, tempBigPlateCnt1, tempMidPlateCnt1) ;
- int equvMidPlateMaxCnt = tempBigPlateCnt1 * 2 + tempMidPlateCnt1 ;//大盘子数量换算成中盘子
-
- FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
- FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
- FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
- FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
- FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
-
- //如果是移动关卡,先构建移动盘子
- int totEquvSmallJewelCnt2 = totEquvSmallJewelCnt ;
- vector<LevelGenerate::PlateIdAndLayerCnt> results ;
- //剩余可以用的中盘子个数
- if( isMovable ) {
- int residueEquvSmlJewelCnt = 0 ;
- results = generatePlateTypeAndLayerCntsForMovablePlates(mulMoveConfig, totEquvSmallJewelCnt2, residueEquvSmlJewelCnt) ;
- totEquvSmallJewelCnt2 = residueEquvSmlJewelCnt ;
- //减去移动的盘子
- for(int ir = 0 ; ir < results.size(); ++ ir ){
- if( fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_LG ) {
- equvMidPlateMaxCnt-=2 ;//减去移动的盘子
- }else if(fgc->getPlateItemById(results[ir]._plateId)->_size == FILLGLOBALCONFIG_PLATESIZE_MD) {
- equvMidPlateMaxCnt-=1 ;//减去移动的盘子
- }
- }
- }
-
- // 本关需要多少个一层中盘子的总数量,
- // 已经去掉了移动盘子所用的宝石(如果有移动盘子的话)
- int equvMidPlateCntOneLyr = ceil( totEquvSmallJewelCnt2 * 1.0 / MID_PLATE_CAP) ;
- int bigPlateCntL1 = 0 ;
- int midPlateCntL1 = equvMidPlateCntOneLyr ;
- if( extdata._bigPlatePercent > 0 ) {
- float bigPercent = extdata._bigPlatePercent*1.0/(extdata._bigPlatePercent+extdata._midPlatePercent) ;
- float midPercent = 1.0 - bigPercent ;
- bigPlateCntL1 = ceil( equvMidPlateCntOneLyr * 1.0 / (2.0+midPercent/bigPercent) ) ;
- midPlateCntL1 = fmax(0, equvMidPlateCntOneLyr - bigPlateCntL1*2 ) ;
- }
-
- int layerCnt0 = 1 ;//盘子层数下限
- int layerCnt1 = 3 ;//盘子层数上限
- //计算可能的层取值范围
- {
- layerCnt0 = fmax(1 , totEquvSmallJewelCnt2 / (equvMidPlateCntOneLyr*MID_PLATE_CAP) ) ;
- if( layerCnt0<3 ) layerCnt1 = 3 ;
- else layerCnt1 = layerCnt0 + 1 ;
- }
-
- int bigPlateCnt0 = bigPlateCntL1 * 1.0 / layerCnt1 ; //大盘子最少需要数量
- int bigPlateCnt1 = bigPlateCntL1 * 1.0 / layerCnt0 + 1; //大盘子最多需要数量
- int midPlateCnt0 = midPlateCntL1*1.0/layerCnt1 ;
- int midPlateCnt1 = midPlateCntL1*1.0/layerCnt0 + 1 ;
-
- bool findFirstAvailableComb = false ;//第一个完全放入宝石的组合,用于当不满足任何条件时,至少返回一个可装入全部宝石的默认方案
- vector<vector<LevelGenerate::PlateIdAndLayerCnt>> possibleResults ;//满足全部百分比要求的组合
- vector<LevelGenerate::PlateIdAndLayerCnt> firstAvailablePlateComb ;//第一个满足全部宝石填充的组合,如果需要移动还要考虑最小移动盘子个数的条件
- int firstAvailableLyrCnt = 0 ;
-
- //难度对盘子数量的限制 普通 难 极难
- //vector< vector<float> > hardPlateCntPercent0 = { {0.3,0.3}, {0.2,0.4}, {0.1,0.5} } ;
- //vector< vector<float> > hardPlateCntPercent1 = { {0.7,0.7}, {0.6,0.8}, {0.5,0.9} } ;
- //这个数据不需要了,通过extdata中直接获取这个数据。
-
- //穷举全部盘子和层的组合找到符合条件的组合
- for(int ibig = bigPlateCnt0; ibig <= bigPlateCnt1; ++ ibig ) {
- for(int imid = midPlateCnt0; imid <= midPlateCnt1 ; ++ imid ) {
- int currEquvMidPlateCnt = imid+ibig*2 ;
- if( currEquvMidPlateCnt==0 ) continue ;
-
- if( findFirstAvailableComb==false || (findFirstAvailableComb && firstAvailableLyrCnt>3 ) ) {
- //保证至少有一个可以满足宝石的盘子组合,优先保存总层数大于3的情况
- //当前盘子组合下最小满足的层数
- int upperLyrCnt = ceil( totEquvSmallJewelCnt2 * 1.0 / (currEquvMidPlateCnt*MID_PLATE_CAP) ) ;
- bool upperLyrCntOk = true ;
- if( findFirstAvailableComb ) {
- if( upperLyrCnt >= firstAvailableLyrCnt ) {
- upperLyrCntOk = false ;
- }
- }
- vector<int> pidArr ;
- vector<int> capArr ;
- vector<int> lyrArr ;
- //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
- for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
- for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(upperLyrCnt); }
- bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if( lyrOk==false && upperLyrCnt>1 ) {
- for(int it=0;it<lyrArr.size();++it ) {
- lyrArr[it] -= 1 ;
- lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if( lyrOk ) break ;
- }
- }
- if( lyrOk && upperLyrCntOk ){
- findFirstAvailableComb = true ;
- firstAvailableLyrCnt = upperLyrCnt ;
- //保存结果
- firstAvailablePlateComb.resize(capArr.size());
- for(int it = 0 ; it < capArr.size(); ++ it ) {
- firstAvailablePlateComb[it]._plateId = pidArr[it] ;
- firstAvailablePlateComb[it]._layerCnt = lyrArr[it] ;
- firstAvailablePlateComb[it]._moveId = MOVEID_NO_MOVE ;
- }
- }
- }
- //计算每个类型的层数
- if( difficulty== FILLGLOBALCONFIG_DIFFCULTY_NORM ) {
- //全部两层
- vector<int> pidArr ;
- vector<int> capArr ;
- vector<int> lyrArr ;
- //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
- for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(2); }
- for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(2); }
- bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if(!lyrOk) continue;
-
- //保存结果
- vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
- for(int it = 0 ; it < capArr.size(); ++ it ) {
- tres[it]._plateId = pidArr[it] ;
- tres[it]._layerCnt = lyrArr[it] ;
- tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
- }
- possibleResults.push_back(tres) ;
-
- }else if( difficulty==FILLGLOBALCONFIG_DIFFCULTY_HARD2 ) {
- //全部3层
- vector<int> pidArr ;
- vector<int> capArr ;
- vector<int> lyrArr ;
- //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
- for(int it=0;it<ibig;++it) { pidArr.push_back(bigPlateV->_id);capArr.push_back(bigPlateV->_bigJewCap*4); lyrArr.push_back(3); }
- for(int it=0;it<imid;++it) { pidArr.push_back(midPlateH->_id);capArr.push_back(midPlateH->_bigJewCap*4); lyrArr.push_back(3); }
- //cout<<"debug big "<<ibig<<" mid "<<imid<<" sml "<<isml<<endl;
- bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if(!lyrOk) continue;
- //保存结果
- vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
- for(int it = 0 ; it < capArr.size(); ++ it ) {
- tres[it]._plateId = pidArr[it] ;
- tres[it]._layerCnt = lyrArr[it] ;
- tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
- }
- possibleResults.push_back(tres) ;
- }else{
- //50% 2层, 50% 3层
- vector<int> pidArr ;
- vector<int> capArr ;
- vector<int> lyrArr ;
- //根据需求文档,非移动盘子,大盘子只用竖的,中盘子只用横的。
- 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); }
- 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); }
- bool lyrOk = isJustFilledAll2(capArr, lyrArr, totEquvSmallJewelCnt2) ;
- if(!lyrOk) continue;
- //保存结果
- vector<LevelGenerate::PlateIdAndLayerCnt> tres(capArr.size()) ;
- for(int it = 0 ; it < capArr.size(); ++ it ) {
- tres[it]._plateId = pidArr[it] ;
- tres[it]._layerCnt = lyrArr[it] ;
- tres[it]._moveId = MOVEID_NO_MOVE ;//不会移动的盘子
- }
- possibleResults.push_back(tres) ;
- }
- }
- }
- //随机挑选一个结果返回
- if( possibleResults.size()> 0 ) {
- int randindex = rand() % possibleResults.size();
- for(int ip = 0 ; ip < possibleResults[randindex].size();++ ip ) {
- results.push_back(possibleResults[randindex][ip]) ;
- }
- }else {
- for(int ip = 0 ; ip < firstAvailablePlateComb.size();++ ip ) {
- results.push_back(firstAvailablePlateComb[ip]) ;
- }
- }
- return results ;//
- }
- //随机排序数组索引值
- vector<int> LevelGenerate::randIndices(const int count0 ) {
- int count = count0 ;
- vector<int> indices ;
- unordered_map<int, bool> dict ;
- while( count > 0 ) {
- int r = rand()%count0;
- if( dict.find(r) == dict.end() ) {
- dict[r] = true ;
- indices.push_back(r) ;
- count-- ;
- }
- }
- return indices;
- }
-
- bool LevelGenerate::isJustFilledAll2(
- const vector<int>& plateCaps,//每个盘子的容量
- const vector<int> eachPlateLyrCnt,//对应盘子的层数
- const int totSmlJewCnt )
- {
- assert(plateCaps.size()>0);
- assert(plateCaps.size()==eachPlateLyrCnt.size());
- int fillcnt1 = 0;
- for(int ip = 0 ;ip<plateCaps.size();++ip ) {
- fillcnt1 += plateCaps[ip] * eachPlateLyrCnt[ip] ;
- }
- if( fillcnt1 < totSmlJewCnt ) return false ;
- if( fillcnt1 == totSmlJewCnt ) return true ;
- for(int ip = 0 ; ip < plateCaps.size();++ip ) {
- int fillcnt2 = fillcnt1 - plateCaps[ip] ;
- if( fillcnt2 < totSmlJewCnt ) {
- return true ;
- }
- }
- return false ;
- }
- unordered_map<int, int> LevelGenerate::randPickJewels( const int needEquvSmlCnt,const float solvedPercent, unordered_map<int,tuple<int,int>>& jewStorages )
- {
- int needEquvSmlCnt2 = needEquvSmlCnt ;
- int storageEquvSmlCnt = 0 ;
- int storageJewTypeCnt = jewStorages.size() ;
- for(auto it=jewStorages.begin();it!=jewStorages.end();++it) storageEquvSmlCnt+= std::get<1>(it->second)*jewSz2SmlCnt(std::get<0>(it->second)) ;
- unordered_map<int, int> res ;
- const float solPer = fmax(0.0,fmin(solvedPercent,1.0f)) ;
-
- //首先尝试可解的百分比部分
- int solEqSmGrpCnt = needEquvSmlCnt*solPer/3 ;
- // 随机尝试solEqSmGrpCnt*2 次取宝石,每次取一组。
- int loopCnt=solEqSmGrpCnt*storageJewTypeCnt*10;//随机迭代数量加大10倍,避免有始终选不到的情况
- while( solEqSmGrpCnt> 0 && storageEquvSmlCnt>0 && loopCnt>0) {
- int randJewI = rand()%storageJewTypeCnt ;
- auto itjew = jewStorages.begin() ;
- std::advance(itjew, randJewI) ;
- int jid = itjew->first ;
- int storage1 = std::get<1>( itjew->second ) ;
- int oneGrpEqSmGrpCnt = jewSz2SmlCnt( std::get<0>(itjew->second) ) ;
- if( storage1>=3 && oneGrpEqSmGrpCnt<=solEqSmGrpCnt ) {
- //库存有,且满足所需可解组数
- std::get<1>(itjew->second)-=3 ;
- solEqSmGrpCnt -= oneGrpEqSmGrpCnt ;
- storageEquvSmlCnt -= oneGrpEqSmGrpCnt*3 ;
- needEquvSmlCnt2 -= oneGrpEqSmGrpCnt*3 ; //本次所需的剩余等效小宝石个数
- res[jid] += 3 ;
- }
- --loopCnt ;
- }
-
- //尝试剩余百分比和上一步剩余没有符合条件的个数
- loopCnt = needEquvSmlCnt2*storageJewTypeCnt ;
- int jindex = 0 ;
- while( loopCnt>0 && needEquvSmlCnt2> 0 && storageEquvSmlCnt>0 ) {
- auto itjew = jewStorages.begin() ;
- std::advance(itjew, jindex) ;
- int jid = itjew->first;
- int sz = std::get<0>(itjew->second) ;
- int stor = std::get<1>(itjew->second) ;
- int eqsmCnt = jewSz2SmlCnt(sz) ;
- if( stor>0 && eqsmCnt <= needEquvSmlCnt2 ) {
- std::get<1>(itjew->second)-=1 ;
- needEquvSmlCnt2-=eqsmCnt ;
- storageEquvSmlCnt-=eqsmCnt ;
- res[jid] += 1 ;
- }
- ++jindex ; if(jindex>=storageJewTypeCnt) jindex=0;//循环取之,直到本层所需全部取完
- --loopCnt;
- }
- return res ;
- }
- int LevelGenerate::jewSz2SmlCnt(int sz)
- {
- switch (sz) {
- case FILLGLOBALCONFIG_JEWELSIZE_LG:
- return 4;break;
- case FILLGLOBALCONFIG_JEWELSIZE_MD:
- return 2;break;
- default:
- return 1;break;
- }
- return 1;
- }
- vector<FillResult> LevelGenerate::fillPlateOneLayer(RandomGridFiller& filler,const int plateId, unordered_map<int,int>& jewStoragesForUse )
- {
- auto fgc = FillGlobalConfig::getInstance() ;
- vector<RandomGridFiller::JewelBox> jewBoxArray ;
- FillGlobalConfig::PlateItem* pl = FillGlobalConfig::getInstance()->getPlateItemById(plateId) ;
- int plateEqSmCap = pl->_bigJewCap*4 ;
- int jewTypeCnt = jewStoragesForUse.size() ;
- int eqSmStorageCnt = 0 ;
- for(auto it = jewStoragesForUse.begin();it!=jewStoragesForUse.end();++it) {
- int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
- eqSmStorageCnt+=it->second*jewEqSmCnt ;
- }
- static int s_debug_cnt = 0;
- //cout<<"debug "<< s_debug_cnt << " storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
- unordered_map<int, int> jewForPlateMap ;// <jewId,Cnt>
- int loopCnt = plateEqSmCap*jewTypeCnt*4;// 随机数量多给4倍
- while(plateEqSmCap>0 && eqSmStorageCnt>0 && loopCnt>0 ) {
- int radv = rand() % jewTypeCnt ;
- auto it = jewStoragesForUse.begin() ;
- std::advance(it, radv) ;
- int jewEqSmCnt = jewSz2SmlCnt( fgc->getJewelItemById(it->first)->_size );
- if( it->second>0 ) {
- if( jewEqSmCnt <= plateEqSmCap ) {
- plateEqSmCap -= jewEqSmCnt ;
- it->second -=1 ;
- eqSmStorageCnt -= jewEqSmCnt ;
- jewForPlateMap[it->first] += 1 ;
- if( it->second== 0 ) {
- jewStoragesForUse.erase(it) ;
- jewTypeCnt-- ;
- }
- }
- }else{
- jewStoragesForUse.erase(it) ;
- jewTypeCnt-- ;
- }
- --loopCnt ;
- }
-
- //cout<<"debug "<< s_debug_cnt ++ <<" storage eqsm count "<<eqSmStorageCnt<< " currplate cap "<< plateEqSmCap <<endl;
-
- for(auto it = jewForPlateMap.begin();it!=jewForPlateMap.end();++it) {
- RandomGridFiller::JewelBox jbox ;
- jbox._cnt = it->second ;
- jbox._jewelTypeId = it->first ;
- jbox._width = fgc->getJewelItemById(it->first)->_bbWidth ;
- jbox._height = fgc->getJewelItemById(it->first)->_bbHeight ;
- jewBoxArray.push_back(jbox) ;
- }
-
- vector<FillResult> fillresults ;
- filler.fill(jewBoxArray, pl->_blx, pl->_bly, pl->_trx, pl->_try, fillresults) ;
- return fillresults ;
- }
- unordered_map<int, int> LevelGenerate::findUnfilledInStorages( unordered_map<int,tuple<int,int>>& jewStorages)
- {
- unordered_map<int, int> res ;
- for(auto itj = jewStorages.begin();itj!=jewStorages.end();++itj) {
- int stor = std::get<1>(itj->second) ;
- int jid = itj->first ;
- if( stor>0 ) {
- res[jid] = stor ;
- std::get<1>(itj->second) = 0 ;
- }
- }
- return res ;
- }
- void LevelGenerate::regroupPlateLyrFillResults(
- vector<tuple<int,int,vector<FillResult>,int>>& pidlyrFillMvidArray,
- vector<PlateFillResult>& results)
- {
- int currLayer = 1 ;//从底层到顶层构建结果数据结构
- int num = pidlyrFillMvidArray.size() ;
- int nloop = num ;
- while( nloop > 0 ) {
- //cout<<"regroup for layer "<<currLayer<<endl;
- for( auto itlyr = pidlyrFillMvidArray.begin(); itlyr!=pidlyrFillMvidArray.end(); ++ itlyr ) {
- int pid = std::get<0>( *itlyr ) ;
- int lyr = std::get<1>( *itlyr ) ;
- vector<FillResult>& frs = std::get<2>(*itlyr) ;
- int moveId = std::get<3>(*itlyr) ;
-
- if(pid>=0) {
- if( lyr==currLayer ) {
- if( lyr==1 ) {
- vector<vector<FillResult>> frArr = {frs} ;
- PlateFillResult pfr ;
- pfr._layersFillResults = frArr ;
- pfr._moveId = moveId ;
- pfr._plateTypeId = pid ;
- results.push_back( pfr ) ;
- num-- ;
- std::get<0>( *itlyr ) = -1 ;
- }else {
- for(auto itPfr = results.begin();itPfr!=results.end();++itPfr ) {
- int pidr = itPfr->_plateTypeId ;
- int mvid = itPfr->_moveId ;
- vector<vector<FillResult>>& frArr = itPfr->_layersFillResults ;
- if( pidr == pid && mvid == moveId && frArr.size()==currLayer-1 ) {
- frArr.push_back(frs);
- num-- ;
- std::get<0>( *itlyr ) = -1 ;
- break ;
- }
- }
- }
- }
- }
- }
- currLayer++ ;
- if( num==0 ) break ;
- nloop--;
- }
- //cout<<"last plate lyr num "<<num<<endl;
- }
- void LevelGenerate::placePlates(const bool movable,
- const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
- const vector<PlateFillResult>& plateFRArr,
- vector<ContourData::Point>& resultPlateCenterPointArr )
- {
- GridPositionTool gpt ;
- vector<int> plateIdArr ;
- vector<int> moveIdArr ;
- for(int ip = 0 ; ip < plateFRArr.size(); ++ ip ) {
- plateIdArr.push_back( plateFRArr[ip]._plateTypeId ) ;
- moveIdArr.push_back( plateFRArr[ip]._moveId ) ;
- }
-
- vector<vector<int>> resPosis ;
-
- string firstMoveTypeCode = "" ;
- string secondMoveTypeCode = "" ;
- if( movable ) {
- firstMoveTypeCode = mulMoveConfig->_first->_type[0] ;
- if( mulMoveConfig->_second ) secondMoveTypeCode = mulMoveConfig->_second->_type[0] ;
- }
- gpt.solve(movable,
- firstMoveTypeCode ,
- secondMoveTypeCode,
- plateIdArr,
- moveIdArr,
- resPosis //这里结果是盘子左下角坐标,下面需要转换成中心坐标。
- ) ;
-
- for(int ip=0;ip<resPosis.size();++ip ) {
- FillGlobalConfig::PlateItem* platePtr = FillGlobalConfig::getInstance()->getPlateItemById(plateIdArr[ip]) ;
- resultPlateCenterPointArr.push_back( { (float)resPosis[ip][0]+platePtr->_bbwid/2 , (float)resPosis[ip][1]+platePtr->_bbhei/2} ) ;
- }
- }
- vector<LevelGenerate::PlateIdAndLayerCnt>
- LevelGenerate::generatePlateTypeAndLayerCntsForMovablePlates(
- const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,
- const int totEquvSmallJewelCnt,
- int& retResidueEquvSmlJewelCnt )
- {
- vector<LevelGenerate::PlateIdAndLayerCnt> results ;
- retResidueEquvSmlJewelCnt = totEquvSmallJewelCnt ;
- FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ;
- FillGlobalConfig::PlateItem* bigPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 1) ;
- FillGlobalConfig::PlateItem* midPlateH = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 1) ;
- FillGlobalConfig::PlateItem* bigPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_LG, 0) ;
- FillGlobalConfig::PlateItem* midPlateV = fgc->getPlateItemBySzNDirection(FILLGLOBALCONFIG_PLATESIZE_MD, 0) ;
-
- const int MAX_MOVE_CONFIG_CNT = 2;
- FillGlobalConfig::MoveConfig* arr[MAX_MOVE_CONFIG_CNT] = { mulMoveConfig->_first , mulMoveConfig->_second } ;
- for(int ii = 0 ; ii < MAX_MOVE_CONFIG_CNT ; ++ ii ) {
- FillGlobalConfig::MoveConfig* moveConfig = arr[ii] ;
- if( moveConfig==nullptr ) continue ;
- //中盘子横
- for(int imid = 0 ; imid < moveConfig->_midPlateCntH ; ++ imid ) {
- PlateIdAndLayerCnt palc ;
- palc._layerCnt = moveConfig->_nLayer ;
- palc._plateId = midPlateH->_id ;
- palc._moveId = ii+1 ;//第一行为1,第二行为2
- results.push_back(palc) ;
- retResidueEquvSmlJewelCnt -= midPlateH->_bigJewCap*4*palc._layerCnt ;
- }
- //中盘子竖
- for(int imid = 0 ; imid < moveConfig->_midPlateCntV ; ++ imid ) {
- PlateIdAndLayerCnt palc ;
- palc._layerCnt = moveConfig->_nLayer ;
- palc._plateId = midPlateV->_id ;
- palc._moveId = ii+1 ;
- results.push_back(palc) ;
- retResidueEquvSmlJewelCnt -= midPlateV->_bigJewCap*4*palc._layerCnt ;
- }
- //大盘子横
- for(int ibig = 0 ; ibig < moveConfig->_bigPlateCntH ; ++ ibig ) {
- PlateIdAndLayerCnt palc ;
- palc._layerCnt = moveConfig->_nLayer ;
- palc._plateId = bigPlateH->_id ;
- palc._moveId = ii+1 ;
- results.push_back(palc) ;
- retResidueEquvSmlJewelCnt -= bigPlateH->_bigJewCap*4*palc._layerCnt ;
- }
- //大盘子竖
- for(int ibig = 0 ; ibig < moveConfig->_bigPlateCntV ; ++ ibig ) {
- PlateIdAndLayerCnt palc ;
- palc._layerCnt = moveConfig->_nLayer ;
- palc._plateId = bigPlateV->_id ;
- palc._moveId = ii+1 ;
- results.push_back(palc) ;
- retResidueEquvSmlJewelCnt -= bigPlateV->_bigJewCap*4*palc._layerCnt ;
- }
- }
- return results ;
- }
- void LevelGenerate::computePlateCount(const FillGlobalConfig::MultiMoveConfig* mmc ,int& retBigPlateCnt, int& retMidPlateCnt )
- {
- if( mmc==nullptr ) {
- retBigPlateCnt = 9 ;
- retMidPlateCnt = 0 ;
- }else
- if( mmc->_first && mmc->_second ) {
- if( mmc->_first->_type.find("A") != string::npos && mmc->_second->_type.find("A") != string::npos ) {
- retBigPlateCnt = 6 ;
- retMidPlateCnt = 8 ;
- }else if( mmc->_first->_type.find("B") != string::npos && mmc->_second->_type.find("B") != string::npos ) {
- retBigPlateCnt = 9 ;
- retMidPlateCnt = 0 ;
- }else if( mmc->_first->_type.find("C") != string::npos && mmc->_second->_type.find("C") != string::npos ) {
- retBigPlateCnt = 11 ;
- retMidPlateCnt = 0 ;
- }else if( mmc->_first->_type.find("B") != string::npos && mmc->_second->_type.find("A") != string::npos) {
- retBigPlateCnt = 6 ;
- retMidPlateCnt = 7 ;
- }else if( mmc->_first->_type.find("C") != string::npos && mmc->_second->_type.find("B") != string::npos ) {
- retBigPlateCnt = 10 ;
- retMidPlateCnt = 0 ;
- }else if( mmc->_first->_type.find("C") != string::npos && mmc->_second->_type.find("A") != string::npos ) {
- retBigPlateCnt = 7 ;
- retMidPlateCnt = 7 ;
- }
-
- }else if( mmc->_first && mmc->_second==nullptr ) {
- if( mmc->_first->_type.find("A") != string::npos ) {
- retBigPlateCnt = 6 ;
- retMidPlateCnt = 7 ;
- }else if( mmc->_first->_type.find("B") != string::npos ) {
- retBigPlateCnt = 9 ;
- retMidPlateCnt = 0 ;
- }else if( mmc->_first->_type.find("C") != string::npos ) {
- retBigPlateCnt = 10 ;
- retMidPlateCnt = 0 ;
- }
- }else {
- retBigPlateCnt = 9 ;
- retMidPlateCnt = 0 ;
- }
-
- }
|