C语言实现简易五子棋小游戏
本文实例为大家分享了C语言实现简单五子棋小游戏的具体代码,供大家参考,具体内容如下
效果图如下:
设计思路:
棋盘设计为15×15格,初始状态光标在棋盘的中央,白棋先走,轮流落子,当一方连成五子或下满棋盘时,游戏结束(连成五子的一方获胜,下满棋盘为和棋)。当游戏一方胜利后显示胜利信息,提示信息利用汉字点阵输出。
程序游戏是一个二维平面图,可用二维数组来实现,数组两个下标可以表示棋盘上的位置,数组元素的值代表棋格上的状态,共有三种情况,分别是0代表空格,1代表白棋,2代表黑棋。程序的主要工作是接收棋手按键操作,棋手1用设定四个键控制光标移动,回车键表示落子。棋手2用另四个键控制光标移动,空格键表示落子。接收到回车键或空格键,说明棋手落子,先判断是否是有效位置,即有棋子的位置不能重叠落子。落子成功后,马上判断以该位置为中心的八个方向:上、下、左、右、左上、左下、右上、右下是否有相同颜色的棋子连成五子,如果连成五子,则游戏结束。
#include<stdio.h> #include<stdlib.h> #include<windows.h> #pragma comment(lib, "WINMM.LIB") #include <mmsystem.h> #include<conio.h> #include<time.h> #define width 32 //棋盘总宽度 #define high 31 //棋盘总高度 #define MAX_X 15 //棋盘横向格子数 #define MAX_Y 15 //棋盘纵向格子数 #define WIDTH (16+width) //游戏总高度 #define HIGH (high+4) //游戏总高度 #define player1 1 //白子玩家 #define player2 2 //黑子玩家 #define emptyPlayer 0//无子 #define Unplayer -2 //中途退出游戏,无玩家获胜 typedef struct Stack{ //记录下每次落子的坐标 int x[MAX_X*MAX_Y]; int y[MAX_X*MAX_Y]; //相当于栈顶指针 int top; }Stack; int pos[MAX_X][MAX_Y];//存储棋盘上各位置处的状态 比如有白子为1, 有黑子为2,无子为0 int px,py; //光标位置 int player = 1;//记录当前玩家 默认玩家从白方开始 int flag1 = 0;//标志游戏开始 int gameOver_player = -1;//判断结束的标志 int pre_px = -1, pre_py = -1;//记录下上一次的坐标位置 void gotoxy(int x,int y);//设置CMD窗口光标位置 void hide_cursor(); //隐藏CMD窗口光标 void map();//打印地图 void game_Description();//打印动态游戏说明 void initMapState();//初始化游戏位置数据 void mapState(int qizi);//数组记录下对应位置的状态 int isGoPlay();//判断是否可以落子 int hasGoPlay(int Player);//以落子处为中心,判断已经落子后的棋盘是否五子相连 void goPlay(int Player, Stack* p);//落子 Player 1 2 0 void yiDongKuang();//移动框 void player1_move();//玩家1_移动 void player2_move();//玩家2_移动 int gameOver();//判断游戏是否结束 Stack* createStack();//创建空栈 void push(Stack* p, int x, int y);//入栈 void color(const unsigned short textColor);//自定义函根据参数改变颜色 //void setColor(unsigned short backColor);//设置游戏背景颜色 void gotoxy(int x,int y)//设置CMD窗口光标位置 { COORD coord; coord.X = x; coord.Y = y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); } void hide_cursor() //隐藏CMD窗口光标 { CONSOLE_CURSOR_INFO cci; cci.bVisible = FALSE; cci.dwSize = sizeof(cci); HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorInfo(handle, &cci); } void color(const unsigned short textColor) //自定义函根据参数改变颜色 { if(textColor>0 && textColor<=15) //参数在0-15的范围颜色 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), textColor); //用一个参数,改变字体颜色 else //默认的字体颜色是白色 SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7); } //打印地图 void map() { int x, y; color(02); /*开始打印棋盘格子*/ //打印横向图格 for(y = 2; y < high - 1; y+=2){ for(x = 1; x < width - 2; x+=2){ gotoxy(x , y); printf("-+"); } } //打印竖向图格 for(y = 1; y < high; y += 2) { for(x = 2; x < width-2; x += 2){ gotoxy(x , y); printf("|"); } } /*打印棋盘格子结束*/ /*开始打印图框*/ //打印棋盘图框 for (y = 0; y < high; y++) { for (x = 0; x < width; x+=2) { if (x == 0 || x == width - 2){ gotoxy(x, y); printf("|"); } if(y == 0 || y == high - 1 ){ gotoxy(x, y); printf("--"); } } } //打印右图框 for(y = 0; y < high; y++){ for(x = width; x < WIDTH; x+=2){ if (x == WIDTH - 2){ gotoxy(x, y); printf("|"); } if(y == 0 || y == high - 1 ){ gotoxy(x, y); printf("--"); } } } //打印下图框 y->high ~ HiGH-1 x->0 ~ WIDTH-2 for(y = high; y < HIGH; y++){ for(x = 0; x < WIDTH; x+=2){ if (x == 0 || x == WIDTH - 2){ gotoxy(x, y); printf("|"); } if(y == high || y == HIGH - 1 ){ gotoxy(x, y); printf("--"); } } } //打印下图框内容 gotoxy( 1, high+1); printf(" 欢迎来到五子棋游戏!"); //打印右图框内容 gotoxy( width-1, 1); printf("游戏说明:"); gotoxy( width-1, 3); printf("1)X表示玩家一棋"); gotoxy( width-1, 4); printf("子,而O表示玩家"); gotoxy( width-1, 5); printf("二棋子"); gotoxy( width-1, 7); printf("2)X先、O后,交替"); gotoxy( width-1, 8); printf("下子,每次只能下"); gotoxy( width-1, 9); printf("一子"); gotoxy( width-1, 11); printf("3)棋子下在棋盘"); gotoxy( width-1, 12); printf("的格子内,棋子下"); gotoxy( width-1, 13); printf("定后,不得向其它"); gotoxy( width-1, 14); printf("点移动"); gotoxy( width-1, 16); printf("4)最先连成五子"); gotoxy( width-1, 17); printf("的一方即为获胜"); gotoxy( width-1, 19); printf("玩家一 移动键:"); gotoxy( width-1, 20); printf("w上 s下 a左 d右"); gotoxy( width-1, 21); printf("下子: 空格键"); gotoxy( width-1, 23); printf("玩家二 移动键:"); gotoxy( width-1, 24); printf("i上 k下 j左 l右"); gotoxy( width-1, 25); printf("下子:回车键"); gotoxy( width+1, 27); color(4); printf("退出键: Y"); gotoxy( width+1, 29); color(6); printf("悔棋键: G"); /*打印图框结束*/ color(02); /*打印棋盘上的四个标记点*/ gotoxy( 3*2+2 , 3*2+2); printf("*"); gotoxy( (MAX_X-4)*2 , 3*2+2); printf("*"); gotoxy( 3*2+2 , (MAX_Y-4)*2); printf("*"); gotoxy( (MAX_X-4)*2 , (MAX_Y-4)*2); printf("*"); /*打印结束*/ /*开始修边*/ /*gotoxy(width - 1, 0); printf(" "); gotoxy(width - 1, high - 1); printf(" ");*/ /*修边结束*/ /*打印地图完成*/ } //打印动态游戏说明 void game_Description() { //打印下图框内容 gotoxy( 1, high+1); printf(" "); if(player == player1){ gotoxy( 1, high+1); color(2); printf(" 玩家一下棋中..."); }else if(player == player2){ gotoxy( 1, high+1); color(2); printf(" 玩家二下棋中..."); } } //初始化游戏位置数据 void initMapState() { for(int i = 0 ; i < MAX_Y; i++){ for(int j = 0; j < MAX_X; j++){ pos[i][j] = 0;//初始状态全为空 } } //注意 光标的位置和存储在数组中的位置是不同的 px = 7; py = 7; gotoxy(py*2+1,px*2+1);//初始位置 } //数组记录下对应位置的状态 void mapState(int qizi) { //2*px+1 = x //2*py+1 = y //px->0~14 //py->0~14 if(px >= MAX_X || px < 0 || py >= MAX_Y || py < 0) return;//其他情况不可以记录状态 pos[px][py] = qizi; } //判断是否可以落子 int isGoPlay() { if(px >= MAX_X || px < 0 || py >= MAX_Y || py < 0) return 0;//其他情况不可以记录状态 if(pos[px][py] == emptyPlayer){//说明无子 return 1; }else{//说明有子 return 0; } } //以落子处为中心,判断已经落子后的棋盘是否五子相连 int hasGoPlay(int Player) { //分为两部分,先记录一部分的相同Player的个数 //再记录下另余部分的个数,相加为相连棋子总个数 int port1 = 0, port2 = 0; int x, y, count; //上下查找 x = px, y = py-1; while(pos[x][y]==Player && y >= 0){ ++port1;//上部分个数 --y;//上移 } y = py+1; while(pos[x][y]==Player && y < MAX_Y){ ++port2;//下部分个数 ++y;//下移 } //计算总数 count = port1 + port2 + 1; if(count >= 5) return 1; //左右查找 port1 = 0, port2 = 0; x = px-1, y = py; while(pos[x][y]==Player && x >= 0){ ++port1;//上部分个数 --x;//左移 } x = px+1; while(pos[x][y]==Player && x < MAX_X){ ++port2;//下部分个数 ++x;//右移 } //计算总数 count = port1 + port2 + 1; if(count >= 5) return 1; //左上右下查找 port1 = 0, port2 = 0; x = px-1, y = py-1; while(pos[x][y]==Player && x >= 0 && y >= 0){ ++port1;//上部分个数 --x;//左移 --y;//上移 } x = px+1, y = py+1; while(pos[x][y]==Player && x < MAX_X && y < MAX_Y){ ++port2;//下部分个数 ++x;//右移 ++y;//下移 } //计算总数 count = port1 + port2 + 1; if(count >= 5) return 1; //右上左下查找 port1 = 0, port2 = 0; x = px+1, y = py-1; while(pos[x][y]==Player && x < MAX_X && y >= 0){ ++port1;//上部分个数 ++x;//左移 --y;//上移 } x = px-1, y = py+1; while(pos[x][y]==Player && x >= 0 && y < MAX_Y){ ++port2;//下部分个数 --x;//右移 ++y;//下移 } //计算总数 count = port1 + port2 + 1; if(count >= 5) return 1; return 0; } //落子 Player 1 2 0 void goPlay(int Player, Stack* p) { if(isGoPlay()){//说明可以落子 mapState(Player);//将对应位置的情况记录在数组中 if(hasGoPlay(Player)){//如果五子相连,则 gameover gameOver_player = Player; //记录此刻胜利玩家,结束游戏 } /*入栈*/ push(p, px, py); /*角色切换*/ if(Player == player1){ player = player2;//切换成玩家1 gotoxy(px*2+1, py*2+1 );//将光标移动到对应位置 color(07); printf("X");//打印玩家1 game_Description();// 动态说明 }else if(Player == player2){ player = player1;//切换成另一个玩家2 gotoxy( px*2+1, py*2+1);//将光标移动到对应位置 color(07); printf("O");//打印玩家2 game_Description();// 动态说明 } } } //入栈 void push(Stack* p, int x, int y) { //将此刻的坐标入栈 int top = p->top; ++p->top;//移动栈针 p->x[top] = x; p->y[top] = y; return; } //出栈 void pop(Stack* p) { int x, y; //出栈,移动栈顶指针 //如果栈为空,则不弹出 if(p->top <= 0) return; --p->top; int top = p->top; //记录下弹出的位置 x = p->x[top]; y = p->y[top]; //在弹出位置打印空格 gotoxy(x*2+1, y*2+1); printf(" "); //抹除记录 pos[x][y] = 0; } //移动框 void yiDongKuang() { //打印移动框 gotoxy(px*2, py*2+1); color(11); printf("["); gotoxy(px*2+2, py*2+1); printf("]"); //打印移动框结束 if(pre_px != -1 && pre_py != -1){ if(pre_px > px && pre_py == py){//当向左移动时 //将上一个位置的右边保持原样 gotoxy(pre_px*2+2, pre_py*2+1); color(2); printf("|"); }else if(pre_px < px && pre_py == py){//当向右移动时 //将上一个位置的左边保持原样 gotoxy(pre_px*2, pre_py*2+1); color(2); printf("|"); }else{//当向上下移动时 //将上一个位置的左右边保持原样 gotoxy(pre_px*2+2, pre_py*2+1); color(2); printf("|"); gotoxy(pre_px*2, pre_py*2+1); color(2); printf("|"); } } pre_px = px; pre_py = py; } //玩家1 移动 void player1_move(Stack* p) { char key; if (_kbhit())//检测是否按键 { fflush(stdin); key = _getch();//保存按键 game_Description();//动态说明 } switch(key) { case 'w': py--;yiDongKuang();break;//上 case 'a': px--;yiDongKuang();break;//左 case 'd': px++;yiDongKuang();break;//右 case 's': py++;yiDongKuang();break;//下 case ' ': goPlay(player1, p);break;//落子 case 'y': gameOver_player = -2; gameOver();//退出游戏 case 'Y': gameOver_player = -2; gameOver();//退出游戏 case 'g': pop(p); pop(p); break;//悔棋 case 'G': pop(p); pop(p); break;//悔棋 default: break; } //限制光标范围 if(py < 0) py = MAX_Y-1; else if(py >= MAX_Y) py = 0; else if(px < 0) px = MAX_X-1; else if(px >= MAX_X) px = 0; gotoxy(2*py+1, 2*px+1); } //玩家2 移动 void player2_move(Stack* p) { char key; if (_kbhit())//检测是否按键 { fflush(stdin); key = _getch();//保存按键 game_Description();//动态说明 } switch(key) { case 'i': py--;yiDongKuang();break;//上 case 'j': px--;yiDongKuang();break;//左 case 'l': px++;yiDongKuang();break;//右 case 'k': py++;yiDongKuang();break;//下 case '\r': goPlay(player2, p);break;//落子 case 'y': gameOver_player = -2; gameOver();//退出游戏 case 'Y': gameOver_player = -2; gameOver();//退出游戏 case 'g': pop(p); pop(p); break;//悔棋 case 'G': pop(p); pop(p); break;//悔棋 default: break; } //限制光标范围 if(py < 0) py = MAX_Y-1; else if(py >= MAX_Y) py = 0; else if(px < 0) px = MAX_X-1; else if(px >= MAX_X) px = 0; gotoxy(2*px+1, 2*py+1); } //创建空栈 Stack* createStack(){ //申请空间 Stack* p = (Stack* )malloc(sizeof(Stack)); //如果未申请到空间 if(p==NULL) return NULL; p->top = 0;//初始化栈顶 return p; } //判断游戏是否结束 int gameOver() { //gamerOver_player -1 表示继续游戏 1 表示白方胜利 2 表示黑方胜利 0 表示平局 //五子相连 一方取胜 y->high ~ HiGH-1 x->0 ~ WIDTH-2 if(gameOver_player == -1){ return 1; }else if(gameOver_player == player1){//白方胜利 gotoxy( 1, high+1); printf("玩家1胜利!!!"); return 0; }else if(gameOver_player == player2){//黑方胜利 gotoxy( 1, high+1); printf("玩家2胜利!!!"); return 0; }else if(gameOver_player == emptyPlayer){//棋盘满棋 平局 gotoxy( 1, high+1); printf("平局!!!"); return 0; }else if(gameOver_player == Unplayer){//中途退出 gotoxy( 1, high+1); printf("正在退出游戏中..."); exit(1); } return 1; } int main(){ //调整游戏框 system("mode con cols=48 lines=35"); //打印地图 map(); //初始化游戏位置数据 initMapState(); //创建空栈 Stack* p = createStack(); //隐藏光标 hide_cursor(); //游戏循环 控制移动 while(gameOver()){ //不断调换人物 if(player == player1) player1_move(p);// 切换玩家1 else if(player == player2) player2_move(p);// 切换玩家2 } free(p); }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。
最新评论