C语言小游戏——三子棋

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

 大家好,在介绍了之前的猜数字游戏后,大家是不是意犹未尽呢?为了锻炼大家的编程能力与培养大家的编程兴趣,今天小编给大家带来了更加有难度的小游戏——三子棋,希望大家跟着小编的思路,灵活应用,提高自己的编程水平。


 1.游戏规则

     三子棋小游戏是民间非常传统的小游戏,就是在一个九宫格中,玩家双方分别先后在一个空格内落子首先将三个棋子连成一条线的玩家获胜,而今天小编给大家带来的是玩家与电脑的对弈的讲解。

2.游戏思路分析

    要实现游戏我们需要三个文件

      1.text.c是为了对我们逻辑实现的测试

      2.game.c是为了实现对游戏的编写

      3.game.h可以理解对game.c内部的封装,来方便其他源文件的调用

     根据游戏规则,我们大致可以把游戏分为这几个模块

         1.游戏菜单与游戏测试的编写

          2.游戏的实现

          2.1棋盘初始化

          2.2棋盘的打印

          2.3玩家下棋

          2.4电脑下棋

          2.5游戏输赢判断

1.游戏菜单与游戏测试的编写

    首先是游戏菜单的编写

void mune()
{
	printf("*************************\n");
	printf("*******  1.play  ********\n");
	printf("*******  0.exit  ********\n");
	printf("*************************\n");
	
}

  其次是游戏测试的编写

void text()
{
	int input=0;
	do 
	{
	 mune(); 
	scanf("%d",&input); 
	switch(input)
	{
		case 1:
		   {
		   game();
		   break;
           }
		case 0:
		   
		   {
		   printf("退出游戏");
		   break;
	       }  
		 default:
		   printf("输入有误"); 
	}	
	}while(input);
}

int main()
{
	text();
	return 0;
}

     这里逻辑是玩家看见菜单选择1.进入,0.退出的规则,下面是效果展现

     进入游戏:

     

    退出游戏:

     

 2.游戏的实现

        这里我们的思路是利用二维数组存储游戏落子内容,先实现棋盘的初始化,然后打印空棋盘,随后就是实现人机互弈与输赢的判断,下面给大家看总代码,接下来就是逐步介绍。

void game()
{
	char broad[3][3];
	srand(time(NULL));
	char ret=0;
	init_broad(broad,ROW,COL);
	print_broad(broad,ROW,COL);
	while(1)
	{   
	    
		men_play(broad,ROW,COL);
		ret=is_win(broad,ROW,COL);
		print_broad(broad,ROW,COL);
		if(ret!='C')
		{
			break;
		}
		
		computer_play(broad,ROW,COL);
		ret=is_win(broad,ROW,COL);
		print_broad(broad,ROW,COL);
		if(ret!='C')
		{
			break;
		}
	
    } 	
	if(ret=='*')
    {
    	printf("玩家获胜\n"); 
	}
	else if(ret=='#')
	{
		printf("电脑获胜\n"); 
	}
	else 
	    printf("平局\n");
    
	
}

     注意:对于实参ROW和COL是我们宏定义在game.h文件中的,之所以使用宏定义是为了未来实现对棋盘行数和列数的更改,以使该游戏不局限于三子棋。

 2.1 棋盘的初始化

    由于我们是利用二维数组记录落子内容,所以初始化就是对数组的初始化,那么为了让大家看起来棋盘为空那么最好的方法就是给数组全部都赋值为空格即可 ,代码展现

void init_broad(char broad[ROW][COL],int row,int col)
{
	int i=0;
	for(i=0;i<=row;i++)
	{
		int j=0;
	    for(j=0;j<=col;j++)
	    {
	    	broad[i][j]=' ';
		}
	}
}

2.2 棋盘的打印

    对于棋盘的打印我们可以从行和列分别入手,先给大家看成品棋盘,然后和大家分析

    

 

  首先我们的思路是按行打印,这里我们可以看到有5行的内容,但是为了我们的参数更好的实现对该实现循环控制,我们可以看作是进行了三次内容的打印,代码如下

void print_broad(char broad[ROW][COL],int row,int col)
{   int i=0;
	for(i=0;i<row;i++)
	{  
	  printf(" %c | %c | %c \n",broad[i][0],broad[i][1],broad[i][2]);
	  printf("___|___|___\n");
	}
}

成果展示

    

 这里我们发现多了一行”___|___|___“对于这里我们可以使用if语句进行选择,代码如下

