#C语言 #手把手学会三子棋

Posted Misaka御坂美琴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了#C语言 #手把手学会三子棋相关的知识,希望对你有一定的参考价值。

一 三子棋游戏实现逻辑

1 游戏菜单界面

2 打印棋盘

3 玩家下棋

4 电脑随机下棋

5 判断胜负

二 具体程序实现

1 游戏主逻辑与游戏菜单界面

1.1主函数设计

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#define COLS 3// 三子棋棋盘为3x3
#define ROWS 3
// 1 该区域用于声明接下来要写的每一个函数,后面会讲到暂时先不管这些函数。(此处我不用头文件引用的方式) 
void InitBoard(int rows, int cols, char board[ROWS][COLS]);
void DispalyBoard(int row, int col, char board[ROWS][COLS]);
void PlayerMove(char board[ROWS][COLS], int rows, int cols);
void PcMove(char board[ROWS][COLS], int rows, int cols);
int is_full(char board[ROWS][COLS], int  rows, int cols);
char IsWin (char board[ROWS][COLS], int rows, int cols);
void menu();
void game();

//2 主函数逻辑
int main()`
{  
   //3 input 接受玩家输入的数字以判断进入(退出)游戏`
int input = 0;
   //4 do while循环可实现玩家循环游戏,玩家也可选择0退出游戏。
