C语言三子棋游戏进阶版详解(包括多子棋)

目录

一,总体思路介绍

二,具体思路的实现

1.初始化游戏界面

2.初始化棋盘

3.打印棋盘

4.玩家移动

5.电脑移动

6.判断输赢

 三,源码展示

game.h

 game.c

  test.c


一,总体思路介绍

对于三子棋相信大家都不陌生,今天我们来用c语言完成三子棋的进阶版也就是多子棋游戏的实现。我的思路主要由六步构成首先是完成选择进行游戏的初始化界面,选择玩三子棋游戏后,我们想既然要玩棋盘类游戏,那肯定就需要有一个棋盘在,所以就有了第二步初始化棋盘但是棋盘初始化后,是要展示在玩家面前的,于是为了展示棋盘好方便下棋,就有了第三步打印棋盘。在棋盘展示在玩家面前之后,玩家要开始下棋,输入相应的坐标,于是就有了第四步玩家移动。玩家移动完之后需要第五步电脑移动,就这样双方来回移动。但是就这样双来回的移动这个游戏就未免显得太无聊了,所以也就需要在双方每次移动之后,系统需要判断游戏的结果。这也就到了第六步判断输赢环节

二,具体思路的实现

1.初始化游戏界面

我们可以先打印出一个选择菜单由玩家选择是否进行游戏,输入的内容进入swich case语句中进行判断并执行,分为三种“开始游戏”,“退出游戏”,“选择错误重新选择”。为防止玩家玩的不够尽兴,需要在整个语句外加上循环语句。以下是具体代码:

void menu()
{
	printf("**************\n");
	printf("****1.play****\n");
	printf("****0.exit****\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;
		
}

2.初始化棋盘

在开始游戏后需要初始化棋盘,既然是个棋盘就会有x,y两个坐标。这就可以构造一个二维数组board[][]来存放这些坐标,而为了以后方便更改棋盘的大小,二维数组的行和列坐标,不能直接用常数作为参数放入,而是在头文件中用#define定义标识符常量ROW,COL,然后将两者放入二维数组的行和列坐标中。

#define ROW 5
#define COL 5

char board[ROW][COL] = { 0 };

在创建完二位数组之后,将该数组传入初始化函数中进行初始化,初始化的目的是为了打印出来更加直观,因此要将数组的每一个元素初始化为空格。如下:

	int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			board[i][j] = ' ';
		}
	}

3.打印棋盘

 为了打印出上图所示的棋盘,我们需要将数组传入打印函数中进行打印。我选择的是一行一行的打印,而每一行又可分为两小行,第一行是由多个“ board[i][j] |”符号组成,要注意在打印该行中最后一个该符号时,“|”符号不需要打印。第二行是由多个“---|”符号组成,也要注意的是打印该行中最后一个该符号时,“|”符号不需要打印。我们一行一行的打印相同的符号,当我们打印到最后一行时,最后一行的第二小行不需要打印。通过两层循环嵌套使用便可以完整的打印出整个棋盘。要注意每行的最后一列和每列的最后一行都不需要打印。代码如下:

int i = 0;
	int j = 0;
	for (i = 0; i < row; i++)
	{
		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");
		}
	}

4.玩家移动

玩家移动是通过输入坐标到相应的棋盘位置上标记为玩家下的棋“*”,首先是玩家坐标的合法性,必须在数组的行和列坐标范围内,然后由于玩家不一定知道数组下标从0开始,因此每次将玩家输入的坐标对应到相应的数组坐标时都要减1。如果玩家输入的坐标对应的位置是“ ”,说明该位置还没有被占用,该位置可以标记为玩家下的棋,否则需要玩家重新输入。代码如下:

	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] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
				printf("该坐标已被占用,请重新输入!\n");

		}
		else
			printf("坐标错误,请重新输入!\n");

	}

5.电脑移动

、电脑的移动需要产生随机数坐标,为了产生随机数需要在主函数中调用srand()函数和time()函数,以及引相应的头文件。

#include<stdlib.h>
#include<time.h>
srand((unsigned int)time(NULL));
x = rand() % row;
y = rand() % col;

