[日常练习] 3. 基于井字棋游戏的C语言实现!


井字棋算是童年课堂上的与同桌默契配合的一大乐趣...躲避着老师“关切”的目光,在眼皮底下“顶风作案”,将“灯下黑”体现的淋漓尽致!在C语言中,也算是一个小的项目,今天,我们就用C语言来实现它!!!追逐童年的一份小乐趣!


游戏介绍:

“井字棋”也称“三子棋”,需要一个3*3的棋盘。假设分为黑、白方,各执黑棋、白棋,双方各下一次,下棋位置必须在棋盘内并且不能占着已有棋子,若能将横3、竖3、斜3任意一种情况都是黑棋/白棋,那么则黑方/白方胜利。要是当棋盘下满还不能分出胜负,那么就是平局。

C语言实现逻辑:

1. 首先,需要一个3*3的棋盘,棋盘使用二维数组配合字符进行打印即可,采用循环结构可以方便我们的操作。

2. 游戏简答可分成:玩家、电脑双方,那么电脑下棋子与玩家下棋子的棋盘都需要进行打印。这是两种不同的重复操作,但大致功能相同,那么可以根据其功能写出两种打印函数。

3. 双方落子是依据在二维数组之内的,给两者不同的字符标识即可进行区分。但是落子规则需要进一步讨论,玩家所输入坐标必须在满足二维数组的要求,不能是负数、不能越界,否则应该重新进行坐标输入。还有一种情况就是,所输入坐标已经有棋子了,这时应该提示玩家重新进行输入,并且电脑应该直接避免这个情况。

4. 判断胜负是游戏很重要的一部分。这一部分也是依据在二维数组的基础上的,可以遍历二维数组的元素,要是横、竖、斜之一存在相同的棋子,那么执该棋子方取得胜利。否则当棋盘填充满的情况下,仍无胜利方,那么就是平局了。


经过上面简单的逻辑分析,为了验证我们逻辑的正确性,现在给出我们的C语言实现的源代码及结果!

测试源代码:

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

void menu()        //打印游戏菜单
{
	printf("************************************\n");
	printf("********《《    1. play    》》*********\n");
	printf("********《《    0. exit    》》*********\n");
	printf("************************************\n");
}

void game()
{
	char board[ROW][COL] = {0};       //以行列作为二维数组的参数值
	char ret = 0;                     //字符类型ret作为载体,便于二维数组中所传字符进行比对
	InitBoard(board, ROW, COL);       //定义一个ROW*COL的空棋盘
	DisplayBoard(board, ROW, COL);    //添加字符/特殊字符(宣扬个性),给棋盘加上边界

	while(1)                          //死循环
	{
		PlayerMove(board, ROW, COL);  //玩家走,定义函数
		ret = IsWin(board, ROW, COL); //判定胜负
		if(ret != ' ')                //如果此二维数组内元素未定义,即为空,在执行下面的电脑走
		{
			break;
		}
		DisplayBoard(board, ROW, COL);//玩家走后打印棋盘
		ComputerMove(board, ROW, COL);//电脑走(一定是空白可赋值,见25--28行)
		ret = IsWin(board, ROW, COL); //判定胜负
		if(ret != ' ')                
		{
			break;
		}
		DisplayBoard(board, ROW, COL);//电脑走后,打印棋盘
	}
	if(ret == '0')                    //
	{
		printf("电脑赢!\n");
	}
	else if(ret == 'X')
	{
		printf("玩家赢!\n");
	}
	else if(ret == 'Q')
	{
		printf("平局!\n");
	}
}


void test()
{
	int input = 0;                        
	srand((unsigned int)time (NULL));       
	do
	{
		menu();
		printf("请选择:>");            //选择开始游戏
		scanf("%d", &input);            //输入选项
		switch(input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择!\n");
		}
	}while(input);                    //循环结构,输错后继续,不准停!
}

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

游戏实现源代码:

#include "game.h"

