C语言 VS2019编译器实现简易井字棋小游戏~_yzxss的博客-程序员秘密_vs2019制作游戏

技术标签: c语言  

本文章将详细说明如何用C语言实现简易的井字棋小游戏,编译器用的是VS2019。

井字棋小游戏

最终效果如图:

在这里插入图片描述

游戏实现

一、创建新项目及游戏文件

1.打开VS创建新的空项目。
2.在解决方案资源管理器选中 源文件 > 右键点击添加 > 新建项 > 选中C++文件并分别创建 game.ctext.c
3.用同样的方法在解决方案资源管理器 创建头文件 game.h
在这里插入图片描述

二、引头文件,定义符号

在game.h引入头文件并定义井字棋的行数和列数。
井字棋是3*3的棋盘,因此定义行数3,列数3。
game.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#define ROW 3 //棋盘行数
#define COL 3 //棋盘列数
#include <stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>

然后在game.c 和 text.c 引入头文件 “game.h”
game.c

#include"game.h"

text.c

#include"game.h"

三、主函数

主函数用do while语句和switch语句构成,定义整形 input 来接收玩家输入的数字,输入0则退出游戏,输入1则开始游戏。输入其他数字时则显示输入错误。
text.c

int main()
{
    
	srand((unsigned int)time(NULL));//设置随机数起点
	int input = 0;//接收玩家输入的数字
	do 
	{
    
		printmenu();//打印菜单
		scanf("%d", &input);
		switch (input)
		{
    
		case 0:
			printf("退出成功!\n");
			break;
		case 1:
			system("cls");//清屏
			printf("开始游戏!\n\n\n");
			playgame();//开始游戏
			break;
		default:
			printf("输入错误,请重试!\n");
			break;
		}
	} while (input);//当input为0,相当于假 退出循环
	return 0;
}

打印菜单

在主函数种do while语句中先打印菜单让玩家知道输入什么开始游戏,输入什么退出游戏。定义函数printmenu() 来打印菜单。在game.c实现函数并在game.h声明。
game.c

void printmenu()
{
    
	printf("■■■■■■■■■■■■■■■\n");
	printf("■■■    1.开始游戏    ■■■\n");
	printf("■■■    0.退出游戏    ■■■\n");
	printf("■■■■■■■■■■■■■■■\n");
	printf("请输入数字‘0’或数字‘1’>>>\n");
}

需要在game.h声明这个函数的存在,不然在text.c用不了。
game.h

void printmenu();

四、开始游戏

当玩家输入数字1,则开始游戏,因此需要在text.c定义一个 playgame() 函数来实现井字棋游戏。playgame()的完整函数将在最后面展示。

void playgame()
{
    
	
}

1.创建二维数组

在playgame函数内定义一个二维数组,用于存储井字棋的棋子信息。如电脑为 字符‘X’ 玩家为 字符‘O’。
text.c > playgame()函数内

char table[ROW][COL]={
    0};//创建一个3行3列的二维数组

2.初始化棋盘

定义一个函数 inittable() 初始化棋盘,将来玩完一盘井字棋后需要清空存储的棋子信息,初始化是十分必要的。然后在playgame函数内传table这个二维数组作为参数。

函数实现:
game.c

void inittable(char table[ROW][COL]) //初始化棋盘
{
    
	for (int i = 0; i < ROW; i++)
	{
    
		for (int j = 0; j < COL; j++)
		{
    
			table[i][j] = ' '; //将信息置为空
		}
	}
}

函数声明:
game.h

void printmenu();//打印菜单 

3.打印棋盘

棋盘的展示也是必不可少的,因此定义一个函数printtable() 用于打印棋盘。利用 ‘ - ’ 以及 ‘ | ’ 打印一个简易的棋盘。
在这里插入图片描述
井字棋可看成
第一行: 空格 棋子 空格 | 空格 棋子 空格 | 空格 棋子 空格

第二行: 横杠 横杠 横杠 | 横杠 横杠 横杠 | 横杠 横杠 横杠

第三行: 空格 棋子 空格 | 空格 棋子 空格 | 空格 棋子 空格

第四行: 横杠 横杠 横杠 | 横杠 横杠 横杠 | 横杠 横杠 横杠

第五行: 空格 棋子 空格 | 空格 棋子 空格 | 空格 棋子 空格

棋子则对应棋盘table内存储的棋子信息。
函数实现:
game.c

