多文件实现三子棋

三子棋

多文件实现,分装成三个模块。
声明部分 game.h

#ifndef _GAME_H_
#define _GAME_H_

#include<stdio.h>
#include<windows.h>
#pragma warning(disable:4996)
#include<string.h>

#include<stdlib.h>
#include<time.h>


#define ROW 3
#define COL 3


void game();
void InitBoard(char Board[][COL],int row,int col);
void ShowBoard(char Board[][COL], int row, int col);
void Player(char Board[][COL], int row, int col);
char Judge(char Board[][COL], int row, int col);
void Computer(char Board[][COL], int row, int col);
//player--0
//computer--x
//‘e’平局
// ‘n'--next
#endif

主架构逻辑
main.c

#include"game.h"
void menu()
{
	printf("欢迎游戏参与三子棋游戏!\n");
	printf("1--玩游戏  2--退出游戏\n");
	printf("请输入你的选项:>\n");
}
int main()
{
	int intput = 0;
	srand((unsigned int)time(NULL));
  do{
	menu();
	scanf("%d", &intput);
	switch (intput)
	{
	case 1:
		game();
		break;
	case 2:
		intput = 0;
		printf("成功退出游戏\n");
		break;
	default:
		printf("输入有误,请重新输入\n");
	}
  }while (intput);

	

	system("pause");
	return 0;
}

游戏具体的实现部分
game.c

#include"game.h"
void InitBoard(char Board[][COL], int row, int col)
{
	//memset函数
	//memset(void*dest,int c,size_t count)
	memset(Board, ' ', row*col*(sizeof(Board[0][0])));


	//int i = 0;
	//for (; i < row; i++)
	//{
	//	int j = 0;
	//	for (; j < col; j++)
	//	{
	//		 Board[i][j]=' '  ;
	//	}
	//}
}
void ShowBoard(char Board[][COL], int row, int col)
{
	//列号
	int j = 0;
	{
		for (j=0; j < col+1; j++)
		{
			printf(" %d  ", j);
		}
	}
	printf("\n");
	
	int i = 0;
	for (; i < row; i++)
	{
		printf(" %d |", i + 1);
		int j = 0;
		for (; j < col; j++)
		{

			printf(" %c |",Board[i][j]);
		}
		printf("\n");
		if (i < row )
		{
			for (j = 0; j <= col; j++)
			{
				printf("___|");
			}
			printf("\n");
		}
	}
	
}

void Player(char Board[][COL], int row, int col)
{
	printf("请输入你所选择位置对应的坐标\n");
	int x = 0;
	int y = 0;
	while (1){
		scanf("%d %d", &x, &y);
		//判断坐标合法性
		//1不被占用
		if (x > 0 && x <= row  && y > 0 && y <= col )
		{
			if (Board[x - 1][y - 1] ==' ')
			{
				Board[x - 1][y - 1] = '0';
				break;
			}
			else
			{
				printf("坐标被占用,请重新输入\n");
				continue;
			}
		}
		//2没有出界
		else
		{
			printf("输入坐标不合法,请重新输入!\n");
		}
	}

}
char Judge(char Board[][COL], int row, int col)
{
	//任何一方赢的情况
	int i = 0;
		//判断一行
	for (; i < row; i++)
	{
		if (Board[i][0] != ' ' && Board[i][0] == Board[i][1] && Board[i][1] == Board[i][2]){
			return Board[i][0];
		}
	}
	   //判断一列
	int j = 0;
	for (j = 0; j < col; j++)
	{
		if (Board[0][j] != ' ' && Board[0][j] == Board[1][j] && Board[1][j] == Board[2][j])
		{
			return Board[0][j];
		}
	}
	   //主对角线
	if (Board[0][0] != ' ' && Board[0][0] == Board[1][1] && Board[1][1] == Board[2][2])
	{
		return Board[0][0];
	}
	   //副对角线
	if (Board[0][2] != ' ' && Board[0][2] == Board[1][1] && Board[1][1] == Board[2][0])
	{
		return Board[1][1];
	}

    //还有空位置--继续
	for (i = 0; i < row; i++)
	{
		for (j = 0; j < col; j++)
		{
			if (Board[i][j] == ' ')
			{
				return 'n';
			}
		}
	}
     //平局
		return 'e';
}

void Computer(char Board[][COL], int row, int col)
{
	do
	{
		int x = rand() % row;
		int y = rand() % col;
		//坐标一定是合法的,关键看有没有被占用
		if (Board[x][y] == ' ')
		{
			Board[x][y] = 'x';
			break;
		}
		//被占用的话就重新生成坐标
	} while (1);//注意语法 do while 语句后有;
	printf("电脑已运行完毕!\n");
}

