This commit is contained in:
Admin
2023-04-13 14:02:08 +08:00
commit 33c813630f
57 changed files with 27736 additions and 0 deletions

63
Make/sudoku/block.cpp Normal file
View File

@@ -0,0 +1,63 @@
#include <cassert>
#include <iostream>
#include "common.h"
#include "block.h"
#include "color.h"
CBlock::CBlock()
: _count(0) {}
bool CBlock::isValid() const
{
assert(MAX_COUNT == _count);
for (int i = 0; i < _count - 1; ++i)
{
for (int j = i + 1; j < _count; ++j)
{
if (UNSELECTED == _numbers[i]->value || UNSELECTED == _numbers[j]->value)
continue;
if (_numbers[i]->value == _numbers[j]->value)
return false;
}
}
return true;
}
bool CBlock::isFull() const
{
for (int i = 0; i < _count; ++i)
{
point_value_t *p_point_value = _numbers[i];
if (nullptr == p_point_value || UNSELECTED == p_point_value->value)
return false;
}
return true;
}
void CBlock::print() const
{
std::cout << "\u2503" << " ";
for (int i = 0; i < _count; ++i)
{
auto number = *(_numbers[i]);
if (0 == number.value)
std::cout << ' ' << " \u2503 ";
else
{
if (number.state == State::ERASED)
std::cout << Color::Modifier(Color::FG_GREEN) << number.value << Color::Modifier(Color::RESET) << " \u2503 ";
else
std::cout << number.value << " \u2503 ";
}
}
std::cout << std::endl;
}
void CBlock::push_back(point_value_t *point)
{
assert(nullptr != point);
_numbers[_count++] = point;
}

22
Make/sudoku/block.h Normal file
View File

@@ -0,0 +1,22 @@
#ifndef _SUDOKU_BLOCK_H_
#define _SUDOKU_BLOCK_H_
////
// 数独行政区域类
class CBlock
{
static const int MAX_COUNT = 9;
public:
CBlock();
bool isValid() const;
bool isFull() const;
void print() const;
void push_back(point_value_t *point);
private:
int _count;
point_value_t *_numbers[MAX_COUNT];
};
#endif

49
Make/sudoku/color.h Normal file
View File

@@ -0,0 +1,49 @@
#ifndef _SUDOKU_COLOR_H
#define _SUDOKU_COLOR_H
#include <iostream>
namespace Color
{
enum Code
{
BOLD = 1,
RESET = 0,
BG_BLUE = 44,
BG_DEFAULT = 49,
BG_GREEN = 42,
BG_RED = 41,
FG_BLACK = 30,
FG_BLUE = 34,
FG_CYAN = 36,
FG_DARK_GRAY = 90,
FG_DEFAULT = 39,
FG_GREEN = 32,
FG_LIGHT_BLUE = 94,
FG_LIGHT_CYAN = 96,
FG_LIGHT_GRAY = 37,
FG_LIGHT_GREEN = 92,
FG_LIGHT_MAGENTA = 95,
FG_LIGHT_RED = 91,
FG_LIGHT_YELLOW = 93,
FG_MAGENTA = 35,
FG_RED = 31,
FG_WHITE = 97,
FG_YELLOW = 33,
};
class Modifier
{
Code code;
public:
Modifier(Code pCode) : code(pCode) {}
friend std::ostream &
operator<<(std::ostream &os, const Modifier &mod)
{
return os << "\033[" << mod.code << "m";
}
};
} // namespace Color
#endif

36
Make/sudoku/command.cpp Normal file
View File

@@ -0,0 +1,36 @@
#include "scene.h"
#include "command.h"
CCommand::CCommand(CScene *pOwner) : _pOwner(pOwner)
{}
CCommand::CCommand(CScene *pOwner, const point_t &point, int preValue, int curValue)
: _pOwner(pOwner), _stPoint(point), _nPreValue(preValue), _nCurValue(curValue) {}
CCommand::CCommand(const CCommand &rhs)
: _pOwner(rhs._pOwner)
, _stPoint(rhs._stPoint)
, _nPreValue(rhs._nPreValue)
, _nCurValue(rhs._nCurValue)
{}
CCommand::~CCommand(){}
bool CCommand::execute(int nInputValue)
{
if (!_pOwner)
return false;
_stPoint = _pOwner->getCurPoint();
return _pOwner->setCurValue(nInputValue, _nPreValue);
}
void CCommand::undo()
{
if (_pOwner)
{
_pOwner->setPointValue(_stPoint, _nPreValue);
}
return;
}

