C语言三子棋简易版

一、步骤详解

1.创建文件

  • 在“源文件”中创建 test.c 文件放置测试主文件,game.c 文件放置游戏自定义函数的实现
  • 在“头文件”中创建 game.h 文件放置函数的声明(可以将调用库函数的头文件统一放进去)
  • 在这里插入图片描述
  • 在两个 .c 文件中调用 .h / .c文件(调用自定义函数用双引号)
//test.c
#include "game.h"

//game.c
#include "game.h"

2.定义主函数

编写 main 函数,调用 test 函数,返回0,test函数就用于程序的所有功能实现

int main()
{
	test();
	return 0;
}

3.编写test函数

  • 编写test函数,构建游戏流程主框架
  • 定义一个变量 input,接收用户输入的值,用 do…while 循环进行判断,只有当用户输入0时,才退出循环,非0时进入游戏。
  • 在循环中调用 menu() 菜单函数,用于用户开启程序后,提示用户如何进入游戏或退出游戏
  • 然后用switch函数判断,当输入1时,进入游戏,调用 game() 函数,然后跳出循环
  • 当输入0时,提示退出循环,并且跳出循环。
  • 如果输入非0非1,提示选择错误,并且重新进入switch函数,再次询问。
void test()
{
	int input = 0;
	do
	{
		menu();
		printf("请选择;>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			//printf("三子棋\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择~\n");
			break;
		}
	} while (input); //非0都是真,因此只有case 0会结束程序
}

4.编写菜单函数

用于提示用户进入游戏

void menu()
{
	printf("****************************\n");
	printf("***** 1.play 0.exit*******\n");
	printf("****************************\n");
}

5.编写游戏函数

用于游戏的整个算法实现

初始化棋盘
  • 数组方式定义棋盘,存放走出的棋盘信息,大小为3行3列,用声明变量的方式定义,以便于后期重复调用和修改此变量,并且给数组的每个元素赋予数字0(0是不可打印字符,类似于初始化数组,但是还是需要标准的初始化)

  • 调用 InitBoard() 函数初始化棋盘,在game.h中声明函数,接着在game.c文件中编写函数,

  • 函数形式参数为 棋盘数组,行,列

  • 定义变量i,j

  • 使用双重for循环进行遍历,给每个元素赋值空格,实现数组的初始化。

char board[ROW][COL] = {0}; //希望数组内容全是空格
InitBoard(board,ROW,COL);
void InitBoard(char board[ROW][COL],int row,int col);
//初始化函数实现
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] = ' ';
		}
	}
}

打印棋盘
  • 调用 DisplayBoard() 函数,展示棋盘,每个框里为 空格元素空格
  • game.h 中声明函数,参数依然为 棋盘数组,行,列
  • 接着在 game.c 文件中编写函数
  • 定义变量i
  • 使用双重for循环,先打印一行,然后打印此行的列,输出格式为 空格元素空格 ,以便于对齐棋盘
  • 其中每打印完一行会有一行的 “ - ” 进行分隔,且每打印完一组 空格元素空格 ,会输出一个 “ | ” 进行分隔
  • 注意:需要进行if判断是否为最后一列/行,最后一列/行不需要分隔
DisplayBoard(board,ROW,COL);
void DisplayBoard(char board[ROW][COL], int row, int col);
	//需要展示数组内容,其实就是打印行列
	//   |   |   
	//---|---|---
	//   |   |
	//---|---|---
	//   |   |  
//展示棋盘函数实现
void DisplayBoard(char board[ROW][COL], int row, int col)
{
	int i = 0;
	for ( i = 0; i < row; i++)
	{
		//1.打印一行的数据
        //下面注释掉的这行不可取,会导致最后一行/列也会有 -- |
		//printf(" %c | %c | %c \n",board[i][0], board[i][1], board[i][2]);
		int j = 0;
		for ( j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if(j < col-1)
				printf("|");
		}
		printf("\n");
		//2.打印分割行
		if (i < row - 1)
		{
			for ( j = 0; j < col; j++)
			{
				printf("---");
				if (j < col - 1)
					printf("|");
			}
			printf("\n");
		}
	}
}

下棋
  • 使用while循环判断,当用户输入1时,开始调用 玩家下棋函数 PlayerMove() 和电脑下棋函数ComputerMove() (两个函数下面都应该再次调用 DisplayBoard() 函数,重新渲染棋局在状况)
  • 两个函数每调用一次,执行相应操作后,应该调用 IsWin() 函数判断玩家/电脑是否胜利
  • 在game.h中声明三个函数,且在game.c文件编写函数
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);

玩家下棋函数
  • 定义x,y两个变量用于存放玩家输入的坐标
  • 提示玩家走后进入while循环,
  • 在while循环中写入if语句,规范限制玩家输入的坐标,使得玩家输入的x,y坐标必须大于1且小于行/列的长度。(玩家输入不需要从数组0开始计算,大众习惯从1开始)
  • 并且在玩家输入非法坐标时提示玩家 “坐标非法,清重新输入”
  • 输入坐标合法化再次判断输入的坐标的位置是否为空,为空则添入*"" ,反之提示玩家 “该坐标被占用,请重新输入”
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);
		//判断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");
			}
		}
		else
		{
			printf("坐标非法,清重新输入\n");
		}
	}
}