void game()
{
     
	//建立棋盘 赋值为空字符 注意类型
	char Board[ROW][COL];
	//初始化棋盘
	InitBoard(Board, ROW, COL);//meyset 初始化另一种方式
    ShowBoard(Board, ROW, COL);
	printf("请玩家先走!\n");
	//玩游戏阶段
	char result = 'n';
	while (1)
	{
	 
	  Player(Board, ROW, COL);
	  ShowBoard(Board, ROW, COL);

	  Judge(Board, ROW, COL);
	  result = Judge(Board, ROW, COL);
	  if (result != 'n')
	  {
		  break;
	  }
	  
	  printf("轮到电脑下棋了!\n");
	  Sleep(1000);
	  Computer(Board, ROW, COL);
	  ShowBoard(Board, ROW, COL);

	  Judge(Board, ROW, COL);
	  result = Judge(Board, ROW, COL);
	  if (result != 'n')
	  {
		  break;
	  }

    }
	switch (result)
	{
	case'x':
		printf("电脑赢!\n");
		break;
	case'0':
		printf("玩家赢!\n");
		break;
	case'e':
		printf("平局,没有一方赢得本次游戏!\n");
		break;
	default:
		printf("hhh\n");
		break;
	}
	system("pause");
	
}

代码解释

=每一个部分开始会先解释这一个部分的功能(或者说逻辑思维关系)之后会具体解释一些函数、语句的用法。
声明部分
主要为整个工程里面需要引用的头文件、定义的宏以及函数的声明。

1.//player–0
//computer–x
//‘e’平局
// ‘n’–next
不同字符所对应的意思
2.#define ROW 3
#define COL 3
动态实现棋盘的变化,代码可维护性比较高
3.在声明函数的部分,请注意是否需要返回值和传什么参。
(二维数组传参本质也是一个指针,故而传递的本质是传址调用)因此通过函数传递数组名—传地址——就可以给数组赋值。
主要框架逻辑

始终要注意的一点就是,系统要上,流程先行
主要框架要有一个流程图在心里,这要代码逻辑性才会强。(故而这也是此游戏最先搭建的部分)

1.do循环让用户自己选择是否进行下一次游戏,而不是一次游戏就结束。
2.用switch case 语句来实现分支选择的功能。
游戏具体的实现部分

写具体游戏之前,要先明白有这个游戏真正在干什么,有哪些需求
整理游戏需求如下:
实现让玩家一步电脑一步在棋盘里下棋并且判断每一步的运行结果。
此代码以玩家先行为例子:
----玩家通过坐标输入,选择下棋的位置(判断坐标输入)
----判断这一步棋对整个游戏的结果(赢了,输了,还是怎么样?当然下的第一步不存在这个问题)
-----电脑通过事先种好的随机种子生成随机数,生成坐标,下棋
-----判断运行结果

1.InitBoard 初始化棋盘部分

建议使用memset 函数,两个for循环也不是不可以,只是memset 一行就会解决。
循环部分不多介绍,主要来谈一下
Memset 函数

memset(void*dest,int c,size_t count)

voiddest 表示指针 ,从哪开始赋值
int c 把它们赋值成什么以及什么类型
size_t count 赋值的字节大小 ==元素个数
每一个元素的字节 rowcol(sizeof(Board[0][0])))

2.ShowBoard 打印棋盘部分

高能预警!!!

先看一个图(因为我画图板技能为0,甚至为负数,所以谅解手画一个棋盘,方便且快速)
在这里插入图片描述
如下我把每一行这样的棋盘样式分解为下图(现在问题就分解为先打印下图这一部分,然后循环就行了)
在这里插入图片描述

实际上打印上图这样的棋盘
先打印空格 然后放字符 再打空格 再一次打印| 对应语句:printf(" %c |",Board[i][j]); 循环三次
换行打印
换行打印三个_一个 | 对应语句:printf(" ___|"); 循环三次

希望我苍白的语言能让你理解(哈哈哈哈哈)

3.Player 玩家下棋部分
判断坐标输入的合法性,以及是否此坐标被占用。若以上情况看都不满足则才可以对此位置赋值。
4.Judge 判断游戏结果部分
主要是
一赢 : ①一行三子连线
②一列三子连线
③主副对角线三子连线
二.无任何一方赢,并且仍有空位置,游戏继续
三.以上均不满足:平局(即棋盘被下完,没有一方胜利)

5.Computer 电脑下棋部分
主要是需要电脑随机生成坐标,并且此坐标没有被占用
在开始时,用时间作为随机数的种子
srand((unsigned int)time(NULL));
用生成随机数函数 注意:生成的随机数是有要求的,保证不会出界。(即必须保证数字 x的范围在0—row-1 ,y的范围在0—col-1。否则你生成任意一个大数字作为坐标,就数组出界)
int x = rand() % row;)
int y = rand() % col;

干货内容已经结束,下面部分可忽略不看

复盘

我不是一个逻辑思维特别强的人,所以以后会特别注重在写这种比较复杂的工程之前,先理清逻辑框架
即使这样会花费很长时间。做不到边敲代码边能理清思路就一点点来!

在这种行数两三百行的代码中,细节真的非常重要,还是有发现一些平常学习不细致的地方。
比如关于任何一方下完棋之后,都要重新赋值rusult 。do{} while(); 语句后面的分号也常常被我遗漏。

大家彼此学习,相互参照!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值