【C语言】------ 实现三子棋


前言

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

在这里插入图片描述


一、三子棋游戏流程

  1. 菜单的选择和创建
  2. 创建棋盘并初始化
  3. 打印棋盘
  4. 玩家下棋(玩家以输入坐标的方式),用’*’表示玩家所下的棋子
  5. 判断输赢(玩家赢 - ‘*’ 电脑赢 - ‘#’ 平局 - ‘Q’)
  6. 电脑下棋
  7. 判断输赢
  8. 打印游戏棋盘并返回菜单

二、游戏实现

1.菜单界面

1表示游戏开始 2表示退出。
在这里插入图片描述

代码如下:

void menu()
{
	printf("************************************\n");
	printf("**********1.play    0.exit**********\n");
	printf("************************************\n");
}
        menu();//打印菜单
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			printf("三子棋\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误!\n");
			break;
		}
	} while (input);

这里我们把menu放在main函数里有助于函数的结构呈现。

2.创建棋盘并初始化

三子棋可看作为3x3的二维数组,所以我们可以定义一个二维数组来构建。在这里我们可以建立一个全局变量方面修改和后续介绍的拓展有关。

#define ROW 5
#define COL 5

数组的初始化用两个for循环嵌套,将数组元素设置为空格
代码如下(示例):

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

3.打印棋盘

创建好棋盘之后将其显示出来,用“|”分割每一列,用”___"设置出该下的棋子的位置。每个空格对应着定义好的二维数组的每个数据元素,使用for循环来打印。
在这里插入图片描述代码如下:

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.玩家下棋

用*表示玩家下的棋子,在玩家下完棋子之后,我们对坐标进行范围合法的判断,会出现坐标位置被占用或者坐标非法(这里我们考虑到越界访问非整型的输入)所以我们用if语句将其声明出来,提示玩家应该重新输入。接收玩家所输入的地址位置(判断的数组元素应该是玩家输入值-1)

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

	while (1)
	{
		printf("请输入坐标;>");

		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");
				break;
			}
		}
		else
		{
			printf("坐标非法,请重新输入!\n");
		}
	}
}

那么我们应该如何去判断棋盘是否为满或者是否位置被占用呢??我们创建一个IsFull的函数来判断是否为满。数组下标从0开始的,所以用循环判断board[i][j]是否为空。

//如果满了返回1  不满返回0
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;
}

5.电脑下棋

要实现电脑下棋,我们可能会有疑惑,怎么才能让电脑去落子,并且是随机的,这里我们引出随机数,srand函数 需要包含头文件 <stdlib.h>和<time.h>头文件,来设置随机数的生成起点,这个函数经常跟rand函数一起使用,是随机数发生器的初始化函数。将电脑下的棋子设置为#。

srand((unsigned int)time(NULL));


代码如下:

void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋;>\n");
	int x = 0;
	int y = 0;
	
	while (1)
	{
		x = rand() % row;//0~2
		y = rand() % col;//0~2
		if (board[x][y] == ' ')
		
			board[x][y] = '#';
			break;
		}
	}
}

6.判断输赢

当玩家和电脑各自下完棋后都要进行输赢的判断,我们知道三子棋的规则,先构成三子在一条线上者为获胜者(包括斜线),那么我们就思路去设置函数分别从行、列、斜线去判断。
在这里,我们约定:

玩家赢 - ‘*’ 电脑赢 - ‘#’ 平局 - ‘Q’ 游戏继续 - ‘C’;


当一条线上都为*或者都为#游戏产生获胜者。
函数的声明:

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

的判断:

//行
	int i = 0;
	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][1];
		}
	}

我们要求每一行的相邻俩个数据元素的值都相等且不等于空,以及以下列和斜线的判断都如此。
的判断:

//列
	int j = 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[1][j];
		}
	}

那么斜线我们应该怎么来用代码实现呢?可以从左斜线和右斜线分别来判断,斜线比较容易理解,只要将board[0][0], board[1][1], board[2][2]三个位置的值两两进行判断,

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

这里有同学会问那这里都限制了坐标为三个,那么还如何能实现五子棋甚至更多的呢?我在这里用循环写了一个代码来实现当ROW和COL变化后该如何进行对角线的判断。

	char ch = board[0][0];
	for (i = 0; i < row; i++)
	{
		if (ch != board[i][i] || ch == ' ')
		{
			break;
		}
		if (i == row - 1)
		{
			return  board[1][1];
		}
	}

	ch = board[0][col - 1];
	int k = col - 1;
	for (i = 0; i < row; i++, j--)
	{
		if (board[i][k] != ch || ch == ' ')
		{
			break;
		}
		if (i == row - 1)
		{
			return  ch;
		}
	}

