三子棋——可修改为多子棋

        三子棋:是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。

本程序可修改为多子棋,只需要修改#define定义的常量大小就行

#define ROW 3
#define COL 3

 

#define ROW 10
#define COL 10

 程序目录:

一、创建头文件文件、源文件(整体代码)

二、游戏基本逻辑(每部分代码的分析)

        1.游戏主页

        2.玩家选择玩游戏还是退出游戏

        3.初始化棋盘

        4.打印棋盘

        5.玩家下棋

        6.判断输赢

        7.电脑下棋

        8.判断输赢

三、游戏结果

        1.通过判断显示获胜方

        2.打印游戏主页,是否再玩一次游戏

程序的具体内容:

一、先创建一个头文件、两个源文件,将代码有规律有逻辑的存放,方便调试

        头文件:game.h 用于游戏代码中的函数(包括库函数、自定义函数)声明、符号定义

#define _CRT_SECURE_NO_WARNINGS
#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);

//判断行
char Winhang(char board[ROW][COL], int row, int col);

//判断列
char Winlie(char board[ROW][COL], int row, int col);

//判断对角线
char Windjx(char board[ROW][COL], int row, int col);

//判断平局
int IsFull(char board[ROW][COL], int row, int col);

       

         源文件:game.c 用于游戏代码的实现,在其中写入自定义函数的相关内容

