先给出完整代码,请给出完整的2个函数,要求注释仅解释功能,不添加任何类似于添加了……、修改了……的注释:
#pragma once
#define NOMINMAX
#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <string>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <random>
#include <stdexcept>
#include <windows.h>
#include <climits>
using PII = std::pair<int, int>;
using str = std::string;
int role_count, snack_count;
void clear() {
std::system("cls");
}
void wait(double second) {
Sleep(static_cast<DWORD>(second * 1000));
}
void wait_key() {
std::system("pause");
}
int ran(int l, int r) {
static std::random_device rd;
static std::mt19937 gen(rd());
std::uniform_int_distribution dis(l, r);
return dis(gen);
}
str get_key(double time) {
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
DWORD prevMode;
GetConsoleMode(hInput, &prevMode);
SetConsoleMode(hInput, ENABLE_WINDOW_INPUT | ENABLE_PROCESSED_INPUT);
DWORD startTime = GetTickCount64();
while (true) {
DWORD elapsed = GetTickCount64() - startTime;
if (elapsed >= static_cast<DWORD>(time)) {
SetConsoleMode(hInput, prevMode);
return "\0";
}
DWORD available;
if (!GetNumberOfConsoleInputEvents(hInput, &available) || available == 0) {
wait(0.01);
continue;
}
INPUT_RECORD inputRecord;
DWORD numEventsRead;
if (ReadConsoleInput(hInput, &inputRecord, 1, &numEventsRead)) {
if (inputRecord.EventType == KEY_EVENT && inputRecord.Event.KeyEvent.bKeyDown) {
WORD vkCode = inputRecord.Event.KeyEvent.wVirtualKeyCode;
if (vkCode == VK_ESCAPE) {
SetConsoleMode(hInput, prevMode);
return "ESC";
}
if (vkCode == VK_UP) {
SetConsoleMode(hInput, prevMode);
return "↑";
}
if (vkCode == VK_DOWN) {
SetConsoleMode(hInput, prevMode);
return "↓";
}
if (vkCode == VK_LEFT) {
SetConsoleMode(hInput, prevMode);
return "←";
}
if (vkCode == VK_RIGHT) {
SetConsoleMode(hInput, prevMode);
return "→";
}
if (vkCode == VK_RETURN) {
SetConsoleMode(hInput, prevMode);
return "ENTER";
}
CHAR asciiChar = inputRecord.Event.KeyEvent.uChar.AsciiChar;
if (asciiChar > 0 && !std::iscntrl(asciiChar)) {
SetConsoleMode(hInput, prevMode);
return str(1, asciiChar);
}
}
}
}
}
class ColorStr {
private:
str outputStr;
WORD textColor;
WORD originalAttr;
WORD ParseColor(const str& colorStr) const {
if (colorStr.empty()) return 0x07;
try {
size_t pos = 0;
int value = std::stoi(colorStr, &pos, 16);
if (pos == colorStr.size()) {
return static_cast<WORD>(value & 0xFF);
}
}
catch (...) {}
return 0x07;
}
public:
ColorStr() : textColor(0x07), originalAttr(0x07) {
outputStr = " ";
}
void SetStr(const str& b) {
outputStr = b;
}
str GetStr() const {
return outputStr;
}
void SetColor(const str& a) {
textColor = ParseColor(a);
}
void print() {
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO csbi;
if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
originalAttr = csbi.wAttributes;
}
else {
originalAttr = 0x07;
}
SetConsoleTextAttribute(hConsole, textColor);
std::cout << outputStr;
SetConsoleTextAttribute(hConsole, originalAttr);
std::cout.flush();
}
};
template <typename Describe, typename Value>
class data_list {
using Descr = Describe;
using pdv = std::pair<Descr, Value>;
std::map<Descr, Value> data;
public:
data_list() {}
~data_list() {}
void add(Descr des, Value val) {
data.insert({ des, val });
}
void erase(Descr des) {
data.erase(des);
}
void print() {
for (auto i : data) {
std::cout << i.first << ' ' << i.second << std::endl;
}
}
size_t size() {
return data.size();
}
void print(Descr idx) {
if (data.empty()) return;
std::cout << idx << ':' << data[idx] << std::endl;
}
Value& operator[](Descr idx) {
return data[idx];
}
operator std::vector<pdv>() {
std::vector<pdv> temp;
for (const auto& p : data) {
temp.push_back(p);
}
return temp;
}
auto begin() {
return data.begin();
}
auto end() {
return data.end();
}
};
class screen {
using vcc = std::vector<std::vector<ColorStr >>;
vcc scr;
size_t n, m;
data_list<str, int> data;
public:
screen(size_t n_, size_t m_) : n(n_), m(m_) {
vcc temp(n, std::vector<ColorStr>(m));
for (auto& row : temp) {
for (auto& cell : row) {
cell.SetStr(" ");
cell.SetColor("F0");
}
}
scr = temp;
}
int& Data(str des) {
return data[des];
}
void add(str des, int val) {
data.add(des, val);
}
void erase(str des) {
data.erase(des);
}
void print() {
ColorStr border;
border.SetColor("F1");
border.SetStr("+");
border.print();
for (size_t i = 0; i < m; i++) {
border.SetStr("-");
border.print();
}
border.SetStr("+\n");
border.print();
for (auto& row : scr) {
border.SetStr("|");
border.print();
for (auto& cell : row) {
cell.print();
}
border.SetStr("|\n");
border.print();
}
border.SetStr("+");
border.print();
for (size_t i = 0; i < m; i++) {
border.SetStr("-");
border.print();
}
border.SetStr("+\n");
border.print();
data.print();
}
std::vector<ColorStr>& operator[](int idx) {
return scr[idx];
}
auto begin() {
return scr.data();
}
auto end() {
return scr.data() + n;
}
size_t x_size() {
return n;
}
size_t y_size() {
return m;
}
};
class role {
public:
role(screen& screen_) : scr(screen_) {
role_count++;
}
virtual ~role() {
role_count--;
}
virtual void operator=(const role& oth) {
scr = oth.scr;
}
protected:
screen& scr;
};
class apple : public role {
int x_, y_;
public:
apple(screen& screen_) : role(screen_) {
regenerate();
}
void regenerate() {
int sx = scr.x_size(), sy = scr.y_size();
do {
x_ = ran(0, sx - 1);
y_ = ran(0, sy - 1);
} while (scr[x_][y_].GetStr() != " ");
}
void update() {
scr[x_][y_].SetStr("c");
scr[x_][y_].SetColor("F4");
}
int x() {
return x_;
}
int y() {
return y_;
}
};
class snack : public role {
std::queue<PII> sna;
apple& app;
int dirx, diry;
str name, current_dir;
bool died, IsRobot;
str color_code;
void calculate_safe_direction(int x, int y) {
int sx = scr.x_size();
int sy = scr.y_size();
std::vector<int> distances = { y, sy - 1 - y, x, sx - 1 - x };
int max_index = std::max_element(distances.begin(), distances.end()) - distances.begin();
switch (max_index) {
case 0:
dirx = 0;
diry = -1;
current_dir = "←";
break;
case 1:
dirx = 0;
diry = 1;
current_dir = "→";
break;
case 2:
dirx = -1;
diry = 0;
current_dir = "↑";
break;
case 3:
dirx = 1;
diry = 0;
current_dir = "↓";
break;
}
}
int dis(int ax, int ay, int bx, int by) {
return std::abs(ax - bx) + std::abs(ay - by);
}
public:
explicit snack(screen& screen_, apple& apple_, str name_, int x, int y, bool IsPlayer = false)
: role(screen_), app(apple_), name(name_), died(false), IsRobot(!IsPlayer) {
dirx = diry = 0;
int sx = scr.x_size(), sy = scr.y_size();
if (x < 0) throw std::out_of_range("x<0");
if (y < 0) throw std::out_of_range("y<0");
if (x >= sx) throw std::out_of_range("x>=screen_x");
if (y >= sy) throw std::out_of_range("y>=screen_y");
if (name_ == "Robot_A") {
color_code = "F3";
}
else if (name_ == "Robot_B"){
color_code = "F5";
}
else {
color_code = "F2";
}
sna.push({ x, y });
scr[x][y].SetStr(current_dir);
scr[x][y].SetColor(color_code);
scr.add(name_, 0);
snack_count++;
calculate_safe_direction(x, y);
}
~snack() {
scr.erase(name);
}
void die() {
size_t sz = sna.size();
for (size_t i = 0; i < sz; i++) {
PII f = sna.front();
sna.pop();
scr[f.first][f.second].SetColor("F8");
sna.push(f);
}
snack_count--;
died = true;
throw std::runtime_error(name + "死了\n总长度达到:" + std::to_string(scr.Data(name) + 1) + '\n');
}
void ChangeDir(str new_dir) {
if (new_dir == "↑" && (dirx != 1 || IsRobot)) {
dirx = -1;
diry = 0;
current_dir = "↑";
}
else if (new_dir == "↓" && (dirx != -1 || IsRobot)) {
dirx = 1;
diry = 0;
current_dir = "↓";
}
else if (new_dir == "←" && (diry != 1 || IsRobot)) {
dirx = 0;
diry = -1;
current_dir = "←";
}
else if (new_dir == "→" && (diry != -1 || IsRobot)) {
dirx = 0;
diry = 1;
current_dir = "→";
}
else if (new_dir != "" && !IsRobot) throw std::invalid_argument("错误的方向参数:" + new_dir);
}
void UpDate(bool Auto = true) {
if (died) return;
if (IsRobot && Auto) {
std::vector<std::tuple<str, int, int >> directions = {
{"↑", -1, 0}, {"↓", 1, 0}, {"←", 0, -1}, {"→", 0, 1}
};
str opposite_dir;
if (current_dir == "↑") opposite_dir = "↓";
else if (current_dir == "↓") opposite_dir = "↑";
else if (current_dir == "←") opposite_dir = "→";
else opposite_dir = "←";
auto& head = sna.back();
int ax = app.x(), ay = app.y();
int best_dist = INT_MAX;
str best_dir = current_dir;
bool found_safe_move = false;
for (const auto& [dir, dx, dy] : directions) {
if (dir == opposite_dir) continue;
int nx = head.first + dx;
int ny = head.second + dy;
if (nx < 0 || ny < 0 || nx >= static_cast<int>(scr.x_size()) || ny >= static_cast<int>(scr.y_size())) continue;
if (scr[nx][ny].GetStr() != " " && scr[nx][ny].GetStr() != "c") continue;
int dist = dis(ax, ay, nx, ny);
if (dist < best_dist || (dist == best_dist && dir == current_dir)) {
best_dist = dist;
best_dir = dir;
found_safe_move = true;
}
else if (found_safe_move == false) {
best_dir = dir;
found_safe_move = true;
}
}
if (found_safe_move) {
ChangeDir(best_dir);
}
}
auto head = sna.back();
scr[head.first][head.second].SetStr(current_dir);
int nx = head.first + dirx;
int ny = head.second + diry;
if (nx < 0 || ny < 0 || nx >= static_cast<int>(scr.x_size()) || ny >= static_cast<int>(scr.y_size())) die();
if (scr[nx][ny].GetStr() != " " && scr[nx][ny].GetStr() != "c") die();
if (scr[nx][ny].GetStr() == "c") {
app.regenerate();
scr.Data(name)++;
}
else {
PII tail = sna.front();
sna.pop();
scr[tail.first][tail.second].SetStr(" ");
scr[tail.first][tail.second].SetColor("F0");
}
sna.push({ nx, ny });
scr[nx][ny].SetStr(current_dir);
scr[nx][ny].SetColor(color_code);
}
};
str filename = "snack.data";
data_list<str, int> score_list;
void run_snack() {
clear();
str name;
std::printf("请输入蛇的名字:");
std::cin >> name;
screen scr(20, 20);
apple app(scr);
int x, y;
std::map<int, bool> IsX, IsY;
x = ran(0, 19), y = ran(0, 19);
bool isquit = name == "ooseven";
snack PlayerSnack(scr, app, name, x, y, !isquit);
IsX[x] = true, IsY[y] = true;
x = ran(0, 19);
while (!IsX[x]) x = ran(0, 19);
y = ran(0, 19);
while (!IsY[y]) y = ran(0, 19);
snack RobotSnackA(scr, app, "Robot_A", x, y, false);
IsX[x] = true, IsY[y] = true;
x = ran(0, 19);
while (!IsX[x]) x = ran(0, 19);
y = ran(0, 19);
while (!IsY[y]) y = ran(0, 19);
snack RobotSnackB(scr, app, "Robot_B", x, y, false);
IsX[x] = true, IsY[y] = true;
wait_key();
clear();
if (isquit) {
bool IsDisplay;
str IsT;
printf("是否显示过程(T/t)?输入其他则不显示:");
std::cin >> IsT;
IsDisplay = IsT == "T" || IsT == "t";
while (true) {
try {
clear();
std::string key = get_key(100);
if (key == "ESC") {
scr.print();
std::printf("\n游戏暂停中(按回车键继续,ESC键退出本局游戏)……\n");
std::fflush(stdout);
str key = get_key(10);
while (key != "ENTER" && key != "ESC") {
wait(0.01);
key = get_key(10);
}
clear();
if (key == "ESC") {
throw std::runtime_error(name + "中途退出了\n总长度达到:" + std::to_string(scr.Data(name) + 1) + '\n');
}
}
if (key == "\0") {
if (IsDisplay) {
for (int i = 0; i < 9; i++) {
PlayerSnack.UpDate();
app.update();
scr.print();
wait(0.2);
clear();
}
PlayerSnack.UpDate();
}
else {
for (int i = 0; i < 10; i++) {
PlayerSnack.UpDate();
app.update();
}
}
}
else {
PlayerSnack.ChangeDir(key);
PlayerSnack.UpDate(false);
}
RobotSnackA.UpDate();
RobotSnackB.UpDate();
app.update();
scr.print();
wait(0.2);
}
catch (const std::exception& e) {
str temp = e.what();
bool equal = true;
for (int i = 0; i < static_cast<int>(name.size()); i++) {
if (temp[i] != name[i]) {
equal = false;
break;
}
}
if (equal) {
score_list[name] = std::max(score_list[name], scr.Data(name));
std::printf("游戏结束:\n%s\n", temp.c_str());
std::printf("当前最高分:%d\n", score_list[name]);
std::printf("----------------积分列表-----------------\n");
std::printf("玩家\t\t最高分\n");
using psi = std::pair<str, int>;
std::vector<psi> temp_list = score_list;
std::stable_sort(temp_list.begin(), temp_list.end(), [](const psi& a, const psi& b) {
return a.second > b.second;
});
for (auto& i : temp_list) {
std::printf("%-20s\t\t%d\n", i.first.c_str(), i.second);
}
std::cout << "-----------------------------------------" << std::endl;
wait_key();
break;
}
}
}
}
else {
while (true) {
try {
clear();
std::string key = get_key(100);
if (key == "ESC") {
scr.print();
std::printf("\n游戏暂停中(按回车键继续,ESC键退出本局游戏)……\n");
std::fflush(stdout);
str key = get_key(10);
while (key != "ENTER" && key != "ESC") {
wait(0.01);
key = get_key(10);
}
clear();
if (key == "ESC") {
throw std::runtime_error(name + "中途退出了\n总长度达到:" + std::to_string(scr.Data(name) + 1) + '\n');
}
}
PlayerSnack.ChangeDir(key);
PlayerSnack.UpDate();
RobotSnackA.UpDate();
RobotSnackB.UpDate();
app.update();
scr.print();
wait(0.2);
}
catch (const std::exception& e) {
str temp = e.what();
bool equal = true;
for (int i = 0; i < static_cast<int>(name.size()); i++) {
if (temp[i] != name[i]) {
equal = false;
break;
}
}
if (equal) {
score_list[name] = std::max(score_list[name], scr.Data(name));
std::printf("游戏结束:\n%s\n", temp.c_str());
std::printf("当前最高分:%d\n", score_list[name]);
std::printf("----------------积分列表-----------------\n");
std::printf("玩家\t\t最高分\n");
using psi = std::pair<str, int>;
std::vector<psi> temp_list = score_list;
std::stable_sort(temp_list.begin(), temp_list.end(), [](const psi& a, const psi& b) {
return a.second > b.second;
});
for (auto& i : temp_list) {
std::printf("%-20s\t\t%d\n", i.first.c_str(), i.second);
}
std::cout << "-----------------------------------------" << std::endl;
wait_key();
break;
}
}
}
}
}
void start() {
clear();
score_list = data_list<str, int>();
if (!std::filesystem::exists(filename)) {
std::printf("未找到存档文件 %s\n", filename.c_str());
wait(0.5);
clear();
return;
}
std::ifstream fin(filename);
if (!fin.is_open()) {
std::printf("打开文件失败\n");
wait(0.5);
clear();
return;
}
std::string header;
std::getline(fin, header);
if (header != "~") {
std::printf("无效文件格式! 期望'~',实际'%s'\n", header.c_str());
fin.close();
wait(0.5);
clear();
return;
}
int seed, salt, res;
fin >> seed >> salt >> res;
fin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
int calculated = (seed * 997 + salt) % 10000;
if (calculated != res) {
std::printf("存档校验失败! 计算值:%d 文件值:%d\n", calculated, res);
fin.close();
wait(0.5);
clear();
return;
}
int record_count;
fin >> record_count;
fin.ignore();
for (int i = 0; i < record_count; ++i) {
std::string name;
int score;
std::getline(fin, name);
fin >> score;
fin.ignore();
score -= salt;
if (fin.fail()||score%seed) {
std::cerr << "读取分数失败,记录索引: " << i << std::endl;
break;
}
score_list.add(name, score);
}
fin.close();
std::printf("成功读取 %d 条记录\n", record_count);
wait_key();
clear();
}
void end() {
clear();
std::ofstream fout(filename);
if (!fout.is_open()) {
std::printf("创建文件失败\n");
wait(0.5);
clear();
return;
}
fout << "~\n";
int seed = ran(1, 256);
int salt = ran(1000, 9999);
int res = (seed * 997 + salt) % 10000;
fout << seed << ' ' << salt << ' ' << res << std::endl;
fout << score_list.size() << std::endl;
for (auto& i : score_list) {
str temp = i.first;
for (auto& c : temp) {
}
fout << temp << '\n' << i.second * seed + salt << std::endl;
}
fout.flush();
fout.close();
std::printf("成功保存 %lld 条记录\n",score_list.size());
wait_key();
clear();
}
void launch_snack() {
start();
char go = 'T';
while (go == 'T' || go == 't') {
clear();
run_snack();
std::printf("再来一次(T/t)? 输入其他则退出:");
std::cin >> go;
}
end();
return;
}
最新发布