do{
     menu();      //5 菜单函数打印游戏菜单
	 scanf("%d", &input);//6 接受一个玩家输入的数  1 代表进入游戏  0 代表退出游戏
	 switch (input)
	 {
	 case 1:
		 printf("游戏开始\\n");
		 game();//7 game()函数是游戏实现的函数
		 break; 
	 case 0:
		 printf("退出游戏\\n");
		 break;
	 default:
		 printf("重新输入\\n");
	}
  }
 while (input);`
 }
 

1.2 menu()函数(打印菜单)

// 打印游戏菜单
void menu()
{
	printf(" *********************\\n");
	printf(" ******* 0.Exit  *****\\n");
	printf("******* 1.Play  *****\\n");
	printf("*********************\\n");
	printf("请选择>>:");
}

1.3 game()函数

// 三子棋游戏实现的game()函数
void game()
{
	char board[ROWS][COLS];// 1 棋盘:通过创建一个3X3的二维数组来表示棋盘
	InitBoard(ROWS,COLS,board);//2(具体代码在后面) 初始化棋盘函数:给二维数组每一个元素赋值
	DispalyBoard(ROWS, COLS, board);//3 (具体代码在后面详述)  打印棋盘

}

1.4 尝试运行一下

2 打印游戏棋盘

InitBoard (初始化二维数组board)函数

DisplayBoard(打印棋盘)函数

2.1 InitBoard void InitBoard(int rows, int cols, char board[ROWS][COLS])

 void InitBoard(int rows, int cols, char board[ROWS][COLS])//  rows 参数代表行 cols 代表列  board代表二维数组
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = ' ';// 给每一char类型元素赋一个值' '(空格)以确保下棋前显示棋盘时我们看到的是一个空棋盘。
		}
	}
}

2.2 DispalyBoard(int row, int col, char board[ROWS][COLS])

void DispalyBoard(int row, int col, char board[ROWS][COLS])
{
	
	for (int i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);// 1 打印空格元素  
			if (j < col - 1) printf("|");//2 分割同一行元素 

		}
		printf("\\n");// 3 一行打印好之后换行
		if (i < row)
		{
			for (j = 0; j < row; j++)
			{
                printf("---");//4 打印分割行 用---分割每一行
				if (j < col - 1) printf("|");
			}
		}
		printf("\\n");
	}

}

2.3 尝试运行一下

3 玩家下棋实现

3.1 void PlayerMove(char board[ROWS][COLS], int rows, int cols)三个参数分别为 1二维数组 2行数 3列数

void PlayerMove(char board[ROWS][COLS], int rows, int cols)
{
	printf("玩家走 ");
	printf("请输入坐标:>");//1 提示玩家输入要下棋的位置的坐标
	
	int x = 0, y = 0, i, j;
		while (1)//2 通过while循环,实现当玩家下棋的位置已经被占用或输入位置错误时能够重新输入。
		{
		scanf("%d %d", &x, &y);//3 输入要下棋位置的(例:1 1代表第一行第一列,代表二维数组中board[0][0])
		if (x >= 1&&x<= rows &&y>=1&&y<= cols)
			{
			i = x - 1; 
			j = y - 1; //4 注意数组的下标从0开始,所以要减一(例:1 1代表第一行第一列,代表二维数组中board[0][0])
			if (board[i][j] == ' ')//5 判断下棋的位置是否是初始化是赋值的空格,若不是表示该位置已被玩家或电脑棋子占用,不能再在这个位置下棋。
				{
					board[i][j] = '*';//6 玩家下棋赋值为'*'
					break;//7 成功下一个棋子后跳出循环
				}
		   else
				{
					printf("坐标被占用请重新输入\\n");//8 提醒该位置被占用
				}
			}
		else
			{
				printf("坐标非法请重新输入\\n");//9 提醒玩家所输入的位置非法(例:坐标4 4 不存在于3X3的棋盘中)
			}
	
		}

}

3.2 调整一下game()函数

void game()
{
	char board[ROWS][COLS];
	char ret = 0;
	InitBoard(ROWS,COLS,board);
	DispalyBoard(ROWS, COLS, board);
	while (1)// 1 实现玩家循环下棋
	{
		PlayerMove(board,ROWS,COLS);//2 玩家下棋
		DispalyBoard(ROWS,COLS,board);//3 将玩家下棋的结果打印显示到屏幕上
	}

3.3 尝试运行一下

4 实现电脑随机下棋

4.1 添加头文件 <time.h> <stdlib.h>

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include <stdlib.h>// 1 包含rand(),rand()生产随机数
#include<time.h>// 2 随机数种子,以免产生伪随机数。

4.2 void PcMove(char board[ROWS][COLS], int rows, int cols)

void PcMove(char board[ROWS][COLS], int rows, int cols)
{
	int x = 0, y = 0;
      printf("PC走:>\\n");
 while (1)
 {
	 x = rand()%rows; y = rand() % cols;//1 令x是0~2的随机数 y是0~2 的随机数
	 if (board[x][y] == ' ')// 2 判断电脑所下位置是否没被下
	 {
		 board[x][y] = '#';//3 # 为电脑的棋子
		 break;
	 }
  }
}

4.3 game()函数调整 添加

PcMove()和 打印电脑下棋后的棋盘

void game()
{
char board[ROWS][COLS];

​ char ret = 0;
​ InitBoard(ROWS, COLS, board);
​ DispalyBoard(ROWS, COLS, board);
​ while (1)
​ {
​ PlayerMove(board, ROWS, COLS);
​ DispalyBoard(ROWS, COLS, board);
​ PcMove(board, ROWS, COLS);// 1 电脑下棋
​ DispalyBoard(ROWS, COLS, board);//2 打印电脑下棋后的棋盘
​ }
}

4.4 运行

5 判断玩家/电脑的胜负

5.1 Is_full函数 判断棋盘是否下满

int is_full(char board[ROWS][COLS], int  rows, int cols)
{
	int i = 0; int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			if (board[i][j] == ' ') return 0;// 1 假如存在空格表示棋盘未下满,跳出循环返回0
		}
	}
	return 1;//2 遍历整个数组也没有找到空格表示棋盘已经下满,返回 1
}

5.2 IsWin函数 ( 判断胜负)

(类型是char ,返回不同的char 类型的值表示不同含义,以让game()函数判断结果)

char IsWin(char board[ROWS][COLS], int rows, int cols)
{  
	  int i = 0;
	for (i = 0; i < rows; i++)
	{
	    // 1 判断是否有一行全为同一个值(某一方的棋子),并且该值不是初始化时的空格。
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][0];// 2 有一行假如全为某一方的棋子,返回该棋子的char类型值给game()函数。

		}
		// 3 判断是否有一列的 值(某一方的棋子) 相同并且该值不能为空格。
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];//4 有一列假如全为某一方的棋子,返回该棋子的char类型值给game()函数。
		}
		//5 同理判断是否左上角到右下角这一条斜线的值是否相同,且不能为初始化时二维数组时赋的给它的空格的值。
		if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
		{
			return board[1][1];
		}
		//6 判断右上角到左下角这条斜线是否相同,且不为空格。
		if (board[0][2] == board[1][1] && board[2][0] == board[1][1] && board[1][1] != ' ')
		{
			return board[1][1];
		}
	}
	// 7 经过前面的判断加入还没有返回一个值表示还未分出胜负,此时判断棋盘是否下满,以判断是否平局。
	if (is_full(board, rows, cols))
	{
		return 'Q';// 8 加入下满给game()函数返回Q表示平局
	}
	else
	{
		return 'C';//9 假如经过前面的判断依然没有返回一个值表示还没有分出胜负,此时返回一个C表示游戏继续。
	}

} 

5.3 在game()函数中加入判断结果的逻辑

void game()
{
		char board[ROWS][COLS];
		InitBoard(ROWS, COLS, board);
		DispalyBoard(ROWS, COLS, board);
		char ret=0;//1 创建一个char类型变量 ret接收IsWin函数的返回值
		while (1)
		{
			PlayerMove(board, ROWS, COLS);
			DispalyBoard(ROWS, COLS, board);
			ret = IsWin(board, ROWS, COLS);
			if (ret != 'C')//3 判断玩家下棋后是否胜出,否则继续下棋循环。
			{
				break;
			}
			
			PcMove(board, ROWS, COLS);
			DispalyBoard(ROWS, COLS, board);
			if (ret != 'C')//4 判断PC下棋后是否胜出,否则继续下棋循环。
			{
				break;
			}
		}
		
		// 4 当ret不等于c时跳出循环,根据ret的值判断结果
		// 4.1 ret=* 表示玩家赢 4.2ret=#表示电脑赢 4.3 ret返回其他值
		if (ret == '*')           printf("Player 胜出\\n");
		else if (ret == '#')      printf("PC 胜出\\n");
		else                      printf("平局\\n");
		

}

6 最终代码和结果展示。


```c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include <stdlib.h>
#include<time.h>
#define COLS 3// 
#define ROWS 3
void menu();
void InitBoard(int rows, int cols, char board[ROWS][COLS]);
void DispalyBoard(int row, int col, char board[ROWS][COLS]);
void PlayerMove(char board[ROWS][COLS], int rows, int cols);
void PcMove(char board[ROWS][COLS], int rows, int cols);
int is_full(char board[ROWS][COLS], int  rows, int cols);
char IsWin(char board[ROWS][COLS], int rows, int cols);
void game();
int main()
{
	int input = 0;
	srand((unsigned int)time(NULL));
	do {
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("游戏开始\\n");
			game();
			break;
		case 0:
			printf("退出游戏\\n");
			break;
		default:
			printf("重新输入\\n");

		}
	} while (input);

}
void menu()
{
	printf("*********************\\n");
	printf("******* 0.Exit  *****\\n");
	printf("******* 1.Play  *****\\n");
	printf("*********************\\n");
	printf("请选择>>:");
}
void InitBoard(int rows, int cols, char board[ROWS][COLS])
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			board[i][j] = ' ';
		}
	}
}
void DispalyBoard(int row, int col, char board[ROWS][COLS])
{
	// 3展示棋盘的逻辑 数据的打印,分割行的打印,分割列的打印
	for (int i = 0; i < row; i++)
	{
		int j = 0;
		for (j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			//1
			if (j < col - 1) printf("|");

		}
		printf("\\n");
		if (i < row)
		{
			for (j = 0; j < row; j++)
			{
				// 2 分割行的打印
				printf("---");
				if (j < col - 1) printf("|");
			}
		}
		printf("\\n");
	}

}
void PlayerMove(char board[ROWS][COLS], int rows, int cols)
{
	printf("玩家走 ");
	printf("请输入坐标:>");
	int x = 0, y = 0, i, j;
	while (1)
	{


		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= rows && y >= 1 && y <= cols)
		{
			i = x - 1; j = y - 1;
			if (board[i][j] == ' ')
			{
				board[i][j] = '*';
				break;
			}
			else
			{
				printf("坐标被占用请重新输入\\n");
			}
		}
		else
		{
			printf("坐标非法请重新输入\\n");
	
		}
	
	}

}
void PcMove(char board[ROWS][COLS], int rows, int cols)
{
	int x = 0, y = 0;
	printf("PC走:>\\n");
	while (1)
	{
		x = rand() % rows; y = rand() % cols;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;

		}
	}

}
int is_full(char board[ROWS][COLS], int  rows, int cols)
{
	int i = 0; int j = 0;
	for (i = 0; i < rows; i++)
	{
		for (j = 0; j < cols; j++)
		{
			if (board[i][j] == ' ') return 0;
		}
	}
	return 1;
}
char IsWin(char board[ROWS][COLS], int rows, int cols)
{
	// 1.1 Player Is Winner 1.2 Pc Is Winner 2 平局  3  继续
	int i = 0;
	for (i = 0; i < rows; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
		{
			return board[i][0];

		}
		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[0][2] == board[1][1] && board[2][0] == board[1][1] && board[1][1] != ' ')
		{
			return board[1][1];
		}
	}
	if (is_full(board, rows, cols))
	{
		return 'Q';
	}
	else
	{
		return 'C';
	}

} 
void game()
{
		char board[ROWS][COLS];
		char ret = 0;
		InitBoard(ROWS, COLS, board);
		DispalyBoard(ROWS, COLS, board);
		while (1)
		{
			PlayerMove(board, ROWS, COLS);
			DispalyBoard(ROWS, COLS, board);
			ret = IsWin(board, ROWS, COLS);
			if (ret != 'C')
			{
				break;
			}

			PcMove(board, ROWS, COLS);
			DispalyBoard(ROWS, COLS, board);
			ret = IsWin(board, ROWS, COLS);
			if (ret != 'C')
			{
				break;
			}
		}
		if (ret == '*') printf("Player 胜出\\n");
		else if (ret == '#') printf("PC 胜出\\n");
		else printf("平局\\n");

}
``

以上是关于#C语言 #手把手学会三子棋的主要内容,如果未能解决你的问题,请参考以下文章

C语言小游戏之·手把手教你做三子棋(简单版)

使用c语言完成简单的三子棋

C语言人工智能 |教你与智能AI对弈三子棋 从此不再孤单寂寞冷

还有这事?——一小时学会三子棋(优化版)

(C语言篇)三子棋的实现

C语言实现三子棋(井字棋)