飞道的博客

C语言---简单五子棋小游戏

316人阅读  评论(0)

效果图如下:

设计思路:
棋盘设计为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);
} 

转载:https://blog.csdn.net/qq_52001969/article/details/117259151
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场