产生随机数坐标后要通过运算使x,y坐标在,数组行和列范围内。然后再判断该坐标对应位置是不是已被其他标记占用,如果没有则电脑用符号“#”标记此处,如果有则电脑再循环产生一组随机数坐标继续判断,直到找到没有被标记占用的位置。代码如下:

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

6.判断输赢

这是整个游戏实现的最重要的一步。在玩家和电脑来回下棋的过程中,会出现输赢。再每次玩家移动或者电脑移动后,都会打印棋盘,然后再判断输赢。那我们该如何判断每次移动后的输赢呢?我们可以创建一个判断输赢的函数is_win(),并创建一个变量ret来接收其返回值,不同返回值对应不同的游戏结果:

	char ret = 0;
		 ret = is_win(board, ROW, COL);

	//is_win='c'表示继续
    //is_win='*'表示玩家赢
	//is_win='#'表示电脑赢
	//is_win='f'表示平局

要注意每次玩家或电脑移动后都需要打印一次棋盘,并判断一次输赢。在整个电脑和玩家下棋的循环过程的最前面,可以加一个清理屏幕的命令。代码如下:

while (1)
	{
		system("cls");
		print(board, ROW, COL);//棋盘打印
		printf("玩家移动\n");
		player_move(board, ROW, COL);//玩家移动
		print(board, ROW, COL);//棋盘打印
		 ret = is_win(board, ROW, COL);
		if (ret != 'c')
			break;
		printf("电脑移动\n");
		computer_move(board, ROW, COL);//电脑移动
		print(board, ROW, COL);//棋盘打印
		 ret = is_win(board, ROW, COL);
		if (ret!='c')
			break;

	}
	 if (ret =='*')
		printf("玩家赢!\n");
	 if (ret == '#')
		printf("电脑赢!\n");
	 if (ret== 'f')
		printf("平局!\n");
	 print(board, ROW, COL);//棋盘打印

接着就是该函数的实现了:

1.首先是对每行进行判断,创建一个变量count,每行中的每一列中不同的数组元素对应着不同的count的变化,当遍历完每一行中的所有元素后,对count的值进行判断,如果count的值等于\pmCOL,那么说明该行所有元素相等都为“*”或“#”,然后返回该元素。否则将count置0继续遍历下一行的所有元素,直到遍历完所有行。

for (i = 0; i < row; i++)
	{
		count = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == '*')
			{
				count++;
			}
			if (board[i][j] == '#')
			{
				count--;
			}
			
		}
		if (count == col || count == -col)
		{
			return board[i][j-1];
		}
	}

2.然后是列判断,与上述行判断类似,创建变量count,每列中的每一行中不同的数组元素对应着不同的count变化,当遍历完每一行中的所有元素后,对count的值进行判断,如果count的值等于\pmROW,那么说明该列所有元素相等都为“*”或“#”,然后返回该元素。否则将count置0继续遍历下一列的所有元素,直到遍历完所有列。

for (j = 0; j < col; j++)
	{
		count = 0;
		for (i = 0; i < row; i++)
		{
			if (board[i][j] == '*')
			{
				count++;
			}
			if (board[i][j] == '#')
			{
				count--;
			}
		}
		if (count == col || count == -col)
		{
			return board[i - 1][j];
		}
	}

3.接着是主对角线判断

仍然需要变量count,只需遍历一遍数组主对角线上的元素,不同的元素对应着count的变化。如果count等于\pmROW或\pmCOL,那么说明主对角线上所有元素相等都为“*”或“#”,然后返回该元素。否则进行下一个判断。代码如下:

count = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][i] == '*')
		{
			count++;
		}
		if (board[i][i] == '#')
		{
			count--;
		}
	}
	if (count == col || count == -col)
	{
		return board[i][i];
	}

4.副对角线判断

与上述主对角线相似,仍然需要变量count,只需遍历一遍数组副主对角线上的元素,不同的元素对应着count的变化。如果count等于\pmROW或\pmCOL,那么说明主对角线上所有元素相等都为“*”或“#”,然后返回该元素。否则进行下一个判断。代码如下:

count = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][col - i - 1] == '*')
		{
			count++;
		}
		if (board[i][col - i - 1] == '#')
		{
			count--;

		}
	}
	if (count == col || count == -col)
	{
		return board[i][col - i - 1];
	}

5.平局判断

