超简单的三子棋,万字大文(保姆级讲解)

大家好啊,三子棋算是对于初学者来说比较困难的一个小程序,今天的文章就来讲一下如何独立从头到尾地做出三子棋小程序,如果您感觉学到了东西,不妨给我一个点赞或者关注,在这里祝您新的一年红红火火。

 

目录65b4ca7085264512a9cd145f24cee1ea.gif

    游戏的整体思路 

 菜单的实现

游戏主程序的实现 

1.棋盘的初始化 

     2.棋盘的展现

  3.玩家下棋 

 4.电脑下棋 

5.游戏胜负的判断

😎博客昵称:陈大大陈

😊座右铭:所谓觉悟,就是在漆黑的荒野上开辟出一条理当前进的光明大道。

😋博主简介:一名热爱C/C++和算法等技术,喜欢运动,爱胡思乱想却胸怀大志的小博主!

😚博主&唠嗑:早中晚安!😄各位CSDN的朋友!😄我是博客新人陈大大陈,希望我的文章能为你带来帮助!欢迎大家在评论区畅所欲言!也希望大家多多为我提出您宝贵的建议!😘如果觉得我写的不错的话还请点个赞和关注哦~😘😘😘

00453bd58f9249b88fb9ad579b9e2a64.gif

 

6956fba909464b188fe654d4563881da.gif  

    游戏的整体思路 

一个较为复杂的小程序一般有着不同的文件来负责不同的功能。我们这里需要新建三个文件。

1. test.c 负责游戏整体流程的实现

2. game.c 负责游戏内部复杂函数的实现

3. game.h 负责包含所有函数所需的头文件

3c1c1346d6cc4d39be19b5e428efe961.png

 需要注意的是,game.h的创建是在头文件,而game.c和test.c的创建则是在源文件。 

且game.c和test.c在创建时选择.cpp文件,而game.h选择.h文件

 菜单的实现

以下是我们实现游戏菜单所需的代码段

我们的菜单应该包含这几种功能

1.游戏的进入以及菜单的打印

2.游戏的退出

3.当输入非法时所跳出的错误提示

void menu()
{
	printf("**********************************\n");
	printf("*********     1 play     *********\n");
	printf("*********     2 exit     *********\n");
	printf("**********************************\n");
}
int main()
{
	int input;
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("三子棋\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

 我们单独设置一个menu函数,当进入游戏时就会出现玩或者不玩的选项

我们设置选择1是进入游戏,而选择0是退出游戏

while(input)的意思是,只要input不为0,那么循环就一直进行下去

 运行截图如下所示 

c13905cd73c84243b5a515a54af9faa4.png

游戏主程序的实现 

1.棋盘的初始化 

下棋是需要棋盘的,我们首先要进行棋盘的初始化。

想象一下三子棋的形态,是不是很像一个三行三列的二维数组? 

我们就创建一个二维数组来表示棋盘,并借以InitBoard函数将数组清空,也就是清空棋盘,从而方便一会儿下棋。

void game()
{
	char board[ROW][COL] = { 0 };
	InitBoard(board, ROW, COL);
}

     2.棋盘的展现

完成了棋盘方格内部的初始化,下一步就是将棋盘的外壳“井”打印出来。

我们再创建一个DisplayBoard函数,打印棋盘外壳。

void DisplayBoard(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 < ROW - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		if (i < ROW - 1) {
			for (j = 0;j < ROW;j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

这个地方难度不高,相信大家一定很容易搞出来,并且方法十分多,我只管抛砖引玉。图案如下。

7455b4b750c9442cb233ee8b859e046f.png

 至于上面出现的ROW和COL两个变量,则是我们为了方便定义的全局变量。

大家在game.h的文件中用define来定义,这里全部取3。

#pragma once
#define COL 3
#define ROW 3
  •  为什么要这样做呢?答案是为了之后的修改。
  • 要是不使用全局变量,如果代表三子棋行和列的变量出现错误,那将出现我们只能一个一个修改的状况,这是非常麻烦的。
  • 所以,方便起见,我们使用便于修改的全局变量。

  3.玩家下棋 

为了实现玩家下棋这一功能,我们要做到以下几点。 

1.对玩家所输入地址的接收,玩家不像程序员,并不知道输入0~2这样的数字,而是会输入从一开始的1~3,所以我们需要将玩家所输入的地址减一。

2.判断玩家下棋的位置是否已有落子,如果不是空白,就重新输入。

3.将玩家下的棋放入对应位置,表现出来。

void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x, y;
	printf("玩家下棋:\n");
	do
	{
		scanf_s("%d%d", &x, &y);
		if (x < 1 || x > row || y < 1 || y > col)//超出范围
		{
			printf("范围超出,请重新输入\n");
			scanf("%d%d", &x, &y);
		}
		if (x >= 1 && x <= row && y >= 1 && y <= col) {
			if (board[x - 1][y - 1] == ' ')//一定要将玩家所输入-1
			{
				board[x - 1][y - 1] = '*';
				break;
			}
			else
			{
				printf("位置已有棋子,请重新输入\n");
			}
		}
	} while (1);
}

使用do while循环,当所输入数字不在范围内,则重新输入。

当目标位置等于‘  ’,也就是没有落子时,再往里下棋,之后再用break跳出。

对于玩家下的棋,我们用‘*’表示

9ff0626c1004468785da17f83476e96f.png

 4.电脑下棋 

要让电脑自动下棋,我们需要引入随机数,随机数的创建依靠下面的代码。 

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

我们通过它调用时间戳产生随机数

2.x = rand() % row;

   y = rand() % col;

通过%row来获取1~3的数字,划定随机数的范围

 下棋之前,照例要进行有无落子的判断。

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

如果成功下棋,就用break跳出,否则再次产生随机数。

对于电脑下的棋,我们用符号‘#’来表示。

 818fcd3d20bd4de0a840d02e1e2a63e3.png

5.游戏胜负的判断 

棋局千变万化,每一步都有可能产生输赢,我们要不断地进行判断。

而判断的时机,就选择在玩家下棋和电脑下棋之后。

我们创建IsWin函数来判断输赢。

  1. 我们返回不同的符号来表示不同的状态
  2. 玩家赢时     -->  返回'*'
  3. 电脑赢时    -->  返回'#'
  4. 平局时         -->  返回'C'
  5. 游戏继续  -->  返回'Q'
void game()
{
	int ret;
	char board[ROW][COL] = { 0 };
	InitBoard(board, ROW, COL);
	DisplayBoard(board, ROW, COL);
	while (1)
	{
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'Q')
		{
			break;
		}
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'Q')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家获胜\n");
	}
	if (ret == '#')
	{
		printf("电脑获胜\n");

	}
	if (ret == 'C')
	{
		printf("平局\n");
	}
}

 以上的代码中包含着IsWIn函数,我们需要用它进行胜负判断,它的功能如下。

1.不仅判断行和列,还要判断两条对角线

2.判断棋盘是否被装满,是否分出胜负

int IsWin(char board[ROW][COL], int row,int col)
{
	int i, j;
	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[1][i] != ' ')
		{
			return board[0][i];
		}
	}
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
	{
		return board[1][1];
}
	if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	if (IsFull(board, row, col) == 1)
	{
		return 'C';
	}
	return 'Q';
}

 这一块的代码比较冗杂。我们还需调用IsFull函数来判断棋盘是否已经被装满。