例如:在这里插入图片描述平局的判断比较简单,当棋盘下满是还没有分别出获胜者则为平局

//没有人赢判断平局
	if (IsFull(board, row, col))
	{
		return 'Q';
	}
	//游戏继续
	return 'C';
}

最后我们 将游戏结束时,再次打印出棋盘,更加直观的展示游戏的过程!

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


三、代码实现

1.game.h–游戏函数的声明

#pragma once
#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);

//玩家赢 - '*'
//电脑赢 - '#'
//平局 - 'Q'
//游戏继续 - 'C'
char IsWin(char board[ROW][COL], int row, int col);

2.game.c–游戏函数的实现

#define _CRT_SECURE_NO_WARNINGS 1
#include "game1.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)
{
  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("玩家下棋;>");

  while (1)
  {
  	printf("请输入坐标;>");

  	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");
  			break;
  		}
  	}
  	else
  	{
  		printf("坐标非法,请重新输入!\n");
  	}

  }
}

void ComputerMove(char board[ROW][COL], int row, int col)
{
  printf("电脑下棋;>\n");

  int x = 0;
  int y = 0;

  while (1)
  {
  	x = rand() % row;//0~2
  	y = rand() % col;//0~2
  	if (board[x][y] == ' ')
  	{

  		board[x][y] = '#';
  		break;
  	}
  }

}
//如果满了返回1  不满返回0
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;
}
char IsWin(char board[ROW][COL], int row, int col)
{
  //行
  int i = 0;
  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][1];
  	}
  }
  //列
  int j = 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[1][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];
  }*/
  char ch = board[0][0];
  for (i = 0; i < row; i++)
  {
  	if (ch != board[i][i] || ch == ' ')
  	{
  		break;
  	}
  	if (i == row - 1)
  	{
  		return  board[1][1];
  	}
  }

  ch = board[0][col - 1];
  int k = col - 1;
  for (i = 0; i < row; i++, j--)
  {
  	if (board[i][k] != ch || ch == ' ')
  	{
  		break;
  	}
  	if (i == row - 1)
  	{
  		return  ch;
  	}
  }

  //没有人赢判断平局
  if (IsFull(board, row, col))
  {
  	return 'Q';
  }
  //游戏继续
  return 'C';
}

3.test.c–测试游戏

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game1.h"
void menu()
{
  printf("************************************\n");
  printf("**********1.play    0.exit**********\n");
  printf("************************************\n");
}

void game()
{
  char ret = 0;
  char board[ROW][COL] = { 0 };
  //初始化棋盘
  InitBoard(board, ROW, COL);
  DisplayBoard(board, ROW, COL);
  //下棋
  while (1)
  {
  	PlayerMove(board, ROW, COL);
  	//判断输赢
  	ret = IsWin(board, ROW, COL);
  	if (ret != 'C')
  	{
  		break;
  	}
  	DisplayBoard(board, ROW, COL);

  	ComputerMove(board, ROW, COL);
  	//判断输赢
  	ret = IsWin(board, ROW, COL);
  	if (ret != 'C')
  	{
  		break;
  	}
  	DisplayBoard(board, ROW, COL);
  }
  if (ret == '*')
  {
  	printf("玩家赢了!\n");
  }
  else if (ret == '#')
  {
  	printf("电脑赢了!\n");
  }
  else
  {
  	printf("平局\n");
  }
  DisplayBoard(board, ROW, COL);
}

int main()
{
  srand((unsigned int)time(NULL));//设置随机数的生成起点
  int input = 0;

  do
  {
  	menu();//打印菜单
  	printf("请选择:>");
  	scanf("%d", &input);
  	switch (input)
  	{
  	case 1:
  		game();
  		printf("三子棋\n");
  		break;
  	case 0:
  		printf("退出游戏\n");
  		break;
  	default:
  		printf("选择错误!\n");
  		break;
  	}
  } while (input);
  return 0;
}

四、总结

第一次写博客,希望各位批评指正,一起学习哦!
三子棋小游戏的实现,需要我们对数组和循环知识的基础,以及函数的思想,相信大家有了一定的了解并且能够创建自己的三子棋小游戏或者更高,那么有没有发现,电脑下棋似乎有点笨呼呼的,那么希望大家能够”各显神通“,赋予电脑能够”聪明“一点儿,我们可以一起交流,如果对大家有所帮助劳烦点点关注哦!
在这里插入图片描述

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FIRM'

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值