32
Make/sudoku/command.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef _SUDOKU_COMMAND_H_
#define _SUDOKU_COMMAND_H_
#include <memory>
#include "common.h"
class CScene;
class CCommand
{
public:
CCommand(CScene* pOwner);
CCommand(CScene *pOwner, const point_t &point, int preValue, int curValue);
CCommand(const CCommand &);
~CCommand();
bool execute(int nInputValue);
void undo();
point_t getPoint() { return _stPoint; }
int getPreValue() { return _nPreValue; }
int getCurValue() { return _nCurValue; }
void setPoint(const point_t &point) { _stPoint = point; }
void setPreValue(int preValue) { _nPreValue = preValue; }
void setCurValue(int curValue) { _nCurValue = curValue; }
private:
CScene* _pOwner;
point_t _stPoint;
int _nPreValue;
int _nCurValue; // actually the member is never used
};
#endif

79
Make/sudoku/common.h Normal file
View File

@@ -0,0 +1,79 @@
#ifndef _SUDOKU_COMMON_H_
#define _SUDOKU_COMMON_H_
static const unsigned int UNSELECTED = 0;
enum class Difficulty : int
{
EASY = 1,
NORMAL,
HARD
};
enum class State : int
{
INITED = 0,
ERASED,
};
enum class KeyMode : int
{
NORMAL = 1,
VIM
};
struct KeyMap
{
const char ESC = 0x1B;
const char U = 0x75;
char UP;
char LEFT;
char DOWN;
char RIGHT;
const char ENTER = 0x0D;
};
struct Normal : KeyMap
{
Normal()
{
UP = 0x77;
LEFT = 0x61;
DOWN = 0x73;
RIGHT = 0x64;
}
};
struct Vim : KeyMap {
Vim()
{
UP = 0x6B;
LEFT = 0x68;
DOWN = 0x6A;
RIGHT = 0x6C;
}
};
using point_t = struct point_t {
int x;
int y;
};
using point_value_t = struct point_value_t {
int value;
State state;
};
class CPointSort
{
public:
bool operator()(const point_t &lhs, const point_t &rhs) const
{
if ((lhs.x == rhs.x) && (lhs.y == rhs.y))
return false;
else
return true;
}
};
#endif

8
Make/sudoku/hello.cpp Normal file
View File

@@ -0,0 +1,8 @@
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World" << endl;
return 0;
}

70
Make/sudoku/input.cpp Normal file
View File

@@ -0,0 +1,70 @@
#include <iostream>
#include <sstream>
#include <string>
#include "common.h"
#include "utility.inl"
// return number of grids to be erased
// 嘿嘿加个注释
int inputDifficulty()
{
cls();
std::string cmd;
int need_erase_grids = 0;
while (true)
{
std::cout << "设置难度1简单 2普通 3困难" << std::endl;
std::cin >> cmd;
try
{
Difficulty difficulty = static_cast<Difficulty>(std::stoi(cmd));
switch (difficulty)
{
case Difficulty::EASY:
need_erase_grids = 20;
break;
case Difficulty::NORMAL:
need_erase_grids = 35;
break;
case Difficulty::HARD:
need_erase_grids = 50;
break;
}
}
catch(...)
{
need_erase_grids = 0;
}
if (need_erase_grids > 0)
break;
std::cout << "输入错误!" << std::endl;
}
return need_erase_grids;
}
KeyMode inputKeyMode()
{
std::string mode;
do
{
message("设置按键模式1正常 2VIM");
std::cin >> mode;
try
{
KeyMode kmd = static_cast<KeyMode>(std::stoi(mode));
return kmd;
} catch (...)
{}
message("输入错误!");
} while (true);
}

7
Make/sudoku/input.h Normal file
View File

@@ -0,0 +1,7 @@
#ifndef _SUDOKU_INPUT_H_
#define _SUDOKU_INPUT_H_
int inputDifficulty();
KeyMode inputKeyMode();
#endif

49
Make/sudoku/main.cpp Normal file
View File

