【C语言】三子棋强化(可改为五子棋,也可改变棋盘大小)



      对于三子棋,我们再熟悉不过了,它的规则我们大家都知道,首先向读者展示一下我的代码运行效果,由于背景是黑色的原因,白棋是图片中黑色的笑脸,对应于ASCII码值为1,黑棋是图片中白色的笑脸对应于ASCII码值为2。


      在此我说明一点,我并没有把使电脑聪明的算法写进去,读者有兴趣可以自己添加,只需要用算法改写(电脑走)函数即可。

//电脑走
void RobotMove(char board[ROWS][COLS])
{
	srand((unsigned int)time(NULL));  //产生随机数

	if ((BoardFull(board)) == 0)
	{
		while (1)
		{
			row = rand() % ROWS;
			col = rand() % COLS;

			if (board[row][col] == ' ')
			{
				board[row][col] = BLACK;
				break;
			}
		}
	}
}

      要三子棋改为五子棋,只需要将头文件define定义的Num的值修改为5即可。同样的,要改变棋盘的大小只需要修改ROW(行数)和COL(列数)即可。同时还可以改变玩家棋子的颜色(黑或白),交换define定义的 BLACK和WHITE的值即可。头文件代码如下:

# ifndef __GAME_H__
# define __GAME_H__
# pragma warning(disable: 4996)


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

# define ROWS 8
# define COLS 10
# define NUM 5
# define BLACK 2
# define WHITE 1 

//初始化棋盘
void InitBoard(char board[ROWS][COLS]);
//打印棋盘
void PrintBoard(char board[ROWS][COLS]);
//玩家走
void PlayerMove(char board[ROWS][COLS]);
//电脑走
void RobotMove(char board[ROWS][COLS]);
//检查输赢
char Check(char board[ROWS][COLS]);

# endif //__GAME_H__

      下面是我写的源码,读者可以通过代码注释理解代码,如果有不对的地方欢迎指点:

game.c

#define _CRT_SECURE_NO_WAENINGS 1

# include "game.h"

int row = 0;
int col = 0;

void game()
{
	char board[ROWS][COLS] = { 0 };
	char ret = ' ';
	int first_player = 0;

	InitBoard(board);

	while (1)
	{
		printf("请选择(0. 电脑先下  1.你先下):\t");
		scanf("%d", &first_player);
		printf("\n");

		switch (first_player)
		{
		case 0:
		{
			for (int i = 0; i < NUM - 2; ++i)  //对于n子棋,它的前n-1次不存在输赢,因此不需要调用Check()函数;
							//比如:对于五子棋,前四次是不需要检查输赢
			{
				RobotMove(board);
				PrintBoard(board);
				PlayerMove(board);
			}
			RobotMove(board);
			PrintBoard(board);
		}
		break;

		case 1:
		{
			for (int i = 0; i < NUM - 1; ++i)
			{
				PrintBoard(board);
				PlayerMove(board);
				RobotMove(board);
			}
			PrintBoard(board);
		}
		break;

		default:
			printf("选择错误,请重新选择:\n\n\n");
			break;
		}

		do
		{
			PlayerMove(board);
			if ((ret = Check(board)) != ' ')
			{
				PrintBoard(board);
				break;
			}

			RobotMove(board);
			if ((ret = Check(board)) != ' ')
			{
				PrintBoard(board);
				break;
			}
			PrintBoard(board);

		} while (ret == ' ');

		if (ret == 2)
		{
			printf("黑棋胜!\n");
			break;
		}

		if (ret == 1)
		{
			printf("白棋胜!\n");
			break;
		}
		if (ret == 'P')
		{
			printf("不容易,平局!\n");
			break;
		}
	}
}

//初始化棋盘
void InitBoard(char board[ROWS][COLS])
{
	int i = 0;
	int j = 0;

	for (i = 0; i < ROWS; i++)
	{
		for (j = 0; j < COLS; j++)
		{
			board[i][j] = ' ';
		}
	}
}

