这是一篇介绍三子棋代码实现的博客,采用C语言,主要介绍思路以及出现的一些错误修正,后跟随有自己实现的代码块,欢迎各位大佬指点,也希望可以给同为小白的同志一些帮助。 ps:主要函数实现已粘贴在文章中,游戏函数以及main函数放在文章末尾。
一、思考方向
1、游戏界面
-
游戏选择菜单——do while 函数 以选择菜单的值确定是否进行游戏或退出游戏;
-
棋子——采用二维数组 定义3×3的二维数组用于存储棋子,并初始化;
-
棋盘——利用二维数组加上'---'与 '|'组合实现 为了便于观察,对棋子进行分割,达到视觉上清晰的效果;
2、下棋的实现
-
玩家下棋——利用'*''#'代表棋子,在棋子数组中更换字符实现 每下一步,便打印一次棋盘,以'*'代表玩家,'#'代表电脑;
-
电脑下棋——采用rand()函数与time函数结合,实现随机效果 更优的办法是电脑可以根据玩家下棋的位置进行堵截效果,使得电脑具有一定的游戏“水平”,奈何自己的代码水平暂时不够,只可暂且实现随机效果;
3、判断输赢
函数返回类型定义为char,返回赢方棋子,以便判断。
二、具体实现
1、选择菜单
自定义menu()函数,利用printf函数打印菜单,在main函数中以input收纳玩家选择,利用switch语句进行选择,
//选择菜单
void menu()
{
printf("*********************\n");
printf("*** 1、开始游戏 *****\n");
printf("*** 0、退出游戏 *****\n");
printf("*********************\n");
}
//主函数运行
int main()
{
int input = 0;
do
{
//打印选择菜单
menu();
scanf("%d", &input);
switch (input)
{
case 1:
//开始游戏
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
2、 棋盘定义
采用二维数组保存棋子并初始化为' ',以#与*代表棋子。
初始化
void Initboard(char (* board)[COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
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++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col -1)
printf("|");//棋盘竖向分割线
}
if(i < row -1)
printf("\n-----------\n");//棋盘横向分割线
}
printf("\n");
}
3、下棋
- 玩家下 包含三种情况: a、棋盘空无棋,正常下; b、棋盘空已被棋子占用; c、坐标输入非法。
//玩家下棋
void player_move(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
printf("玩家下\n");
while (1)
{
printf("请输入要下的坐标:");
scanf("%d %d", &x, &y);
if (x > 0 && x <= row && y > 0 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
printf("坐标已被占用,请重新输入\n");
}
else
printf("坐标非法,请重新输入\n");
}
}
- 电脑随机下 只需判断在棋盘空处下棋便好。
//电脑下棋
void computer_move(char board[ROW][COL], int row, int col)
{
int x = 0, y = 0;
printf("电脑下\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
4、判断输赢
每次下棋都需判断,根据判断的结果决定是否继续,判断会出现四种结果: a、玩家赢了 b、玩家输了 c、棋盘已满,造成平局 d、棋盘未满,游戏继续 此处利用简单的穷举法进行判断。
//判断输赢
//玩家赢返回‘*’,输返回‘#’,平局返回‘Q’,继续返回‘C’
static int isfull(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++)
{
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][0] == board[i][2] && board[i][0] != ' ')
return board[i][0];
}
//判断行
for (i = 0; i < row; i++)
{
if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ')
return board[0][i];
}
//判断对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ' || board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[1][1];
if (isfull(board, row, col))
return 'Q';
else
return 'C';
}
三、一些小tip
- 定义棋盘大小时可以采用#define定义标识符代表常量,便于后续修改;
- 在函数传参时,传过去的二维数组须用二维数组接收,或采用数组指针;
//例如
int main()
{
char a[3][3] = { 0 };
test1(a);
test2(a);
return 0;
}
//方式1,同类型数组接收
void test1(char a[3][3])
{
}
//方式2,数组指针接收,不可用char* a[3],由于[]的优先级大于*,
//此时为指针数组, char (*a)[3]才是数组指针
void test2(char (*a)[3])
{
}
- 判断输赢时,可以直接返回棋子字符,减少判断代码;
- 定义函数时可以采用另一个.c文件用以保存函数,达到封装效果;
- 在函数调用行列时,最好利用形参采用局部变量,而非使用全局变量; 例如,本文中利用#define将行列分别定义为ROW,COL,但在函数中依旧采用传参的方式,因为函数内部若使用了外部定义的全局变量,便导致离开此全局变量后函数便不可用,从而使得函数的可移植性降低。
四、main函数以及游戏函数
//游戏函数
void game()
{
char ret = 0;//用以判断输赢
//棋盘
char board[ROW][COL] = { 0 };
//初始化棋盘
Initboard(board, ROW, COL);
//打印棋盘
Displayboard(board, ROW, COL);
while (1)
{
//玩家下棋
player_move(board, ROW, COL);
Displayboard(board, ROW, COL);
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'C')
break;
//电脑下棋
computer_move(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("平局\n");
}
//main函数
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}