一、步骤详解
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;
}