//打印棋盘  
void PrintBoard(char board[ROWS][COLS])
{
	int i = 0;
	int j = 0;
	
	for (i = 0; i < COLS; ++i)
	{
		printf(" ___");
	}
	printf("\n");
	for (i = 0; i < ROWS; ++i)
	{
		for (j = 0; j < COLS; ++j)
		{
			printf("| ");
			printf("%c", board[i][j]);
			printf(" ");
		}	
		printf("|\n");
		for (j = 0; j < COLS; ++j)
		{
			printf("|___");
		}
		printf("|\n");
	}
	printf("\n");
}

//玩家走
void PlayerMove(char board[ROWS][COLS])
{
	printf("请输入你想下的坐标: ");
	scanf("%d %d", &row, &col);
	row--;
	col--;

	if (board[row][col] == ' ')
	{
		board[row][col] = WHITE;
	}
	else
	{
		printf("坐标有误,请重新输入\n");
		PlayerMove(board);
	}
}

//电脑走
void RobotMove(char board[ROWS][COLS])
{
	printf("电脑下!!!!!!!!!!!!!!\n");
	srand((unsigned int)time(NULL));  //产生随机数

	if ((BoardFull(board)) == 0)
	{
		while (1)
		{
			row = rand() % ROWS;
			col = rand() % COLS;

			if (board[row][col] == ' ')
			{
				board[row][col] = BLACK;
				break;
			}
		}
	}
}

//判断输赢
char Check(char board[ROWS][COLS])
{
	int i = 0;

	if (BoardFull(board) == 1)
	{
		return 'P';
		PrintBoard(board);
	}
	else
	{	
		int n = 1;

		//判断本次落棋的地方和 上方及下方是否存在NUM个连续相同的棋子
		//先往上方依次扫描NUM-1个位置的过程中如果碰到相同棋子,则给标志加一,
		//如果碰到边界、空位符或者不同的棋子则反向扫描,下面扫描其它方向时同理
		for (i = 1; i < NUM; ++i)
		{
			if ((row - i) < 0 || board[row - i][col] != board[row][col])
			{
				break;
			}
			else
			{
				n++;
			}
		}	
		if (n >= NUM)
		{
			return board[row][col];
		}
		//此时,开始从起始位置向下扫描
		for (i = 1; i < NUM; ++i)
		{
			if ((row + i) >= ROWS || board[row + i][col] != board[row][col])
			{
				break;
			}
			else
			{
				n++;
			}
		}	
		if (n >= NUM)
		{
			return board[row][col];
		}
		
		 n = 1;
		//判断本次落棋的地方和 右上方及左下方是否存在NUM个连续相同的棋子
		for (i = 1; i < NUM; ++i)
		{
			if ((row - i) < 0 || (col + i) >= COLS || board[row - i][col + i] != board[row][col])
			{
				break;
			}
			else
			{
				n++;
			}
		}
		if (n >= NUM)
		{
			return board[row][col];
		}
		//此时,开始从起始位置左下方扫描
		for (i = 1; i < NUM; ++i)
		{
			if ((row + i) >= ROWS || (col - i) < 0 || board[row + i][col - i] != board[row][col])
			{
				break;
			}
			else
			{
				n++;
			}
		}
		if (n >= NUM)
		{
			return board[row][col];
		}

		n = 1;
		//判断本次落棋的地方和左右方是否存在NUM个连续相同的棋子
		for (i = 1; i < NUM; ++i)
		{
			if ((col - i) < 0 || board[row][col - i] != board[row][col])
			{
				break;
			}
			else
			{
				n++;
			}
		}
		if (n >= NUM)
		{
			return board[row][col];
		}
		//此时,开始从起始位置向右扫描
		for (i = 1; i < NUM; ++i)
		{
			if ((col + i) >= COLS || board[row][col + i] != board[row][col])
			{
				break;
			}
			else
			{
				n++;
			}
		}
		if (n >= NUM)
		{
			return board[row][col];
		}

		 n = 1;
		//判断本次落棋的地方和 左上方及右下方是否存在NUM个连续相同的棋子
		for (i = 1; i < NUM; ++i)
		{
			if ((row - i) < 0 || (col - i) < 0 || board[row - i][col - i] != board[row][col])
			{
				break;
			}
			else
			{
				n++;
			}
		}
		if (n >= NUM)
		{
			return board[row][col];
		}
		//此时,开始从起始位置右下方扫描
		for (i = 1; i < NUM; ++i)
		{
			if ((row + i) >= ROWS || (col + i) >= COLS || board[row + i][col + i] != board[row][col])
			{
				break;
			}
			else
			{
				n++;
			}
		}
		if (n >= NUM)
		{
			return board[row][col];
		}
		return ' ';
	}
}

