一、三子棋游戏介绍
三子棋是黑白棋的一种。三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。将正方形对角线连起来,相对两边依次摆上三个双方棋子,只要将自己的三个棋子走成一条线,对方就算输了。但是,有很多时候会出现和棋的情况。
![](https://i-blog.csdnimg.cn/blog_migrate/d1da83a89d5d0c6dda0f2d9c98d83255.jpeg)
如果两个人都掌握了技巧,那么一般来说就是平棋。一般来说,第二步下在中间最有利(因为第一步不能够下在中间),下在角上次之,下在边上再次之。最大的好处就是随便找个地方就可以玩这个简单而有趣的游戏了。
二、主函数test部分
我们将代码分到下面三个部分来写
test.c用来实现主函数
game.c用来实现游戏函数
game.h用来声明函数
2.1设计菜单
首先在我们需要设计一个游戏开始菜单,玩家可以自行选择开始游戏,游戏模式,结束游戏,下面是在主函数写的菜单代码
void menu()
{
printf("*****************************\n");
printf("******** 1. play ******\n");
printf("******** 0. eixt ******\n");
printf("*****************************\n");
}
2.2 test函数
test函数通过使用一个Switch函数,根据用户输入input的值来选择游戏模式,开始游戏或者退出游戏,若用户选择1,则进入game函数进行游戏。
void test()
{
int input = 0;
do
{
menu();
printf("请选择:");
scanf("%d", &input);
switch (input)
{
case 0:
printf("退出游戏\n");
break;
case 1:
game();
break;
default:
printf("选择错误\n");
break;
}
} while (input);
}
2.3 主函数部分
主函数仅调用test函数,其它函数进行分开写,由test函数调用,这样写会让程序简洁,更加清晰,方便读者理解程序。
int main()
{
srand((unsigned)time(NULL));
test();
return 0;
}
三、游戏设计部分
3.1初始化棋盘函数
void init_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (int i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
3.2 打印棋盘函数
打印棋盘时要注意,棋盘最右边不需要打印“|”,棋盘最下边不需要打印“—”,所以使用了if判断函数,当j < col – 1才打印“|”,i < row – 1才打印“—”,这样打印出来的出事化棋盘就如下图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/81aafbd50c4bd2937de57ab4829f6c31.png)
void print_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
3.3玩家下棋函数
玩家下棋函数要注意的一点是,数组下表是从0开始,但玩家在下棋不一定会知道这个规则,所以我们让玩家输入的坐标从1开始,再将输入的坐标进行-1的操作。
void player_move(char board[ROW][COL], int row, int col)
{
printf("玩家下棋\n");
while (1)
{
int x = 0;
int y = 0;
printf("请输入要下的棋坐标");
scanf("%d %d", &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("该坐标已被占用,请重新输入坐标");
}
}
else
{
printf("坐标非法");
}
}
}
3.5电脑下棋函数
电脑下棋这里采用时间随机函数,通过rand()取到的随机值进行对行和列取余,保证随机值在0~行和列数之间的数。
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
3.6判断输赢函数
判断输赢函数主要由四个子函数组成,分别为判断行、判断列、判断对角线以及判断是否平局,具体判断方法是根据三个位置的符号都相等且不为空格时成立,若没有满足胜利的情况,进入判断是否平局函数,判断是否平局函数调用了一个is_full子函数,它的作用是用来判断是否棋盘满了,如果没有分出胜负,又判断出棋盘满了,则视为平局,返回字符P;
static 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)
{
int i = 0;
int j = 0;
//判断三行
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2] && board[i][0] != ' ')
return board[i][0];
}
//判断三列
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')
return board[0][j];
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[0][0];
}
if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
{
return board[0][0];
}
//判断是否平局
if (is_full(board, ROW, COL) == 1)
{
return 'P';
}
return 'C';
}
3.7 主函数中game函数模块
该模块主要用于调用game.c中的各个游戏实现函数,该函数由一个循环构成,只有当一方胜利或平局时才会跳出循环。
void game()
{
char board[ROW][COL];
//初始化棋盘
init_board(board, ROW, COL);
print_board(board,ROW, COL);
int ret;
while (1)
{
//玩家下棋
player_move(board, ROW, COL);
print_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
//判断输赢
if (ret != 'C')
{
break;
}
//电脑下棋
computer_move(board, ROW, COL);
print_board(board, ROW, COL);
//判断输赢
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
//根据返回值进行游戏输赢的判定
if (ret == '*')
printf("玩家胜利\n");
else if (ret == '#')
printf("电脑胜利\n");
else if (ret=='P')
printf("平局\n");
}
四、game.h函数
该函数主要进行头文件以及函数的声明,还用了define定义行和列,这样做的好处是方便棋盘大小的修改,如修改成10*10的棋盘,我们只需要进行修改define定义的值就可以了。
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
//初始化棋盘
void init_board(char board[ROW][COL],int row, int col);
//打印棋盘
void print_board(char board[ROW][COL], int row, int col);
//玩家下棋
void player_move(char board[ROW][COL], int row, int col);
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col);
//判断输赢
char is_win(char board[ROW][COL], int row, int col);
五、测试结果
5.1玩家胜利
![](https://i-blog.csdnimg.cn/blog_migrate/a619b0bed316764ab07e5c0a659377ac.png)
5.2电脑胜利
![](https://i-blog.csdnimg.cn/blog_migrate/628576a88475cb960bd511ad3411c010.png)
5.3平局
![](https://i-blog.csdnimg.cn/blog_migrate/5fdb4941ab0aad1126a3efc99bac95ab.png)
六、总结
在进行三子棋游戏设计时,应该先理清楚设计的思路和逻辑,然后再将各个部分功能函数进行实现,还有设计时还需要从玩家的角度考虑问题,比如玩家输入时的坐标从1开始。还有棋盘设计时,要灵活设计,利用宏定义行和列,方便后面修改棋盘的大小。