C语言初阶---不太聪明的三子棋游戏

相信每个人都玩过手画的三子棋游戏,这篇文章将用初阶C语言的内容来实现没那么聪明的三子棋游戏。

目录

一、三子棋游戏基本逻辑

二、代码实现

三、游戏总代码


一、三子棋游戏基本逻辑

1.1 进入菜单选择,进入游戏,打印棋盘。

1.2 电脑和玩家不断轮流下棋,每一次下棋,判断输赢,直至出现一方获胜或者平局,游戏结束,再次进入菜单选择,继续或退出游戏。

二、代码实现

由于三子棋游戏需要多个模块共同完成,多个文件可以处理各自模块的功能,整个游戏的脉络也会更加清晰,代码可读性更高。因此创建源文件和头文件,分别为 实现整个游戏程序test.c,实现游戏内容game.c和游戏函数声明game.h。game.h用来进行函数声明,在test.c中调用的函数都需要在game.h中声明,test.c和game.c包含game.h。

三、游戏总代码

1.1进入菜单选择,选择进入游戏,打印棋盘

打印菜单代码

void menu()
{
	printf("*********************\n");
	printf("*****  1.play   *****\n");
	printf("*****  0.exit   *****\n");
	printf("*********************\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();//打印菜单的函数
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("进入游戏,\n");//输入1,进入游戏
			break;
		case 0:
			printf("退出游戏!\n");//输入0.退出游戏
			break;
		default :
			printf("选择错误,请重新选择!\n");//输入非1、0,重新选择
			break;
		}

	} while (input);//输入非0,循环继续,输入0,退出游戏,循环结束
}

运行结果

 继续实现游戏内容,菜单选择1,进入游戏,调用game()函数来实现。

int main()
{
	int input = 0;
	do
	{
		menu();//打印菜单的函数
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("进入游戏,\n");//输入1,进入游戏
			game();//game()函数是三子棋游戏的核心,它是实现三子棋游戏内容的函数
			break;
		case 0:
			printf("退出游戏!\n");//输入0.退出游戏
			break;
		default:
			printf("选择错误,请重新选择!\n");//输入非1、0,重新选择
			break;
		}

	} while (input);//输入非0,循环继续,输入0,退出游戏,循环结束
}

 进入游戏后,显示3x3棋盘,但棋盘怎么来实现?

 棋盘实际上是一个二维数组,来存放所下的棋子。

 因此先创建一个名为board的二维数组,并且初始化,放入空格。

棋盘的行数和列数直接定义在game.h中,方便更改。

 在test.c文件中调用game()函数,在game函数中来初始化棋盘。

game.h文件


#pragma once
#include<stdio.h>
#define ROW 3//打印三行的棋盘
#define COL 3//打印三列的棋盘
void initboard(char board[ROW][COL], int row,int  col);




test.c文件
在game()函数中调用initboard函数来初始化棋盘

void game()
{
	char board[ROW][COL] = { 0 };
	initboard(board, ROW, COL);//初始化棋盘

}

game.c文件
写函数来初始化棋盘

void initboard(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] = ' ';
		}
	}
}

 初始化棋盘后,开始打印3x3棋盘网格

3x3棋盘网格是一个“井”字网格,接下来就写函数来打印“井”字网格

game.h
函数声明

void displayboard(char board[ROW][COL], int row, int  col);


test.c
在game()函数中调用打印棋盘的函数

void game()
{
	char board[ROW][COL] = { 0 };
	initboard(board, ROW, COL);//初始化棋盘
	displayboard(board, ROW, COL);//打印棋盘

}

game.c
写函数,打印棋盘

void displayboard(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++)
		{
			printf(" %c ",board[i][j]);//%c是留给下棋的位置
			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");
			
		}
	}
}

运行结果 ,完成棋盘打印

 

1.2玩家电脑轮流下棋,判断输赢,游戏结束或者游戏继续。 

在game.c中写玩家下棋的函数--playermove函数,玩家或者电脑下棋函数执行完,再次调用displayboard函数打印棋盘,打印下棋后的棋盘

game.c

void playermove(char board[ROW][COL], int row, int  col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋,请输入坐标:");
	scanf("%d %d", &x, &y);
	if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入的坐标是否越界
	{
		if (board[x - 1][y - 1] == ' ')//判断坐标是否被占用
			//玩家不知道数组下标从0开始,因此玩家输入的坐标应当-1,与二维数组下标相对应
		{
			board[x - 1][y - 1] = '*';//玩家下的棋子为'*';
		}
		else
		{
			printf("坐标被占用,请重新输入:");
		}
	}
	else
	{
		printf("输入的坐标有误,请重新输入:");
	}

	
}