//判断棋盘是否下满
//这里注意的是这个函数内部封装即可,不需要向往展示,这也是代码安全性的一种考虑
static int BoardFull(char board[ROWS][COLS])
{
	int i = 0;
	int j = 0;
	for (i = 0; i<ROWS; i++)
	{
		for (j = 0; j<COLS; j++)
		{
			if (board[i][j] == ' ')      //棋盘未满时返回0,否则返回1  
				return 0;
		}
	}
	return 1;
}

test.c

#define _CRT_SECURE_NO_WAENINGS 1

#pragma warning(disable: 4996)

# include "game.h"
# include <windows.h>

void game();
void menu()
{
	printf("***********************************\n\n");
	printf("1.开始游戏\t");
	printf("0.退出游戏\n\n");
	printf("***********************************\n");
}

int main()
{
	int choose = 1;

	while (choose)
	{
		menu();

		printf("请选择(0或1):\t");
		scanf("%d", &choose);

		printf("\n");

		switch (choose)
		{
		case 0:
			printf("下次再见~\n");
			break;
		case 1:
			game();
			break;
		default:
			printf("选择错误,请重新选择:\n\n\n");
			break;
		}
	}

	system("pause");
	return 0;
}

如果读者有什么疑问,欢迎留言。

    

三子棋改为五子棋需要增强判断输赢的算法,以下是一种可能的实现方式: 1. 增加一个判断函数,用于判断目前的棋盘上是否有五子连珠 ``` int check_five(int board[15][15], int row, int col, int player) { int count = 1; int i, j; // 检查横向 for (i = col + 1; i < 15 && board[row][i] == player; i++) { count++; } for (i = col - 1; i >= 0 && board[row][i] == player; i--) { count++; } if (count >= 5) return 1; // 检查纵向 count = 1; for (i = row + 1; i < 15 && board[i][col] == player; i++) { count++; } for (i = row - 1; i >= 0 && board[i][col] == player; i--) { count++; } if (count >= 5) return 1; // 检查右上到左下斜线 count = 1; for (i = row - 1, j = col + 1; i >= 0 && j < 15 && board[i][j] == player; i--, j++) { count++; } for (i = row + 1, j = col - 1; i < 15 && j >= 0 && board[i][j] == player; i++, j--) { count++; } if (count >= 5) return 1; // 检查左上到右下斜线 count = 1; for (i = row - 1, j = col - 1; i >= 0 && j >= 0 && board[i][j] == player; i--, j--) { count++; } for (i = row + 1, j = col + 1; i < 15 && j < 15 && board[i][j] == player; i++, j++) { count++; } if (count >= 5) return 1; return 0; } ``` 2. 在落子时,判断是否存在连成五子连珠的情况 ``` int row, col; // 玩家落子代码 if (check_five(board, row, col, player)) { printf("Player %d wins!\n", player); break; } ``` 3. 在每次落子后,判断是否平局 ``` int i, j, count = 0; for (i = 0; i < 15; i++) { for (j = 0; j < 15; j++) { if (board[i][j] == 0) { count++; } } } if (count == 0) { printf("Draw!\n"); break; } ``` 这些修改可以让游戏判断连成五子连珠,并且增加平局的判断。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值