c语言——小游戏代码实现(三子棋)

目录

一. 游戏规则

二. 知识储备

三. 代码实现

3.1 多文件理解形式

3.2 代码实现

3.2.1 test.c

3.2.2 game.c

3.2.3 game.h       


一. 游戏规则

      相信大家都有玩过五子棋,三子棋游戏则是五子棋的缩小版,游戏规则为,所下棋子首先连成三个一条线的一方获胜,如果棋盘下满双方都没有获胜,则视为平局。玩完一局后,玩家可以根据自己的意愿选择继续游戏或者退出游戏。游戏代码用多文件形式完成。

二. 知识储备

       此游戏的实现,对while,do while循环语句,if else多分支语句,switch选择语句,以及函数的调用,数组等知识进行了综合应用。对于初学者来说很有综合性,能够很好的检验自己的c语言前期学习效果。此外代码中rand函数以及srand函数的解释见笔者上一篇博客,猜数字游戏。

三. 代码实现

3.1 多文件理解形式

       在实际工作中,往往一个大型项目的开发需要很多人的团队一起来完成,如果在一个文件里面写代码这并不现实。因此对于大型项目的开发,都是将其分割成不同功能不同模块,分开完成再组合起来应用。这种将代码封装成不同功能的模块的形式,也能够使得代码维护变得相对容易。本游戏的代码实现,对多文件完成代码进行了简单应用,希望对初学者有所帮助。

3.2 代码实现

3.2.1 test.c

此文件中包含主函数,游戏主体,及游戏菜单函数的代码。

#define _CRT_SECURE_NO_WARNINGS

#include "game.h"

//三子棋游戏,玩完一把不退出,应用多文件形式写代码

//菜单
void menu()
{
	printf("****************************\n");
	printf("********** 1.paly **********\n");
	printf("********** 0.exit **********\n");
	printf("****************************\n");
}

//游戏主体
void game()
{
	char Board[ROW][COL] = {0};
	char ret = 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 != 'C')
			break;
		ComputerMove(Board, ROW, COL);
		DisplayBoard(Board, ROW, COL);
		ret = isWin(Board, ROW, COL);
		if (ret != 'C')
			break;
	}
	if (ret == '*')
	{
		printf("玩家胜利!\n");
	}
	else if (ret == '#')
	{
		printf("电脑胜利!\n");
	}
	else
		printf("平局!\n");
}

int main()
{
	int input = 0;
	srand((unsigned)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;
}

       各种头文件的引用,及函数的声明都放在game.h这个头文件里,因此在test.c中要包含             #include  "game.h",注意是用的双引号并不是尖括号。进入主函数,首先打印菜单,根据菜单的提示进行选择,开始游戏或者退出游戏,由switch选择语句完成,用do while循环语句实现游戏的循环。

       选择1开始游戏后,则进入game函数,定义一个char类型的二维数组,用其表示棋盘,并用函数对其初始化,将数组元素都初始化为空格。接着通过DispalyBoard函数对棋盘进行优化,使其呈现出边框。 然后进入while循环,通过PlayerMove函数ComputerMove函数分别实现双方的落子,每方落子之后都再次通过DispalyBoard函数打印棋盘。并且每一方落子之后都要通过isWin函数判断输赢,并将返回值传给ret。

                                 

 游戏菜单                                                        棋盘

3.2.2 game.c

#define _CRT_SECURE_NO_WARNINGS

#include "game.h"

void InitBoard(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 DisplayBoard(char Board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	for (i = 0;i < row;i++)
	{
		//打印数据
		for (j = 0;j < row;j++)
		{
			printf(" %c ", Board[i][j]);
			if ((j < col - 1))
				printf("|");//保持棋盘竖分割线的连续性
		}
		printf("\n");

		//打印棋盘分割线
		for (j = 0;j < row;j++)
		{
			if (i < row - 1)
				printf("---");
			if ((i < row - 1) && (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] == ' ')
			{
				printf("可以落子\n");
				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 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] == ' ')
				return 0;
		}
	}

	return 1;
}

char isWin(char Board[ROW][COL], int row, int col)
{
	int i = 0;
	int j = 0;
	int count1 = 0;
	int count2 = 0;
	//行
	for (i = 0;i < row;i++)
	{
		count1 = 0;
		count2 = 0;
		for (j = 0;j < col;j++)
		{
			if (Board[i][j] == '*')
				count1++;
			if (Board[i][j] == '#')
				count2++;
		}
		if (count1 == col)
		{
			return '*';
		}
		if (count2 == col)
		{
			return '#';
		}
	}
	//列
	for (j = 0;j < col;j++)
	{
		count1 = 0;
		count2 = 0;
		for (i = 0;i < row;i++)
		{
			if (Board[i][j] == '*')
				count1++;
			if (Board[i][j] == '#')
				count2++;
		}
		if (count1 == row)
		{
			return '*';
		}
		if (count2 == row)
		{
			return '#';
		}
	}
	//主对角线
	count1 = 0;
	count2 = 0;
	for (i = 0;i < row;i++)
	{
		for (j = 0;j < col;j++)
		{
			if (i == j)
			{
				if (Board[i][j] == '*')
					count1++;
				if (Board[i][j] == '#')
					count2++;
			}
			if (count1 == row)
			{
				return '*';
			}
			if (count2 == row)
			{
				return '#';
			}
		}
	}
	//副对角线
	count1 = 0;
	count2 = 0;
	for (i = 0;i < row;i++)
	{
		for (j = 0;j < col;j++)
		{
			if (i + j == row - 1)
			{
				if (Board[i][j] == '*')
					count1++;
				if (Board[i][j] == '#')
					count2++;
			}
			if (count1 == row)
			{
				return '*';
			}
			if (count2 == row)
			{
				return '#';
			}
		}
	}
	if (isFull(Board, row, col) == 1)
		return 'Q';

	return 'C';
}

       此文件中包含棋盘初始化函数,棋盘打印函数,玩家落子函数,电脑落子函数,判断输赢及棋盘是否已满函数。InitBoard函数通过两层for循环实现对二维数组表示的棋盘的全部元素初始化为空格;DisplayBoard函数,外层for循环控制行数的递增,里面还嵌套两个for循环,第一个for循环实现对数据的打印,按照空格、数据、空格加‘ | ’ 的方式打印,‘ | ’是棋盘的竖分割线,为了保证棋盘的美观性,每一行的最后一列不打印‘ | ’。第二个for循环实现对棋盘剩余分割线的打印,逐行打印,打印完一行后换行;PlayerMove函数实现玩家落子,玩家的落子方式按正常从1开始算每行每列,因此写代码时要注意对玩家输入的坐标进行减1的操作,来对应数组下标;ComputerMove函数实现电脑落子,借助rand函数实现电脑随机下棋;isFull函数判断棋盘是否已满,如果其中有一个元素是空格则返回0,否则返回1;isWin函数判断输赢,分别判断行、列、主对角线、副对角线元素,用count自增计数的方式累计一行中相等元素的个数来判断输赢。

3.2.3 game.h
       

#pragma once

#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);

  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值