在is_win()函数中嵌套调用函数is_full(),如果判断是平局is_full()返回1,否则返回0.其返回值可以创建变量ret来接收。如果ret等于1,则返回“f”,否则结束该判断。重点是is_full()函数的实现:在该函数中我们需要遍历数组中的所有元素,只要有元素为“ ”,说明该数组还有位置没有被标记,该函数直接返回0;如果遍历完所有元素都没有找到“ ”,说明该数组所有位置都被标记了,该函数返回1.代码如下:

int is_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;
}
int ret = 0;
ret = is_full(board, ROW, COL);
if (ret == 1)
	{
		return 'f';
	}

6.如果上述任何一种判断都没有返回值,则返回“c”,说明游戏继续。

return 'c';

 三,源码展示

game.h

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

#define ROW 5
#define COL 5

void init(char board[ROW][COL], int row, int col);
void print(char board[ROW][COL], int row, int col);
void player_move(char board[ROW][COL], int row, int col);
void computer_move(char board[ROW][COL], int row ,int col);
char is_win(char board[ROW][COL], int row, int col);

 game.c

#include"game.h"
void init( 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 print(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]);
			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 player_move(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] == ' ')
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
				printf("该坐标已被占用,请重新输入!\n");

		}
		else
			printf("坐标错误,请重新输入!\n");

	}
	
}
void computer_move(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	while (1)
	{
		 x = rand() % row;
		 y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
int is_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;
}
char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	int ret = 0;
	int count = 0;
	ret = is_full(board, ROW, COL);
	//三子棋游戏判断
	//for (i = 0; i < row; i++)
	//{
	//	
	//	if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][1] != ' ')
	//		return board[i][0];
	//}
	//for (j = 0; j < col; j++)
	//{
	//	if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
	//		return board[0][j];
	//}
	//if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
	//	return board[1][1];
	//if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
	//	return board[1][1];
	//多子棋游戏判断
	for (i = 0; i < row; i++)
	{
		count = 0;
		for (j = 0; j < col; j++)
		{
			if (board[i][j] == '*')
			{
				count++;
			}
			if (board[i][j] == '#')
			{
				count--;
			}
			
		}
		if (count == col || count == -col)
		{
			return board[i][j-1];
		}
	}
	for (j = 0; j < col; j++)
	{
		count = 0;
		for (i = 0; i < row; i++)
		{
			if (board[i][j] == '*')
			{
				count++;
			}
			if (board[i][j] == '#')
			{
				count--;
			}
		}
		if (count == col || count == -col)
		{
			return board[i - 1][j];
		}
	}
	count = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][i] == '*')
		{
			count++;
		}
		if (board[i][i] == '#')
		{
			count--;
		}
	}
	if (count == col || count == -col)
	{
		return board[i][i];
	}
	count = 0;
	for (i = 0; i < row; i++)
	{
		if (board[i][col - i - 1] == '*')
		{
			count++;
		}
		if (board[i][col - i - 1] == '#')
		{
			count--;

		}
	}
	if (count == col || count == -col)
	{
		return board[i][col - i - 1];
	}
	if (ret == 1)
	{
		return 'f';
	}
	return 'c';
	
}

  test.c

#include"game.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;
	init(board, ROW, COL);//棋盘初始化
	print(board, ROW, COL);//棋盘打印
	while (1)
	{
		system("cls");
		print(board, ROW, COL);//棋盘打印
		printf("玩家移动\n");
		player_move(board, ROW, COL);//玩家移动
		print(board, ROW, COL);//棋盘打印
		 ret = is_win(board, ROW, COL);
		if (ret != 'c')
			break;
		printf("电脑移动\n");
		computer_move(board, ROW, COL);//电脑移动
		print(board, ROW, COL);//棋盘打印
		 ret = is_win(board, ROW, COL);
		if (ret!='c')
			break;

	}
	 if (ret =='*')
		printf("玩家赢!\n");
	 if (ret == '#')
		printf("电脑赢!\n");
	 if (ret== 'f')
		printf("平局!\n");
	 print(board, ROW, COL);//棋盘打印

	//is_win='c'表示继续
    //is_win='*'表示玩家赢
	//is_win='#'表示电脑赢
	//is_win='f'表示平局

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值