目录
1.功能需求分析
2.功能设计与实现
1.主体框架test.c
2.功能实现game.c
3.头文件game.h
3.结果展示
模拟实现简版三子棋小项目涉及了综合知识点,主要有函数、数组,也有分支循环的运用,还有多文件操作。很好地将所学知识点结合运用,主要考察的是整体结构设计和设计函数的逻辑。
1.功能需求分析
三子棋主要有以下几个功能模块:
- 棋盘初始化
- 玩家走
- 电脑走
- 判断状态
- 显示棋盘
三子棋主要有以下几个功能模块:
- 棋盘初始化
- 玩家走
- 电脑走
- 判断状态
- 显示棋盘
2.功能设计与实现
1.主体框架test.c
void menu()
{
printf("*****************************************n");
printf("************ 1.开始游戏 **************n");
printf("************ 0.离开游戏 **************n");
printf("*****************************************n");
}
void game()
{
//定义棋盘
char board[ROW][COL]={0};
//初始化棋盘
initboard(board, ROW, COL);
//打印棋盘
printboard(board, ROW, COL);
//棋子移动
char ret = 0;//记录棋局的状态
while (1)
{
playermove(board, ROW, COL);//玩家走
printboard(board, ROW, COL);//显示棋盘内容
ret = is_win(board, ROW, COL);//棋局的状态
if (ret != 'C')
break;
computermove(board, ROW, COL);//电脑走
printboard(board, ROW, COL);//显示棋盘内容
printf("n");
ret = is_win(board, ROW, COL);//棋局的状态
if (ret != 'C')
break;
}
if (ret == '*')
{
printf("玩家赢!n");
}
else if (ret == '#')
{
printf("电脑赢!n");
}
else if (ret == 'Q')
{
printf("平局!n");
}
printboard(board, ROW, COL);
printf("n");
printf("请选择是否重新游戏?n");
}
int main()
{
int input = 0;
do
{
srand((unsigned int)time(NULL));
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("离开游戏n");
break;
default:
printf("输入错误,请重新选择!n");
break;
}
} while (input);
return 0;
}
2.功能实现game.c
实现所需功能:
- 棋盘初始化
- 玩家走
- 电脑走
- 判断状态--已优化
- 显示棋盘--已优化
功能模块注解:对于功能3,只是实现了随机下棋:对于功能4和5,都可以适配N子棋
void menu()
{
printf("*****************************************n");
printf("************ 1.开始游戏 **************n");
printf("************ 0.离开游戏 **************n");
printf("*****************************************n");
}
void game()
{
//定义棋盘
char board[ROW][COL]={0};
//初始化棋盘
initboard(board, ROW, COL);
//打印棋盘
printboard(board, ROW, COL);
//棋子移动
char ret = 0;//记录棋局的状态
while (1)
{
playermove(board, ROW, COL);//玩家走
printboard(board, ROW, COL);//显示棋盘内容
ret = is_win(board, ROW, COL);//棋局的状态
if (ret != 'C')
break;
computermove(board, ROW, COL);//电脑走
printboard(board, ROW, COL);//显示棋盘内容
printf("n");
ret = is_win(board, ROW, COL);//棋局的状态
if (ret != 'C')
break;
}
if (ret == '*')
{
printf("玩家赢!n");
}
else if (ret == '#')
{
printf("电脑赢!n");
}
else if (ret == 'Q')
{
printf("平局!n");
}
printboard(board, ROW, COL);
printf("n");
printf("请选择是否重新游戏?n");
}
int main()
{
int input = 0;
do
{
srand((unsigned int)time(NULL));
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("离开游戏n");
break;
default:
printf("输入错误,请重新选择!n");
break;
}
} while (input);
return 0;
}
2.功能实现game.c
实现所需功能:
- 棋盘初始化
- 玩家走
- 电脑走
- 判断状态--已优化
- 显示棋盘--已优化
功能模块注解:对于功能3,只是实现了随机下棋:对于功能4和5,都可以适配N子棋
实现所需功能:
- 棋盘初始化
- 玩家走
- 电脑走
- 判断状态--已优化
- 显示棋盘--已优化
功能模块注解:对于功能3,只是实现了随机下棋:对于功能4和5,都可以适配N子棋
1.棋盘初始化--将所有位置初始化为空格,开始要空棋盘
void initboard(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
2.打印棋盘--让你知道棋盘的状态
void printboard(char board[ROW][COL], int row, int col)
{
//注:
//理解为ROW行,每一行其实又包括两行(两个部分),第一行为“棋子”和分割(|),第二行为“---”和分割(|)
//其中每行的末尾不需分割(|),最后一行没有“---”和分割(|),即没有(第二部分)
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)//每行的第一个部分
{
printf(" %c ", board[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");
}
}
}
3.玩家走
void playermove(char board[ROW][COL], int row, int col)
{
//玩家走要考虑提示走的对不对
//对--坐标在范围内且坐标未被访问过
//错--一是不在坐标范围内,二是坐标已被占用
while (1)
{
int x = 0, y = 0;
printf("玩家走:");
scanf("%d %d", &x, &y);
if (1 <= x && x <= row && 1 <= y && y <= col)//输入范围要合法
{
//考虑玩家下棋的坐标是从1开始的,所以要减一以满足数组的下标;坐标不仅要合法还要不能重复走
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标已被占用,请重新输入!");
}
}
else
{
printf("非法输入,请重新输入!n");
}
}
}
4.电脑走--随机
void computermove(char board[ROW][COL], int row, int col)
{
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
printf("电脑走:n");
board[x][y] = '#';
break;
}
}
}
5.判断局势
返回值注解:'Q':平局; 'C':继续下棋;
'#':电脑赢; '*' :玩家赢
int is_full(char board[ROW][COL], int row, int col)
{
//判断平局
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
char is_win(char board[ROW][COL], int row, int col)
{
//判断行
//注解:遍历整个二维数组,两两比较,遍历范围少一列,因为当遍历到倒数第二列时,比较的是最后两列的内容。
//所以以比较到最后两个时,判断列+1等于最后最后一列作为输出条件。
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col - 1; j++)
{
if (board[i][j] == board[i][j + 1] && board[i][j] != ' ')//两两比较,要考虑这一行还没下棋的情况(' ')
{
if ((j + 1 == col - 1))//遍历到最后一列,说明这一行都是一样的,赢了
{
return board[i][j];
}
}
else
{
break;
}
}
}
//判断列
for (int j = 0; j < col; j++)
{
for (int i = 0; i < row - 1; i++)
{
if (board[i][j] == board[i + 1][j] && board[i][j] != ' ')
{
if (i + 1 == row - 1)
{
return board[i][j];
}
}
else
{
break;
}
}
}
//判断正对角
for (int i = 0, j = 0; i < row - 1; i++, j++)
{
if (board[i][j] == board[i + 1][j + 1] && board[i][j] != ' ')
{
if (i + 1 == row - 1)
{
return board[i][j];
}
}
else
{
break;
}
}
//判断副对角
for (int i = 0, j = row - 1; i < row - 1; i++, j--)
{
if (board[i][j] == board[i + 1][j - 1] && board[i][j] != ' ')
{
if (i + 1 == row - 1)
{
return board[i][j];
}
}
else
{
break;
}
}
//判断平局--无位置可下棋则为平局
int tmp = is_full(board, ROW, COL);
if (tmp == 1)
return 'Q';//平局
else
return 'C';//继续下棋
}
3.头文件game.h
包含.c文件所需的库函数、宏定义以及各功能函数的声明
#pragma once #include#include #include //行和列宏定义 #define ROW 3 #define COL 3 //函数声明 void initboard(char board[ROW][COL], int row, int col); void printboard(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 is_win(char board[ROW][COL], int row, int col);