void print_broad(char broad[ROW][COL],int row,int col)
{   int i=0;
	for(i=0;i<row;i++)
	{  
	  printf(" %c | %c | %c \n",broad[i][0],broad[i][1],broad[i][2]);
	  if(i<row-1)
	      printf("___|___|___\n");
	}
}

实现展现:

 这里我们发现已经实现了我如上图的实现,但是对于列,我们可以利用和行相同的思想进行拆解打印。方便参数控制,以实现未来对行列打印的更改,这里我就不再讲解,直接给大家上代码

void print_broad(char broad[ROW][COL],int row,int col)
{   int i=0;
	for(i=0;i<row;i++)
	{   int j=0;
	    for(j=0;j<col;j++)
	    {
		printf(" %c ",broad[i][j]);
		if(j<col-1)
		   printf("|");	
	    }
	    printf("\n");
	 if(i<row-1)
		 for(j=0;j<col;j++)
	    {
	     printf("___");
		if(j<col-1)
		   printf("|");	
	    }
	    printf("\n");
	}
}

 2.3 玩家下棋

  玩家这里用的是坐标控制棋子的落点,由于玩家不知道数组是从0开始记数的,所以这里我们要给玩家输入的坐标行列各减一,还有用if语句判断输入坐标的合法性,以及玩家输入位置是否已经被输入,以上两点有一个不满足就要求玩家重新输入,代码如下

void men_play(char broad[ROW][COL],int row,int col)
{   
    int x=0;
	int y=0;
	printf("玩家下棋\n"); 
	while(1)
	{
		printf("输入填入的坐标:\n");
		scanf("%d %d",&x,&y);
		if(x<1&&x>row&&y<1&&y>col)
		{
			printf("非法输\n");
		} 
		else
		{
		  if(broad[x-1][y-1]==' ')
		  {
		  broad[x-1][y-1]='*';
		  break;
	      }
	    }
    }
}

2.4 电脑下棋

  电脑下棋就是对数组直接控制,只需要我们用随机数控制二维数组的行列就可以,对于随机数的产生我在猜数字游戏中有详细的介绍,随机数产生后我们需要判断随机数控制的的位置是否已经被输入,如果已经被输入,需要让系统再次产生随机数,代码如下

void computer_play(char broad[ROW][COL],int row,int col)
{  
  printf("电脑下棋\n"); 
    while(1)
	{
	
	     int x=rand()%row;
		 int y=rand()%col;
		 if(x>=0&&x<row&&y>=0&&y<col)
		 {
		 	 if(broad[x][y]==' ')
		 	 {
		 	    broad[x][y]='#';
		 	    break;
		 	 }
	     }
   }
	
}

现在给大家演示一下人机对弈的过程

这里我们看到玩家已经获胜,但是系统并没有提示接下来就需要我们编写下一个函数。

 2.5 游戏输赢判断

  对于判断输赢函数的编写我们在游戏实现函数中用ret接收以进行判断,对于不同的结果我们返回不同的符号。

由于玩家输入的是” * “为了便于从数组中提取所以用 表示玩家已经获胜,同理用 #表示电脑获胜,游戏继续我们用 ‘ C ’表示,平局用‘ Q ’表示。

对于三子棋,我们主要从行,列,对角线是否三个成一条线判断,对于平局,只需要数组全部不是空格后仍然没有三个成一条线就成立,这里我们再用一个函数is_full()判断即可。下面就是判断输赢代码演示:

char is_win(char broad[ROW][COL],int row,int col)
{
	int i=0;
    for(i=0;i<row;i++)
    {
    	if(broad[i][0]==broad[i][1]&&broad[i][1]==broad[i][2]&&broad[i][2]!=' ')
    	{
    		return broad[i][0];
		}
	}
    for(i=0;i<col;i++)
    {
    	if(broad[0][i]==broad[1][i]&&broad[1][i]==broad[2][i]&&broad[2][i]!=' ')
    	{
    		return broad[0][i];
		}
	}
	if(broad[0][0]==broad[1][1]&&broad[1][1]==broad[2][2]&&broad[2][2]!=' '||
	broad[0][2]==broad[1][1]&&broad[1][1]==broad[2][0]&&broad[2][0]!=' ')
	{
		return broad[1][1];
	}
	if(is_full(broad,ROW,COL)==1)
	{
		return 'Q';
	}
	else 
	    return 'C';
	
}

对于is_full()函数,代码如下:

int is_full(char broad[ROW][COL],int row,int col)
{
	int i=0;
	for(i=0;i<row;i++)
	{
		int j=0;
	    for(j=0;j<col;j++)
	    {   
	    	if(broad[i][j]==' ')
	    	      return 0;
		}
	}
	return 1;
}

