【C语言】实现三子棋小游戏(注释详解)


前言

三子棋的棋盘是一个九宫格,双方轮流落子,若有一方横竖或者对角线有三个棋子连成一条直线则胜利。但是三子棋有很多种和棋情况。


一、基本思路流程介绍

1.创建一个用户交互菜单
2.创建一个棋盘并初始化
3.打印一个棋盘
4.玩家落子
5.判定胜负关系
6.电脑落子
7.判定胜负关系
8.结束

二、代码实现

1.用户交互菜单(Menu函数)

void Menu()//游戏选择及面
{
	printf("+-------------------------------+\n");
	printf("| 1. Play              0. Exit  |\n");
	printf("+-------------------------------+\n");
}

在这里插入图片描述



2.初始化棋盘(InitBoard函数)

static void InitBoard(char board[][COL], int row, int col)//初始化棋盘
{
	for (int i = 0; i < row; i++){  
		for (int j = 0; j < col; j++){     //使用一个二维数组初始化棋盘
			board[i][j] = INIT;            //全部设置为INIT宏定义的空格
		}
	}
}

我们的棋盘实际上是一个二维数组,初始化过程实际上是我们使用了一个双重for循环,给每一个数组元素赋值为空格。



3.打印棋盘(ShowBoard函数)

代码如下(示例):

static void ShowBoard(char board[][COL], int row, int col){
			
	system("cls");  //调用dos命令窗口进行清屏操作,即刷新棋盘
	printf(" ");
	for (int i = 0; i < col; i++){
		printf("%4d", i + 1);
	}
		printf("\n--+---+---+---\n");
	
		for (int i = 0; i < row; i++){
			printf("%-2d", i + 1); //2
			for (int j = 0; j < col; j++){
				printf("| %c ", board[i][j]); //12
			}
			printf("\n--+---+---+---\n");
		}

	}

在这里我们把打印输出棋盘设置为一个函数,这样在后面对方输入坐标的时候直接调用函数再次打印就可以了。



4.玩家落子(PlayerMove函数)

static void PlayerMove(char board[][COL], int row, int col){   //人选择落子位置
	int x = 0;
	int y = 0;
	while (1){
		printf("请输入你想落子的位置坐标<x,y>");  
		scanf("%d,%d", &y ,&x);
		if (x<1 || x>3 || y<1 || y>3){              //非法性判断,因为棋盘为3x3
			printf("超出了棋盘范围,请从新输入!");
			continue;
		}
		if (board[x - 1][y - 1] == INIT){        //只有当这个格子为空的时候才可以落子
			board[x - 1][y - 1] = WHITE;         //落下的棋子为白子
			break;
		}
		else{
			printf("此格子已被占用,请从新输入");   
		}
	}
}

1.玩家需要采用输入x,y的坐标来落子。
2.因为棋盘的大小是3x3的所以要对x和y进行合法性判定。
3.在落子之前还要判定玩家输入的坐标是否已经有棋子。
4.我们在头文件中宏定义了玩家的落子为WHITE 棋子为x。



5.电脑落子(ComputerMove函数)

static void ComputerMove(char board[][COL], int row, int col){  //电脑自动落子
	
	while (1){
		int x = rand() % 3;   //生成的随机数对三取余,生成的数字只可能为0,1,2
		int y = rand() % 3;
		if (board[x][y] == INIT){
			board[x][y] = BLACK;
			break;
		}
	  }
}

对生成的随机数%3取余,这样就得到了0,1,2的随机数。刚好满足我们定义的3x3的二维数组的下标。



6.判定胜负关系(IsEnd函数)

