经典小游戏之三子棋

目录

标题1.开始创建

标题2.一个菜单

标题3.状态选择

标题4.创建棋盘

标题5.动态的棋盘行和列

标题6.棋盘初始化

标题7.棋盘的打印

标题8.玩家下棋

标题9.电脑下棋

 标题10.判断输赢


三子棋想必大家并不陌生,作为经典游戏之一对于我们的代码训练有着非常大的好处。

今天我们就来逐步剖析下三子棋的逻辑思路和代码实现。

首先这种超过一百行以上的代码是不太适用于一个.c文件里实现,所以我们采用分装的方法。

既要为理清思路也要为后期的更改创造便利。

上代码:

game.h(函数声明)

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3 //行
#define COL 3 //列
//打印棋盘
void printf_board(char board[ROW][COL], int row, int col);
//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);
//玩家下棋
void play_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断输赢
char is_win(char board[ROW][COL], int row, int col);

game.c(函数实现)

#include"game.h"

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

}

void printf_board(char board[ROW][COL],int row,int col)
{
	int a = 0;
	int b = 0;
	//打印“  | |  ”
	for(a = 0;a < row;a++)
	{
		for(b = 0;b < col;b++)
		{
			printf(" %c ", board[a][b]);
			if (b < col - 1)
				printf("|");
		}
		printf("\n");
		//打印“---|---|---”
		if (a < row - 1)
		{
			for (b = 0; b < col; b++)
			{
				printf("---");
				if (b < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

void play_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:>\n");  
    
	while(1)
	{
		printf("请输入坐标(如:1 1 ):\n");
		scanf("%d %d", &x, &y);
		//判断坐标的合法性/是否被占用?
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if(board[x - 1][y - 1]==' ')//玩家输入的值是大于数组的,所以要-1处理。
			{
				board[x - 1][y - 1] = '*';//坐标合法将空格置换成*
				break;
			}

			else
			{
				printf("该坐标被占用,请重新输入!\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
}

void computer_move(char board[ROW][COL], int row, int col)  
{
	printf("电脑下棋:>\n");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
//棋盘未满返回0否则返回1
static int is_full(char board[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(' '==board[i][j])
			{
				return 0;
			}
		}
	}
	return 1;
}

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

	}
	if(board[0][0]==board[1][1] && board[1][1]==board[2][2] && board[1][1]!=' ')
	{
		return board[1][1];
	}
	if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	//判断平局
	if(is_full(board,row,col)==1)
	{
		return 'Q';
	}
	return 'C';

}

tase.c(测试文件)

#include"game.h"
void menu()
{ 
	printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");

}
 void play_game()
{
	 char ret = 0;
	 printf("玩游戏\n");
	 char board[ROW][COL] = { 0 };
	 init_board(board, ROW, COL);//初始化棋盘
	 printf_board(board, ROW, COL);//打印棋盘
	 while (1)
	 {
		 play_move(board, ROW, COL);//玩家下棋
	     ret=is_win(board,ROW,COL);
		 if (ret != 'C')
			 break;
		 printf_board(board, ROW, COL);//打印棋盘
		 computer_move(board, ROW, COL);//电脑下棋
		 if (ret != 'C')
			 break;
		 printf_board(board, ROW, COL);//打印棋盘
	 }
//玩家赢“*”
//电脑赢“#”
//平局“Q”
//游戏继续“C”
	 if(ret=='*')
	 {
		 printf("玩家赢!\n");
	 }
	 else if(ret=='#')
	 {
		 printf("电脑赢!\n");
	 }
	 else
	 {
		 printf("平局!\n");
	 }
	 printf_board(board, ROW, COL);
} 
int main()
{
	int a = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &a);
		switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (a);
	return 0;
}

以上就是我们三子棋的整个代码,不过这么多要是我也是看着头大,不过俗话说从无到有,代码都是一步步想出来然后堆砌成程序。

现在我们开始一步步创建三子棋:

标题1.开始创建

首先我们向,既然要做一个游戏至少让它运行一次,这里我们采用do while循环

tase.c

#include<stdio.h>
int main()
{
  do
  {
   
  }while();
  return 0;
}

do while是先加入表达式后判断的语句,正是做一个菜单的不二之选。

标题2.一个菜单

既然提到菜单,拿我们肯定要做一个嘛,毕竟再简陋也得有个门面来撑着不是?

tase.c

#include<stdio.h>
void menu()
{
    printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");
}
int main()
{
  int a = 0;
  do
  {
   menu();
   printf("请选择\n");
   scanf("%d",&a);
  }while();
}

为了实现菜单功能我们分装了一个menu函数然后在函数内部写了一个相对奢华(但不多)的菜单,然后友情提示如何选择。

标题3.状态选择

既然菜单出来了但是怎么确定玩家选择什么状态呢?此时我们突然想起switch语句可以帮助我们

tase.c

#include<stdio.h>
void menu()
{
    printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");
}
int main()
{
  int a = 0;
  do
  {
   menu();
   printf("请选择\n");
   scanf("%d",&a);
   switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
  }while(a);
}

现在我们对于玩家选择的游戏状态已经写好,选1进入play_game函数,选0退出游戏,乱选则是重新选择,为了do while的判断我们在while的参数中加入键入值来控制。

标题4.创建棋盘

那有一个问题很多的小明就问了:既然我么创建的play_game函数那我怎么没见到呢?

 别急现在才是重头戏

tase.c

#include<stdio.h>
void menu()
{
    printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");
}
void play_game()
{
	 printf("玩游戏\n");
	 char board[3][3] = { 0 };
}
int main()
{
  int a = 0;
  do
  {
   menu();
   printf("请选择\n");
   scanf("%d",&a);
   switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
  }while(a);
}

众所周知三子棋的棋盘是三行三列的九宫格并且不可能用数字当棋子,所以我们用char类型的二维数组可以搭建。

但此时问题很多的小明又提问:那天我想玩五子棋了咋整,不会我还得一个个改吧?

标题5.动态的棋盘行和列

之前我们提到分装函数就起到了作用!

新开文件:game.h

#define ROW 3 //行
#define COL 3 //列

我们在自己创立的头文件中声明了ROWCOL这两个函数。

tase.c

#include<stdio.h>
#include"game.h"
void menu()
{
    printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");
}
void play_game()
{
	 printf("玩游戏\n");
	 char board[ROW][COL] = { 0 };
}
int main()
{
  int a = 0;
  do
  {
   menu();
   printf("请选择\n");
   scanf("%d",&a);
   switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
  }while(a);
}

此时我们发现既然要分装函数每个文件都得引用头文件,要是用的多了岂不是太啰嗦?

为了懒癌患者福音,我决定把stdio.h直接装入“game.h”里,这样只要引用game.h就行!

game.h

#include<stdio.h>
#define ROW 3 //行
#define COL 3 //列

 tase.c

#include"game.h"
void menu()
{
    printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");
}
void play_game()
{
	 printf("玩游戏\n");
	 char board[ROW][COL] = { 0 };
}
int main()
{
  int a = 0;
  do
  {
   menu();
   printf("请选择\n");
   scanf("%d",&a);
   switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
  }while(a);
}

呼~看着就舒服,以后要用其他库函数所需要的头文件直接加入game.h豪华全家桶就行!

标题6.棋盘初始化

棋盘出来了,但是全是我们初始化全是零,我总不能在一堆零上下棋吧?

0   0   0

0   0   0   ------->这不是搞笑吗?

0   0   0

所以我们要将棋盘初始化成能下字符的空格!

tase.c

#include"game.h"
void menu()
{
    printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");
}
void play_game()
{
	 printf("玩游戏\n");
	 char board[ROW][COL] = { 0 };
     init_board(board, ROW, COL);//初始化棋盘
}
int main()
{
  int a = 0;
  do
  {
   menu();
   printf("请选择\n");
   scanf("%d",&a);
   switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
  }while(a);
}

创建init_board函数来初始棋盘,但是大家别忘了在game.h中声明哦,不然是用不了力(恼)

game .h

#include<stdio.h>

#define ROW 3 //行
#define COL 3 //列

//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);

对于init_board函数的声明和调用已经完成,现在我们应该谈谈函数的实现了吧?

召唤!game.c!

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

}

传数组,传形参,这些都是老生常谈的话题我就不赘述了。

我们用两个for循环来控制行和列,最后在board的[i][j]全部替换成空格。

标题7.棋盘的打印

现在的棋盘初始化完成,但是一堆空格比一堆零好不到那里去吧?

所以啊,对于美工还是要有追求滴

空格   空格   空格                                                             ---|---|---

空格   空格   空格   ——>NONONO!                             ---|---|---——>YESYESYES!

空格   空格   空格                                                             ---|---|---

tase.c

#include"game.h"
void menu()
{
    printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");
}
void play_game()
{
	 printf("玩游戏\n");
	 char board[ROW][COL] = { 0 };
     init_board(board, ROW, COL);//初始化棋盘
     printf_board(board, ROW, COL);//打印棋盘
}
int main()
{
  int a = 0;
  do
  {
   menu();
   printf("请选择\n");
   scanf("%d",&a);
   switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
  }while(a);
}

game.h

#include<stdio.h>

#define ROW 3 //行
#define COL 3 //列

//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);
//打印棋盘
void printf_board(char board[ROW][COL], int row, int col);

game.c

#include"game.h"

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

}

void printf_board(char board[ROW][COL],int row,int col)
{
	int a = 0;
	int b = 0;
	//打印“  | |  ”
	for(a = 0;a < row;a++)
	{
		for(b = 0;b < col;b++)
		{
			printf(" %c ", board[a][b]);
			if (b < col - 1)
				printf("|");
		}
		printf("\n");
		//打印“---|---|---”
		if (a < row - 1)
		{
			for (b = 0; b < col; b++)
			{
				printf("---");
				if (b < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

可以看到我将棋盘所需要的部件分别拆开打印,这样的好处就是能够控制字符落子处(%c)并且打印的棋盘可以动态调整。

3X3:                                     10X10: 

标题8.玩家下棋

game.h

#include<stdio.h>

#define ROW 3 //行
#define COL 3 //列

//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);
//打印棋盘
void printf_board(char board[ROW][COL], int row, int col);
//玩家下棋
void play_move(char board[ROW][COL], int row, int col);

game.c

#include"game.h"

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

}

void printf_board(char board[ROW][COL],int row,int col)
{
	int a = 0;
	int b = 0;
	//打印“  | |  ”
	for(a = 0;a < row;a++)
	{
		for(b = 0;b < col;b++)
		{
			printf(" %c ", board[a][b]);
			if (b < col - 1)
				printf("|");
		}
		printf("\n");
		//打印“---|---|---”
		if (a < row - 1)
		{
			for (b = 0; b < col; b++)
			{
				printf("---");
				if (b < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

void play_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:>\n");  
    
	while(1)
	{
		printf("请输入坐标(如:1 1 ):\n");
		scanf("%d %d", &x, &y);
		//判断坐标的合法性/是否被占用?
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if(board[x - 1][y - 1]==' ')//玩家输入的值是大于数组的,所以要-1处理。
			{
				board[x - 1][y - 1] = '*';//坐标合法将空格置换成*
				break;
			}

			else
			{
				printf("该坐标被占用,请重新输入!\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
}

tase.c

#include"game.h"
void menu()
{
    printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");
}
void play_game()
{
	 printf("玩游戏\n");
	 char board[ROW][COL] = { 0 };
     init_board(board, ROW, COL);//初始化棋盘
     printf_board(board, ROW, COL);//打印棋盘
     while(1)
     { 
          play_move(board, ROW, COL);//玩家下棋
          printf_board(board, ROW, COL);//打印棋盘
     }
}
int main()
{
  int a = 0;
  do
  {
   menu();
   printf("请选择\n");
   scanf("%d",&a);
   switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
  }while(a);
}

这里的逻辑是:玩家不可能像程序员一样知道二维数组的坐标(第一行:0  1)因此输入的值是大于数组坐标。

进行-1处理后就是我们所知的二维数组的坐标,最后加入下棋后把空格替换成*(玩家棋子)再打印一次棋盘显示。

小明:为什么玩家下棋要来一次while死循环?

:那有下棋就下一次的你说是不。

标题9.电脑下棋

game.h

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define ROW 3 //行
#define COL 3 //列


//打印棋盘
void printf_board(char board[ROW][COL], int row, int col);
//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);
//玩家下棋
void play_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);

game.c

#include"game.h"

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

}

void printf_board(char board[ROW][COL],int row,int col)
{
	int a = 0;
	int b = 0;
	//打印“  | |  ”
	for(a = 0;a < row;a++)
	{
		for(b = 0;b < col;b++)
		{
			printf(" %c ", board[a][b]);
			if (b < col - 1)
				printf("|");
		}
		printf("\n");
		//打印“---|---|---”
		if (a < row - 1)
		{
			for (b = 0; b < col; b++)
			{
				printf("---");
				if (b < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

void play_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:>\n");  
    
	while(1)
	{
		printf("请输入坐标(如:1 1 ):\n");
		scanf("%d %d", &x, &y);
		//判断坐标的合法性/是否被占用?
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if(board[x - 1][y - 1]==' ')//玩家输入的值是大于数组的,所以要-1处理。
			{
				board[x - 1][y - 1] = '*';//坐标合法将空格置换成*
				break;
			}

			else
			{
				printf("该坐标被占用,请重新输入!\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
}

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

tase.c

#include"game.h"
void menu()
{
    printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");
}
void play_game()
{
	 printf("玩游戏\n");
	 char board[ROW][COL] = { 0 };
     init_board(board, ROW, COL);//初始化棋盘
     printf_board(board, ROW, COL);//打印棋盘
     while(1)
     { 
          play_move(board, ROW, COL);//玩家下棋
          printf_board(board, ROW, COL);//打印棋盘
          computer_move(board, ROW, COL);//电脑下棋
          printf_board(board, ROW, COL);//打印棋盘
          
     }
}
int main()
{
  int a = 0;
  srand((unsigned int)time(NULL));
  do
  {
   menu();
   printf("请选择\n");
   scanf("%d",&a);
   switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
  }while(a);
}

 电脑下棋与玩家下棋的逻辑差不多,由于我们为了简单演示没有写高级算法,所以用了时间戳和随机数。

利用rand函数提供的数然后取余ROWCOL,将随机下棋位置控制在棋盘之内。

//取时间戳装入空指针然后强制转换成int类型

srand((unsigned int)time(NULL));

//取模控制在棋盘之内

int x = rand() % row;

int y = rand() % col;

 标题10.判断输赢

game.h

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 10 //行
#define COL 10 //列

//打印棋盘
void printf_board(char board[ROW][COL], int row, int col);
//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);
//玩家下棋
void play_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断输赢
char is_win(char board[ROW][COL], int row, int col);

game.c

#include"game.h"

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

}

void printf_board(char board[ROW][COL],int row,int col)
{
	int a = 0;
	int b = 0;
	//打印“  | |  ”
	for(a = 0;a < row;a++)
	{
		for(b = 0;b < col;b++)
		{
			printf(" %c ", board[a][b]);
			if (b < col - 1)
				printf("|");
		}
		printf("\n");
		//打印“---|---|---”
		if (a < row - 1)
		{
			for (b = 0; b < col; b++)
			{
				printf("---");
				if (b < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

void play_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:>\n");  
    
	while(1)
	{
		printf("请输入坐标(如:1 1 ):\n");
		scanf("%d %d", &x, &y);
		//判断坐标的合法性/是否被占用?
		if (x >= 1 && x <= row && y >= 1 && y <= col)
		{
			if(board[x - 1][y - 1]==' ')//玩家输入的值是大于数组的,所以要-1处理。
			{
				board[x - 1][y - 1] = '*';//坐标合法将空格置换成*
				break;
			}

			else
			{
				printf("该坐标被占用,请重新输入!\n");
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
}

void computer_move(char board[ROW][COL], int row, int col)  
{
	printf("电脑下棋:>\n");
	while (1)
	{
		int x = rand() % row;
		int y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
//棋盘未满返回0否则返回1
static int is_full(char board[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(' '==board[i][j])
			{
				return 0;
			}
		}
	}
	return 1;
}

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

	}
	if(board[0][0]==board[1][1] && board[1][1]==board[2][2] && board[1][1]!=' ')
	{
		return board[1][1];
	}
	if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	//判断平局
	if(is_full(board,row,col)==1)
	{
		return 'Q';
	}
	return 'C';

}

tase.c

#include"game.h"
void menu()
{ 
	printf("************************\n");
	printf("******   1.play   ******\n");
	printf("******   2.exit   ******\n");
	printf("************************\n");

}
 void play_game()
{
	 char ret = 0;
	 printf("玩游戏\n");
	 char board[ROW][COL] = { 0 };
	 init_board(board, ROW, COL);//初始化棋盘
	 printf_board(board, ROW, COL);//打印棋盘
	 while (1)
	 {
		 play_move(board, ROW, COL);//玩家下棋
	     ret=is_win(board,ROW,COL);
		 if (ret != 'C')
			 break;
		 printf_board(board, ROW, COL);//打印棋盘
		 computer_move(board, ROW, COL);//电脑下棋
		 if (ret != 'C')
			 break;
		 printf_board(board, ROW, COL);//打印棋盘
	 }
//玩家赢“*”
//电脑赢“#”
//平局“Q”
//游戏继续“C”
	 if(ret=='*')
	 {
		 printf("玩家赢!\n");
	 }
	 else if(ret=='#')
	 {
		 printf("电脑赢!\n");
	 }
	 else
	 {
		 printf("平局!\n");
	 }
	 printf_board(board, ROW, COL);
} 
int main()
{
	int a = 0;
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择:");
		scanf("%d", &a);
		switch(a)
		{
		case 1:
			play_game();
			break;
		case 0:
			printf("退出游戏!\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
			break;
		}
	} while (a);
	return 0;
}

一把游戏的状态无非就是:赢了,输了,平局。

所以在is_win函数中我用了两个for循环检测横三行竖三列是否有三个相同的棋子,又用两个if语句检查左上右下,右上左下三个格子是否有相同的棋子判断输赢。

如果平局了怎么办?此时我们分装了is_full函数来表示平局的结果,如果is_full检测棋盘上有空格则返回0不然返回1

is_win中if判断如果is_full等于1返回Q不然返回C

于是那个屁事很多的小明又问:那这个Q和C到底是啥意思,我咋就不懂呢?还有你不是说函数要声明(game.h)再实现(game.c)?

嗯.....大家可以回到tase.c文件的play_game函数中仔细看

 void play_game()
{
	 char ret = 0;
	 printf("玩游戏\n");
	 char board[ROW][COL] = { 0 };
	 init_board(board, ROW, COL);//初始化棋盘
	 printf_board(board, ROW, COL);//打印棋盘
	 while (1)
	 {
		 play_move(board, ROW, COL);//玩家下棋
	     ret=is_win(board,ROW,COL);
		 if (ret != 'C')
			 break;
		 printf_board(board, ROW, COL);//打印棋盘
		 computer_move(board, ROW, COL);//电脑下棋
		 if (ret != 'C')
			 break;
		 printf_board(board, ROW, COL);//打印棋盘
	 }

我们的QC就是用来平局,我先是创建了一个char类型的函数叫ret用来存放字符,接着我们play_movecomputer_move下都加入了一个条件。

 if (ret != 'C')
             break;

 然后我们在看看这个

static int is_full(char board[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(' '==board[i][j])
			{
				return 0;
			}
		}
	}
	return 1;
}
if(is_full(board,row,col)==1)
	{
		return 'Q';
	}
	return 'C';

如果is_full等于1了那肯定返回Q,此时play_movecomputer_move都不等于'c'那就break直接跳出我们的那个while(1)的死循环来到下面的语句

if(ret=='*')
	 {
		 printf("玩家赢!\n");
	 }
	 else if(ret=='#')
	 {
		 printf("电脑赢!\n");
	 }
	 else
	 {
		 printf("平局!\n");
	 }
	 printf_board(board, ROW, COL);

返回的Q即既不等于*也不等于#,那就只有一条路走嘛,平局!

至于为啥不去声明,那纯粹是感觉没有必要,因为is_full函数本身就是为了is_win函数而去分装实现的,我们这里偷个懒就用static函数直接隐藏起来就行了。

不知不觉我从中午十二点整写到下午四点整了,大约写了一万五千多字(虽然有代码凑数)。

我们这篇从无到有的三子棋代码已经写完,其实也不算全,主要是关于电脑下棋的逻辑和胜负判断的逻辑一个用随机数算法一个写死只能判断3X3。如果你有兴趣的话可以再现有代码基础上进行改造升级

那今天就到这里了,再不走就不礼貌了......

PS:其实累了,倦了,开摆2333333

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值