#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)
{
	printf("\n");

	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)
		{
			int j = 0;
			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("\n");

	printf("玩家请下棋\n");

	while (1)
	{
		printf("请输入坐标(以行数和列数为坐标):》");
		scanf("%d %d", &x, &y);

		if (x>=0 && x <= row && y>=0 && 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)
{

	char ret = 0;
	//判断行赢   赢了返回temp   没赢返回s
	ret = Winhang(board, ROW, COL);
	if (ret != 's')
	{
		return ret;
	}
	//判断列赢
	ret = Winlie(board, ROW, COL);
		if(ret!='s')
	{
			return ret;
	}

	//判断对角线
	ret = Windjx(board, ROW, COL);
	if (ret != 's')
	{
		return ret;
	}

	//判断平局
	if (IsFull(board, row, col))
	{
		return 'q';
	}
	return 'c';

}


//判断行
char Winhang(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	char temp = 0;
again:
	while (i < row)
	{
		temp = board[i][0];
		if (board[i][0] != ' ')
		{
			while (j < col)
			{
				if (board[i][j] == board[i][0])
				{
					j++;
				}
				else
				{
					i++;
					j = 0;
					goto again;
				}
			}
			return temp;
		}
		else
		{
			i++;
		}
	}
	return 's';
}





char Winlie(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	char temp = 0;
again:
	while (j<col)
	{
		temp = board[0][j];
		if (board[0][j] != ' ')
		{
			while (i<row)
			{
				if (board[i][j] == board[0][j])
				{
					i++;
				}
				else
				{
					j++;
					i = 0;
					goto again;
				}
			}
			return temp;
		}
		else
		{
			j++;
		}
	}
	return 's';
}




//判断对角线
char Windjx(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	char temp = 0;
	//第一条对角线
	//for (i = 0, j = 0; i < row, j < col; i++, j++)
	while(i < row && j < col)
	{
		

		if (board[0][0]!=' ')
		{
				temp = board[0][0];
				if (board[0][0] == board[i][j])
				{
					i++;
					j++;
				}
				else
				{
					goto again;
				}
		}
		else
		{
			goto again;
		}
	}
	return temp;


	//第二条对角线
again:
	i = 0;
	j = COL-1;
	temp = board[0][j];
	while(i<row && j<col && j>=0)
	{
		if (temp != ' ')
		{
			if (temp == board[i][j])
			{
				i++;
				j--;
			}
			else
			{
				return 's';
			}
		}
		else
		{
			return 's';
		}
	}
	return temp;

}




//判断平局
int IsFull(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 用于测试游戏的逻辑

#include"game.h"


void game()
{
	char ret = 0;
	char board[ROW][COL] = { 0 };
	//初始化棋盘
	Initboard(board, ROW, COL);
	//打印棋盘
	Displayboard(board, ROW, COL);
	while (1)
	{
		//玩家下棋
		Playermove(board, ROW, COL);
		Displayboard(board, ROW, COL);
		// 判断输赢  返回*玩家赢   返回#电脑赢     返回q平局    返回c继续
		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");
		Displayboard(board, ROW, COL);

	}
	if (ret == '#')
	{
		printf("电脑赢了\n");
		Displayboard(board, ROW, COL);

	}
	if (ret == 'q')
	{
		printf("平局了\n");
		Displayboard(board, ROW, COL);

	}
}
void menu()
{
	printf("	     三子棋\n");
	printf("********************************\n");
	printf("*********0.exit  1.paly*********\n");
	printf("********************************\n");

}
int main()
{
	srand((unsigned int)time(NULL));//设置随机数的的生成起点
	int input = 0;
	do
	{
		menu();
		printf("请选择:>>");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

二、游戏的逻辑

        1.游戏主页:需要给玩家两个选择(0.退出游戏        1.玩游戏),我们将游戏主页写入函数中,需要时直接调用,避免代码重复书写带来麻烦。

//游戏主页
void menu()
{
	printf("	     三子棋\n");
	printf("********************************\n");
	printf("*********0.exit  1.paly*********\n");
	printf("********************************\n");

}

        玩家选择退出游戏:0.exit 对应的退出程序

        玩家选择玩游戏:1.play 对应进入游戏主程序

        switch语句来实现:对于两种选择0和1,有不同的答案,对于输入其它数字,则输入错误,需要重新选择,因此可以使用switch语句来实现。

        do......while循环:由于必须要有一个正确的选择,所以需要循环此过程,直到选择出一个结果,此处我们选择do......while循环,此循环的特点是至少执行循环一次,即进入游戏就得选择,循环的判断部分我们用玩家输入的input来作为判断,用它的好处在于除了选择 0 ,输入的其它正整数(除0外的其它值为真)都将会执行该循环,直到做出正确的选择。

int main()
{
	srand((unsigned int)time(NULL));//设置随机数的的生成起点
	int input = 0;
	do
	{
		menu();
		printf("请选择:>>");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			game();        //进入游戏主程序
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

        2.初始化棋盘和棋子:三子棋的棋盘是一个九宫格,首先需要一个二维数组来存放玩家与电脑下的棋子,先将该二维数组初始化为0,用“ * ”表示玩家棋子,用“ # ”表示电脑棋子,棋盘的初始化和打印也需要运用到二维数组。下面我将用自定义函数一一实现各部分的内容。

初始化棋盘(函数):Initboard(board, ROW, COL);

        函数传参内容包括:二维数组board[ ][ ]        #define定义的标识符常量ROW(行数)、COL(列数)

函数定义:

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

                函数中用char board[ROW][COL]接收传递过来二维数组,int row、int col分别接收传过来的ROW、COL。先将二维数组初始化,全部放入'空格'。

        3.打印棋盘:棋盘由棋子部分、分割部分(界线)两部分组成

 

         将表格细分开为:“ %c | %c | %c ”、“---|---|---”,可以观察到:最后一个字符后没有“|”,而在最后一行没有分割线“---”,仅有“|”,我们针对每一层次需要打印的内容用 if 语句来约束实现。

打印棋盘:Displayboard(board, ROW, COL);

函数定义:

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)
		{
			int j = 0;
			for (j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
			printf("\n");
		}
	}
}

        4.玩家下棋:下棋的过程是一个循环的过程“ 玩家下棋→打印棋盘→判断输赢→电脑下棋→打印棋盘→判断输赢 ”,并且该循环为死循环,直到分出胜负后才满足跳出循环的条件,此处用循环while(1)来实现。无论是对于玩家下棋还是电脑下棋,都需要判断下棋的位置是否是空的,若该位置有棋子了,则不能在此再落子;若输入的坐标超出范围了,则需要提醒玩家输入坐标有错,需要重新输入。

玩家下棋:Playermove(board, ROW, COL);

函数定义:

void Playermove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家请下棋\n");

	while (1)
	{
		printf("请输入坐标(以行数和列数为坐标):》");
		scanf("%d %d", &x, &y);

		if (x>=0 && x <= row && y>=0 && y <= col)
		{
			if (board[x - 1][y - 1] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("该位置已有棋子,请重新下棋\n");
			}
		}
		else
		{
			printf("输入错误,请重新输入坐标\n");
		}
	}
}

        玩家通过输入对应的行数、列数确定落子的位置,玩家棋子用“ * ”表示。

        5.判断输赢:分别对行、列、对角线进行判断,若有三子相同连在一起则为赢。此处需要用一个变量来承接返回值,用来反馈判断结果,再输出结果。

        返回值“ c ”:表示暂无胜负,继续程序

        返回值“ * ”:表示玩家赢了

        返回值“ # ”:表示电脑赢了

        返回值“ q ”:表示平局

判断输赢:Iswin(board, ROW, COL);

函数定义:

char Iswin(char board[ROW][COL], int row, int col)
{

	char ret = 0;
	//判断行赢   赢了返回temp   没赢返回s
	ret = Winhang(board, ROW, COL);
	if (ret != 's')
	{
		return ret;
	}
	//判断列赢
	ret = Winlie(board, ROW, COL);
		if(ret!='s')
	{
			return ret;
	}

	//判断对角线
	ret = Windjx(board, ROW, COL);
	if (ret != 's')
	{
		return ret;
	}
	return 'c';
}

        在该函数中又包含了三个函数,分别用于判断行、列、对角线的情况,均用变量ret承接返回值。

向函数Iswin(board, ROW, COL)反馈其返回值

        返回“ s ”:表示没有赢的情况

        返回“ temp ”:其值可能为“ * ”“ # ”,分别表示玩家、电脑满足判断的条件

判断行:Winhang(board, ROW, COL);

函数定义:

char Winhang(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	char temp = 0;
again:
	while (i < row)
	{
		temp = board[i][0];
		if (board[i][0] != ' ')
		{
			while (j < col)
			{
				if (board[i][j] == board[i][0])
				{
					j++;
				}
				else
				{
					i++;
					j = 0;
					goto again;
				}
			}
			return temp;
		}
		else
		{
			i++;
		}
	}
	return 's';
}

        判断思路:先判断每一行的第一个元素是否为空格,若为空格则直接跳转到下一行的判断;若不为空格,再依次判断本行后面的元素是否与第一个元素相同,若中途有与第一个元素不同的元素出现,则直接跳出while循环进行下一行的判断;若本行元素均与本行的第一个元素相同,则跳出循环,返回本行的第一个元素。

判断列:Winlie(board, ROW, COL);

函数定义:

char Winlie(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	char temp = 0;
again:
	while (j<col)
	{
		temp = board[0][j];
		if (board[0][j] != ' ')
		{
			while (i<row)
			{
				if (board[i][j] == board[0][j])
				{
					i++;
				}
				else
				{
					j++;
					i = 0;
					goto again;
				}
			}
			return temp;
		}
		else
		{
			j++;
		}
	}
	return 's';
}

        判断思路:先判断每一列的第一个元素是否为空格,若为空格则直接跳转到下一列的判断;若不为空格,再依次判断本列后面的元素是否与第一个元素相同,若中途有与第一个元素不同的元素出现,则直接跳出while循环进行下一列的判断;若本列元素均与本行的第一个元素相同,则跳出循环,返回本列的第一个元素。

判断对角线:Windjx(board, ROW, COL);

       函数定义:

char Windjx(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	char temp = 0;
	//第一条对角线
	//for (i = 0, j = 0; i < row, j < col; i++, j++)
	while(i < row && j < col)
	{
		

		if (board[0][0]!=' ')
		{
				temp = board[0][0];
				if (board[0][0] == board[i][j])
				{
					i++;
					j++;
				}
				else
				{
					goto again;
				}
		}
		else
		{
			goto again;
		}
	}
	return temp;


	//第二条对角线
again:
	i = 0;
	j = COL-1;
	temp = board[0][j];
	while(i<row && j<col && j>=0)
	{
		if (temp != ' ')
		{
			if (temp == board[i][j])
			{
				i++;
				j--;
			}
			else
			{
				return 's';
			}
		}
		else
		{
			return 's';
		}
	}
	return temp;

}

     判断思路:对角线有两条对角线

        第一条对角线:先判断对角线第一个元素board [0][0]是否为空格,若为空格则直接跳转到第二条对角线的判断;若不为空格,则判断该对角线上的第二个元素board [1][1]是否与第一个元素相同,再依次判断本对角线后面的元素是否与第一个元素相同;若均相同则返回第一个元素;若不同,则跳转到第二条对角线的判断。

        第二条对角线:先判断对角线第一个元素board [0][COL-1](若为三子棋就是board [0][2])是否为空格,若为空格则返回“ s ”;若不为空格,则判断该对角线上的第二个元素board [i][j](若为三子棋则对应board [1][1])是否与第一个元素相同,再依次判断本对角线后面的元素是否与第一个元素相同;若均相同则返回第一个元素;若不同,则返回“ s ”

判断平局:IsFull(board, row, col);

       函数定义:

int IsFull(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;
}

        判断思路:经过行、列、对角线的判断,若棋盘上再也没有空格存在,则该情况为平局。用if()语句来控制返回值,若括号内值为1,则返回“ q ”;若括号内值为0,则不执行if()语句,直接按照程序顺序返回“ c ”。

        6.电脑下棋:此处需要生成随机数表示下棋是随机下,若想电脑掌握更好的下棋步骤,需要对下棋步骤进行要求,此过程复杂,暂时不编写。

电脑下棋:Computermove(board, 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;
		}
	 }
}

        用函数rand()生成随机数,为了让随机数满足棋盘中每个位置的坐标要求,若为三子棋则需要随机生成0 、1 、2,用随机数分别对行数和列数取余就行,为而调用rand()函数就需要调用srand()函数来生成随机数的起点,在调用srand()函数时需要使用time()函数来形成时间戳,这样就能成功生成随机数,而这样的函数只需要调用一次就行了,所以将它放入了main函数。对time()函数传入一个空指针NULL,将其返回值用强制类型转换(unsigned int)为无符号的整形。

         再对电脑的棋子进行判断

三、游戏结果:对判断输赢的返回值进行判断最后的赢家,并打印出结果和游戏主页,让玩家在次选择是否再玩一次。

 

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值