C语言编写三子棋游戏:从概念到思路到实现

目录

一.文章概述

二.游戏规则概述

三.理解思路

1. 定义游戏数据结构

2. 游戏搭建思路及其步骤

·菜单选择列表:

·初始化棋盘:所有位置均为空格

·创建棋盘样式

·设置玩家下棋

·设置电脑下棋

·检查游戏状态:

四.代码示例

一.game.c部分

二.game.h部分

三.test.c部分

结论


一.文章概述

本文将深入探讨用C语言实现一个经典的双人策略游戏——三子棋(Tic Tac Toe)。我们不仅会详细解释游戏规则、数据结构选择,还会阐述如何设计和编码游戏的逻辑流程。通过本篇文章,读者能够理解如何从概念分析到具体代码实现,一步步构建出完整的三子棋游戏。

二.游戏规则概述

三子棋是一种经典的两人策略游戏,通常在一个3x3(本次代码可以随意更改棋盘大小)的网格上进行。玩家轮流放置他们的标记(这里代码玩家下棋用“*”,电脑下棋用“#”来示例),目的是在横行、竖列或斜对角线上获得三个连续的标记及为获胜。

1.一个玩家形成一条直线上的三个标记。

2.所有的格子都被占用(平局)。

三.理解思路

1. 定义游戏数据结构

创建一个二维数组来表示棋盘。使用字符型数组 

//存放数据需要一个3*3的二维数组
	char board[ROW][COL] = {0};

 来存储每个位置的棋子,其中 ‘’, ‘*’, 和 ‘#’分别代表空位、玩家和电脑。

2. 游戏搭建思路及其步骤

·菜单选择列表

//声明菜单是menu定义格式
void menu()
{
	printf("*******************************\n");
	printf("********    1. play      ******\n");
	printf("********    0. exit      ******\n");
	printf("*******************************\n");
}

·初始化棋盘:所有位置均为空格

//初始化棋盘
	InitBoard(board, ROW, COL);
//方法一
void InitBoard(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++)
		{
			board[i][j] = ' ';
		}
	}
}
//方法二
void InitBoard(char board[ROW][COL], int row, int col)
{
    memset(&board[0][0], ' ', row*col*sizeof(board[0][0]));
}

·创建棋盘样式

void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 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)
		{
			for (j = 0; j < col; j++)
			{
				printf("---");
				if(j<col-1)
					printf("|");
			}
		}
		printf("\n");
	}
}

·设置玩家下棋

使用循环结构(如 while 循环)来处理玩家和电脑输入,询问玩家和电脑选择的位置并验证。通常需要一个函数来接受用户输入的行和列,并转换为有效的数组索引。

//判断玩家下棋输入坐标是否符合要求
//若符合要求,则判断该位置是否是没有超出棋盘范围的
//若没有超出且该位置是空的,玩家就下棋
//为了能达成赢,输,平局三种其一的局面
//需要while不停的循环
void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋:>\n");

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

·设置电脑下棋

//电脑采用随机下棋的方式
//当所下位置是空的话,则电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("电脑下棋>:\n");

	while (1)
	{
        //假如row=9
	    //rand()%row=0-8
	    //那么+1就是1-9
		x = rand() % row;
		y = rand() % col;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}

·检查游戏状态

需要有函数来检查游戏是否结束(是否有胜者或平局)和验证下棋操作的有效性(确保不是重复落子、非空位等)。

//判断输赢
//玩家赢 - '*'
//电脑赢 - '#'
//平局   - '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][0] != ' ')
		{
			return board[i][0];
		}
	}
	for (i = 0; i < col; i++)
	{
        //判断列
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];
		}
	}
	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];
	}
	//判断是否平局
	if (IsFull(board, row, col))
	{
		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] == ' ')
			{
            //没有空格子了就直接返回0终止程序
				return 0;
			}
		}
	}
    //继续下棋
	return 1;
}

四.代码示例

一.game.c部分

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"


void InitBoard(char board[ROW][COL], int row, int col)
{
	int i,j;

	//方法一
	//for (i = 0; i < row; i++)
	//{
	//	for (j = 0; j < col; j++)
	//	{
	//		//刚开始棋盘上是什么都没有的
	//		board[i][j]=' ';
	//	}
	//}

	//方法二  包含头文件#include "string.h"
	//函数规定将&/*部分指向的地方前多大空间转化为空格(' ')
	memset(&board[0][0], ' ', row * col * sizeof(board[0][0]));

}