//打印棋盘
void printtable(char table[ROW][COL])
{
    
	
	for (int i = 0; i < ROW; i++)
	{
    
		//打印空格 棋子 空格 | 空格 棋子 空格 | 空格 棋子 空格
		for (int j = 0; j < COL; j++)
		{
    
			printf(" %c ", table[i][j]);
			if (j < COL - 1)
			{
    
				printf("|");
			}		
		}
		printf("\n");
		
		//打印 横杠 横杠 横杠 | 横杠 横杠 横杠 | 横杠 横杠 横杠
		if (i < ROW - 1)
		{
    
			for (int j = 0; j < COL; j++)
			{
    
				printf("---");
				if (j < COL - 1)
				{
    
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

函数声明:
game.h

void printtable(char table[ROW][COL]);//打印棋盘

4.玩家下棋

当有了棋盘后,玩家就可以开始下棋了。定义函数 player() 接收玩家输入的想下棋的位置 即第几行,第几列。如果这个位置在棋盘table中对应的下标元素为空,这将这个元素置为字符‘O’。如玩家输入第二行第二列,对应table二维数组下标为[1] [1]。

函数实现:
game.c

//玩家下棋
void player(char table[ROW][COL])
{
    
	printf("玩家(O)走>>>> (输入: 行 空格 列 ) \n");
	int row = 0;
	int col = 0;
	int k = 0;
	while (1)
	{
    
		scanf("%d %d", &row,&col);
		if (row > 0 && row <= ROW && col>0 && col<=COL && table[row - 1][col - 1] == ' ')
		{
    
			table[row-1][col-1] = 'O';
			break;
		}
		else
		{
    
			printf("输入错误,请重试\n");
			continue;
		}
	}
}

函数声明:
game.h

void computer(char table[ROW][COL]);//电脑下棋

5.电脑下棋

玩家下完棋后,就到电脑下棋了。这里运用随机数代替电脑下棋算法。
首先在主函数设置随机数起点。

int main()
{
    
	srand((unsigned int)time(NULL));
	return 0;
}

定义computer() 函数,然后使用rand()函数 随机生成第row行,第col列,如果这个位置在棋盘table中对应的下标元素为空,这将这个元素置为字符‘X’。

函数实现:
game.c

//电脑下棋
void computer(char table[ROW][COL])
{
    
	printf("电脑(X)走>>>>\n");
	while (1)
	{
    
		int col = rand() % COL;
		int row = rand() % ROW;
		if (table[row][col] != ' ')
		{
    
			continue;
		}
		else
		{
    
			table[row][col] = 'X';
			break;
		}
	}
	Sleep(500);
}

函数声明:
game.h

void computer(char table[ROW][COL]);//电脑下棋

6.判断游戏是否结束

当双方有一方下棋时,应该实时检查游戏是否结束,如电脑胜利,玩家胜利还是平局,不然游戏将无止境。因此定义函数check() 检测是否游戏结束,定义iswin() 检测是胜利还是失败还是平局还是继续游戏。

check() 函数如何判断一方的胜利呢?其实只需要分别检测井字棋的三行三列以及两个斜线八条连线 对应的三个元素是否相同,如果相同,返回对应元素的字符,如返回‘O’ 则知道是玩家赢了。如果八条连线对应的元素没有三个都相同,且已经没有空位了,返回字符‘P’表示平局。如果还有空格则返回字符‘C’表示游戏继续。
接着通过iswin() 函数打印游戏结束后是谁赢的信息,并退出游戏循环。游戏结束返回1,没有结束返回0。
函数实现
game.c

//检测是否游戏结束
char check(char table[ROW][COL])
{
    
	int i = 0;
	int j = 0;

	for (j = 0; j < COL; j++)
	{
    
		if (table[j][0] == table[j][1] && table[j][1] == table[j][2] && table[j][0] != 0)//判断竖
		{
    
			return table[j][0];
		}
	}

	for (i = 0; i < ROW; i++)
	{
    
		if (table[0][i] == table[1][i] && table[1][i] == table[2][i] && table[0][i] != 0)//判断横
		{
    
			return table[0][i];
		}
	}

	if (table[0][0] == table[1][1] && table[2][2] == table[1][1] && table[1][1] != 0)//判断斜行
	{
    
		return table[0][0];
	}

	if (table[0][2] == table[1][1] && table[1][1] == table[2][0] && table[1][1] != 0)//判断斜行
	{
    
		return table[0][2];
	}

	for (i = 0; i < ROW; i++)   //判断是否继续 不是两方胜利也不是平局 
	{
    
		for (j = 0; j < COL; j++)
		{
    
			if (table[i][j] == ' ')
			{
    
				return 'C';
			}
		}
	}
	return 'P'; //判断平局
}

//检测是胜利还是失败还是平局还是继续游戏。
int iswin(char table[ROW][COL])
{
    
	char ret = check(table);
	if (ret == 'O')
	{
    
		printf("恭喜你赢了!玩家胜利\n");
		return 1;
	}
	else if (ret == 'X')
	{
    
		printf("很遗憾你输了!电脑胜利\n");
		return 1;
	}
	else if (ret == 'P')
	{
    
		printf("平局!!!");
		return 1;
	}
	else
	{
    
		return 0;
	}
}

函数声明
game.h

//检测是否游戏结束
char check(char table[ROW][COL]);

//检测是胜利还是失败还是平局还是继续游戏
int iswin(char table[ROW][COL]);

7.playgame完整函数

有了以上的函数,就可以将它们放入游戏函数内了。

void playgame()
{
    
	char table[ROW][COL] = {
     0 };
	inittable(table);//初始化棋盘
	printtable(table);//打印棋盘

	//进入游戏循环
	while (1)
	{
    			
		player(table);//玩家下棋
		system("cls");//清屏
		printtable(table);//打印棋盘
		if (iswin(table))//检测是否游戏结束
		{
    
			system("pause");
			system("cls");//清屏
			break;
		}

		computer(table);//电脑下棋
		system("cls");//清屏
		printtable(table);//打印棋盘
		if (iswin(table))//检测是否游戏结束
		{
    
			system("pause");
			system("cls");//清屏
			break;
		}
	}
}

以上就是井字棋的游戏实现的所有内容,可以参考下面的完整代码~

完整代码

game.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#define ROW 3 //棋盘行数
#define COL 3 //棋盘列数
#include <stdio.h>
#include<stdlib.h>
#include<time.h>
#include<windows.h>

//打印菜单
void printmenu();

//初始化棋盘
void inittable(char table[ROW][COL]);

//打印棋盘
void printtable(char table[ROW][COL]);

//玩家下棋
void player(char table[ROW][COL]);

//电脑下棋
void computer(char table[ROW][COL]);

//检测是否游戏结束
char check(char table[ROW][COL]);

//检测是胜利还是失败还是平局还是继续游戏
int iswin(char table[ROW][COL]);

game.c

#include"game.h"

//打印菜单
void printmenu()
{
    
	printf("■■■■■■■■■■■■■■■\n");
	printf("■■■    1.开始游戏    ■■■\n");
	printf("■■■    0.退出游戏    ■■■\n");
	printf("■■■■■■■■■■■■■■■\n");
	printf("请输入数字‘0’或数字‘1’>>>\n");
}

//初始化棋盘
void inittable(char table[ROW][COL])
{
    
	for (int i = 0; i < ROW; i++)
	{
    
		for (int j = 0; j < COL; j++)
		{
    
			table[i][j] = ' ';
		}
	}
}

//打印棋盘
void printtable(char table[ROW][COL])
{
    
	for (int i = 0; i < ROW; i++)
	{
    
		for (int j = 0; j < COL; j++)
		{
    
			printf(" %c ", table[i][j]);
			if (j < COL - 1)
			{
    
				printf("|");
			}		
		}
		printf("\n");
		if (i < ROW - 1)
		{
    
			for (int j = 0; j < COL; j++)
			{
    
				printf("---");
				if (j < COL - 1)
				{
    
					printf("|");
				}
			}
		}
		printf("\n");
	}
}

//玩家下棋
void player(char table[ROW][COL])
{
    
	printf("玩家(O)走>>>> (输入: 行 空格 列 ) \n");
	int row = 0;
	int col = 0;
	int k = 0;
	while (1)
	{
    
		scanf("%d %d", &row,&col);
		if (row > 0 && row <= ROW && col>0 && col<=COL && table[row - 1][col - 1] == ' ')
		{
    
			table[row-1][col-1] = 'O';
			break;
		}
		else
		{
    
			printf("输入错误,请重试\n");
			continue;
		}
	}
}

//电脑下棋
void computer(char table[ROW][COL])
{
    
	printf("电脑(X)走>>>>\n");
	while (1)
	{
    
		int col = rand() % COL;
		int row = rand() % ROW;
		if (table[row][col] != ' ')
		{
    
			continue;
		}
		else
		{
    
			table[row][col] = 'X';
			break;
		}
	}
	Sleep(500);
}


char check(char table[ROW][COL])
{
    
	int i = 0;
	int j = 0;

	for (j = 0; j < COL; j++)
	{
    
		if (table[j][0] == table[j][1] && table[j][1] == table[j][2] && table[j][0] != 0)//判断竖
		{
    
			return table[j][0];
		}
	}

	for (i = 0; i < ROW; i++)
	{
    
		if (table[0][i] == table[1][i] && table[1][i] == table[2][i] && table[0][i] != 0)//判断横
		{
    
			return table[0][i];
		}
	}

	if (table[0][0] == table[1][1] && table[2][2] == table[1][1] && table[1][1] != 0)//判断斜行
	{
    
		return table[0][0];
	}

	if (table[0][2] == table[1][1] && table[1][1] == table[2][0] && table[1][1] != 0)//判断斜行
	{
    
		return table[0][2];
	}

	for (i = 0; i < ROW; i++)   //判断是否继续 不是两方胜利也不是平局 
	{
    
		for (j = 0; j < COL; j++)
		{
    
			if (table[i][j] == ' ')
			{
    
				return 'C';
			}
		}
	}
	return 'P'; //判断平局
}

int iswin(char table[ROW][COL])
{
    
	char ret = check(table);
	if (ret == 'O')
	{
    
		printf("恭喜你赢了!玩家胜利\n");
		return 1;
	}
	else if (ret == 'X')
	{
    
		printf("很遗憾你输了!电脑胜利\n");
		return 1;
	}
	else if (ret == 'P')
	{
    
		printf("平局!!!");
		return 1;
	}
	else
	{
    
		return 0;
	}
}

text.c

#include"game.h"

void playgame()
{
    
	char table[ROW][COL] = {
     0 };
	inittable(table);//初始化棋盘
	printtable(table);//打印棋盘

	//进入游戏循环
	while (1)
	{
    			
		player(table);//玩家下棋
		system("cls");//清屏
		printtable(table);//打印棋盘
		if (iswin(table))//检测是否游戏结束
		{
    
			system("pause");
			system("cls");//清屏
			break;
		}

		computer(table);//电脑下棋
		system("cls");//清屏
		printtable(table);//打印棋盘
		if (iswin(table))//检测是否游戏结束
		{
    
			system("pause");
			system("cls");//清屏
			break;
		}
	}
}

int main()
{
    
	srand((unsigned int)time(NULL));
	int input = 0;
	do 
	{
    
		printmenu();//打印菜单
		scanf("%d", &input);
		switch (input)
		{
    
		case 0:
			printf("退出成功!\n");
			break;
		case 1:
			system("cls");
			printf("开始游戏!\n\n\n");
			playgame();
			break;
		default:
			printf("输入错误,请重试!\n");
			break;
		}
	} while (input);
	return 0;
}
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yzxss/article/details/124456827

智能推荐

git/github的使用(入门到中阶)_chuojiaogu5656的博客-程序员秘密

内容最后更新时间:2017-08-10以下内容是我在收集而来,再经过自己的经验修改而成,希望对你有用(在不断的更新中)博客地址欢迎来到Github初识Github版本控制的介绍熟练使用Git/Github是互联网公司程序员的必备技能之一。当开发中遇到困难或者职业技能遇到瓶颈时,Gi...

三维目标识别算法综述_3D视觉工坊的博客-程序员秘密

点击上方“3D视觉工坊”,选择“星标”干货第一时间送达目前三维点云数据的获取方法相对快捷,同时三维点云数据的采集不受光照影响,也规避了二维图像遇到的光照、姿态等问题,因此基于点云数据的三...

激光SLAM与视觉SLAM的现状与趋势_3D视觉工坊的博客-程序员秘密

点击上方“3D视觉工坊”,选择“星标”干货第一时间送达整理:公众号@机器人e资讯本文仅做学术分享,如有侵权,请联系删除。本文作者龙建睿,深圳市大道智创科技有限公司联合创始人&amp;研发...

stream, formatter, serialize(-)_gideon的博客-程序员秘密

移植BT已经进行了两个星期了,还剩下最后一部分代码。深深体会到不同编译器对标准的各行其道给开发人员带来的痛苦。今天的精神状态不是很好,开发思路有点受阻,正好将这段时间的思路做个整理。前几天看到程序员上有一篇文章讲序列化的,觉得讲得不是很深入。加上自己开发了的基础库也已经进入第二个版本了,也想来说上两句,如有疏漏请指正。在写之前先解释一下标题的几个概念stream        凡是

微信小程序存在的风险_浅谈微信小程序会中病毒事件_深蓝保的博客-程序员秘密

小程序其实是云端数据,不在软件里,所以小程序没有进入的端口,所以华为的管家也检测不出来,但是你按照腾讯的方法收索的话,就等于默认开通小程序,把你的数据放到云端,同时你拥有的账号就绑定了一大堆应用程序,,这些程序你永远也别想删除掉,除非不用那个帐号,至于删除数据的权利在腾讯手里。如今的社会是一个充斥着移动数据的大时代。我们不需要走出家,就可以吃到可口的饭菜,不需要出门逛街,就可以买到漂亮的衣服;也许...

SHA1算法实现及详解_Y-peak的博客-程序员秘密_sha1算法

SHA1算法实现及详解SHA1算法详解SHA1算法是Hash算法的一种。SHA1算法的最大输入长度小于2^64比特的消息,输入消息(**明文**)以512比特的分组为单位处理,输出160比特的消息摘要(**密文**)源代码#include &lt;stdio.h&gt;#include &lt;stdlib.h&gt;#include &lt;string.h&gt;#pragma warning(disable:4996)/*定义用到的常量*/unsigned int A = 0x6

随便推点

如何在循环中删除List集合中的元素_请你吃王中王的博客-程序员秘密_集合循环删除元素

一、首先是最基本的for循环for(int i=0;i&lt;list.size();i++){ if(list.get(i).equals("del")) list.remove(i);}remove()方法删除元素后会立刻更新List的size,因此index也发生了变化,会导致漏掉某些元素。解决办法1、在删除某一个元素后直接break,当然这种情况只适合删...

ASP.NET错误登陆3次,锁定账户_吖Q的博客-程序员秘密

这是昨天我自己写的,没有一个函数,全部是一条思路理下来。有点乱,有时间的童鞋可以给点意见,功能都是可以实现的!(以下是基于winform开发的)using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;

和SimpleCursorAdapter有关的小问题_YZQ0817的博客-程序员秘密

今天学习sqlite的时候,用到了simpleCursorAdapter.SimpleCursorAdapter是Android专门为了连接数据库与视图而产生的。他是将从数据库表中获取的数据显示到ListView的桥梁。按照网上教程,我利用ListView体现SimpleCursorAdapter的用法。1 ListView list=(ListView)find...

TCP三次握手的原理及攻击手段_weixin_33953384的博客-程序员秘密

TCP/IP是很多的不同的协议组成,实际上是一个协议组, TCP用户数据报表协议(也称作TCP传输控制协议,Transport Control Protocol。可靠的主机到主机层协议。这里要先强调一下,传输控制协议是OSI网络的第四层的叫法,TCP传输控制协议是TCP/IP传输的6个基本协议的一种。两个TCP意思非相同。 )。TCP是一种可靠的面向连接...

【数据分析】APP活动运营:应关注哪些数据指标(in)_YYIverson的博客-程序员秘密

活动策划是APP运营比较常见的方法,也是快速拉新、活跃用户的方法之一;一个好的活动通过正确的渠道投放,带来的传播效应是非常强大的!而现在讲究的是精细化运营,任何事情都是需要用数据说话;因此每一次活动,在活动前期、活动上线期间、活动结束后复盘都应该关注各种数据指标。活动策划(准备阶段)需要思考哪些数据指标策划一个活动,肯定要明确自己做活动的一个目的是什么?更偏重的是品牌传播、拉新?...

激光SLAM框架总结_YOULANSHENGMENG的博客-程序员秘密_激光slam

一、激光SLAM简介基于激光雷达的同时定位与地图构建技术(simultaneous localization and mapping, SLAM)以其准确测量障碍点的角度与距离、 无须预先布置场景、可融合多传感器、 在光线较差环境工作、 能够生成便于导航的环境地图等优势,成为目前定位方案中不可或缺的新技术。激光 SLAM 任务是搭载激光雷达的主体于运动中估计自身的位姿,同时建立周围的环境地图。而准确的定位需要精确的地图,精确的地图则来自于准确的定位,定位侧重自身位姿估计,建图侧重外部环境重建。S

推荐文章

热门文章

相关标签