【c语言】三子棋游戏

此代码可以根据你所规定行数,来进行游戏,不仅限于3行3列的

设计思路

  • 由于这个代码相较于平常所写的,代码比较多,故我采用多文件管理,减少维护成本
    • 函数声明放在game.h头文件
    • 与游戏有关函数定义放在game.c源文件
    • main函数单独放在main.c中
  • 设计代码时,先写出主体逻辑,然后边测试逻辑的正确性边进行代码的具体实现

如下:

先从主函数开始写出大体逻辑
int main(void)
{
	int input = 0;
	do
	{
		menu();

		printf("请输入你的选择:");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏!");
			break;
		default:
			printf("输入错误,请重新输入!");
			break;
		}

	} while (input);
	

	return 0;
}

菜单函数
void menu()
{
	printf("**********************************\n");
	printf("*****     1.play   0.exit    *****\n");
	printf("**********************************\n");
}

写出game函数的逻辑

1. **你要下棋要棋盘,所以创建一个二维数组来充当棋盘** 1. **此时就要有初始化棋盘的函数,先写出来** 1. **打印棋盘出来让玩家下棋,所以需要一个打印棋盘的函数** 1. **此时玩家就可以开始下棋了,需要一个玩家下棋的函数** 1. **打印棋盘** 1. **玩家下完棋后,电脑下棋,需要一个电脑下棋的函数** 1. **并且在玩家或者电脑下完棋后,需要判断1.谁赢了 2. 是否平局(棋盘是否已满)若上述都没有发生则继续 ,故这是一个玩家下棋,电脑下棋是一个循环的过程**
void game()
{
	char board[ROW][COL];
	char ret = 0;
	srand((unsigned)time(NULL));

	InitBoard(board, ROW, COL);

	PrintBoard(board, ROW, COL);
	while (1)
	{
		
		PlayerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
        
		board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, 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] = ' ';
		}
	}
}

打印棋盘
  • 打印棋盘就要打印出一个框架

image.png

仔细观察这个棋盘,可以发现对于棋盘的每一行来说:都是由这两行组成,只是最后一行没有打印而已

  • 第一行: 三个空格加|。。。。 。。
  • 第二行:三个下划线加|。。。。。。

image.png

所以可以写成如下代码

void PrintBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
    int j = 0;
    for(i=0; i<row; i++)
    {	
        printf("  %c |  %c | %c | %c | %c \n", board[i][0],board[i][1],.. board[i][4]);
        if(i<row-1)
            printf("---|---|---|---|---\n");
    }
	
}

但是上述代码有个问题,就是它的列数是固定的,所以我们又要在行的规律基础上找出列的规律,从而写出代码

我们观察可以发现,棋盘的每一列都是由两部分组成:只是棋盘的最后一列的第二部分没有打印而已

  • 第一部分:三个空格
  • 第二部分:一个 |
  • 对于分割部分类似

代码如下:

void PrintBoard(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");
	}
}

玩家走

逻辑比较简单,就是判断是否覆盖以及是否越界,注意:玩家的坐标和程序员的坐标不一样

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	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("该位置已被占!");
			}
		}
		else
		{
			printf("请重新输入!");
		}
	}

}

电脑走

电脑走只需考虑覆盖问题即可

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;
		}
	}		
}

判断棋盘情况

分为四种情况:

  1. 玩家赢 返回‘*’
  2. 电脑赢,返回‘#

判断谁赢分为四种情况考虑:直接返回相同的那个字符,若返回*则玩家赢,返回#则电脑赢

  • 行相同:
  • 列相同:
  • 主对角线相同:
  • 副对角线相同:
  1. 平局(棋盘是否已满),返回 ’Q‘
  2. 继续游戏,返回-‘C’