@@ -0,0 +1,49 @@
#include <iostream>
#include <string>
#include <cstring>
#include "scene.h"
#include "input.h"
#include "test.h"
#define _TEST_ 0
static void printHelp() {
std::cout << std::endl;
std::cout << "sudoku - a little game in command line" << std::endl
<< std::endl;
std::cout << "Usage:" << std::endl;
std::cout << "\t sudoku [-l <progressFile>]" << std::endl << std::endl;
std::cout << "Options:" << std::endl;
std::cout << "\t -l <path> \t specify path of progress file to load, optional." << std::endl
<< std::endl;
}
int main(int argc, char **argv)
{
#if _TEST_
test_case1();
getchar();
#else
CScene scene;
if (argc == 1) {
int eraseGridNumber = inputDifficulty();
scene.generate();
scene.eraseRandomGrids(eraseGridNumber);
}
else if (argc == 3 && !strcmp(argv[1], "-l")) {
// load saved game progress
scene.load(argv[2]);
}
else {
printHelp();
return 0;
}
scene.setMode(inputKeyMode());
scene.play();
#endif
return 0;
}

369
Make/sudoku/scene.cpp Normal file
View File

@@ -0,0 +1,369 @@
#include <cmath>
#include <iostream>
#include <fstream>
#include <memory.h>
#include <map>
#include <unordered_map>
#include <vector>
#include "common.h"
#include "scene.h"
#include "utility.inl"
CScene::CScene(int index)
: _max_column(pow(index, 2))
, _cur_point({0, 0})
{
init();
}
CScene::~CScene()
{
if(keyMap) delete keyMap;
}
void CScene::show() const
{
cls();
printUnderline();
for (int row = 0; row < _max_column; ++row)
{
CBlock block = _row_block[row];
block.print();
printUnderline(row);
}
}
void CScene::setMode(KeyMode mode)
{
switch (mode)
{
case KeyMode::NORMAL:
keyMap = new Normal;
break;
case KeyMode::VIM:
keyMap = new Vim;
break;
}
}
void CScene::printUnderline(int line_no) const
{
for (int colunm = 0; colunm < 9; ++colunm)
std::cout << "\u254B" << "\u2501" << ((_cur_point.y == line_no && _cur_point.x == colunm)?"^":"\u2501") << "\u2501";
std::cout << "\u254B" << std::endl;
}
void CScene::init()
{
memset(_map, UNSELECTED, sizeof _map);
// column_block 所有列
for (int col = 0; col < _max_column; ++col)
{
CBlock column_block;
for (int row = 0; row < _max_column; ++row)
{
column_block.push_back(_map + row * 9 + col);
}
_column_block[col] = column_block;
}
// row_block 所有行
for (int row = 0; row < _max_column; ++row)
{
CBlock row_block;
for (int col = 0; col < _max_column; ++col)
{
row_block.push_back(_map + row * 9 + col);
}
_row_block[row] = row_block;
}
// xy_block 所有九宫格, [行][列]
for (int block_index = 0; block_index < _max_column; ++block_index)
{
CBlock xy_block;
int xy_begin = block_index / 3 * 27 + block_index % 3 * 3;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
xy_block.push_back(_map + xy_begin + i * 9 + j);
}
}
_xy_block[block_index / 3][block_index % 3] = xy_block;
}
return;
}
bool CScene::setCurValue(const int nCurValue, int &nLastValue)
{
auto point = _map[_cur_point.x + _cur_point.y * 9];
if (point.state == State::ERASED)
{
nLastValue = point.value;
setValue(nCurValue);
return true;
}
else
return false;
}
void CScene::setValue(const point_t& p, const int value)
{
_map[p.x + p.y * 9].value = value;
}
void CScene::setValue(const int value)
{
auto p = _cur_point;
this->setValue(p, value);
}
// 选择count个格子清空
void CScene::eraseRandomGrids(const int count)
{
point_value_t p = {UNSELECTED, State::ERASED};
std::vector<int> v(81);
for (int i = 0; i < 81; ++i) {
v[i] = i;
}
for (int i = 0; i < count; ++i) {
int r = random(0, v.size() - 1);
_map[v[r]] = p;
v.erase(v.begin() + r);
}
}
bool CScene::isComplete()
{
// 任何一个block未被填满则肯定未完成
for (size_t i = 0; i < 81; ++i)
{
if (_map[i].value == UNSELECTED)
return false;
}
// 同时block里的数字还要符合规则
for (int row = 0; row < 9; ++row)
{
for (int col = 0; col < 9; ++col)
{
if (!_row_block[row].isValid() ||
!_column_block[col].isValid() ||
!_xy_block[row / 3][col / 3].isValid())
return false;
}
}
return true;
}
void CScene::save(const char *filename) {
std::fstream fs;
// TODO: check whether the file has existed
fs.open(filename, std::fstream::in | std::fstream::out | std::fstream::app);
// save _map
for (int i = 0; i < 81; i++) {
fs << _map[i].value << ' ' << static_cast<int>(_map[i].state) << std::endl;
}
// save _cur_point
fs << _cur_point.x << ' ' << _cur_point.y << std::endl;
// save _vCommand
fs << _vCommand.size() << std::endl;
for (CCommand command : _vCommand) {
point_t point = command.getPoint();
fs << point.x << ' ' << point.y << ' '
<< command.getPreValue() << ' '
<< command.getCurValue() << std::endl;
}
fs.close();
}
void CScene::load(const char *filename) {
std::fstream fs;
// TODO: check whether the file has existed
fs.open(filename, std::fstream::in | std::fstream::out | std::fstream::app);
// load _map
for (int i = 0; i < 81; i++) {
int tmpState;
fs >> _map[i].value >> tmpState;
_map[i].state = static_cast<State>(tmpState);
}
// load _cur_point
fs >> _cur_point.x >> _cur_point.y;
// load _vCommand
int commandSize;
fs >> commandSize;
for (int i = 0; i < commandSize; i++) {
point_t point;
int preValue, curValue;
fs >> point.x >> point.y >> preValue >> curValue;
_vCommand.emplace_back(this, point, preValue, curValue);
}
}
void CScene::play()
{
show();
char key = '\0';
while (1)
{
key = getch();
if (key >= '0' && key <= '9')
{
CCommand oCommand(this);
if (!oCommand.execute(key - '0'))
{
std::cout << "this number can't be modified." << std::endl;
}
else
{
_vCommand.push_back(std::move(oCommand)); // XXX: move without move constructor
show();
continue;
}
}
if (key == keyMap->ESC)
{
message("quit game ? [Y/N]");
std::string strInput;
std::cin >> strInput;
if (strInput[0] == 'y' || strInput[0] == 'Y')
{
message("do you want to save the game progress ? [Y/N]");
std::cin >> strInput;
if (strInput[0] == 'y' || strInput[0] == 'Y')
{
message("input path of the progress file: ", false);
std::cin >> strInput;
save(strInput.c_str());
}
exit(0);
} else
{
message("continue.");
}
}
else if (key == keyMap->U)
{
if (_vCommand.empty())
message("no more action to undo.");
else
{
CCommand& oCommand = _vCommand.back();
oCommand.undo();
_vCommand.pop_back();
show();
}
}
else if (key == keyMap->LEFT)
{
_cur_point.x = (_cur_point.x - 1) < 0 ? 0 : _cur_point.x - 1;
show();
}
else if (key == keyMap->RIGHT)
{
_cur_point.x = (_cur_point.x + 1) > 8 ? 8 : _cur_point.x + 1;
show();
}
else if (key == keyMap->DOWN)
{
_cur_point.y = (_cur_point.y + 1) > 8 ? 8 : _cur_point.y + 1;
show();
}
else if (key == keyMap->UP)
{
_cur_point.y = (_cur_point.y - 1) < 0 ? 0 : _cur_point.y - 1;
show();
}
else if (key == keyMap->ENTER)
{
if (isComplete())
{
message("congratulation! you win!");
getchar();
exit(0);
}
else
{
message("sorry, not completed.");
}
}
}
}
// 一个场景可以多次被初始化
void CScene::generate()
{
// XXX: pseudo random
static char map_pattern[10][10] = {
"ighcabfde",
"cabfdeigh",
"fdeighcab",
"ghiabcdef",
"abcdefghi",
"defghiabc",
"higbcaefd",
"bcaefdhig",
"efdhigbca"};
std::vector<char> v = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'};
// 产生字母到数字的随机映射
std::unordered_map<char, int> hash_map;
for (int i = 1; i <= 9; ++i)
{
int r = random(0, v.size() - 1);
hash_map[v[r]] = i;
v.erase(v.begin() + r);
}
// 填入场景
for (int row = 0; row < 9; ++row)
{
for (int col = 0; col < 9; ++col)
{
point_t point = {row, col};
char key = map_pattern[row][col];
setValue(point, hash_map[key]);
}
}
assert(isComplete());
return;
}
bool CScene::setPointValue(const point_t &stPoint, const int nValue)
{
auto point = _map[stPoint.x + stPoint.y * 9];
if (State::ERASED == point.state)
{
_cur_point = stPoint;
setValue(nValue);
return true;
}
else
return false;
}
point_t CScene::getCurPoint()
{
return _cur_point;
}

