- gf25071 的博客
游戏合集(ai)
- @ 2026-3-5 20:05:33
有bug
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <string>
#include <cstdio>
#ifdef _WIN32
#include <windows.h>
#include <conio.h>
#else
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#define Sleep(x) usleep((x)*1000)
#endif
using namespace std;
// 跨平台按键检测与读取
#ifdef _WIN32
int key_hit() { return _kbhit(); }
int get_key() { return _getch(); }
#else
int key_hit() {
struct termios oldt, newt;
int oldf;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
oldf = fcntl(STDIN_FILENO, F_GETFL, 0);
fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK);
int ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
fcntl(STDIN_FILENO, F_SETFL, oldf);
if (ch != EOF) {
ungetc(ch, stdin);
return 1;
}
return 0;
}
int get_key() {
struct termios oldt, newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
int ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
return ch;
}
#endif
// 跨平台清屏
void cls() {
#ifdef _WIN32
system("cls");
#else
system("clear");
#endif
}
// 控制台颜色设置(跨平台)
void color(int c) {
#ifdef _WIN32
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c);
#else
switch (c) {
case 1: printf("\033[31m"); break; // 红
case 2: printf("\033[32m"); break; // 绿
case 3: printf("\033[33m"); break; // 黄
case 4: printf("\033[34m"); break; // 蓝
case 5: printf("\033[35m"); break; // 紫
case 6: printf("\033[36m"); break; // 青
case 7: printf("\033[37m"); break; // 白
default: printf("\033[0m"); break; // 重置
}
#endif
}
void resetColor() { color(0); }
// 光标定位(x列,y行)
void gotoxy(int x, int y) {
#ifdef _WIN32
COORD pos = {(short)x, (short)y};
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
#else
printf("\033[%d;%dH", y + 1, x + 1);
#endif
}
// 隐藏光标
void hideCursor() {
#ifdef _WIN32
CONSOLE_CURSOR_INFO cci;
cci.bVisible = FALSE;
cci.dwSize = 1;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
#else
printf("\033[?25l");
#endif
}
// 显示光标(用于游戏结束后恢复)
void showCursor() {
#ifdef _WIN32
CONSOLE_CURSOR_INFO cci;
cci.bVisible = TRUE;
cci.dwSize = 1;
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
#else
printf("\033[?25h");
#endif
}
//================================================================================
// 贪吃蛇游戏
//================================================================================
#define S_W 24 // 蛇游戏宽度
#define S_H 14 // 蛇游戏高度
struct Point {
int x, y;
};
Point snake[100]; // 蛇身坐标
int s_len; // 蛇长度
int fx, fy; // 食物坐标
int dir; // 移动方向:1上 2下 3左 4右
bool s_over; // 游戏结束标记
// 初始化贪吃蛇
void s_init() {
s_over = false;
s_len = 3;
// 初始蛇身位置(中间)
snake[0] = {S_W / 2, S_H / 2};
snake[1] = {S_W / 2 - 1, S_H / 2};
snake[2] = {S_W / 2 - 2, S_H / 2};
dir = 4; // 初始向右
srand(time(0));
// 随机生成食物
fx = rand() % S_W;
fy = rand() % S_H;
}
// 绘制贪吃蛇游戏界面
void s_draw() {
gotoxy(0, 0);
// 绘制上边框
color(3);
for (int i = 0; i < S_W + 2; i++) printf("#");
resetColor();
printf("\n");
// 绘制游戏区域
for (int y = 0; y < S_H; y++) {
color(3);
printf("#"); // 左边框
resetColor();
for (int x = 0; x < S_W; x++) {
bool isSnake = false;
// 绘制蛇身
for (int i = 0; i < s_len; i++) {
if (snake[i].x == x && snake[i].y == y) {
color(2);
printf("O");
resetColor();
isSnake = true;
break;
}
}
// 不是蛇身则判断是否是食物
if (!isSnake) {
if (x == fx && y == fy) {
color(1);
printf("*");
resetColor();
} else {
printf(" ");
}
}
}
color(3);
printf("#\n"); // 右边框
resetColor();
}
// 绘制下边框
color(3);
for (int i = 0; i < S_W + 2; i++) printf("#");
resetColor();
// 显示分数(长度-初始长度)和操作提示
printf("\nScore: %d W/A/S/D移动 ESC退出", s_len - 3);
}
// 处理贪吃蛇输入
void s_input() {
if (key_hit()) {
int c = get_key();
if (c == 27) { s_over = true; return; } // ESC退出
// 方向控制(防止反向移动)
if ((c == 'w' || c == 'W') && dir != 2) dir = 1; // 上
if ((c == 's' || c == 'S') && dir != 1) dir = 2; // 下
if ((c == 'a' || c == 'A') && dir != 4) dir = 3; // 左
if ((c == 'd' || c == 'D') && dir != 3) dir = 4; // 右
}
}
// 贪吃蛇逻辑处理
void s_logic() {
// 蛇身跟随移动(从后往前复制)
for (int i = s_len - 1; i > 0; i--) snake[i] = snake[i - 1];
// 蛇头移动
switch (dir) {
case 1: snake[0].y--; break; // 上
case 2: snake[0].y++; break; // 下
case 3: snake[0].x--; break; // 左
case 4: snake[0].x++; break; // 右
}
// 边界检测
if (snake[0].x < 0 || snake[0].x >= S_W || snake[0].y < 0 || snake[0].y >= S_H) {
s_over = true;
}
// 撞自己检测
for (int i = 1; i < s_len; i++) {
if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
s_over = true;
break;
}
}
// 吃食物逻辑
if (snake[0].x == fx && snake[0].y == fy) {
s_len++; // 长度+1
// 重新生成食物
fx = rand() % S_W;
fy = rand() % S_H;
}
}
// 启动贪吃蛇游戏
void playSnake() {
cls();
hideCursor();
s_init();
while (!s_over) {
s_draw();
s_input();
s_logic();
Sleep(130); // 控制游戏速度
}
// 游戏结束
cls();
color(1);
printf("==== Game Over ====\n");
resetColor();
printf("Score: %d\nPress any key back...\n", s_len - 3);
// 清空按键缓冲区
while (key_hit()) get_key();
// 等待按键
while (!key_hit()) Sleep(50);
get_key();
showCursor();
}
//================================================================================
// 俄罗斯方块游戏
//================================================================================
#define T_W 10 // 方块宽度
#define T_H 20 // 方块高度
int t_map[T_H][T_W] = {0}; // 游戏地图(0空 1有方块)
// 7种方块形状(I/L/J/Z/S/T/O)
int shape[7][4][4] = {
{{0,0,0,0},{1,1,1,1},{0,0,0,0},{0,0,0,0}}, // I
{{0,1,0,0},{0,1,0,0},{0,1,1,0},{0,0,0,0}}, // L
{{0,1,0,0},{0,1,0,0},{1,1,0,0},{0,0,0,0}}, // J
{{0,0,1,0},{0,1,1,0},{0,1,0,0},{0,0,0,0}}, // Z
{{0,1,0,0},{0,1,1,0},{0,0,1,0},{0,0,0,0}}, // S
{{0,1,0,0},{1,1,1,0},{0,0,0,0},{0,0,0,0}}, // T
{{1,1,0,0},{1,1,0,0},{0,0,0,0},{0,0,0,0}} // O
};
int cx, cy; // 当前方块坐标
int t_type; // 当前方块类型
bool t_over; // 游戏结束标记
// 绘制俄罗斯方块界面
void t_draw() {
gotoxy(0, 0);
// 上边框
color(6);
for (int i = 0; i < T_W + 2; i++) printf("#");
resetColor();
printf("\n");
// 游戏区域
for (int y = 0; y < T_H; y++) {
color(6);
printf("#"); // 左边框
resetColor();
for (int x = 0; x < T_W; x++) {
// 绘制已固定的方块
if (t_map[y][x]) {
color(5);
printf("■");
resetColor();
} else {
// 绘制当前移动的方块
bool isCurrent = false;
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (shape[t_type][i][j] && cx + j == x && cy + i == y) {
color(4);
printf("■");
resetColor();
isCurrent = true;
break;
}
}
if (isCurrent) break;
}
if (!isCurrent) printf(" ");
}
}
color(6);
printf("#\n"); // 右边框
resetColor();
}
// 下边框
color(6);
for (int i = 0; i < T_W + 2; i++) printf("#");
resetColor();
// 操作提示
printf("\nW:旋转 A:左移 D:右移 S:下移 ESC:退出");
}
// 检测方块移动/旋转是否合法
bool t_check(int x, int y, int ty) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (shape[ty][i][j]) {
int nx = x + j, ny = y + i;
// 边界检测
if (nx < 0 || nx >= T_W || ny >= T_H) return false;
// 碰撞检测(ny>=0才检测,避免方块在顶部外的情况)
if (ny >= 0 && t_map[ny][nx]) return false;
}
}
}
return true;
}
// 锁定方块到地图
void t_lock() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
if (shape[t_type][i][j]) {
t_map[cy + i][cx + j] = 1;
}
}
}
// 消除满行
for (int y = T_H - 1; y >= 0; y--) {
bool isFull = true;
for (int x = 0; x < T_W; x++) {
if (!t_map[y][x]) {
isFull = false;
break;
}
}
if (isFull) {
// 行上移
for (int yy = y; yy > 0; yy--) {
memcpy(t_map[yy], t_map[yy - 1], T_W * sizeof(int));
}
memset(t_map[0], 0, T_W * sizeof(int)); // 最上行清空
y++; // 重新检查当前行
}
}
}
// 生成新方块
void t_new() {
cx = T_W / 2 - 2;
cy = 0;
t_type = rand() % 7;
// 无法生成新方块则游戏结束
if (!t_check(cx, cy, t_type)) t_over = true;
}
// 移动方块
void t_move(int dx, int dy) {
if (t_check(cx + dx, cy + dy, t_type)) {
cx += dx;
cy += dy;
} else if (dy != 0) {
// 下移失败则锁定方块并生成新方块
t_lock();
t_new();
}
}
// 旋转方块
void t_rot() {
// 保存原形状
int tmp[4][4];
memcpy(tmp, shape[t_type], sizeof(tmp));
// 顺时针旋转90度
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
shape[t_type][i][j] = tmp[3 - j][i];
}
}
// 旋转后不合法则恢复原形状
if (!t_check(cx, cy, t_type)) {
memcpy(shape[t_type], tmp, sizeof(tmp));
}
}
// 启动俄罗斯方块游戏
void playTetris() {
cls();
hideCursor();
memset(t_map, 0, sizeof(t_map));
t_over = false;
srand(time(0));
t_new();
int cnt = 0;
while (!t_over) {
t_draw();
// 处理输入
if (key_hit()) {
int c = get_key();
if (c == 27) break; // ESC退出
if (c == 'a' || c == 'A') t_move(-1, 0); // 左移
if (c == 'd' || c == 'D') t_move(1, 0); // 右移
if (c == 's' || c == 'S') t_move(0, 1); // 下移
if (c == 'w' || c == 'W') t_rot(); // 旋转
}
// 自动下落
if (++cnt % 18 == 0) t_move(0, 1);
Sleep(30);
}
// 游戏结束
cls();
color(1);
printf("==== Game Over ====\n");
resetColor();
printf("Press any key back...\n");
while (key_hit()) get_key();
while (!key_hit()) Sleep(50);
get_key();
showCursor();
}
//================================================================================
// 扫雷游戏
//================================================================================
#define M_W 9 // 扫雷宽度
#define M_H 9 // 扫雷高度
#define M_NUM 10 // 地雷数量
int m_map[M_H][M_W]; // 地图:-1=地雷 0-8=周围地雷数
int m_show[M_H][M_W]; // 显示状态:0=未点开 1=已点开 2=标记
bool m_over, m_win; // 游戏结束/胜利标记
// 初始化扫雷
void m_init() {
memset(m_map, 0, sizeof(m_map));
memset(m_show, 0, sizeof(m_show));
m_over = m_win = false;
srand(time(0));
// 随机生成地雷
int c = 0;
while (c < M_NUM) {
int x = rand() % M_W, y = rand() % M_H;
if (m_map[y][x] != -1) {
m_map[y][x] = -1;
c++;
}
}
// 计算每个格子周围地雷数
for (int y = 0; y < M_H; y++) {
for (int x = 0; x < M_W; x++) {
if (m_map[y][x] != -1) {
int cnt = 0;
// 遍历8个方向
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
if (dx == 0 && dy == 0) continue;
int nx = x + dx, ny = y + dy;
if (nx >= 0 && nx < M_W && ny >= 0 && ny < M_H && m_map[ny][nx] == -1) {
cnt++;
}
}
}
m_map[y][x] = cnt;
}
}
}
}
// 递归展开空白区域
void m_open(int x, int y) {
// 边界/已点开/标记检测
if (x < 0 || x >= M_W || y < 0 || y >= M_H || m_show[y][x] != 0) return;
m_show[y][x] = 1; // 标记为已点开
// 空白格(0)则递归展开周围
if (m_map[y][x] == 0) {
for (int dy = -1; dy <= 1; dy++) {
for (int dx = -1; dx <= 1; dx++) {
if (dx == 0 && dy == 0) continue;
m_open(x + dx, y + dy);
}
}
}
// 检查胜利条件:所有非地雷格子都已点开
int opened = 0;
for (int y = 0; y < M_H; y++) {
for (int x = 0; x < M_W; x++) {
if (m_map[y][x] != -1 && m_show[y][x] == 1) {
opened++;
}
}
}
if (opened == M_W * M_H - M_NUM) {
m_win = true;
m_over = true;
}
}
// 绘制扫雷界面
void m_draw() {
gotoxy(0, 0);
color(3);
printf("==== 扫雷 ====\n");
resetColor();
// 绘制列号
printf(" ");
for (int x = 0; x < M_W; x++) {
printf("%d ", x + 1);
}
printf("\n");
// 绘制游戏区域
for (int y = 0; y < M_H; y++) {
// 行号
color(3);
printf("%d ", y + 1);
resetColor();
for (int x = 0; x < M_W; x++) {
if (m_over && m_map[y][x] == -1) {
// 游戏结束显示地雷
color(1);
printf("* ");
resetColor();
} else if (m_show[y][x] == 2) {
// 标记
color(5);
printf("! ");
resetColor();
} else if (m_show[y][x] == 1) {
// 已点开
if (m_map[y][x] == 0) {
printf(" ");
} else {
color(4);
printf("%d ", m_map[y][x]);
resetColor();
}
} else {
// 未点开
color(7);
printf("# ");
resetColor();
}
}
printf("\n");
}
// 提示信息
if (m_win) {
color(2);
printf("恭喜胜利!ESC退出\n");
resetColor();
} else if (m_over) {
color(1);
printf("踩到地雷!ESC退出\n");
resetColor();
} else {
printf("操作:W/A/S/D移动光标 空格点开 F标记 ESC退出\n");
}
}
// 扫雷输入处理
void m_input(int &cx, int &cy) {
if (key_hit()) {
int c = get_key();
switch (c) {
case 27: m_over = true; break; // ESC退出
case 'w': case 'W': if (cy > 0) cy--; break; // 上
case 's': case 'S': if (cy < M_H - 1) cy++; break; // 下
case 'a': case 'A': if (cx > 0) cx--; break; // 左
case 'd': case 'D': if (cx < M_W - 1) cx++; break; // 右
case ' ': // 空格点开
if (m_show[cy][cx] == 0) {
if (m_map[cy][cx] == -1) {
m_over = true; // 踩雷
} else {
m_open(cx, cy); // 展开区域
}
}
break;
case 'f': case 'F': // 标记/取消标记
if (m_show[cy][cx] == 0) {
m_show[cy][cx] = 2;
} else if (m_show[cy][cx] == 2) {
m_show[cy][cx] = 0;
}
break;
}
}
}
// 启动扫雷游戏
void playMinesweeper() {
cls();
hideCursor();
m_init();
int cx = 0, cy = 0; // 光标位置
while (!m_over) {
m_draw();
// 绘制光标
gotoxy(cx * 2 + 2, cy + 2);
m_input(cx, cy);
Sleep(50);
}
// 最后绘制一次(显示地雷/胜利)
m_draw();
// 等待按键
printf("Press any key back...\n");
while (key_hit()) get_key();
while (!key_hit()) Sleep(50);
get_key();
showCursor();
}
//================================================================================
// 主菜单
//================================================================================
void showMenu() {
cls();
color(3);
printf("==== 小游戏合集 ====\n");
resetColor();
printf("1. 贪吃蛇\n");
printf("2. 俄罗斯方块\n");
printf("3. 扫雷\n");
printf("0. 退出\n");
printf("请选择(0-3):");
}
int main() {
int choice = -1;
while (choice != 0) {
showMenu();
// 读取选择
while (!key_hit()) Sleep(50);
choice = get_key() - '0';
switch (choice) {
case 1: playSnake(); break;
case 2: playTetris(); break;
case 3: playMinesweeper(); break;
case 0: break;
default:
cls();
printf("输入错误,请重新选择!\n");
Sleep(1000);
break;
}
}
cls();
printf("感谢游玩!\n");
return 0;
}