//void DispalyBoard(char board[ROW][COL], int row, int col)
//{
//	int i, j;
//
//	for (i = 0; i < row; i++)
//	{
//		//写死了只能打印3列
//		printf(" %c | %c | %c \n",board[i][0], board[i][1], board[i][2]);
//		if (i < row - 1)
//		{
//			printf("---|---|---\n");
//		}
//	}
//
//}


void DispalyBoard(char board[ROW][COL], int row, int col)
{
	int i, j;

	//灵活变换的棋盘
	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 PlayerMove(char board[ROW][COL], int row, int col)
{
	int x = 0;
	int y = 0;
	printf("玩家下棋\n");
	
	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");
			}
		}
		else
		{
			printf("超出范围,请重新输入\n");
		}
	}
}

//随机下棋,只要是空就下
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;
		}
	}
}

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

//判断输赢
//玩家赢 - '*'
//电脑赢 - '#'
//平局   - '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][0] != ' ')
		{
			return board[i][0];
		}
	}
	//判断列
	for (i = 0; i < col; i++)
	{
		
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
		{
			return board[0][i];
		}
	}
	
	///判断主副对角线
	//为什么要是board[1][1] != ' ',board[0][0] != ' '不可以吗,前面不都是判断了board[1][1] ==board[0][0]
	//因为他是中间相互公共部分,是00或者22的话
	//意思就是如果要改的话,主副对角线就要检查对角位置就可以了,用中心检查是为了提高代码效率而已
	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];
	}

	//判断平局
	if (Is_Full(board, row, col))
	{
		return 'Q';
	}

	return 'C';
}

二.game.h部分

#pragma once
 
//头文件的包含
#include <string.h>
#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);

//判断输赢
char IsWin(char board[ROW][COL],int row, int col);

三.test.c部分

#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"

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

void game()
{
	//如果是这样的话,确实打印出了棋盘
	//但是直接打印的话那么如何落子输入?
	/*printf("  |  |  \n");
	printf("--|--|--\n");
	printf("__|__|__\n");
	printf("  |  |  \n");*/

	//运用数组解决问题
	//存放一个3*3的数组
	char board[ROW][COL] = { 0 };
	char ret = 0;

	//初始化棋盘
	InitBoard(board, ROW, COL);

	//打印棋盘
	DispalyBoard(board, ROW, COL);

	while (1)
	{
	//下棋
	//玩家下
		PlayerMove(board, ROW, COL);
	//打印
		DispalyBoard(board, ROW, COL);
	//判断输赢
		ret=IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			//在这里不判断谁赢
			//当不平局直接跳出,再进行判断
			//节省了代码
			break;
		}
	//电脑下
		ComputerMove(board, ROW, COL);
	//打印
		DispalyBoard(board, ROW, COL);
	//判断输赢
		ret = IsWin(board, ROW, COL);
		if (ret != 'C')
		{
			break;
		}
	}

	if ('*' == ret)
	{
		printf("玩家赢\n");
	}
	else if ('#' == ret )
	{
		printf("电脑赢\n");
	}
	else if ('C' == ret)
	{
		printf("平局\n");
	}


}

int main()
{
	int input=0;
	srand((unsigned int)time(NULL));
	//这个循环是为了能一直输入选择并且完成任务
	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;
}

结论

这个简单的C语言程序实现了三子棋的基本功能:定义游戏数据结构、游戏搭建思路及其步骤、检查胜利条件和切换玩家等。使用标准输入输出函数进行人机交互,并通过数组来管理棋盘状态。


我期待这篇博客示例能为你提供宝贵的思路和指导,在使用C语言构建三子棋游戏的过程中遇到问题时找到有效的解决方案。在这段旅程中,请记住,正确地挑选并应用合适的函数是关键所在——这一点在实际编程过程中尤为重要。通过合理选择这些功能,你可以确保程序不仅高效而且易于维护。希望这个资源能成为你编程之旅中的得力助手,并激发你进一步探索和优化代码的热情。

  • 16
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值