适合刚入门0基础三子棋游戏的代码实现和设计思路

目录

1.什么是三子棋游戏

2.三子棋游戏代码实现的设计思路

(1).基本思路(创建几个文件及其设计意义)

(2)游戏基本框架

3.三子棋代码实现

(1)游戏的外部封装

(2)先要打印棋盘

(3)初始化数组(应该是第一步,先初始化数组在打印数组,放在第二步是为了解释为什们要初始化数组)

(4)玩家下棋

(5)电脑下棋

(6).判断游戏输赢

(7)组装函数

test.c的内容(就是游戏逻辑)

game.h的内容(函数的定义和头文件的声明,能在其他两个文件中使用)

game.c的内容(封装函数的声明和内容)

4.最后总结


1.什么是三子棋游戏

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

2.三子棋游戏代码实现的设计思路

(1).基本思路(创建几个文件及其设计意义)

test.c文件      测试三子棋游戏

game.h文件    测试游戏函数的函数声明

game.c文件     游戏函数的实现

test.c:放主函数及其代码的基本框架,以及三子棋的基本逻辑。

game.h: 放三子棋游戏函数的函数声明,以及一些头文件声明,方便在test.c和game.c中使用。

game.c:实现游戏函数的内容。

(2)游戏基本框架

游戏思路有了接下来就要设计游戏框架,进而一步一步的实现游戏,一步步封装游戏。下棋可定要有棋盘,然后我们下棋,电脑下棋,在判断输赢。这就是三子棋游戏的基本框架

  1. 先要打印棋盘
  2. 在初始化棋盘(下面会将为什们要初始化棋盘)
  3. 玩家下棋
  4. 电脑下棋
  5. 判断输赢

3.三子棋代码实现

(1)游戏的外部封装

对于三子棋游戏不可能玩一把就不玩了,所以应写循环,玩完一把在玩下一把,不想玩就退出,对于这个游戏至少应该进行一次,所以用do-while()循环。为了让玩家看的明白怎么我玩应该封装一个菜单函数,1---进入游戏,0---退出游戏。为什们这么设置也是有用意的,在循环中0---表示假,就可以直接退出游戏,而1--表示真就可以进入游戏,我们需要选择,可以用switch语句进行选择。下面就是代码实现。可以在游戏函数简单写一个输出函数printf简单模拟游戏函数,然后在简单运行一下,看现在已写代码的正确性。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
void menu()
{
	printf("***************************\n");
	printf("******1---进入游戏*********\n");
	printf("******0---退出游戏*********\n");
	printf("***************************\n");
}
void game()
{
	printf("游戏开始\n");
}
int main()
{
	int input = 0;
	do
	{
		menu();
		printf("请输入n->");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

(2)先要打印棋盘

在游戏函数中应该先打印棋盘,而棋盘应用数组来存放要打印这种棋盘。先写打印棋盘函数,在game.h文件写定义,然后在game.c和test.c文件引用#include "game.h"使用game.h中定义的东西,打印棋盘其实就找到规律就很好打印了,两个循环一个打印行一个打印列,___三个下划线中间的下划线要用数组的第一个内容填,打印“ %c ”和“|”这个只有当j!=COL时不打印“|”,其他的都依次类推,就非常简单了。打印棋盘代码如下

void print_board(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++)
		{
			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");
	}
}

 

这是上述代码打印的棋盘,单数打印的好像有问题,数据行好像并没有打印,是因为初始化数据为0,在ASCⅡ表中0,表示null空字符,所以没打印;所以应该让棋盘初始化为空格,让其也打印出来。所以第一步是将数组初始化为空格。

(3)初始化数组(应该是第一步,先初始化数组在打印数组,放在第二步是为了解释为什们要初始化数组)

初始化为空格就会留一个空,打印棋盘就会好看

//初始化函数 将数组初始化为空格
void init_board(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] = ' ';
		}
	}
}

(4)玩家下棋

 打印玩棋盘就开始玩游戏,玩家下棋,玩家输入'*',电脑下棋,电脑输入'#'。所以先写玩家下棋函数,

玩家下棋应该下的合法,没有被电脑下棋占用,而且也不能超过棋盘的大小,

如果坐标不合法,就重新输入,这时就需要用到循环while(1),一直进行循环,知道合法就break跳出循环。

唯一需要注意的点就是玩家不是程序员,他们下棋就是看棋盘的坐标,并不是根据数组的坐标从0开始,(非常重要)