实现演示:

 (还有两个结果大家可以自行演示,总代码在最下方

    以上就是三子棋的所有板块的书写,为了让大家更好的进行对代码的观看和理解,下面我把所有代码整个在一起

总代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
void mune()
{
	printf("*************************\n");
	printf("*******  1.play  ********\n");
	printf("*******  0.exit  ********\n");
	printf("*************************\n");
	
}
void init_broad(char broad[ROW][COL],int row,int col)
{
	int i=0;
	for(i=0;i<=row;i++)
	{
		int j=0;
	    for(j=0;j<=col;j++)
	    {
	    	broad[i][j]=' ';
		}
	}
}
void print_broad(char broad[ROW][COL],int row,int col)
{   int i=0;
	for(i=0;i<row;i++)
	{   int j=0;
	    for(j=0;j<col;j++)
	    {
		printf(" %c ",broad[i][j]);
		if(j<col-1)
		   printf("|");	
	    }
	    printf("\n");
	 if(i<row-1)
		 for(j=0;j<col;j++)
	    {
	     printf("___");
		if(j<col-1)
		   printf("|");	
	    }
	    printf("\n");
	}
}
void men_play(char broad[ROW][COL],int row,int col)
{   
    int x=0;
	int y=0;
	printf("玩家下棋\n"); 
	while(1)
	{
		printf("输入填入的坐标:\n");
		scanf("%d %d",&x,&y);
		if(x<1&&x>row&&y<1&&y>col)
		{
			printf("非法输\n");
		} 
		else
		{
		  if(broad[x-1][y-1]==' ')
		  {
		  broad[x-1][y-1]='*';
		  break;
	      }
	    }
    }
}
int is_full(char broad[ROW][COL],int row,int col)
{
	int i=0;
	for(i=0;i<row;i++)
	{
		int j=0;
	    for(j=0;j<col;j++)
	    {   
	    	if(broad[i][j]==' ')
	    	      return 0;
		}
	}
	return 1;
}
void computer_play(char broad[ROW][COL],int row,int col)
{  
  printf("电脑下棋\n"); 
    while(1)
	{
	
	     int x=rand()%row;
		 int y=rand()%col;
		 if(x>=0&&x<row&&y>=0&&y<col)
		 {
		 	 if(broad[x][y]==' ')
		 	 {
		 	    broad[x][y]='#';
		 	    break;
		 	 }
	     }
   }
	
}
char is_win(char broad[ROW][COL],int row,int col)
{
	int i=0;
    for(i=0;i<row;i++)
    {
    	if(broad[i][0]==broad[i][1]&&broad[i][1]==broad[i][2]&&broad[i][2]!=' ')
    	{
    		return broad[i][0];
		}
	}
    for(i=0;i<col;i++)
    {
    	if(broad[0][i]==broad[1][i]&&broad[1][i]==broad[2][i]&&broad[2][i]!=' ')
    	{
    		return broad[0][i];
		}
	}
	if(broad[0][0]==broad[1][1]&&broad[1][1]==broad[2][2]&&broad[2][2]!=' '||
	broad[0][2]==broad[1][1]&&broad[1][1]==broad[2][0]&&broad[2][0]!=' ')
	{
		return broad[1][1];
	}
	if(is_full(broad,ROW,COL)==1)
	{
		return 'Q';
	}
	else 
	    return 'C';
	
}


void game()
{
	char broad[3][3];
	srand(time(NULL));
	char ret=0;
	init_broad(broad,ROW,COL);
	print_broad(broad,ROW,COL);
	while(1)
	{   
	    
		men_play(broad,ROW,COL);
		ret=is_win(broad,ROW,COL);
		if(ret!='C')
		{
			break;
		}
		
		computer_play(broad,ROW,COL);
		ret=is_win(broad,ROW,COL);
		print_broad(broad,ROW,COL);
		if(ret!='C')
		{
			break;
		}
	
    } 	
	if(ret=='*')
    {
    	printf("玩家获胜\n"); 
	}
	else if(ret=='#')
	{
		printf("电脑获胜\n"); 
	}
	else 
	    printf("平局\n");
    
	
}
void text()
{
	int input=0;
	do 
	{
	 mune(); 
	scanf("%d",&input); 
	switch(input)
	{
		case 1:
		   {
		   game();
		   break;
           }
		case 0:
		   
		   {
		   printf("退出游戏");
		   break;
	       }  
		 default:
		   printf("输入有误"); 
	}	
	}while(input);
}

int main()
{
	text();
	return 0;
}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半只牛马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值