test.c

void game()
{
	char board[ROW][COL] = { 0 };
	initboard(board, ROW, COL);//初始化棋盘
	displayboard(board, ROW, COL);//打印棋盘
	playermove(board, ROW, COL);//玩家下棋
	displayboard(board, ROW, COL);//打印棋盘

}

 运行结果

 每次下完棋后,都要打印下棋后的棋盘,判断输赢,所以打印棋盘函数,判断输赢的函数放在循环中反复调用,直至出现平局或获胜。

本次游戏,玩家所下的棋子是*,电脑所下的棋子是#

论如何通过代码来判断输赢:赢得情况有三种:一列,一行,对角

写win函数来判断输赢,三种获胜得情况实现任意一种,则win函数就返回获胜的这个棋子元素到test.c中,在test.c的game()中判断,若返回来的元素是*,则为玩家获胜,若是#,则是电脑获胜,若是C,则游戏继续,若是Q,则是平局

下面来实现玩家下棋,判断三种获胜和平局的情况:

game.c

char win(char board[ROW][COL], int row, int  col)
{
	int i = 0;
	//判断行
	for (i = 0; i < col; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')//同1行棋子相等并且不是空格
		{
			return board[i][1];//返回获胜的棋子元素
		}
	}
	//判断列
	for (i = 0; i < row; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')//同1列棋子相同并且不是空格
		{
			return board[1][i];
		}
	}
	//判断对角
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')//对角的元素相同
	{
		return board[0][0];
	}
	if (full(board, ROW, COL))//full函数判断平局,寻找二维数组中是否还有空格,有空格则游戏继续,没有空格则平局
	{
		return 'Q';
	}
	else
	{
		return 'C';
	}


}

int full(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++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}

	return 1;

}


test.c

while(1)
{
		playermove(board, ROW, COL);//玩家下棋
		ret = win(board, ROW, COL);//判断输赢
        if (ret != 'C')//游戏继续,函数返回C,若不是C,则是出现了平局或者获胜的情况,循环结束
		{
			break;
		}
         displayboard(board, ROW, COL);//打印棋盘
}
	
if (ret == 'Q')
	{
		printf("平局!\n");
	}
else if (ret == '#')
	{
		printf("玩家获胜!\n");
	}
else if (ret == '*')
	{
		printf("电脑获胜!");
	}

       displayboard(board, ROW, COL);//打印棋盘 

 接着电脑下棋,判断输赢

电脑下棋,调用rand()函数来产生随机数,调用srand()初始化rand产生随机数种子。

玩家和电脑反复下棋放在循环中,每一次调用玩家或电脑下棋函数,输入一次坐标

test.c

void game()
{
	int ret = 0;
	char board[ROW][COL] = { 0 };
	initboard(board, ROW, COL);//初始化棋盘
	displayboard(board, ROW, COL);//打印棋盘
	while (1)
	{
		playermove(board, ROW, COL);//玩家下棋
		ret = win(board, ROW, COL);//判断输赢
		if (ret != 'C')
		{
			break;
		}
		displayboard(board, ROW, COL);//打印棋盘

		computermove(board, ROW, COL);//电脑下棋
		ret = win(board, ROW, COL);//判断输赢
		if (ret != 'C')
		{
			break;
		}
		displayboard(board, ROW, COL);//打印棋盘

	}
	if (ret == 'Q')
	{
		printf("平局!\n");
	}
	else if (ret == '*')
	{
		printf("玩家获胜!\n");
	}
	else if (ret == '#')
	{
		printf("电脑获胜!\n");
	}
	displayboard(board, ROW, COL);//打印棋盘


}

game.c

void computermove(char board[ROW][COL], int row, int  col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋:\n");
	while (1) 
	{
		//调用rand函数,产生随机数
		x = rand() % row;//行数范围为0-row
		y = rand() % col;//列数范围为0-col
		if (board[x][y] == ' ')//判断坐标是否被占用

		{
			board[x][y] = '#';//电脑下的棋子为'#';
			break;
		}
	}
	
}

三子棋游戏代码到这里已经全部完成了,看运行效果 

   

 三、游戏总代码

test.c

