c语言实现三子棋

这是我学习编程的第12天,今天我完成了一个简单的三子棋游戏,如果作者有哪里写的不对或者不好的地方,大家可以指出来,话不多说我们开始吧!

建立大体的框架,创建了一个头文件和两个源文件,创建的头文件来声明各类功能函数,一个源文件用来定义函数,另一个用来测试代码。

c语言实现三子棋

我所标记的是需要创建的三个文件,文件添加好后我们来完成其大体的框架。

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
void InItboard(char board[ROW][COL], int row, int  col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int  row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);

这是头文件需要包含的库以及需要声明的函数,我将所有需要的头文件都包含在game1.h这个头文件中,在其他源文件使用的时候就只需包含这个头文件就可以。

首先,我们要分析这个游戏的玩法,c语言实现三子棋棋盘打印在屏幕上大概就是这个样子,简易版的一个棋盘,玩家走一步,电脑就会走一步,当有一方的棋子一列或一行或是对角线上有三个棋子相同了,那么这方会获胜。

接下来,游戏菜单选择的基本功能

分析游戏菜单功能应该是一个选择功能,并且可以一直进行你想要的选择,那么就需要将其写进一个循环。这里我使用了do while循环每次进行选择都会有菜单的打印,之后就是选择对应的功能

1.玩游戏0.退出游戏。这里我用到了switch循环。

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


int main()
{
	
	int input = 0;
	do
	{
		Menu();
		printf("请选择:\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("输入有误,请重新选择:");
			break;
		}

	} while (input);

	return 0;
}

菜单选择的功能就很好的完成了,接下来是设计各类函数来完成游戏的各类功能。

将各类函数放在一个函数中去调用,这里我将每个功能函数放在了game()这个函数中去调用。

并且在头文件包含每个函数的声明。

void InItboard(char board[ROW][COL], int row, int  col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int  row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);

首先,棋盘的创建和初始化。其中棋盘我们可以很容易的将其抽象成一个二维字符数组,二维数组的行列我们可以用宏来定义方便以后进行修改,这里也是一样在头文件中定义就可,

#define ROW 3
#define COL 3

接下来就是创建以及初始化,这里我们设计了一个InItboard()的函数用其来初始化数组,这个过程是很容易的,只需遍历到二维数组的每一个元素将其赋值’ ‘ ,代码如下: 

void InItboard(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++)
		{
			board[i][j] = ' ';
		}
	}

棋盘初始化后我们需要将棋盘打印出来,设计了函数DisplayBoard()考虑到未来代码修改后的可操作性,将打印棋盘写活代码如下:

void DisplayBoard(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++)
		{
			printf(" %c ", board[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");

	}
}

棋盘展示后,需要设计人和电脑下棋的功能,首先要设计人和电脑的下棋函数,我们先来设计人的下棋功能,设计一个函数PlayerMove()这个函数中要实现,玩家输入一个坐标,将坐标赋值给这个二维数组,即棋盘,需要注意的是:要判断坐标是否在规定范围内,以及所输入的坐标是否已经被占用。代码如下:

void PlayerMove(char board[ROW][COL],int  row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请选择你要走的坐标:***注意坐标之间用空格隔开:\n");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col) //判断输入的坐标是否在范围内
		{
			if (board[x - 1][y - 1] == ' ')           //判断输入的坐标是否被占用
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标不在范围内,请重新选择\n");
		}

	}

}

接下来,我们要设计电脑下棋的函数ComputerMove(),由于作者是初学者能力有限,我们就色痕迹一个简单随机功能来实现电脑的动作,首先我们需要一个生成随机值的函数rand()这个函数会生成一个随机值,我们用到这个函数就必须要引用其所需的头文件,<stdlib.h>并要借助这个函数实现srand((unsigned int)time(NULL));其中time函数也需引用头文件<time.h>,我们还需要生成的随机值在3以内,只需将生成的值%row或col即可,代码如下:

void ComputerMove(char board[ROW][COL], int row, int col)
{
	
	int x = 0;
	int y = 0;
	printf("电脑走:>\n");

	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

电脑和人的动作函数都完成后,在游戏时候应该是人和电脑每走一步就会现实一遍现在的棋盘,所以在调用这两个函数后要再调用打印棋盘函数。

然后我们需要设计一个判断输赢以及平局的函数来,这个函数需要在每次人或者电脑动作完成后都要被调用,首先,我们来设计这个函数,函数所要实现的功能有,如果有某一行或者某一列或者是对角线上有三个元素相同,若为’*‘则玩家获胜,若为’#‘则为电脑获胜,如果棋盘满了,没有以上情况,即为平局。代码如下:

char IsWin(char board[ROW][COL], int row, int col)
{
	//1. 判断输赢
	int i = 0;
	int j = 0;
	int flag = 0;
	for (i = 0; i < row; i++)             //判断行是否有三个相同元素 如果有直接结束函数并返回相应的值
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
		{
			if (board[i][0] == '*')
			{
				return '*';
			}
			else if (board[i][0] == '#')
			{
				return '#';
			}

		}
	}
	for (i = 0; i < row; i++)            //判断对角线是否有三个相同元素 如果有直接结束函数并返回相应的值
	{
		if( (board[0][0] == board[1][1] && board[1][1] == board[2][2])||(board[0][2])==board[1][1]&&board[1][1]==board[2][0] )
		{
			if (board[1][1] == '*')
			{
				return '*';
			}
			else if (board[1][1] == '#')
			{
				return '#';
			}

		}

	}
	for (j = 0; j < col; j++)            //判断列是否有三个相同元素 如果有直接结束函数并返回相应的值
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j])
		{
			if (board[0][j] == '*')
			{
				return '*';
			}
			else if (board[0][j] == '#')
			{
				return '#';
			}


		}

	}

	for (int i = 0; i < row; i++)         //判断棋盘是否已满    
	{
		for (int j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				flag = 1;
			}
		}
	}
	if (flag)
	{
		return 'C';
	}
	else
		return '\0';

}

这三个函数的功能设计好后,将它们整合到一个循环当中实现下棋。

while (1)           //下棋
	{
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
}

当返回值不是’C‘时终止循环,并将返回值进行判断输赢情况。游戏结束后,即调用一次game()函数,之后跳出switch继续进行游戏的选择。

测试文件中代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include"game1.h"
//打印菜单
void Menu()
{
	printf("******************\n");
	printf("******1.play *****\n");
	printf("******0.exit *****\n");
	printf("******************\n");
}
void game()
{
	char board[ROW][COL];
//初始化棋盘
	InItboard(board,ROW,COL);
//打印棋盘
	DisplayBoard(board, ROW, COL);
	int ret = 0;
while (1)           //下棋
	{
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局\n");
	}
}
int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		Menu();
		printf("请选择:\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			break;
		default:
			printf("输入有误,请重新选择:");
			break;
		}

	} while (input);

	return 0;
}

游戏源文件中,代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include"game1.h"
void InItboard(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++)
		{
			board[i][j] = ' ';
		}
	}
}
void DisplayBoard(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++)
		{
			printf(" %c ", board[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 PlayerMove(char board[ROW][COL], int  row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		printf("请选择你要走的坐标:***注意坐标之间用空格隔开:\n");
		scanf("%d%d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col) //判断输入的坐标是否在范围内
		{
			if (board[x - 1][y - 1] == ' ')           //判断输入的坐标是否被占用
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("坐标被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标不在范围内,请重新选择\n");
		}

	}
}
	

void ComputerMove(char board[ROW][COL], int row, int col)
{
	
	int x = 0;
	int y = 0;
	printf("电脑走:>\n");

	while (1)
	{
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

char IsWin(char board[ROW][COL], int row, int col)
{
	//1. 判断输赢
	int i = 0;
	int j = 0;
	int flag = 0;
	for (i = 0; i < row; i++)             //判断行是否有三个相同元素 如果有直接结束函数并返回相应的值
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
		{
			if (board[i][0] == '*')
			{
				return '*';
			}
			else if (board[i][0] == '#')
			{
				return '#';
			}

		}
	}
	for (i = 0; i < row; i++)            //判断对角线是否有三个相同元素 如果有直接结束函数并返回相应的值
	{
		if( (board[0][0] == board[1][1] && board[1][1] == board[2][2])||(board[0][2])==board[1][1]&&board[1][1]==board[2][0] )
		{
			if (board[1][1] == '*')
			{
				return '*';
			}
			else if (board[1][1] == '#')
			{
				return '#';
			}

		}

	}
	for (j = 0; j < col; j++)            //判断列是否有三个相同元素 如果有直接结束函数并返回相应的值
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j])
		{
			if (board[0][j] == '*')
			{
				return '*';
			}
			else if (board[0][j] == '#')
			{
				return '#';
			}


		}

	}

	for (int i = 0; i < row; i++)         //判断棋盘是否已满    
	{
		for (int j = 0; j < col; j++)
		{
			if (board[i][j] == ' ')
			{
				flag = 1;
			}
		}
	}
	if (flag)
	{
		return 'C';
	}
	else
		return '\0';

}

头文件中的代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
void InItboard(char board[ROW][COL], int row, int  col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int  row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);

在最后编译时,这三个文件会整合到一起。

我们来测试一下:

c语言实现三子棋

 由于作者初学,能力还有限,这个电脑动作功能不是很智能,在未来作者能力提升后,会对游戏进行改进。希望大家理解,如果我的代码哪里有问题,希望大家指出来!让我们共同进步,这次的三子棋就到这里了,以后我会陆续更新其他的文章,感谢大家支持!

上一篇:Java实现三子棋小游戏


下一篇:剑指 Offer 12. 矩阵中的路径