52
Make/sudoku/scene.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef _SUDOKU_SCENE_H_
#define _SUDOKU_SCENE_H_
#include <iostream>
#include <vector>
#include "common.h"
#include "block.h"
#include "command.h"
// 加个东西
//数独场景类
class CScene
{
public:
CScene(int index = 3);
virtual ~CScene();
void generate();
void show() const;
bool setCurValue(const int nCurValue, int& nLastValue);
bool setPointValue(const point_t&, const int);
point_t getCurPoint();
void eraseRandomGrids(const int count);
bool isComplete();
void play();
void save(const char *filename);
void load(const char *filename);
void setMode(KeyMode mode);
private:
void init(); // 将每个格子的指针放到block里面
void setValue(const int);
void setValue(const point_t &, const int);
void printUnderline(int line_no = -1) const;
private:
KeyMap *keyMap{};
int _max_column;
point_t _cur_point;
CBlock _column_block[9];
CBlock _row_block[9];
CBlock _xy_block[3][3];
point_value_t _map[81];
std::vector<CCommand> _vCommand;
};
#endif

19
Make/sudoku/test.cpp Normal file
View File

@@ -0,0 +1,19 @@
#include "test.h"
#include <time.h>
#include <iostream>
using namespace std;
//生成棋盘,10s
void test_case1()
{
CScene scene;
time_t begin, end;
time(&begin);
scene.generate();
time(&end);
scene.show();
cout << end - begin << endl;
}

