c语言版三子棋
经过一段时间对c语言的学习,需要完成一个比较小的项目来锻炼自己对c语言的理解和应用。于是我选择了用c语言实现三子棋这一个难度适中的小项目!
想要完整地、清晰地实现三子棋的功能。必须有一个清晰地思路,再将思路转化为一个个功能不同的函数,最终实现三子棋人和电脑对战的效果。首先我先构想需要实现的功能,将这些功能封装成没一个函数,函数的具体实现在后面的过程中再具体完善。
首先我先要清楚我将要通过定义一个3*3的二维数组来完成三子棋基本功能,通过对二维数组的改变来实现三子棋的各个操作。并且将数组行和列分别进行宏定义方便后边功能的实现。
下面是我完成三子棋各个功能的函数声明。
在有了整体思路之后,我便开始编写主函数,在主函数里在通过逻辑功能来实现三子棋的每一个选择和判断!
在main函数里我先定义出一个char型的二维数组用来形成3*3的棋盘,并对棋盘进行初始化。通过while循环来控制玩家在一局之后是否可以继续,内层while循环来控制电脑和玩家的每一次下棋操作,直到判断出输赢或平局后退出!内层while循环先实现玩家输入坐标,通过调用玩家下棋的函数void player_move(char board[ROWS][COLS], int row, int col);来实现玩家的操作,再调用电脑下棋的函数void computer_move(char board[ROWS][COLS], int row, int col);来实现人与电脑的对战。最后调用判断输赢的函数char check_win(char board[ROWS][COLS], int row, int col);来判断并打印出输赢!具体实现如下面截图!
在完成整体框架之后,便是要实现具体的每一个函数功能,首先便是要完成主选择界面和对棋盘的初始化,主界面是通过printf函数来打印出你所需要的格式,期盼的初始化的调用库函数memset(board, ' ', sizeof(char)*ROWS*COLS); 来为棋盘的每一个位置赋值空格,memset函数所引用的头文件是#include<string.h>。具体实现如下图:
接着需要具体实现玩家下棋的函数void player_move(char board[ROWS][COLS], int row, int col);该函数不需要返回参数,但需要将board这个棋盘的二维数组地址、用户输入的行row和用户输入的列col这三个参数传至函数的形参。
函数内部通过if判断该坐标是否已经被棋子所占,若数组该位置为空则将代表玩家棋子的‘X’存入该位置、并打印出棋盘。否则该位置已经有棋子,输出坐标非法让用户重新输入坐标,再调用玩家下棋的函数通过递归来实现玩家的一次操作。
在玩家下棋的函数完成后便需要完善电脑下棋的函数void computer_move(char board[ROWS][COLS], int row, int col),该函数同样需要三个形参:二维数组地址、总行数和总列数。函数内部需要调用随机函数rand()来生成符合规则的随机坐标以表示电脑的棋子‘0’所存放的位置,该函数我用了goto语句来实现循环,直至将电脑的棋子放入数组空的元素。该函数里很关键的一点是在电脑产生随机数的前面要进行输赢的判断!调用判断输赢的函数char check_win(char board[ROWS][COLS], int row, int col)赋值给字符‘c’来判断是否玩家已经胜出,若玩家已经胜出则该程序可直接结束。电脑下棋的函数代码如下,判断输赢函数之后讲解:
最后需要实现的就是判断输赢的函数char check_win(char board[ROWS][COLS], int row, int col);该函数同样需要三个形参:二维数组地址、行数和列数。然后通过for循环判断每一行是否为同一种棋子,每一列是否为同一种棋子,或者对角线是否为同一种棋子并且返回该棋子的char型,在最后调用该函数时通过返回棋子的判断谁赢。在该函数的实现中需要考虑棋盘下满仍没有分出胜负即平局这一种情况!具体实现如下图:
实现三子棋这一程序虽然逻辑简单,但是其中仍有许多细节需要注意和完善。通过自己的努力完成了一个小游戏不止给我带来了成就感更带给我许多收获!以后我会继续努力积累更多的经验,来完成更优秀的程序。下面附一下三子棋游戏的截图和源代码:
主界面:
玩家赢:
电脑赢:
平局:
附:源代码
#define _CRT_SECURE_NO_WARNINGS 1
#define ROWS 3 //数组的行
#define COLS 3 //数组的列
#include<stdio.h>
#include<time.h>
#include<windows.h>
#include<string.h>
int main_menu(); //主选择菜单
void putin_board(char board[ROWS][COLS], int row, int col); //初始化棋盘
void chessboard(char board[ROWS][COLS]); //在窗口打印棋盘
void player_move(char board[ROWS][COLS], int row, int col); //玩家下棋
void computer_move(char board[ROWS][COLS], int row, int col); //电脑下棋
char check_win(char board[ROWS][COLS], int row, int col); //判断输赢
int main_menu() //主选择菜单
{
int x;
printf("--------------\n");
printf("| 1.play |\n");
printf("| 0.exit |\n");
printf("--------------\n");
printf("请选择0或1:\n");
scanf("%d",&x);
return x;
}
void putin_board(char board[ROWS][COLS], int row, int col) //初始化棋盘
{
memset(board, ' ', sizeof(char)*ROWS*COLS); //为数组赋值空格
}
void chessboard(char board[ROWS][COLS]) //打印棋盘
{
printf("--------------\n");
printf("| %c | %c | %c |\n", board[0][0], board[0][1], board[0][2]);
printf("--------------\n");
printf("| %c | %c | %c |\n", board[1][0], board[1][1], board[1][2]);
printf("--------------\n");
printf("| %c | %c | %c |\n", board[2][0], board[2][1], board[2][2]);
printf("--------------\n");
}
void player_move(char board[ROWS][COLS], int row, int col) //玩家下棋
{
if ((board[row][col] == ' ') && (row >= 0 && row <= 2) && (col >= 0 && col <= 2))
{
board[row][col] = 'X';
chessboard(board);
}
else
{
printf("输入坐标非法!\n");
printf("请重新输入坐标:");
scanf("%d%d", &row, &col);
player_move(board, row-1, col-1);
}
}
void computer_move(char board[ROWS][COLS], int row, int col) //电脑下棋
{
int a, b; //a,b 为电脑随机的坐标
char c=' ';
srand((unsigned)time(NULL)); //用时间做种,每次产生随机数不一样
c = check_win(board, ROWS - 1, COLS - 1);
if (c == ' ')
{
again:
a = rand() % row; //随机0到row-1的任意值
b = rand() % col;
if (board[a][b] == ' ')
{
printf("电脑输入:\n");
board[a][b] = 'O';
chessboard(board);
}
else
{
goto again;
}
}
char check_win(char board[ROWS][COLS], int row, int col) //判断输赢
{
int i, j;
for (i = 0; i <= row; i++) //判断行是否相同
{
if ((board[i][0] == board[i][1]) && (board[i][1] == board[i][2]))
{
return board[i][0];
}
}
for (j = 0; j <= col; j++) //判断列是否相同
{
if ((board[0][j] == board[1][j]) && (board[1][j] == board[2][j]))
{
return board[0][j];
}
}
if ((board[0][0] == board[1][1]) && (board[1][1] == board[2][2]))
{
return board[0][0];
}
if ((board[2][0] == board[1][1]) && (board[1][1] == board[0][2]))
{
return board[1][1];
}
for (i = 0; i <= row ; i++) //判断平局
{
for (j = 0; j <= col ; j++)
{
if (board[i][j] == ' ')
goto judge;
}
}
judge:
if (i == 3 && j == 3)
{
return 'P';
}
return ' ';
}
int main()
{
int x=1;
char c = ' ';
int row = ROWS, col = COLS; //定义用户输入的行和列
char board[ROWS][COLS];
x=main_menu();
while (x != 0)
{
putin_board(board, row, col); //初始化棋盘
c = ' '; //每次游戏前对c赋值空格
while (c ==' ')
{
printf("请输入坐标:\n");
scanf("%d%d", &row, &col); //用户输入下棋的坐标
player_move(board, row-1, col-1);
computer_move(board, ROWS, COLS);
c = check_win(board, ROWS-1, COLS-1); //判断输赢 返回空继续
if (c == 'X') //玩家赢
{
printf("玩家赢\n");
}
if (c == 'O') //电脑赢
{
printf("电脑赢\n");
}
if (c == 'P') //平局
{
printf("平局!\n");
}
}
x = main_menu();
}
return 0;
}