//玩家下棋
void player_board(char board[ROW][COL], int row, int col)
{
	int i = 0;//横坐标
	int j = 0;//纵坐标
	while (1)
	{
		printf("请输入坐标->");
		scanf("%d%d", &i, &j);
		//玩家输入坐标是否合法
		if (i >= 1 && i <= row && j >= 1 && j <= col )
		{
			if (board[i - 1][j - 1] == ' ')//是否被占用
			{
				board[i - 1][j - 1] = '*';//玩家输入*
				break;
			}
			else
			{
				printf("坐标已被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标不合法,请重新输入\n");
		}
	}
}

(5)电脑下棋

电脑下棋就可以类比玩家下棋了,也需要一个循环,让坐标合法。只不过电脑下棋是随机的,需要写一个随机函数,rand()函数,需要用到srand函数和time函数,具体内容去查rand函数的使用

//电脑下棋随机下棋()
void computer_board(char board[ROW][COL], int row, int col)
{
	int x = rand() % row;//随机x的坐标,而且对3取余,正好是0,1,2符合数组的大小
	int y = rand() % col;//随机y的坐标,而且对3取余,正好是0,1,2符合数组的大小
	while (1)
	{
		if (board[x][y] == ' ')//判断坐标是否合法
		{
			board[x][y] = '#';//电脑输入#
			break;
		}
	}
}

(6).判断游戏输赢

  1. 玩家赢       返回*
  2. 电脑赢       返回#
  3. 平局          返回Q
  4. 游戏继续    返回C

对于三子棋游戏,游戏有4种方式,对于这个游戏,玩家赢,返回 *,电脑赢返回#,对于为什们返回这个,肯定是因为简单呀(具体情况请看代码为什们简单),在电脑下完或者玩家下完,就判断输赢,看返回值在进行下一步,所以在test.c文件中的game函数中应该这样设计游戏思路,代码如下:需要在定义一个is_win()函数,来通过返回值来判断输赢。is_win()函数在下面代码的下面。

void game()
{
	char ret = 0;
	char board[ROW][COL] = { 0 };
	//初始化数组
	init_board(board, ROW, COL);
	//打印棋盘函数
	print_board(board,ROW,COL);
	while (1)//进行循环玩家下棋,电脑下棋知道棋盘下满在通过break跳出循环。
	{
		//玩家下棋
		player_board(board, ROW, COL);
		//每当玩家下完应该判断游戏输赢,如果等于C就继续游戏,不等于C,就跳出循环,输出游戏结果。
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
			break;
		print_board(board, ROW, COL);//玩家下完需要看棋盘下在哪里了,因此需要打印棋盘。
		
		//电脑下棋
		computer_board(board, ROW, COL);
		//每当电脑下完应该判断游戏输赢,如果等于C就继续游戏,不等于C,就跳出循环,输出游戏结果。
		int ret = is_win(board, ROW, COL);
		if (ret != 'C')
			break;
		print_board(board, ROW, COL);//电脑下完也需要看其下在哪里了
	}
	if (ret == '*')//为什们打印这个就是玩家赢,请看后面判断输赢代码
	{
		printf("玩家胜利\n");
	}
	else if (ret == '#')//为什们打印这个就是电脑赢,请看后面判断输赢代码
	{
		printf("电脑胜利\n");
	}
	else if (ret == 'Q')
	{
		printf("双方平局\n");
	}
	print_board(board, ROW, COL);//打印最后结果的的棋盘。结束游戏

}

is_win()函数的封装,及为什么要返回#和*都在注释中,为什们封装is_full()函数也在注释中

//判断棋盘满了没
//满了返回1,没满返回0
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] == ' ')//有空格返回0,说明没有满
				return 0;
		}
	}
	//没有空格,说明满了,就直接返回1.
	return 1;
}
char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	//判断玩家和电脑赢把所有方式列出来
	//判断一行的内容是否相等且不等于空格
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
			//可以直接返回内容,又方便又易懂,
			//所以在is_win()函数中通过返回*和#来看玩家赢和电脑赢,不用写两遍,分别判断玩家和电脑
			return board[i][0];
	}
	//判断一列的内容是否相等且不等于空格
	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')
			// 可以直接返回内容,又方便又易懂,
			//所以在is_win()函数中通过返回*和#来看玩家赢和电脑赢,不用写两遍,分别判断玩家和电脑
			return board[0][j];
	}
	//判断两条斜线是否相等
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
		return board[0][0];
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
		return board[0][2];


	//判断玩家和电脑赢,在判断是否平局,还有是否继续
	//判断平局和继续要判断棋盘是否满了,所以在封装一个函数是否满了
	if (is_full(board, ROW, COL) == 1)
		return 'Q';
	else
		return 'C';
}

(7)组装函数

现在函数就都封装完了,框架也有了,最后组装在一块就好了。

唯一注意的一点就是一些头文件放在game.h中,像#include<stdio.h>很多,然后在去test.c和game.c中引用就好了不需要重复定义

test.c的内容(就是游戏逻辑)

#define _CRT_SECURE_NO_WARNINGS 1
//使用game.h中的函数定义和头文件的使用
#include "game.h"

