SudokuSolver 2.6 新增功能程序实现

本次版本实现了 用C++实现的数独解题程序 SudokuSolver 2.6 的新功能及相关分析 里介绍的猜测级别相关的新功能。具体代码实现如下。

CQuizDealer 类声明部分的修改

增加了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;


showLevels 接口实现



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 }


dealGuess 接口实现



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 }


doInteractGuess 接口实现



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 }


guess 接口实现小修改



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;
...
}


run 接口实现小修改



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


runrun 接口实现小修改



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);
...}