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

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