c/c++趣味小游戏集
趣味字符界面小游戏集。源码取自或参考网络,可以在Dev-C++中编译的c/c++趣味小游戏。
特别提示:1、走迷宫游戏和推箱子中的黑方块符号,若不会输入可用“囗”(wéi)字代替;2、windows10中使用Dev-C++编译运行没问题,但在windows11中发现失真——对不齐。
一、走迷宫游戏
能随机生成迷宫,用方向键移动A,从“入”口走到“出”口。
源码如下:
#include <stdio.h>#include <conio.h>#include <windows.h>#include <time.h>#define Height 25 //迷宫的高度,必须为奇数#define Width 25 //迷宫的宽度,必须为奇数#define Wall 1#define Road 0#define Start 2#define End 3#define Esc 5#define Up 1#define Down 2#define Left 3#define Right 4int map[Height+2][Width+2];void gotoxy(int x,int y) //移动坐标 {COORD coord;coord.X=x;coord.Y=y;SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), coord );}void hidden()//隐藏光标{HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);CONSOLE_CURSOR_INFO cci;GetConsoleCursorInfo(hOut,&cci);cci.bVisible=0;//赋1为显示,赋0为隐藏SetConsoleCursorInfo(hOut,&cci);}void create(int x,int y) //随机生成迷{int c[4][2]= {0,1,1,0,0,-1,-1,0};//四个方向int i,j,t;//将方向打乱for (i=0;i<4;i++) {j=rand()%4;t=c[i][0];c[i][0]=c[j][0];c[j][0]=t;t=c[i][1];c[i][1]=c[j][1];c[j][1]=t;}map[x][y]=Road;for (i=0;i<4;i++)if(map[x+2*c[i][0]][y+2*c[i][1]]==Wall) {map[x+c[i][0]][y+c[i][1]]=Road;create(x+2*c[i][0],y+2*c[i][1]);}}int get_key() //接收按键 {char c;while(c=getch()) {if(c==27) return Esc;//Escif(c!=-32)continue;c=getch();if(c==72) return Up;//上if(c==80) return Down;//下if(c==75) return Left;//左if(c==77) return Right;//右}return 0;}void paint(int x,int y) //画迷宫 {gotoxy(2*y-2,x-1);switch(map[x][y]) {case Start:printf("入");break;//画入口case End:printf("出");break;//画出口case Wall:printf("▇");break;//画墙case Road:printf(" ");break;//画路}}void game() {int x=2,y=1;//玩家当前位置,刚开始在入口处int c;//用来接收按键while(1) {gotoxy(2*y-2,x-1);printf("A");//画出玩家当前位置if(map[x][y]==End) //判断是否到达出口 {gotoxy(30,24);printf("\n");//printf("到达终点,按任意键结束");getch();break;}c=get_key();if(c==Esc) {gotoxy(0,24);break;}switch(c) {case Up: //向上走if(map[x-1][y]!=Wall) {paint(x,y);x--;}break;case Down: //向下走if(map[x+1][y]!=Wall) {paint(x,y);x++;}break;case Left: //向左走if(map[x][y-1]!=Wall) {paint(x,y);y--;}break;case Right: //向右走if(map[x][y+1]!=Wall) {paint(x,y);y++;}break;}}}int main() {int i,j;srand((unsigned)time(NULL));//初始化随即种子hidden();//隐藏光标for (i=0;i<=Height+1;i++)for (j=0;j<=Width+1;j++)if(i==0||i==Height+1||j==0||j==Width+1) //初始化迷宫map[i][j]=Road; else map[i][j]=Wall;create(2*(rand()%(Height/2)+1),2*(rand()%(Width/2)+1));//从随机一个点开始生成迷宫,该点行列都为偶数for (i=0;i<=Height+1;i++) //边界处理 {map[i][0]=Wall;map[i][Width+1]=Wall;}for (j=0;j<=Width+1;j++) //边界处理 {map[0][j]=Wall;map[Height+1][j]=Wall;}map[2][1]=Start;//给定入口map[Height-1][Width]=End;//给定出口for (i=1;i<=Height;i++)for (j=1;j<=Width;j++) //画出迷宫paint(i,j);game();//开始游戏getch();return 0;}
二、推箱子
源码:
#include <stdio.h>#include <stdlib.h>#include <conio.h>int map[2][7][8] ={//0:空的 1:■ :墙//3:☆ 4:★ //目的地和箱子//5:※ //人//7:⊙ //目的(3)和箱子(4)在一起//8:※ //人(5)和目的(3)在一起//为让多种情况使用一种算法{1, 1, 1, 1, 1, 1, 1, 1,1, 0, 0, 0, 0, 0, 0, 1,1, 3, 1, 0, 1, 1, 3, 1,1, 4, 0, 0, 4, 0, 3, 1,1, 0, 1, 0, 1, 1, 4, 1,1, 0, 0, 5, 0, 0, 0, 1,1, 1, 1, 1, 1, 1, 1, 1},{1, 1, 1, 1, 1, 1, 1, 1,1, 0, 0, 0, 0, 0, 0, 1,1, 3, 1, 0, 1, 1, 3, 1,1, 3, 4, 5, 4, 0, 3, 1,1, 4, 1, 0, 1, 1, 4, 1,1, 0, 0, 0, 0, 0, 0, 1,1, 1, 1, 1, 1, 1, 1, 1}};int cas = 0;//为0表示第一关//记录每一关的箱子数 或者是项目和目的在一起的总数int boxSum[2] = {3,4};//地图绘图void drawMap(){for (int i = 0; i < 7; i++){for (int j = 0; j < 8; j++){if (j == 0)printf("\t\t");switch (map[cas][i][j]){////0:空的 1:■ :墙case 0:printf(" ");break;case 1:printf("■");break;//3:☆ 4:★ //目的地和箱子case 3:printf("☆");break;case 4:printf("★");break;//5:※ //人case 5:case 8:printf("※");break;case 7:printf("⊙");break;//7:⊙ //目的(3)和箱子(4)在一起//8:※ //人(5)和目的(3)在一起}}printf("\n");}}//按键处理void keyDown(){//分析按键过程//定位人在哪里//人有两种情况:第一个是:人,第二个:人站在目的上int i, j;for (i = 0; i < 7; i++){for (j = 0; j < 8; j++){if (map[cas][i][j] == 5 || map[cas][i][j] == 8){break;}}if (map[cas][i][j] == 5 || map[cas][i][j] == 8){break;}}char ch = _getch();//看不见的字符输入,+头文件 conio.hswitch (ch){//72 80 75 77case 'w':case 'W':case 72://下一个地方等于空地或者是目的 能走if (map[cas][i - 1][j] == 0 || map[cas][i - 1][j] == 3){//3+5=8 :表示目的和人在一起//新地方(map[i-1][j])人(5)来了map[cas][i - 1][j] += 5;//老地方(map[i][j])人(5)走了map[cas][i][j] -= 5;}//如果下一个是箱子,要进一步判断能走//注意点:箱子两种状态:箱子,箱子和目的在一起else if (map[cas][i - 1][j] == 4 || map[cas][i - 1][j] == 7){//做箱子的下一个地方判断能不能走if (map[cas][i - 2][j] == 0 || map[cas][i - 2][j] == 3){//新的地方箱子来了map[cas][i - 2][j] += 4;//箱子的位置:箱子(-4)走了 人来(+5)map[cas][i - 1][j] += 1;//原来的地方人走了map[cas][i][j] -= 5;}}break;case 's':case 'S':case 80://下一个地方等于空地或者是目的 能走if (map[cas][i + 1][j] == 0 || map[cas][i + 1][j] == 3){//3+5=8 :表示目的和人在一起//新地方(map[i-1][j])人(5)来了map[cas][i + 1][j] += 5;//老地方(map[i][j])人(5)走了map[cas][i][j] -= 5;}else if (map[cas][i + 1][j] == 4 || map[cas][i + 1][j] == 7){//做箱子的下一个地方判断能不能走if (map[cas][i + 2][j] == 0 || map[cas][i + 2][j] == 3){//新的地方箱子来了map[cas][i + 2][j] += 4;//箱子的位置:箱子(-4)走了 人来(+5)map[cas][i + 1][j] += 1;//原来的地方人走了map[cas][i][j] -= 5;}}break;case 'a':case 'A':case 75://下一个地方等于空地或者是目的 能走if (map[cas][i][j - 1] == 0 || map[cas][i][j - 1] == 3){//3+5=8 :表示目的和人在一起//新地方(map[i-1][j])人(5)来了map[cas][i][j - 1] = map[cas][i][j - 1] + 5;//老地方(map[i][j])人(5)走了map[cas][i][j] = map[cas][i][j] - 5;//j+=5 j=j+5}else if (map[cas][i][j - 1] == 4 || map[cas][i][j - 1] == 7){//做箱子的下一个地方判断能不能走if (map[cas][i][j - 2] == 0 || map[cas][i][j - 2] == 3){//新的地方箱子来了map[cas][i][j - 2] += 4;//箱子的位置:箱子(-4)走了 人来(+5)map[cas][i][j - 1] += 1;//原来的地方人走了map[cas][i][j] -= 5;}}break;case 'D':case 'd':case 77://下一个地方等于空地或者是目的 能走if (map[cas][i][j + 1] == 0 || map[cas][i][j + 1] == 3){//3+5=8 :表示目的和人在一起//新地方(map[i-1][j])人(5)来了map[cas][i][j + 1] += 5;//老地方(map[i][j])人(5)走了map[cas][i][j] -= 5;}//下一个地方是箱子,判断箱子的下一个地方是不是目的和空地else if (map[cas][i][j + 1] == 4 || map[cas][i][j + 1] == 7){//做箱子的下一个地方判断能不能走if (map[cas][i][j + 2] == 0 || map[cas][i][j + 2] == 3){//新的地方箱子来了map[cas][i][j + 2] += 4;//箱子的位置:箱子(-4)走了 人来(+5)map[cas][i][j + 1] += 1;//原来的地方人走了map[cas][i][j] -= 5;}}break;}}//胜负判断//用什么判断胜负: 箱子到达目的的个数int gameOver(){int count = 0;//所有的地方找一遍for (int i = 0; i < 7; i++){for (int j = 0; j < 8; j++){if (map[cas][i][j] == 7)count++;}}return count;}//箱子数是零的时候也是胜利int gameOver2(){int count = 3;//所有的地方找一遍for (int i = 0; i < 7; i++){for (int j = 0; j < 8; j++){if (map[cas][i][j] == 3)count--;}}return count;}int main(){while (1){printf("\n\t用方向键或w a s d键移动※推动★进入☆\n",cas+1);printf("\n\t\t 共两关 第 %d 关\n",cas+1);drawMap();if (gameOver() == boxSum[cas]){cas++;if (cas == 2)break;else printf("\n\t\t 该关 OK!按任一键进继续\n");}keyDown();system("cls");}printf("游戏结束!");printf("\n");system("pause");return 0;}
三、汉诺塔
源码如下:
#include <bits/stdc++.h>#include <conio.h>#include <windows.h>using namespace std;const int COLUMN[4] = { 0, 2, 5, 8 };const int DISC_CNT_MAX = 10;const int ROW_OP_CNT = 2, COL_OP_CNT = 16;const int ROW_MESSAGE = 3, COL_MESSAGE = 16;const int ROW_HELP = 15, COL_HELP = 1;const int ROW_MAX = 30, COL_MAX = 120;const int BLUE = 1;const int GREEN = 2;const int CYAN = 3;const int AQUA = 3;const int RED = 4;const int PURPLE = 5;const int YELLOW = 6;const int WHITE = 7;int n;stack<int> rod[4];int sz[4] = { 0 };int pos1, pos2;int key;bool prev_key_is_esc;int op_cnt;bool is_moving;int moved_disc;template <typename T>inline T read() {T x = 0;T multiplier = 1;char ch = getchar();while (ch < '0' || ch > '9') { if (ch == '-') { multiplier = -1; } ch = getchar();}while (ch >= '0' && ch <= '9') { x = (x << 3) + (x << 1) + (ch & 15); ch = getchar();}return x * multiplier;}void set_caret_pos(int row = 1, int col = 1) {COORD pos;pos.X = col - 1;pos.Y = row - 1;SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);}int get_caret_row() {CONSOLE_SCREEN_BUFFER_INFO info;GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);return info.dwCursorPosition.Y + 1;}int get_caret_col() {CONSOLE_SCREEN_BUFFER_INFO info;GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);return info.dwCursorPosition.X + 1;}pair<int, int> get_caret_pos() {CONSOLE_SCREEN_BUFFER_INFO info;GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);return make_pair(info.dwCursorPosition.Y + 1, info.dwCursorPosition.X + 1);}void set_foreground_color(int x, bool intensity = false) {SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), x | (intensity << 3));}void set_cursor_visibility(bool visibility = true) {CONSOLE_CURSOR_INFO cc_info;cc_info.bVisible = visibility;cc_info.dwSize = 1;SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cc_info);}void disp_init_state(int n) {for (int i = 1; i <= n; i++) { set_caret_pos(i, COLUMN[1]); printf("%d", i);}for (int i = 1; i <= 3; i++) { set_caret_pos(n + 1, COLUMN[i] - 1); printf("---"); set_caret_pos(n + 2, COLUMN[i]); putchar('A' + i - 1);} set_caret_pos(ROW_OP_CNT, COL_OP_CNT);printf("0");}void disp_help() {set_caret_pos(ROW_HELP, COL_HELP);printf("如何玩:\n" "数字表示光盘的尺寸.\n" "将A杆上圆盘移动到C杆上,每次一个.\n" "每个杆上的圆盘必须按大小升序堆叠.\n" "使用左右箭头键选择杆.\n" "按Enter键拾取选定杆上的顶部圆盘.\n" "然后使用左右键移动.\n" "按ESC取消当前移动.\n" "再次按Enter键可将圆盘放置.\n" "按R重新启动.\n" "按ESC键两次退出.\n");}void disp_pos(int pos1, int pos2 = 0) {for (int i = 1; i <= 3; i++) { set_caret_pos(n + 3, COLUMN[i]); printf(" ");}set_caret_pos(n + 3, COLUMN[pos1]);printf("^");if (pos2) { set_caret_pos(n + 3, COLUMN[pos2]); set_foreground_color(GREEN, true); printf("^"); set_foreground_color(WHITE);}}void clear() {for (int i = 1; i <= DISC_CNT_MAX + 3; i++) { for (int j = 1; j <= COL_MAX; j++) { set_caret_pos(i, j); putchar(' '); }}}void moving_disc(int pos1, int pos2) {int x = rod[pos1].top(); set_caret_pos(n + 1 - sz[pos1], COLUMN[pos1]);set_foreground_color(RED, true);printf("%d", x);set_foreground_color(WHITE); set_caret_pos(n - sz[pos2] + (pos1 == pos2), COLUMN[pos2]);set_foreground_color(GREEN, true);printf("%d", x);set_foreground_color(WHITE);}void update_discs(int pos1, int pos2) {int x = rod[pos1].top(); set_caret_pos(n + 1 - sz[pos1], COLUMN[pos1]);printf(" ");rod[pos1].pop();sz[pos1]--; rod[pos2].push(x);sz[pos2]++;set_caret_pos(n + 1 - sz[pos2], COLUMN[pos2]);printf("%d", x);}void remove_temp_disc(int pos) {set_caret_pos(n - sz[pos], COLUMN[pos]);printf(" ");}void update_op_cnt() {op_cnt++;set_caret_pos(ROW_OP_CNT, COL_OP_CNT);printf("%d", op_cnt);}int main() {printf("输入光盘数量(不超过 %d): ", DISC_CNT_MAX);n = min(read<int>(), DISC_CNT_MAX); set_cursor_visibility(false);disp_help(); for (; n <= DISC_CNT_MAX; n++) { clear(); for (int i = 1; i <= 3; i++) { while (!rod[i].empty()) { rod[i].pop(); } sz[i] = 0; } for (int i = n; i >= 1; i--) { rod[1].push(i); } sz[1] = n; is_moving = false; pos1 = 1; op_cnt = 0; prev_key_is_esc = false; disp_init_state(n); disp_pos(1); while (true) { if (sz[3] == n) { set_caret_pos(ROW_MESSAGE, COL_MESSAGE); if (op_cnt != (1 << n) - 1) { printf("你用%d个动作完成了谜题.",op_cnt); } else { printf("祝贺你用最少的动作完成了谜题 " ); } Sleep(2000); break; } key = getch(); if (key == 224) { key = getch(); if (!is_moving) { if (key == 75) { // Left arrow key pos1 = (pos1 + 1) % 3 + 1; } else if (key == 77) { // Right arrow key pos1 = pos1 % 3 + 1; } disp_pos(pos1); } else { remove_temp_disc(pos2); if (key == 75) { // Left arrow key pos2 = (pos2 + 1) % 3 + 1; } else if (key == 77) { // Right arrow key pos2 = pos2 % 3 + 1; } moving_disc(pos1, pos2); disp_pos(pos1, pos2); } } else if (key == 13) { // Enter key if (!is_moving) { if (rod[pos1].empty()) { continue; } is_moving = true; moved_disc = rod[pos1].top(); pos2 = pos1; moving_disc(pos1, pos2); disp_pos(pos1, pos2); } else { if (!rod[pos2].empty() && rod[pos2].top() < moved_disc) { set_caret_pos(ROW_MESSAGE, COL_MESSAGE); printf("提示:光盘未按升序堆叠在棒上。"); continue; } is_moving = false; update_discs(pos1, pos2); update_op_cnt(); pos1 = pos2; disp_pos(pos1); } } else if (key == 27) { // Escape key if (prev_key_is_esc) { // Double ESC break; } if (is_moving) { is_moving = false; remove_temp_disc(pos2); update_discs(pos1, pos1); disp_pos(pos1); } else { prev_key_is_esc = true; } } else if (key == 'R' || key == 'r') { n--; break; } } if (prev_key_is_esc && key == 27) { // Double ESC break; }} set_caret_pos(ROW_MAX - 1, 1); return 0;}
四、贪吃蛇
源码如下:
#include <iostream>#include <cstdio>#include <cstdlib>#include <ctime>#include <conio.h>#include <cmath>#include <windows.h>using namespace std; /*** 光标定位 ***/HANDLE hout=GetStdHandle(STD_OUTPUT_HANDLE);COORD coord; void locate(int x,int y){ coord.X=y; coord.Y=x; SetConsoleCursorPosition(hout,coord);}; /*** 隐藏光标 ***/void hide(){ CONSOLE_CURSOR_INFO cursor_info={1,0}; SetConsoleCursorInfo(hout, &cursor_info);} /*** 生成随机数 ***/double random(double start, double end){ return start+(end-start)*rand()/(RAND_MAX + 1.0);} /*** 定义地图的长宽,蛇的坐标,长度,方向,食物的位置 ***/int m,n; struct node{ int x,y;}snake[1000]; int snake_length,dir;node food;int direct[4][2]={{-1,0},{1,0},{0,-1},{0,1}}; /*** 输出墙 ***/void print_wall(){ cout << " "; for (int i=1;i<=n;i++) cout << "-"; cout << endl; for (int j=0;j<=m-1;j++) { cout << "|"; for (int i=1;i<=n;i++) cout << " "; cout << "|" << endl; } cout << " "; for (int i=1;i<=n;i++) cout << "-";} /*** 首次输出蛇,其中snake[0]代表头 ***/void print_snake(){ locate(snake[0].x,snake[0].y); cout << "@"; for (int i=1;i<=snake_length-1;i++) { locate(snake[i].x,snake[i].y); cout << "*"; }} /*** 判断是否撞墙或者自撞 ***/bool is_correct(){ if (snake[0].x==0 || snake[0].y==0 || snake[0].x==m+1 || snake[0].y==n+1) return false; for (int i=1;i<=snake_length-1;i++) { if (snake[0].x==snake[i].x && snake[0].y==snake[i].y) return false; } return true;} /*** 随机生成并输出食物位置 ***/bool print_food(){ srand((unsigned)time(0)); bool e; while (1) { e=true; int i=(int) random(0,m)+1,j=(int) random(0,n)+1; food.x=i;food.y=j; for (int k=0;k<=snake_length-1;k++) { if (snake[k].x==food.x && snake[k].y==food.y) { e=false;break; } } if (e) break; } locate(food.x,food.y); cout << "$"; return true;} /*** 蛇的前进 ***/bool go_ahead(){ node temp; bool e=false; temp=snake[snake_length-1]; for (int i=snake_length-1;i>=1;i--) snake[i]=snake[i-1]; snake[0].x+=direct[dir][0]; snake[0].y+=direct[dir][1]; locate(snake[1].x,snake[1].y); cout << "*"; /*** 吃到了食物 ***/ if (snake[0].x==food.x && snake[0].y==food.y) { snake_length++; e=true; snake[snake_length-1]=temp; } /*** 输出此时蛇状态 ***/ if (!e) { locate(temp.x,temp.y); cout << " "; } else print_food(); locate(snake[0].x,snake[0].y); cout << "@"; /*** 如果自撞 ***/ if (!is_correct()) { system("cls"); cout << "You lose!" << endl << "Length: " << snake_length << endl; return false; } return true;} /*** 主函数 ***/int main(){system("mode con cols=80 lines=30"); //设置cmd窗口大小system("color 2"); //设置字符颜色:0 黑;1 深蓝;2 深绿;3 深青;4 深红;5 深紫;6 深褐 cout << "--------------------贪吃蛇---------------------" << endl; cout << "先选择难度.请在1-10中输入1个数,1最简单,10则最难" << endl; cout << "然后进入游戏画面,以方向键控制方向.祝你游戏愉快!" << endl; cout << "-----------------------------------------------" << endl; cout << "请输入难度级别:" ; m=25; n=40; if (m<10 || n<10 || m>25 || n>40) { cout << "ERROR" << endl; system("pause"); return 0; } int hard; cin >> hard; if (hard<=0 || hard>100) { cout << "ERROR" << endl; system("pause"); return 0; } /*** 数据全部初始化,包括蛇长,位置,方向 ***/ snake_length=5; clock_t a,b; char ch; double hard_len; for (int i=0;i<=4;i++) { snake[i].x=1; snake[i].y=5-i; } dir=3; /*** 输出初始地图,蛇与食物 ***/ system("cls"); hide(); print_wall(); print_food(); print_snake(); locate(m+2,0); cout << "Now length: "; /*** 开始游戏 ***/ while (1) { /*** 难度随长度增加而提高 ***/ hard_len=(double)snake_length/(double) (m*n); /*** 调节时间,单位是ms ***/ a=clock(); while (1) { b=clock(); if (b-a>=(int)(400-30*hard)*(1-sqrt(hard_len))) break; } /*** 接受键盘输入的上下左右,并以此改变方向 ***/ if (kbhit()) { ch=getch(); if (ch==-32) { ch=getch(); switch(ch) { case 72: if (dir==2 || dir==3) dir=0; break; case 80: if (dir==2 || dir==3) dir=1; break; case 75: if (dir==0 || dir==1) dir=2; break; case 77: if (dir==0 || dir==1) dir=3; break; } } } /*** 前进 ***/ if (!go_ahead()) break; /*** 在最后输出此时长度 ***/ locate(m+2,12); cout << snake_length; } system("pause"); return 0;}
附录、C++控制cmd窗口最大化
//cmd窗口最大化控制#include<windows.h>#include<iostream>using namespace std; HWND hwnd=GetForegroundWindow();//使hwnd代表最前端的窗口 int main(){//ShowWindow(hwnd,SW_MINIMIZE);//最小化 hwnd 所代表的窗口ShowWindow(hwnd,SW_MAXIMIZE);//最大化 hwnd 所代表的窗口 return 0;}