123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812 |
- //
- // 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 ;
- }
- // 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<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 ;
- }
-
- }
|