mirror of
https://gitee.com/yanmu_ym/cpp.git
synced 2026-06-17 06:36:14 +08:00
MAKE
This commit is contained in:
63
Make/sudoku/block.cpp
Normal file
63
Make/sudoku/block.cpp
Normal 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
22
Make/sudoku/block.h
Normal 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
49
Make/sudoku/color.h
Normal 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
36
Make/sudoku/command.cpp
Normal 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
32
Make/sudoku/command.h
Normal 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
79
Make/sudoku/common.h
Normal 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
8
Make/sudoku/hello.cpp
Normal 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
70
Make/sudoku/input.cpp
Normal 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
7
Make/sudoku/input.h
Normal 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
49
Make/sudoku/main.cpp
Normal 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
369
Make/sudoku/scene.cpp
Normal 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
52
Make/sudoku/scene.h
Normal 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
19
Make/sudoku/test.cpp
Normal 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
9
Make/sudoku/test.h
Normal 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
78
Make/sudoku/utility.inl
Normal 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
|
||||
Reference in New Issue
Block a user