//菜单函数给用户看的然后在做出选择
void menu()
{
	printf("***************************\n");
	printf("******1---进入游戏*********\n");
	printf("******0---退出游戏*********\n");
	printf("***************************\n");
}
void game()
{
	char ret = 0;
	char board[ROW][COL] = { 0 };
	//初始化数组
	init_board(board, ROW, COL);
	//打印棋盘函数
	print_board(board,ROW,COL);
	while (1)//进行循环玩家下棋,电脑下棋知道棋盘下满在通过break跳出循环。
	{
		//玩家下棋
		player_board(board, ROW, COL);
		//每当玩家下完应该判断游戏输赢,如果等于C就继续游戏,不等于C,就跳出循环,输出游戏结果。
		ret = is_win(board, ROW, COL);
		if (ret != 'C')
			break;
		print_board(board, ROW, COL);//玩家下完需要看棋盘下在哪里了,因此需要打印棋盘。
		
		//电脑下棋
		computer_board(board, ROW, COL);
		//每当电脑下完应该判断游戏输赢,如果等于C就继续游戏,不等于C,就跳出循环,输出游戏结果。
		int ret = is_win(board, ROW, COL);
		if (ret != 'C')
			break;
		print_board(board, ROW, COL);//电脑下完也需要看其下在哪里了
	}
	if (ret == '*')//为什们打印这个就是玩家赢,请看后面判断输赢代码
	{
		printf("玩家胜利\n");
	}
	else if (ret == '#')//为什们打印这个就是电脑赢,请看后面判断输赢代码
	{
		printf("电脑胜利\n");
	}
	else if (ret == 'Q')
	{
		printf("双方平局\n");
	}
	print_board(board, ROW, COL);//打印最后结果的的棋盘。结束游戏

}
int main()
{
	srand((unsigned int)time(NULL));
	int input = 0;
	do
	{
		menu();
		printf("请输入n->");
		scanf("%d", &input);
		switch(input)
		{
		case 1:
			game();
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
			break;
		}
	} while (input);
	return 0;
}

game.h的内容(函数的定义和头文件的声明,能在其他两个文件中使用)

#pragma once
#define ROW 3
#define COL 3
#include<stdio.h>
#include<time.h>
#include <stdlib.h> 
//初始化棋盘
void init_board(char board[ROW][COL], int row, int col);

//打印棋盘
void display_board(char board[ROW][COL], int row, int col);
//玩家下棋
void player_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断输赢
char is_win(char board[ROW][COL], int row, int col);

game.c的内容(封装函数的声明和内容)

//引用game.h中的函数定义和头文件的使用
#include"game.h"
//初始化数组
void init_board(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 print_board(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++)//打印第一行数据
		{
			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 player_board(char board[ROW][COL], int row, int col)
{
	int i = 0;//横坐标
	int j = 0;//纵坐标
	while (1)
	{
		printf("请输入坐标->");
		scanf("%d%d", &i, &j);
		//玩家输入坐标是否合法
		if (i >= 1 && i <= row && j >= 1 && j <= col )
		{
			if (board[i - 1][j - 1] == ' ')
			{
				board[i - 1][j - 1] = '*';
				break;
			}
			else
			{
				printf("坐标已被占用,请重新输入\n");
			}
		}
		else
		{
			printf("坐标不合法,请重新输入\n");
		}
	}
}
//电脑下棋
void computer_board(char board[ROW][COL], int row, int col)
{
	int x = rand() % row;//随机x的坐标,而且对3取余,正好是0,1,2符合数组的大小
	int y = rand() % col;//随机y的坐标,而且对3取余,正好是0,1,2符合数组的大小
	while (1)
	{
		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] == ' ')//有空格返回0,说明没有满
				return 0;
		}
	}
	//没有空格,说明满了,就直接返回1.
	return 1;
}
//判断游戏情况输赢
char is_win(char board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	//判断玩家和电脑赢把所有方式列出来
	//判断一行的内容是否相等且不等于空格
	for (i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
			//可以直接返回内容,又方便又易懂,
			//所以在is_win()函数中通过返回*和#来看玩家赢和电脑赢,不用写两遍,分别判断玩家和电脑
			return board[i][0];
	}
	//判断一列的内容是否相等且不等于空格
	for (j = 0; j < col; j++)
	{
		if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')
			// 可以直接返回内容,又方便又易懂,
			//所以在is_win()函数中通过返回*和#来看玩家赢和电脑赢,不用写两遍,分别判断玩家和电脑
			return board[0][j];
	}
	//判断两条斜线是否相等
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
		return board[0][0];
	if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
		return board[0][2];


	//判断玩家和电脑赢,在判断是否平局,还有是否继续
	//判断平局和继续要判断棋盘是否满了,所以在封装一个函数是否满了
	if (is_full(board, ROW, COL) == 1)
		return 'Q';
	else
		return 'C';
}

4.最后总结

其实这个内容不难,就是这个逻辑,只要多看几遍,多练习几遍,逻辑想明白就会很简单。以上就是三子棋游戏的全部代码,源码,只要通过自己的努力自己写出来,肯定成就感满满,而且再让别人玩你的三子棋游戏,你的感觉肯定会不一样的。让我们一起加油!!!!

  • 18
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

桐桐超努力

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

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

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

打赏作者

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

抵扣说明:

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

余额充值