本次版本实现了 用C++实现的数独解题程序 SudokuSolver 2.6 的新功能及相关分析 里介绍的猜测级别相关的新功能。具体代码实现如下。
增加了showLevels 接口:
void showQuiz(); void showLevels();
增加了交互式猜测模式查询与修改接口 guessMode:
void guessMode(std::string& ex) { size_t pos = ex.find_first_not_of(" \t"); if (pos != std::string::npos) { ex.erase(0, pos); m_guessMode = (u8)strtoul(ex.c_str(), 0, 10); } printf("In interactive guessing mode:%d (0:no; other:yes)\n", (int)m_guessMode); }
构造函数成员初始化部分小修改:
CQuizDealer() : m_state(STA_UNLOADED), m_guessLevel(0), m_guessPos(0), m_guessValPos(0), m_soluSum(0), m_bigSum(0), m_bigbigSum(0), m_steps(0), m_bigSteps(0), m_bigbigSteps(0), m_mode(0), m_guessMode(0), m_maxLevel(0) {};
增加交互式猜测实现接口:
void doInteractGuess(u8& guessIdx); bool dealGuess(std::string& strGuess, u8& guessIdx);
增加两个成员变量:
u8 m_guessMode; // 0:auto-guess; other:interactive guess u8 m_maxLevel;
1 void CQuizDealer::showLevels() 2 { 3 if (m_stkSnap.empty()) { 4 printf("No guess level info\n"); 5 return; 6 } 7 std::stack<Snapshot*> stkSnap = m_stkSnap; 8 u8 levels = (u8)stkSnap.size(); 9 printf("At guess level %d:\n", (int)levels); 10 for (u8 level = levels; level > 0; --level) { 11 Snapshot* pSnap = stkSnap.top(); 12 u8 pos = pSnap->guessPos; 13 u8 val = pSnap->seqCell[pos].candidates[pSnap->guessValPos]; 14 u8 sum = pSnap->seqCell[pos].candidates[0]; 15 printf("Level %d [%d,%d]=%d (%d out of %d)\n", (int)level, (int)pos / 9 + 1, (int)pos % 9 + 1, (int)val, (int)pSnap->guessValPos, (u8)sum); 16 stkSnap.pop(); 17 } 18 }
1 bool CQuizDealer::dealGuess(std::string& strGuess, u8& guessIdx) 2 { 3 size_t pos = strGuess.find_first_not_of(" \t"); 4 if (pos == std::string::npos) 5 return true; 6 if (strGuess[pos] != '[') 7 return false; 8 strGuess.erase(0, pos + 1); 9 pos = strGuess.find_first_of(","); 10 if (pos == std::string::npos) 11 return false; 12 std::string str = strGuess.substr(0, pos); 13 u8 row = (u8)strtoul(str.c_str(), 0, 10); 14 if (row == 0 || row > 9) 15 return false; 16 --row; 17 strGuess.erase(0, pos + 1); 18 pos = strGuess.find_first_of("]"); 19 if (pos == std::string::npos) 20 return false; 21 str = strGuess.substr(0, pos); 22 u8 col = (u8)strtoul(str.c_str(), 0, 10); 23 if (col == 0 || col > 9) 24 return false; 25 --col; 26 u8 newIdx = row * 9 + col; 27 if (m_seqCell[newIdx].val != 0) 28 return false; 29 strGuess.erase(0, pos + 1); 30 pos = strGuess.find_first_of("="); 31 if (pos == std::string::npos) 32 return false; 33 str = strGuess.erase(0, pos + 1); 34 u8 val = (u8)strtoul(strGuess.c_str(), 0, 10); 35 if (val == 0 || val > 9) 36 return false; 37 for (u8 idx = 1; idx <= m_seqCell[newIdx].candidates[0]; ++idx) { 38 if (val == m_seqCell[newIdx].candidates[idx]) { 39 if (idx != 1) { 40 u8 tmp = m_seqCell[newIdx].candidates[1]; 41 m_seqCell[newIdx].candidates[1] = val; 42 m_seqCell[newIdx].candidates[idx] = tmp; 43 } 44 guessIdx = newIdx; 45 return true; 46 } 47 } 48 return false; 49 }
1 void CQuizDealer::doInteractGuess(u8& guessIdx) 2 { 3 std::string strGuess; 4 while (true) { 5 u8 val = m_seqCell[guessIdx].candidates[1]; 6 printf("Take a guess please, by default it will be [%d,%d]=%d:\n", (int)guessIdx / 9 + 1, (int)guessIdx % 9 + 1, (int)val); 7 getline(std::cin, strGuess); 8 if (dealGuess(strGuess, guessIdx)) 9 return; 10 printf("Invalid guess; please try again more carefully.\n"); 11 } 12 }
void CQuizDealer::guess(u8 guessIdx) { if (m_guessMode != 0) doInteractGuess(guessIdx); incSteps(); ++m_guessLevel; if (m_guessLevel > m_maxLevel) m_maxLevel = m_guessLevel; m_guessPos = guessIdx; ... }
void CQuizDealer::run(ulong tilsteps) { ... std::cout << "Run time: " << clock() - begin << " milliseconds; steps: " << m_steps << ", solution sum: " << m_soluSum << ".\n"; std::cout << " Biggest level on this run(til): " << (int)m_maxLevel << "\n"; m_maxLevel = 0; }
void CQuizDealer::runrun(ulong newsum) { ... std::cout << "Run-run time: " << clock() - begin << " milliseconds; current solutions: " << s_soluSum << std::endl; std::cout << " biggest level ever on this quiz: " << (int)m_maxLevel << std::endl; std::cout << " steps: " << m_bigbigSteps << " # " << m_bigSteps << " # " << m_steps << std::endl; std::cout << " total solutions: " << m_bigbigSum << " # " << m_bigSum << " # " << m_soluSum << ".\n"; }
// 1.0 2021/9/20 // 2.0 2021/10/2 // 2.1 2021/10/4 // 2.2 2021/10/10 // 2.3 2021/10/17 // 2.4 2021/10/19 // 2.5 2021/10/23 #define STR_VER "Sudoku Solver 2.6 2021/10/30 by readalps\n\n" void showOrderList() { printf(STR_VER); printf("Order List:\n"); printf("load-quiz <file>: load quiz from file\n"); printf("show: show quiz info\n"); printf("levels: show info about guess levels\n"); printf("run-mode [1|2|0]: query or change working mode\n"); printf("guess-mode [1|0]: query or change guessing mode\n"); printf("step: step forward\n"); printf("run: run till the end or a new solution met\n"); printf("runtil <steps>: run till certain steps run\n"); printf("runrun <sum>: run till the end or certain new solutions met\n"); printf("bye: quit\n"); } void dealOrder(std::string& strOrder) { std::string strEx; if ("bye" == strOrder) setQuit(); else if (matchPrefixEx(strOrder, "load-quiz ", strEx)) CQuizDealer::instance()->loadQuiz(strEx); else if ("show" == strOrder) CQuizDealer::instance()->showQuiz(); else if ("levels" == strOrder) CQuizDealer::instance()->showLevels(); else if (matchPrefixEx(strOrder, "run-mode", strEx)) CQuizDealer::instance()->mode(strEx); else if (matchPrefixEx(strOrder, "guess-mode", strEx)) CQuizDealer::instance()->guessMode(strEx); ... }