完善game函数逻辑
void game()
{
	char board[ROW][COL];
	char ret = 0;
	srand((unsigned)time(NULL));

	InitBoard(board, ROW, COL);

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

判断棋盘情况的函数
char IsWin(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	char flag[ROW]; //保存数据来判断是否相同
	int temp = 0;
	//判断行相同
	for (i = 0; i < row; i++)
	{
        //将每一行的字符传给flag数组
		for (j = 0; j < col; j++)
		{
			flag[j] = board[i][j];
		}
        //判断flag数组中是否都相同
		for (j = 0; j < col - 1; j++)
		{
			
			if (flag[j] != flag[j + 1]) 
			{
				break;
			}
		}
		if (col-1 == j && flag[0] != ' ')  //若跳出来时j=col-1,则说明比较完毕,都相同
		{
			return flag[0];
		}
	}
	//判断列相同
	while (temp < col)
	{
        //将每一类分别传给flag数组
		for (i = 0; i < row; i++)
		{
			for (j = 0; j < col; j++)   //对于列是否赢
			{
				if (temp == j)
				{
					flag[i] = board[i][j];
					break;
				}
			}
		}
        //判断flag中是否相同
		for (j = 0; j < col - 1; j++)
		{
			if (flag[j] != flag[j + 1])
				break;
		}
		if (j == col - 1 && flag[0] != ' ')
			return flag[0];
		temp++;
	}
	//判断主对角线相同
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (i == j)
			{
				flag[i] = board[i][j];
			}
		}
	}
	for (j = 0; j < col-1; j++)
	{
		if (flag[j] != flag[j + 1])
			break;
	}
	if (j == col - 1 && flag[0] != ' ')
		return flag[0];

	//判断副对角线相同,因为两个坐标加起来恰好等于列数(行数)-1,所以可以设置如下
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (i + j == (col - 1))
			{
				flag[i] = board[i][j];
			}
		}
	}
	for (j = 0; j < col - 1; j++)
	{
		if (flag[j] != flag[j + 1])
			break;
	}
	if (j == col - 1 && flag[0] != ' ')
		return flag[0];

	//是否平局,将判断棋盘是否已满封装为一个函数
	int ret = IsFull(board, row, col);
	if (1 == ret)
		return 'Q';
	return 'C';
}

判断棋盘是否已满
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;
}

完整代码如下:
#define _CRT_SECURE_NO_WARNINGS 1

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

#define ROW 5
#define COL 5
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);

//打印棋盘
void PrintBoard(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 _CRT_SECURE_NO_WARNINGS 1
#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 PrintBoard(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");
	}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;

	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("该位置已被占!");
			}
		}
		else
		{
			printf("请重新输入!");
		}
	}

}
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)
{
	int i = 0;
	int j = 0;
	char flag[ROW];
	int temp = 0;
	//判断行
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			flag[j] = board[i][j];
		}
		for (j = 0; j < col; j++)
		{
			if (j == col - 1)
				break;
			if (flag[j] != flag[j + 1])
			{
				break;
			}
		}
		if (col-1 == j && flag[0] != ' ')
		{
			return flag[0];
		}
	}
	//判断列
	while (temp < col)
	{
		for (i = 0; i < row; i++)
		{
			for (j = 0; j < col; j++)   //对于列是否赢
			{
				if (temp == j)
				{
					flag[i] = board[i][j];
					break;
				}
			}
		}
		for (j = 0; j < col - 1; j++)
		{
			if (flag[j] != flag[j + 1])
				break;
		}
		if (j == col - 1 && flag[0] != ' ')
			return flag[0];
		temp++;
	}
	//主对角线
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (i == j)
			{
				flag[i] = board[i][j];
			}
		}
	}
	for (j = 0; j < col-1; j++)
	{
		if (flag[j] != flag[j + 1])
			break;
	}
	if (j == col - 1 && flag[0] != ' ')
		return flag[0];

	//副对角线
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (i + j == (col - 1))
			{
				flag[i] = board[i][j];
			}
		}
	}
	for (j = 0; j < col - 1; j++)
	{
		if (flag[j] != flag[j + 1])
			break;
	}
	if (j == col - 1 && flag[0] != ' ')
		return flag[0];

	//是否平局
	int ret = IsFull(board, row, col);
	if (1 == ret)
		return 'Q';
	return 'C';
}
//判断棋盘是否已满
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;
}
#define _CRT_SECURE_NO_WARNINGS 1

#include"game.h"


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

void game()
{
	char board[ROW][COL];
	char ret = 0;
	srand((unsigned)time(NULL));

	InitBoard(board, ROW, COL);

	PrintBoard(board, ROW, COL);
	while (1)
	{
		
		PlayerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if ('C' != ret)
			break;
		ComputerMove(board, ROW, COL);
		PrintBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if ('C' != ret)
			break;
	}
	if ('#' == ret)
		printf("电脑赢!\n");
	if ('*' == ret)
		printf("玩家赢!\n");
	if ('Q' == ret)
		printf("平局!\n");
}
int main(void)
{
	int input = 0;
	do
	{
		menu();

		printf("请输入你的选择:");
		scanf("%d", &input);

		switch (input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出游戏!");
			break;
		default:
			printf("输入错误,请重新输入!");
			break;
		}

	} while (input);
	

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值