#define  _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
	printf("*********************\n");
	printf("*****  1.play   *****\n");
	printf("*****  0.exit   *****\n");
	printf("*********************\n");
}
void game()
{
	int ret = 0;
	char board[ROW][COL] = { 0 };
	initboard(board, ROW, COL);//初始化棋盘
	displayboard(board, ROW, COL);//打印棋盘
	while (1)
	{
		playermove(board, ROW, COL);//玩家下棋
		ret = win(board, ROW, COL);//判断输赢
		if (ret != 'C')
		{
			break;
		}
		displayboard(board, ROW, COL);//打印棋盘

		computermove(board, ROW, COL);//电脑下棋
		ret = win(board, ROW, COL);//判断输赢
		if (ret != 'C')
		{
			break;
		}
		displayboard(board, ROW, COL);//打印棋盘

	}
	if (ret == 'Q')
	{
		printf("平局!\n");
	}
	else if (ret == '*')
	{
		printf("玩家获胜!\n");
	}
	else if (ret == '#')
	{
		printf("电脑获胜!\n");
	}
	displayboard(board, ROW, COL);//打印棋盘


}
int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();//打印菜单的函数
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("进入游戏,\n");//输入1,进入游戏
			game();//game()函数是三子棋游戏的核心,它是实现三子棋游戏内容的函数
			break;
		case 0:
			printf("退出游戏!\n");//输入0.退出游戏
			break;
		default:
			printf("选择错误,请重新选择!\n");//输入非1、0,重新选择
			break;
		}

	} while (input);//输入非0,循环继续,输入0,退出游戏,循环结束
}

game.c

#define  _CRT_SECURE_NO_WARNINGS
#include"game.h"
void initboard(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 displayboard(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++)
		{
			printf(" %c ",board[i][j]);//%c是留给给待下棋的位置
			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;
	printf("玩家下棋,请输入坐标:");
	while (1)
	{
		scanf("%d %d", &x, &y);
		if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入的坐标是否越界
		{
			if (board[x - 1][y - 1] == ' ')//判断坐标是否被占用
				//玩家不知道数组下标从0开始,因此玩家输入的坐标应当-1,与二维数组下标相对应
			{
				board[x - 1][y - 1] = '*';//玩家下的棋子为'*';
				break;
			}
			else
			{
				printf("坐标被占用,请重新输入:");
			}
		}
		else
		{
			printf("输入的坐标有误,请重新输入:");
		}

	}
	
}

char win(char board[ROW][COL], int row, int  col)
{
	int i = 0;
	//判断行
	for (i = 0; i < col; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')//同1行棋子相等并且不是空格
		{
			return board[i][1];//返回获胜的棋子元素
		}
	}
	//判断列
	for (i = 0; i < row; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')//同1列棋子相同并且不是空格
		{
			return board[1][i];
		}
	}
	//判断对角
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')//对角的元素相同
	{
		return board[0][0];
	}
	if (full(board, ROW, COL))
	{
		return 'Q';
	}
	else
	{
		return 'C';
	}


}
void computermove(char board[ROW][COL], int row, int  col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋:\n");
	while (1)
	{
		//调用rand函数,产生随机数
		x = rand() % row;//行数范围为0-row
		y = rand() % col;//列数范围为0-col
		if (board[x][y] == ' ')//判断坐标是否被占用

		{
			board[x][y] = '#';//电脑下的棋子为'#';
			break;
		}
	}
	
}
int full(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++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}

	return 1;

}

game.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3//打印三行的棋盘
#define COL 3//打印三列的棋盘
//1.初始化棋盘
void initboard(char board[ROW][COL], int row,int  col);
//2.打印棋盘
void displayboard(char board[ROW][COL], int row, int  col);
//3.玩家下棋
void playermove(char board[ROW][COL], int row, int  col);
//4.判断输赢
char win(char board[ROW][COL], int row, int  col);
//5.电脑下棋
void computermove(char board[ROW][COL], int row, int  col);
//6.判断平局
int full(char board[ROW][COL], int row, int  col);

      三子棋游戏到这里已经全部实现了,我之所以称这个版本的三子棋游戏是不太聪明的三子棋游戏,因为这个版本的电脑下棋没有目的性,不会去刻意阻止玩家获胜,也没有获胜的目的性,这个版本的三子棋完全是由C语言初阶的内容实现的,因此功能没那么强大。

       若文章有什么问题或者建议,欢迎各位大佬留言或者点赞。


版权声明:本文为m0_67872788原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。