static char IsEnd(char board[][COL], int row, int col){
	for (int i = 0; i < row; i++){   //判定所有列是否有三个相同的棋子
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] \
			&& board[i][0] != INIT)                      //\为续行符
		{
			return board[i][0];   //此位置的返回值为WHITE或者BLACK
		}
	}
	for(int j = 0; j < col; j++){   //判定所有行是否有三个相同的棋子
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] \
			&& board[0][j] != INIT)                      //\为续行符
		{
			return board[0][j];   //此位置的返回值为WHITE或者BLACK
		}
	}
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && //判定对角线是否有三个棋子相等
		board[1][1] != INIT){       
		return board[1][1];   
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] &&  //判定对角线是否有三个棋子相等
		board[1][1] != INIT){
		return board[1][1];  
	}
	for (int i = 0; i < row; i++){       //判断其格子是否满了,若不满则继续游戏
		for (int j = 0; j < col; j++){
			if (board[i][j] == INIT){
				return NEXT;
			}
		}
	}
	return DRAW;      //上述所有情况都不满足,则为平局
}
   

1.若同一行或同一列三个非空元素相同则胜利,返回值为棋子类型。
2.若对角线三个非空元素相同则胜利,返回值为棋子类型。
3.判断其格子是否满了,若不满则继续游戏。
4.其他条件均不满足则为平局。




7.Game()函数

void Game()
{
	char board [ROW][COL]; //定义棋盘
	InitBoard(board, ROW, COL);  //初始化棋盘
	srand((unsigned long)time(NULL)); //生成随机数种子
	char result= 0;
	while (1){
		ShowBoard(board, ROW, COL);    //展示棋盘
		PlayerMove(board, ROW, COL);   //人开始选择落子位置
		result = IsEnd(board, ROW, COL); //判断游戏结果,若结果不是继续则退出。
		if (result != NEXT){
			break;   
		}
		ShowBoard(board, ROW, COL);    //展示棋盘
		ComputerMove(board, ROW, COL);   //电脑随机落子
		result = IsEnd(board, ROW, COL); 判断游戏结果,若结果不是继续则退出。
		if (result != NEXT){
			break;
		}	 
	}
	ShowBoard(board, ROW, COL);   //展示棋盘 
	switch (result){           //判断棋局结果
	case WHITE:     
		printf("你赢了!\n\n");
		break;
	case BLACK:
		printf("你输了\n\n");
		break;
	case DRAW:
		printf("平局啦!\n\n");
	default:
		break;
	}


}


三、总代码

#ifndef __Test_H__
#define __Test_H__

#include<stdio.h>
#include<Windows.h>
#include<time.h>
#include<stdlib.h>  
#pragma warning(disable:4996)

#define ROW 3
#define COL 3

#define INIT ' '   //宏定义初始化输入的值为空
#define WHITE 'X'//白方是Player 棋子为X
#define BLACK 'O'//黑方是Computer 棋子为O
#define DRAW 'D'//
#define NEXT 'N'//
 extern void Game();
#endif

void Menu()//游戏选择及面
{
	printf("+-------------------------------+\n");
	printf("| 1. Play              0. Exit  |\n");
	printf("+-------------------------------+\n");
}
int main()
{
	int select = 0;
	int quit = 0;
	while (!quit )
	{
		Menu();
		printf("请选择开始或退出");
		scanf("%d", &select);
		switch (select){
		case 1:            //选择1则开始游戏
			Game();   
			break;
		case 0:
			quit = 1;
			break;
		default:
			printf("输入错误,请从新输入\n");
			break;
		}

   }
	system("pause");
}


static void InitBoard(char board[][COL], int row, int col);//初始化棋盘
static void ShowBoard(char board[][COL], int row, int col);
static char IsEnd(char board[][COL], int row, int col);
static void ComputerMove(char board[][COL], int row, int col);
static void PlayerMove(char board[][COL], int row, int col);