9
Make/sudoku/test.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef _SUDOKU_TEST_H_
#define _SUDOKU_TEST_H_
#include "scene.h"
void test_case1();
#endif

78
Make/sudoku/utility.inl Normal file
View File

@@ -0,0 +1,78 @@
#ifndef _SUDOKU_UTILITY_INL_
#define _SUDOKU_UTILITY_INL_
#include <cstdlib>
#include <ctime>
#include <cassert>
#include <iostream>
//not real random,return number between [begin,end]
inline unsigned int random(int begin, int end)
{
assert(end >= begin && begin >= 0);
srand(time(NULL));
return (unsigned int)rand() % (end - begin + 1) + begin;
}
//网上找的均匀化随机数算法,不含max,非随机,弃用
inline int AverageRandom(int min, int max)
{
int minInteger = min * 10000;
int maxInteger = max * 10000;
srand(time(NULL));
int randInteger = rand() * rand();
int diffInteger = maxInteger - minInteger;
int resultInteger = randInteger % diffInteger + minInteger;
return (resultInteger / 10000);
}
inline void message(const char* msg = "", bool lf = true)
{
std::cout << msg;
if (lf) std::cout << std::endl;
}
#ifdef _WIN32
#include <conio.h>
#else
#ifdef __linux__
#include <termio.h>
#include <cstdio>
#elif __APPLE__
#include <termios.h>
#endif
inline char getch(void)
{
struct termios tmtemp, tm;
char c;
int fd = 0;
if (tcgetattr(fd, &tm) != 0)
{ /*获取当前的终端属性设置并保存到tm结构体中*/
return -1;
}
tmtemp = tm;
cfmakeraw(&tmtemp); /*将tetemp初始化为终端原始模式的属性设置*/
if (tcsetattr(fd, TCSANOW, &tmtemp) != 0)
{ /*将终端设置为原始模式的设置*/
return -1;
}
c = getchar();
if (tcsetattr(fd, TCSANOW, &tm) != 0)
{ /*接收字符完毕后将终端设置回原来的属性*/
return 0;
}
return c;
}
#endif
inline void cls(void)
{
#ifdef _WIN32
system("cls");
#else
system("clear");
#endif
}
#endif