void InitBoard(char arr[ROW][COL], int row, int col)   //函数不需返回值,需要二维数组、行数、列数作为函数参数
{
	int i = 0;                          //注:在从game.h拷贝函数名的时候需要去除 ";" 否则会提示错误:在文件范围内找到“{”(是否缺少函数头?)
	int j = 0;

	for(i=0; i<row; i++)
	{
		for(j=0; j<col; j++)        //遍历二维数组
		{
			arr[i][j] = ' ';        //初始化二维数组
		}
	}
}

void DisplayBoard(char arr[ROW][COL],int row, int col)   //函数参数与InitBoard相同,功能为打印有边界的棋盘,即给二维数组赋值
{
	int i = 0;
	int j = 0;

	for(i=0; i<row; i++)                                //遍历二维数组
	{
		for(j=0; j<col; j++)
		{
			printf(" %c ", arr[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 arr[ROW][COL],int row, int col)
{
	int x = 0;
	int y = 0;
	
	printf("玩家走:\n");
	while(1)
	{
		printf("请输入坐标:");
		scanf("%d%d", &x, &y);
		if((x>=1 && x<=3)&&((y>=1 && x<=3)))                     //保证玩家输入坐标正确性
		{
			if(arr[x-1][y-1] == ' ')                             //玩家输入坐标与二维数组下标之间相差1
		{
			arr[x-1][y-1] = '*';                                 //如果为空,即未被占用,则赋值为字符X
			break;
		}
			else
		{
			printf("坐标已被占用\n");                            //被占用提示
		}
	}
		else                                                     //不在if语句限值之内即非法
		{
			printf("坐标非法\n"); 
		}                         
	}
}

void ComputerMove(char arr[ROW][COL],int row, int col)           //电脑落子
{
	int x = 0;
	int y = 0;
	printf("电脑走:>\n");
	while(1)
	{
		x=rand() % 3;                                              //得二维数组下标0  1  2,对3取模即可
     	y=rand() % 3;
		if(arr[x][y] == ' ')                                
		{
			arr[x][y] = 'o';                                     //若为空,对其赋值
			break;
		}
	}
	printf("电脑坐标:%d %d\n", x+1, y+1);
}    

//当进程没有退出时 会产生错误  1>LINK : fatal error LNK1104: 无法打开文件“E:\A-bite\A\game\Debug\game.exe”

static int IsFull(char arr[ROW][COL],int row, int col)  //不为接口函数,不需要放入game.h,仅在此使用,无法进行test.c中调用
{
	int i = 0;
	int j = 0;

	for(i=0; i<row; i++)                                //遍历二维数组
	{
		for(j=0; j<col; j++)
		{
			if(arr[i][j] == ' ')                        //判断是否仍有空值
				return 0;                               //有空值返回0
		}
	}
	return 1;                                           //无空值返回1
}

char IsWin(char arr[ROW][COL],int row, int col)         //判断胜负
{
	int i = 0;
	for(i=0; i<row; i++)                                //判断行  是否能胜利
	{
		if(arr[i][0]==arr[i][1] && arr[i][1]==arr[i][2] && arr[i][0]!=' ')
		{
			return arr[i][0];                           //若三子相同,且不能为空,返回元素内值
		}
	} 

	for(i=0; i<col; i++)                                //判断列  是否能胜利
	{
		if(arr[0][i]==arr[1][i] && arr[1][i]==arr[2][i] && arr[1][i]!=' ')
		{
			return arr[1][i];
		}
	}

	if(arr[0][0]==arr[1][1] && arr[1][1]==arr[2][2] && arr[1][1] != ' ')   //判断正对角线能否胜利
	{
		return arr[1][1];
	}

	if(arr[0][2]==arr[1][1] && arr[1][1]==arr[2][0] && arr[1][1] != ' ')   //判断反对角线能否胜利
	{
		return arr[1][1];
	}

	if(IsFull(arr, row, col))                                              //判定平局
	{
		return 'Q';
	}
	return  ' ';                                     //继续
}

头文件及函数声明:

#ifndef __GAME_H__
#define __GAME_H__
#include<stdio.h>

#define ROW 3
#define COL 3

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


#endif  //__GAME_H__

猜你喜欢

转载自blog.csdn.net/yl_puyu/article/details/83048410