void Game()
{
	char board [ROW][COL]; //定义棋盘
	InitBoard(board, ROW, COL);  //初始化棋盘
	srand((unsigned long)time(NULL)); //生成随机数种子
	char result= 0;
	while (1){
		ShowBoard(board, ROW, COL);    //展示棋盘
		PlayerMove(board, ROW, COL);   //人开始选择落子位置
		result = IsEnd(board, ROW, COL); //判断游戏结果,若结果不是继续则退出。
		if (result != NEXT){
			break;   
		}
		ShowBoard(board, ROW, COL);    //展示棋盘
		ComputerMove(board, ROW, COL);   //电脑随机落子
		result = IsEnd(board, ROW, COL); 判断游戏结果,若结果不是继续则退出。
		if (result != NEXT){
			break;
		}	 
	}
	ShowBoard(board, ROW, COL);   //展示棋盘 
	switch (result){           //判断棋局结果
	case WHITE:     
		printf("你赢了!\n\n");
		break;
	case BLACK:
		printf("你输了\n\n");
		break;
	case DRAW:
		printf("平局啦!\n\n");
	default:
		break;
	}
}

static void InitBoard(char board[][COL], int row, int col)//初始化棋盘
{
	for (int i = 0; i < row; i++){  
		for (int j = 0; j < col; j++){     //使用一个二维数组初始化棋盘
			board[i][j] = INIT;            //全部设置为INIT宏定义的空格
		}
	}
}

static void ShowBoard(char board[][COL], int row, int col){	  //展示棋盘	
	system("cls");  //调用dos命令窗口进行清屏操作,即刷新棋盘
	printf(" ");
	for (int i = 0; i < col; i++){
		printf("%4d", i + 1);
	}
		printf("\n--+---+---+---\n");
	
		for (int i = 0; i < row; i++){
			printf("%-2d", i + 1); //2
			for (int j = 0; j < col; j++){
				printf("| %c ", board[i][j]); //12
			}
			printf("\n--+---+---+---\n");
		}

	}

static void PlayerMove(char board[][COL], int row, int col){   //人选择落子位置
	int x = 0;
	int y = 0;
	while (1){
		printf("请输入你想落子的位置坐标<x,y>");  
		scanf("%d,%d", &y ,&x);
		if (x<1 || x>3 || y<1 || y>3){              //非法性判断,因为棋盘为3x3
			printf("超出了棋盘范围,请从新输入!");
			continue;
		}
		if (board[x - 1][y - 1] == INIT){        //只有当这个格子为空的时候才可以落子
			board[x - 1][y - 1] = WHITE;         //落下的棋子为白子
			break;
		}
		else{
			printf("此格子已被占用,请从新输入");   
		}
	}
}


static void ComputerMove(char board[][COL], int row, int col){  //电脑自动落子
	
	while (1){
		int x = rand() % 3;   //生成的随机数对三取余,生成的数字只可能为0,1,2
		int y = rand() % 3;
		if (board[x][y] == INIT){
			board[x][y] = BLACK;
			break;
		}
	  }
}

static char IsEnd(char board[][COL], int row, int col){  //判断结果
	for (int i = 0; i < row; i++){   //判定所有列是否有三个相同的棋子
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] \
			&& board[i][0] != INIT)                      //\为续行符
		{
			return board[i][0];   //此位置的返回值为WHITE或者BLACK
		}
	}
	for(int j = 0; j < col; j++){   //判定所有行是否有三个相同的棋子
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] \
			&& board[0][j] != INIT)                      //\为续行符
		{
			return board[0][j];   //此位置的返回值为WHITE或者BLACK
		}
	}
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && //判定对角线是否有三个棋子相等
		board[1][1] != INIT){       
		return board[1][1];   
	}
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] &&  //判定对角线是否有三个棋子相等
		board[1][1] != INIT){
		return board[1][1];  
	}
	for (int i = 0; i < row; i++){       //判断其烦是否满了,若不满则继续游戏
		for (int j = 0; j < col; j++){
			if (board[i][j] == INIT){
				return NEXT;
			}
		}
	}
	return DRAW;      //上述所有情况都不满足,则为平局
}
   

  • 47
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 24
    评论
评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

3 ERROR(s)

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

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

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

打赏作者

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

抵扣说明:

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

余额充值