生成随机数
  • 生成随机数需要 *#include <stdlib.h> 、#include <time.h>*头文件,用到了 srand() 、time()、rand() 函数
  • 首先在test函数里编写 srand((unsigned int)time(NULL)); 代码,
  • time(NULL):获得系统时间的时间戳(1970.1.1 00:00:00)至今的秒数,然后转换成无符号整型(不带正负号的整数),再将得到的返回值传递给srand函数。(NULL表示直接传入一个空指针)
  • rand() 函数产生的是伪随机数字,每次执行是相同的,若要不相同,就需要使用srand获得的无符号整数经行初始化,因为srand函数是是根据时间戳获得的,因此可以保证永远不会相同。
  • rand函数在运行前会查看前面是否调用过srand函数,以及是否有设
  • 定的随机数种子 (unsigned int)time(NULL) 进行初始化,从而自动执行,不需要再次调用。
//time函数返回的时间戳作为srand函数的随机值
srand((unsigned int)time(NULL));

电脑下棋函数
  • 定义x,y两个变量用于存放电脑输入的坐标
  • 提示电脑输入后进入while循环
  • rand() 函数生成的随机数 模上行/列 ,赋值给x,y
  • 判断得到目标位置为空后,输入 “#”
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;
		}
	}
}

判断是否胜利函数

四种游戏的状态
玩家赢了 - ‘*’
电脑赢了 - ‘#’
平局结束 - ‘Q’
平局继续 - ‘C’

  • 定义变量i,编写一个for循环,当条件小于行时进入循环进行判断,如果棋盘的某一行元素都相等且都不等于空,则返回
  • 列、对角线相同
  • 编写 IsFull() 函数,判断是否平局,循环遍历棋盘的每一个元素,如果都不为空,则返回1,表示平局了
  • 如果为1,则返回 ‘Q’,提示平局
  • 反之返回’C’,游戏继续
  • 如果得到ret得到返回结果不等于C,则退出循环,进行判断谁赢, “*” 是玩家赢, “#” 是电脑赢,反之平局
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
	break;
}
if (ret == '*')
	{
		printf("玩家赢\n");
	}
	else if (ret == '#')
	{
		printf("电脑赢\n");
	}
	else
	{
		printf("平局");
	}

二、源代码

#define _CRT_SECURE_NO_WARNINGS

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


//告诉我们四种游戏的状态
// 玩家赢了 - '*'
// 电脑赢了 - '#'
// 平局结束 - 'Q'
// 平局继续 - 'C'
char IsWin(char board[ROW][COL],int row,int col);
#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;
	for ( i = 0; i < row; i++)
	{
		//1.打印一行的数据
		//printf(" %c | %c | %c \n",board[i][0], board[i][1], board[i][2]);
		int j = 0;
		for ( j = 0; j < col; j++)
		{
			printf(" %c ", board[i][j]);
			if(j < col-1)
				printf("|");
		}
		printf("\n");
		//2.打印分割行
		if (i < row - 1)
		{
			for ( j = 0; j < col; j++)
			{
				printf("---");
				if (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);
		//判断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");
			}
		}
		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;
		}
	}
}

//是否平局
//返回1:棋盘满了
//返回0:棋盘没满
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;
	//判断行是否相等
	for ( i = 0; i < row; i++)
	{
		if (board[i][0] == board[i][1]&&board[i][1]==board[i][2] && board[i][1] != ' ')
		{
			return board[i][1];
		}
	}
	//判断列是否相等
	for (i = 0; i < col; i++)
	{
		if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
		{
			return board[1][i];
		}
	}
	//对角线判断
	if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[1][1] != ' ')
		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 'Q';
	}
	return 'C';
}

//导入自己的头文件用双引号
#include "game.h"


/* -- 测试三子棋游戏 -- */

void menu()
{
	printf("****************************\n");
	printf("***** 1.play 0.exit*******\n");
	printf("****************************\n");
}
//游戏的整个算法实现
void game()
{
	char ret = 0;
	//数组 - 存放走出的棋盘信息
	//未来想更改棋盘的行列,可直接在game.h里修改
	//0是不可打印字符,类似于初始化数组,但是还是需要标准的初始化
	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 != '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("平局");
	}
}
void test()
{
	int input = 0;
	//time函数返回的时间戳作为srand函数的随机值
	srand((unsigned int)time(NULL));
	do
	{
		menu();
		printf("请选择;>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();
			//printf("三子棋\n");
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,请重新选择~\n");
			break;
		}
	} while (input); //非0都是真,因此只有case 0会结束程序
}

int main()
{
	test();
	return 0;
}

三、代码效果

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值