// // LevelGenerate.hpp // auto_fill_jewel_v3 // // Created by Red on 2024/11/23. // 关卡生成类,包含生成盘子组合,然后填充宝石。 #ifndef LevelGenerate_hpp #define LevelGenerate_hpp #include #include using std::string; #include "contourdata.h" #include "FillGlobalConfig.hpp" #include "FillResult.hpp" #include "RandomGridFiller.hpp" #include using std::tuple; #include "levelinputdata.h" #include "levelextinputdata.h" struct LevelGenerate { public: //盘子ID和层数 struct PlateIdAndLayerCnt { PlateIdAndLayerCnt():_plateId(-1),_layerCnt(0),_moveId(0){} int _plateId ; int _layerCnt ; int _moveId ;//0-静态盘子 1-第一行移动盘子 2-第二行移动盘子 } ; public: LevelGenerate():_seed(11231627){} void setSeed(int s) { _seed = s ;} int getSeed() { return _seed ; } void generateAll(FillGlobalConfig::LevelData levelData, string outname) ; //盘子和宝石的组合有解返回true,反之返回false bool generate( FillGlobalConfig::LevelData levelData, const bool isMovable, const FillGlobalConfig::MultiMoveConfig* mulMoveConfig , //移动盘子配置,如果isMovable为false,这个参数忽略,可以传入nullptr vector& resultPlateFillResults, vector& resultPlateCenterPointArr ) ; //将输入数据拆分成基本输入参数和扩展输入参数作为输入 bool generate_v2( const LevelInputData& indata, const LevelExtInputData& extdata, vector& resultPlateFillResults, vector& resultPlateCenterPointArr, string& error) ; private: int _seed ; //根据难度数据和宝石总数计算需要使用的每个盘子的个数 /// @param difficulty 难度:0-普通,1-难,2-极难 /// @param totEquvSmallJewelCnt 全部等效小盘子数量 /// @return 返回盘子和层数的组合 vector generatePlateTypeAndLayerCnts(const int difficulty,const int totEquvSmallJewelCnt); //根据难度数据和宝石总数计算需要使用的每个盘子的个数 //考虑可移动关卡的条件 vector generatePlateTypeAndLayerCnts2(const bool isMovable,const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,const int difficulty,const int totEquvSmallJewelCnt); //相对于generatePlateTypeAndLayerCnts2通过随机数计算盘子数量, generatePlateTypeAndLayerCnts3使用输入盘子百分比计算盘子数量。 vector generatePlateTypeAndLayerCnts3(const bool isMovable,const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,const int difficulty,const int totEquvSmallJewelCnt,const LevelExtInputData& extdata ); //生成针对可移动盘子的组合 //残余等效小宝石数量返回到 residueEquvSmlJewelCnt 里面 vector generatePlateTypeAndLayerCntsForMovablePlates(const FillGlobalConfig::MultiMoveConfig* mulMoveConfig,const int totEquvSmallJewelCnt, int& retResidueEquvSmlJewelCnt ); //判断一个组合是否恰恰装入宝石个数,规则是如果少一个盘就恰好装不下. bool isJustFilledAll2( const vector& plateCaps,//每个盘子的容量 const vector eachPlateLyrCnt,//对应盘子的层数 const int totSmlJewCnt) ; vector randIndices(const int count0 ) ; /// 随机从库存中取出needEquvSmlCnt个等效小宝石,取出的宝石从库存减掉 /// @param needEquvSmlCnt 需要取出的等价小宝石数量 /// @param unsolvedPercent 取出宝石的不可解百分比 /// @param jewStorages 库存数据,取出数据要从库存减去,key:jewId value:tuple /// @return 返回宝石ID和对应的数量 unordered_map randPickJewels( const int needEquvSmlCnt,const float solvedPercent, unordered_map>& jewStorages ) ; /// 填充一个盘子,用掉的宝石从库存减掉 vector fillPlateOneLayer(RandomGridFiller& filler,const int plateId, unordered_map& jewStoragesForUse ) ; /// 宝石尺寸转等效小宝石数量 int jewSz2SmlCnt(int sz) ; /// 查找库存剩余的宝石,返回 jewId,Cnt,并扣除库存数量 unordered_map findUnfilledInStorages(unordered_map>& jewStorages); /// 整理结果数据为 关卡-盘子-层-宝石的层次结构 void regroupPlateLyrFillResults( vector,int>>& pidlyrFillMvidArray, vector& results ) ; /// 摆放盘子 void placePlates(const bool movable, const FillGlobalConfig::MultiMoveConfig* mulMoveConfig, const vector& plateFRArr, vector& resultPlateCenterPointArr ) ; // 根据移动盘子情况计算关卡大盘子数量和中盘子数量,该数字包含移动盘子和非移动盘子。 void computePlateCount(const FillGlobalConfig::MultiMoveConfig* mmc ,int& retBigPlateCnt, int& retMidPlateCnt ) ; } ; #endif /* LevelGenerate_hpp */