// // FillGlobalConfig.cpp // auto_fill_jewel_v3 // // Created by Red on 2024/11/25. // #include "FillGlobalConfig.hpp" using namespace ArduinoJson; #include using std::ifstream; #include FillGlobalConfig* FillGlobalConfig::_s_instance = nullptr ; bool FillGlobalConfig::init(string filename) { // _plateContours.clear(); // _jewelContours.clear() ; // ifstream ifs( filename.c_str() ); // if( ifs.good()==false ) return false ; // DynamicJsonBuffer buffer ; // JsonObject& root = buffer.parse(ifs) ; // string platedir = root["plate_contour_dir"].as() ; // string jeweldir = root["jewel_contour_dir"].as() ; // JsonArray& parr =root["plate_names"].as() ; // JsonArray& jarr =root["jewel_names"].as() ; // _plateContours.resize(parr.size()); // _jewelContours.resize(jarr.size()); // // for(int i=0;i() ; // string fullname1 = platedir + name1 ; // _plateContours[i]._name = name1 ; // _plateContours[i]._contour.readFromJsonFile(fullname1) ; // } // for(int i=0;i() ; // string fullname1 = jeweldir + name1 ; // _jewelContours[i]._name = name1 ; // _jewelContours[i]._contour.readFromJsonFile(fullname1) ; // } return true; } FillGlobalConfig* FillGlobalConfig::getInstance() { if( _s_instance == nullptr ) { _s_instance = new FillGlobalConfig ; //_s_instance->init("config.json") ; _s_instance->initJewelItems("sg_jewel_items.csv") ; _s_instance->initLevelDatas("sg_level_data.csv") ; _s_instance->initPlateItems("sg_plate_items.csv") ; _s_instance->initMoveConfigDatas("sg_move_config_data.csv") ; _s_instance->initGridBoxDatas("sg_gridbox_positions.csv") ; } return _s_instance ; } ContourData* FillGlobalConfig::getContourDataByPngName(string& pngname) { for(auto it = _jewelContours.begin(); it!=_jewelContours.end();++it ) { if( it->_name.find(pngname) != string::npos ) { return &(it->_contour) ; } } return nullptr ; } bool FillGlobalConfig::initJewelItems( string filename ) { _mapJewelItems.clear() ; ifstream ifs( filename.c_str() ) ; if( ifs.good()==false ) return false ; string line ; //跳过第一行 std::getline(ifs, line) ; vector tokens ; while( std::getline(ifs, line) ) { if( line.length() > 2 ) { tokens.clear() ; boost::split(tokens, line, boost::is_any_of(",")); if( tokens.size()>=13 ) { JewelItem ji ; ji._id = atof(tokens[0].c_str()) ; ji._category = tokens[1] ; ji._jewelName = tokens[2] ; ji._code1 = tokens[3] ; ji._code2 = tokens[4] ; ji._size = (tokens[5].compare("SM")==0)?FILLGLOBALCONFIG_JEWELSIZE_SM:((tokens[5].compare("MD")==0)?FILLGLOBALCONFIG_JEWELSIZE_MD:FILLGLOBALCONFIG_JEWELSIZE_LG) ; ji._scale = atof( tokens[6].c_str() ) ; ji._pngName = tokens[7] ; ji._yzName = tokens[8] ; ji._contourName = tokens[9] ; ji._bbWidth = atof( tokens[10].c_str() ) ; ji._bbHeight = atof( tokens[11].c_str() ) ; ji._etc = tokens[12] ; _mapJewelItems[ji._id] = ji ; } } } return true ; } bool FillGlobalConfig::initLevelDatas( string filename ) { _mapLevelDatas.clear() ; ifstream ifs( filename.c_str() ) ; if( ifs.good()==false ) return false ; string line ; //跳过第一行 std::getline(ifs, line) ; LevelData tempLevelData ; tempLevelData._id = -1 ;//初始化 vector tokens ; while( std::getline(ifs, line) ) { bool isDataLine = false; if( line.length() > 2 ) { tokens.clear() ; boost::split(tokens, line, boost::is_any_of(",")); if( tokens.size()>=6 ) { isDataLine = true ; int lid = atof(tokens[0].c_str()) ; int subid = atof(tokens[1].c_str()) ; int difficulty = atof(tokens[2].c_str()) ; int jewId = atof(tokens[3].c_str()) ; string jewSz = tokens[4]; //ignored int grpcnt = atof( tokens[5].c_str() ) ; if( tempLevelData._id == -1 ) { tempLevelData._id = lid ; tempLevelData._subId = subid ; tempLevelData._difficulty = difficulty ; } tempLevelData._jewelIds.push_back(jewId) ; tempLevelData._cnts.push_back(grpcnt*3) ; } } if( isDataLine==false ) { //出现空行, 记录临时关卡 if( tempLevelData._id>0 ) { _mapLevelDatas[tempLevelData._id].push_back(tempLevelData) ; } //清空临时关卡数据 tempLevelData._id = -1 ; tempLevelData._subId = -1 ; tempLevelData._difficulty = -1; tempLevelData._cnts.clear() ; tempLevelData._jewelIds.clear() ; } } //最后一个临时对象是否是有效关卡数据 if( tempLevelData._id>0 ) { _mapLevelDatas[tempLevelData._id].push_back(tempLevelData) ; tempLevelData._id = -1 ; tempLevelData._cnts.clear() ; tempLevelData._jewelIds.clear() ; } return true ; } bool FillGlobalConfig::initPlateItems( string filename ) { _mapPlateItems.clear() ; _mapPlateIdArray.clear() ; ifstream ifs( filename.c_str() ) ; if( ifs.good()==false ) return false ; string line ; //跳过第一行 std::getline(ifs, line) ; vector tokens ; while( std::getline(ifs, line) ) { if( line.length() > 2 ) { tokens.clear() ; boost::split(tokens, line, boost::is_any_of(",")); if( tokens.size()>=13 ) { PlateItem pi ; pi._id = atof(tokens[0].c_str()) ; pi._name = tokens[1] ; int sz = 0 ; string szStr = tokens[2] ; //if( szStr.compare("SM")==0 ) sz = FILLGLOBALCONFIG_PLATESIZE_SM ; if( szStr.compare("MD")==0 ) sz = FILLGLOBALCONFIG_PLATESIZE_MD; else if( szStr.compare("LG")==0 ) sz = FILLGLOBALCONFIG_PLATESIZE_LG; else continue; //无效盘子跳过 pi._size = sz ; pi._pngName = tokens[3] ; pi._contourName = tokens[4] ; pi._blx = atof( tokens[5].c_str() ) ;//bottom left pi._bly = atof( tokens[6].c_str() ) ; pi._trx = atof( tokens[7].c_str() ) ;//top right pi._try = atof( tokens[8].c_str() ) ; pi._bigJewCap = atof( tokens[9].c_str() ) ; pi._bbwid = atof( tokens[10].c_str()) ; pi._bbhei = atof( tokens[11].c_str()) ; pi._heng = atof( tokens[12].c_str()) ; _mapPlateItems[pi._id] = pi ; _mapPlateIdArray[sz].push_back(pi._id) ; } } } return true ; } bool FillGlobalConfig::initMoveConfigDatas( string filename ) { _mapMoveConfigDatas.clear() ; ifstream ifs( filename.c_str() ) ; if( ifs.good()==false ) return false ; string line ; //跳过第一行 std::getline(ifs, line) ; vector tokens ; while( std::getline(ifs, line) ) { if( line.length() > 2 ) { tokens.clear() ; boost::split(tokens, line, boost::is_any_of(",")); if( tokens.size()>=9 ) { MoveConfig mhc ; mhc._id = atof( tokens[0].c_str() ) ; mhc._type = tokens[1] ; mhc._lowestEquvSmlJewelCnt = atof( tokens[2].c_str() ) ; mhc._nLayer = atof( tokens[3].c_str() ) ; mhc._midPlateCntH = atof( tokens[4].c_str() ) ; mhc._midPlateCntV = atof( tokens[5].c_str() ) ; mhc._bigPlateCntH = atof( tokens[6].c_str() ) ; mhc._bigPlateCntV = atof( tokens[7].c_str() ) ; mhc._hard = atof( tokens[8].c_str() ) ; _mapMoveConfigDatas[mhc._id] = mhc ; } } } return true ; } bool FillGlobalConfig::initGridBoxDatas(string filename) { _mapGridBoxDatas.clear() ; ifstream ifs( filename.c_str() ) ; if( ifs.good()==false ) return false ; string line ; //跳过第一行 std::getline(ifs, line) ; vector tokens ; while( std::getline(ifs, line) ) { if( line.length() > 2 ) { tokens.clear() ; boost::split(tokens, line, boost::is_any_of(",")); if( tokens.size()>=11 ) { GridBoxCell gbc ; gbc._name = tokens[0] ; gbc._move = atof( tokens[1].c_str() ) ; gbc._bigIndex = atof( tokens[2].c_str() ) ; gbc._mid1Index = atof( tokens[3].c_str() ) ; gbc._mid2Index = atof( tokens[4].c_str() ) ; gbc._bigllx = atof( tokens[5].c_str() ) ; gbc._biglly = atof( tokens[6].c_str() ) ; gbc._mid1llx = atof( tokens[7].c_str() ) ; gbc._mid1lly = atof( tokens[8].c_str() ) ; gbc._mid2llx = atof( tokens[9].c_str() ) ; gbc._mid2lly = atof( tokens[10].c_str() ) ; gbc._bigFilled = false; gbc._mid1Filled = false; gbc._mid2Filled = false ; _mapGridBoxDatas[gbc._name].push_back(gbc); } } } return true ; } vector FillGlobalConfig::getSecondRoundMoveConfigDatas(int equvSmCnt) { vector res ; FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ; if( 96 <= equvSmCnt && equvSmCnt < 144 ) { vector tarr = getMoveConfigDatasByTypeAndNLayers("A", 2) ; for(auto m:tarr) res.push_back(m) ; }else if( 144<= equvSmCnt && equvSmCnt < 192 ) { vector tarr = getMoveConfigDatasByTypeAndNLayers("A", 2) ; for(auto m:tarr) res.push_back(m) ; vector tarr1 = getMoveConfigDatasByTypeAndNLayers("A", 3) ; for(auto m:tarr1) res.push_back(m) ; vector tarr2 = getMoveConfigDatasByTypeAndNLayers("B", 2) ; for(auto m:tarr2) res.push_back(m) ; }else if( 192<=equvSmCnt && equvSmCnt < 216 ) { vector tarr = getMoveConfigDatasByTypeAndNLayers("A", 2) ; for(auto m:tarr) res.push_back(m) ; vector tarr1 = getMoveConfigDatasByTypeAndNLayers("A", 3) ; for(auto m:tarr1) res.push_back(m) ; vector tarr2 = getMoveConfigDatasByTypeAndNLayers("B", 2) ; for(auto m:tarr2) res.push_back(m) ; vector tarr3 = getMoveConfigDatasByTypeAndNLayers("C", 2) ; for(auto m:tarr3) res.push_back(m) ; }else if( 216<= equvSmCnt && equvSmCnt < 288 ) { vector tarr = getMoveConfigDatasByTypeAndNLayers("A", 2) ; for(auto m:tarr) res.push_back(m) ; vector tarr1 = getMoveConfigDatasByTypeAndNLayers("A", 3) ; for(auto m:tarr1) res.push_back(m) ; vector tarr2 = getMoveConfigDatasByTypeAndNLayers("B", 2) ; for(auto m:tarr2) res.push_back(m) ; vector tarr3 = getMoveConfigDatasByTypeAndNLayers("B", 3) ; for(auto m:tarr3) res.push_back(m) ; vector tarr4 = getMoveConfigDatasByTypeAndNLayers("C", 2) ; for(auto m:tarr4) res.push_back(m) ; }else if( 288 <= equvSmCnt ) { vector tarr = getMoveConfigDatasByTypeAndNLayers("A", 2) ; for(auto m:tarr) res.push_back(m) ; vector tarr1 = getMoveConfigDatasByTypeAndNLayers("A", 3) ; for(auto m:tarr1) res.push_back(m) ; vector tarr2 = getMoveConfigDatasByTypeAndNLayers("B", 2) ; for(auto m:tarr2) res.push_back(m) ; vector tarr3 = getMoveConfigDatasByTypeAndNLayers("B", 3) ; for(auto m:tarr3) res.push_back(m) ; vector tarr4 = getMoveConfigDatasByTypeAndNLayers("C", 2) ; for(auto m:tarr4) res.push_back(m) ; vector tarr5 = getMoveConfigDatasByTypeAndNLayers("C", 3) ; for(auto m:tarr5) res.push_back(m) ; } return res ; } vector FillGlobalConfig::getFirstRoundMoveConfigDatas(int equvSmCnt) { vector res ; FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ; if( equvSmCnt < 48 ) { return res ;//empty }else if( 48<=equvSmCnt && equvSmCnt<96 ) { res = getMoveConfigDatasByTypeAndNLayers("A", 1) ; }else if( 96<=equvSmCnt && equvSmCnt<144 ) { res = getMoveConfigDatasByTypeAndNLayers("A", 2) ; }else if( 144<= equvSmCnt && equvSmCnt < 192 ) { vector tarr1 = getMoveConfigDatasByTypeAndNLayers("A", 2) ; vector tarr2 = getMoveConfigDatasByTypeAndNLayers("A", 3) ; vector tarr3 = getMoveConfigDatasByTypeAndNLayers("B", 2) ; for(auto mc:tarr1) res.push_back(mc) ; for(auto mc:tarr2) res.push_back(mc) ; for(auto mc:tarr3) res.push_back(mc) ; }else if( 192<=equvSmCnt && equvSmCnt<216 ) { vector tarr1 = getMoveConfigDatasByTypeAndNLayers("A", 2) ; vector tarr2 = getMoveConfigDatasByTypeAndNLayers("A", 3) ; vector tarr3 = getMoveConfigDatasByTypeAndNLayers("B", 2) ; vector tarr4 = getMoveConfigDatasByTypeAndNLayers("C", 2) ; for(auto mc:tarr1) res.push_back(mc) ; for(auto mc:tarr2) res.push_back(mc) ; for(auto mc:tarr3) res.push_back(mc) ; for(auto mc:tarr4) res.push_back(mc) ; }else if( 216<=equvSmCnt && equvSmCnt<288 ) { vector tarr1 = getMoveConfigDatasByTypeAndNLayers("A", 2) ; vector tarr2 = getMoveConfigDatasByTypeAndNLayers("A", 3) ; vector tarr3 = getMoveConfigDatasByTypeAndNLayers("B", 2) ; vector tarr4 = getMoveConfigDatasByTypeAndNLayers("C", 2) ; vector tarr5 = getMoveConfigDatasByTypeAndNLayers("B", 3) ; for(auto mc:tarr1) res.push_back(mc) ; for(auto mc:tarr2) res.push_back(mc) ; for(auto mc:tarr3) res.push_back(mc) ; for(auto mc:tarr4) res.push_back(mc) ; for(auto mc:tarr5) res.push_back(mc) ; }else if( 288 <= equvSmCnt ) { vector tarr1 = getMoveConfigDatasByTypeAndNLayers("A", 2) ; vector tarr2 = getMoveConfigDatasByTypeAndNLayers("A", 3) ; vector tarr3 = getMoveConfigDatasByTypeAndNLayers("B", 2) ; vector tarr4 = getMoveConfigDatasByTypeAndNLayers("C", 2) ; vector tarr5 = getMoveConfigDatasByTypeAndNLayers("B", 3) ; vector tarr6 = getMoveConfigDatasByTypeAndNLayers("C", 3) ; for(auto mc:tarr1) res.push_back(mc) ; for(auto mc:tarr2) res.push_back(mc) ; for(auto mc:tarr3) res.push_back(mc) ; for(auto mc:tarr4) res.push_back(mc) ; for(auto mc:tarr5) res.push_back(mc) ; for(auto mc:tarr6) res.push_back(mc) ; } return res ; } vector FillGlobalConfig::getMoveConfigDatasByTypeAndNLayers(string type,int nlayer) { vector res ; FillGlobalConfig* fgc = FillGlobalConfig::getInstance() ; int cnt = fgc->getMoveConfigCount() ; for(int i = 0 ; igetMoveConfigDataByIndex(i) ; if( mhc->_type.find(type) != string::npos ) { if(mhc->_nLayer == nlayer ) { res.push_back( mhc ) ; } } } return res ; } vector FillGlobalConfig::getAllMoveConfigByJewels(LevelData& levelData) { vector res ; int equvSmJewelCnt = 0 ; for(int ij = 0 ; ij < levelData._jewelIds.size() ; ++ ij ) { int jid = levelData._jewelIds[ij] ; int cnt = levelData._cnts[ij] ; FillGlobalConfig::JewelItem* jewel = this->getJewelItemById(jid); if( jewel->_size == FILLGLOBALCONFIG_JEWELSIZE_LG ) { cnt=cnt*4 ; }else if(jewel->_size == FILLGLOBALCONFIG_JEWELSIZE_MD ) { cnt=cnt*2 ; } equvSmJewelCnt += cnt ; } if( equvSmJewelCnt == 0 ) return res ;//empty. //第一个可移动行 vector residueSmJewCnts ;//第一行剩余宝石 vector firstMoveConfigs = getFirstRoundMoveConfigDatas(equvSmJewelCnt) ; int num1 = firstMoveConfigs.size() ;//第一个移动行的可能方案 for(int i1 = 0 ; i1 < num1 ; ++ i1 ) { FillGlobalConfig::MoveConfig* mc = firstMoveConfigs[i1] ; int res1 = equvSmJewelCnt - mc->_lowestEquvSmlJewelCnt ; vector secondConfigs = getSecondRoundMoveConfigDatas(res1) ; bool secondAtLeasetHaveOneSolution = false ; if( secondConfigs.size()>0 ) { //存在第二移动行的情况 for(int i2 = 0 ; i2 < secondConfigs.size(); ++ i2 ) { //第二行组合必须是 BA , CB , CA 这个顺序,也就是说第二行的字母ASCII值要小于等第一行的字母值 if( secondConfigs[i2]->_type[0] <= mc->_type[0] ) { FillGlobalConfig::MultiMoveConfig mmc ; mmc._first = mc ; mmc._second = secondConfigs[i2] ; res.push_back(mmc) ; secondAtLeasetHaveOneSolution = true ; } } } if( secondAtLeasetHaveOneSolution==false ) { //无二移动行的情况 FillGlobalConfig::MultiMoveConfig mmc ; mmc._first = mc ; mmc._second = nullptr ; res.push_back(mmc) ; } } return res ; } FillGlobalConfig::PlateItem* FillGlobalConfig::getPlateItemBySzNDirection(int plateSzId,int heng) { if( _mapPlateIdArray.find(plateSzId) != _mapPlateIdArray.end() ) { vector& idarr = _mapPlateIdArray[plateSzId] ; for(int ii = 0 ; ii < idarr.size();++ii ) { PlateItem* pi = this->getPlateItemById( idarr[ii] ) ; if( pi!=nullptr ) { if( pi->_heng == heng ) { return pi ; } } } return nullptr ; }else{ return nullptr; } } void FillGlobalConfig::clearGridBoxFilledStatus() { for(auto it = _mapGridBoxDatas.begin(); it!=_mapGridBoxDatas.end();++it ) { vector& arr = it->second ; for(auto itg = arr.begin(); itg != arr.end(); ++ itg ) { itg->_bigFilled = false ; itg->_mid1Filled = false; itg->_mid2Filled = false ; } } } FillGlobalConfig::GridBoxCell* FillGlobalConfig::getLowestUnfilledGridBox(string name,const int moveid,const int iPlateSiz,ContourData::Point& retPositionLL) { if( name.compare("")==0 ) name = "NN" ; int index = 9999 ; GridBoxCell* res = nullptr ; if( _mapGridBoxDatas.find(name) == _mapGridBoxDatas.end() ) { //如果没找到组合,那么把字母反过来组合 string name2 ; for(int ic = 0 ;ic& arr = _mapGridBoxDatas[name] ; for(int ig = 0 ; ig < arr.size(); ++ ig ) { GridBoxCell& gbc = arr[ig] ; if( gbc._move == moveid ) { if( iPlateSiz == FILLGLOBALCONFIG_PLATESIZE_LG ) { if( gbc._bigIndex!=-1 && (gbc._bigFilled==false && gbc._mid1Filled == false&& gbc._mid2Filled == false ) && gbc._bigIndex < index ) { index = gbc._bigIndex ; res = &gbc ; retPositionLL.x = gbc._bigllx ; retPositionLL.y = gbc._biglly ; } }else { // FILLGLOBALCONFIG_PLATESIZE_MD if( gbc._mid1Index != -1 &&(gbc._bigFilled==false && gbc._mid1Filled == false ) && gbc._mid1Index < index ) { index = gbc._mid1Index ; res = &gbc ; retPositionLL.x = gbc._mid1llx ; retPositionLL.y = gbc._mid1lly ; } if( gbc._mid2Index != -1 &&(gbc._bigFilled==false && gbc._mid2Filled == false ) && gbc._mid2Index < index ) { index = gbc._mid2Index ; res = &gbc ; retPositionLL.x = gbc._mid2llx ; retPositionLL.y = gbc._mid2lly ; } } } } } return res ; } void FillGlobalConfig::setFilled( GridBoxCell* gbc , const int iPlateSiz ) { if( iPlateSiz == FILLGLOBALCONFIG_PLATESIZE_LG ) { gbc->_bigFilled = true ; }else { if( gbc->_mid1Index != -1 && gbc->_mid1Filled == false ) { gbc->_mid1Filled = true ; }else if( gbc->_mid2Index!=-1 && gbc->_mid2Filled==false ) { gbc->_mid2Filled = true ; } } }