如果棋盘被装满且未分胜负,那就返回‘C’,代码如下。

int IsFull(char board[ROW][COL], int row, int col)
{
	int i, j;
	for (i = 0;i < ROW;i++)
	{
		for (j = 0;j < COL;j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;//只要有一个空格没有被填满,就返回0
			}
		}
	}
	return 1;
}

所以游戏的test.c文件应该这么写 

#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void game()
{
	int ret;
	char board[ROW][COL] = { 0 };
	InitBoard(board, ROW, COL);
	DisplayBoard(board, ROW, COL);
	while (1)
	{
		PlayerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'Q')
		{
			break;
		}
		ComputerMove(board, ROW, COL);
		DisplayBoard(board, ROW, COL);
		ret = IsWin(board, ROW, COL);
		if (ret != 'Q')
		{
			break;
		}
	}
	if (ret == '*')
	{
		printf("玩家获胜\n");
	}
	if (ret == '#')
	{
		printf("电脑获胜\n");

	}
	if (ret == 'C')
	{
		printf("平局\n");
	}
}


int main()
{
	srand((unsigned int)time(NULL));
	int input;
	do
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("三子棋\n");
			game();
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择\n");
			break;
		}
	} while (input);
	return 0;
}

不要忘记包含“game.h”,那里包含着所需的头文件和函数声明。

下面是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] = ' ';
		}
	}
}
void DisplayBoard(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 < ROW - 1)
			{
				printf("|");
			}
		}
		printf("\n");
		if (i < ROW - 1) {
			for (j = 0;j < ROW;j++)
			{
				printf("---");
				if (j < col - 1)
				{
					printf("|");
				}
			}
		}
		printf("\n");
	}
}
void menu()
{
	printf("**********************************\n");
	printf("*********     1 play     *********\n");
	printf("*********     2 exit     *********\n");
	printf("**********************************\n");
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
	printf("电脑下棋\n");
	int x, y;
	
	while (1)
	{x = rand() % ROW;
	y = rand() % COL;
		if (board[x][y] == ' ')
		{
			board[x][y] = '#';
			break;
		}
	}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
	int x, y;
	printf("玩家下棋:\n");
	do
	{
		scanf_s("%d%d", &x, &y);
		if (x < 1 || x > row || y < 1 || y > col)
		{
			printf("范围超出,请重新输入\n");
			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");
			}
		}
	} while (1);
}
int IsFull(char board[ROW][COL], int row, int col)
{
	int i, j;
	for (i = 0;i < ROW;i++)
	{
		for (j = 0;j < COL;j++)
		{
			if (board[i][j] == ' ')
			{
				return 0;
			}
		}
	}
	return 1;
}
int IsWin(char board[ROW][COL], int row,int col)
{
	int i, j;
	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[1][i] != ' ')
		{
			return board[0][i];
		}
	}
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
	{
		return board[1][1];
}
	if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
	{
		return board[1][1];
	}
	if (IsFull(board, row, col) == 1)
	{
		return 'C';
	}
	return 'Q';
}

最后是game.h文件

#pragma once
#define COL 3
#define ROW 3
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
void menu();
void DisplayBoard(char board[ROW][COL],int row,int col);
void InitBoard(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);
int IsFull(char board[ROW][COL], int row, int col);
int IsWin(char board[ROW][COL], int row, int col);

 下面让我们快乐的来上一把三子棋!

f353f49bb9d34769b58be79a04909576.png

5ac25950203948b69fd854542b7f1ae4.png

轻松赢下比赛! 


本篇文章旨在分享三子棋的写法。🤠希望我的文章能够让大家有所收获!😋😋😋大佬们如果对我的文章有什么建议,或者认为那里写的不好,请在评论区写下您宝贵的意见!😀如果觉得我写的不错的话还请点个赞和关注哦~我会持续输出编程的知识的!🌞🌞🌞 

 

评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

陈大大陈

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

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

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

打赏作者

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

抵扣说明:

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

余额充值