三子棋游戏的思路分享
今天,我很高兴和大家分享一下我练习三子棋的感受与一些思路。
- 首先我们先建一个工程,这次与往常不一样,为了把代码细分清楚,建立一个头文件(game.h)(用于一些头文件的包含,以及一些函数的声明),再建立两个源文件(game.c和test.c)(一个是游戏代码即一些函数部分,一个是测试部分主要是一些外部框架)。
- 然后先搭建一个框架,如下图
这个菜单部分我们可以通过一个menu()来实现,代码如下:
void menu()
{
printf("******************\n");
printf("*** 1.play ***\n");
printf("*** 0.exit ***\n");
printf("******************\n");
}
此外,我们通过输入的数字来进行参与游戏,是1则参与游戏,是0则结束游戏,如果输入其他数字则打印输入错误,重新输入。大家看到这个根据输入的数字来进行不同的操作,有没有想到switch语句呢?我们就通过这个来实现它,test.c源文件中的代码如下:
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();//三子棋的游戏
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择!\n");
break;
}
} while (input);
return 0;
}
让我们先试一下,看看能不能实现这个功能。
大家看到这个是不是还是觉得很简单呢,让我们继续挖深吧!
3.现在就是game()内部这个大工程了。
(1)因为我们设计的是三子棋,所以我们看成是一个字符数组,三行三列,因为这是棋盘,我们直接把数组名写成board,board[ROW][COL],
我们在这里不直接将数组的行列数直接写出来,可以进行宏定义,这样有助于兼容性,如果下次做五子棋或者其他形式,可以直接在宏定义中修改一下信息。我们在game.h头文件中的代码如下:
#define ROW 3
#define COL 3
我们只需要在各个源文件中加上
#include "game.h"
即可。
(2)我们对棋盘数组进行初始化,令每一位都是空格。在game.h我们写出一个函数InitBoard()声明
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
然后我们就可以在game.c中实现这个函数了。
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] = ' ';
}
}
}
(3)初始化棋盘后,我们先打印一下棋盘,和上面的初始化棋盘类似,先声明一下
//打印棋盘
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++)
{
//打印数据
printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);
//打印分割的行
if (i < row - 1)
printf("---|---|---\n");
}
}
这种代码虽然实现了棋盘的打印,但是兼容性不好,如果不打印三子棋棋盘,改成五子棋等等,则这个代码就不行了。所以现在对代码进行修改,将打印改成循环形式
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
//打印数据
//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");
//打印分割的行
if (i < row - 1)
{
//printf("---|---|---\n");
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
棋盘打印就出来了,无论是三子棋还是五子棋还是其他形式,只要改变一下宏定义就可以打印出正确的棋盘。
(4)现在我们就可以进行下棋环节了。因为这个是人工对战,所以我们搞出两个函数玩家下棋和电脑下棋,代码如下:
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row,int col);
(5)现在我们进行PlayerMove()函数的代码书写,我们通过读取输入的坐标进行对棋盘数组元素的变化,同时也要防止一些特殊情况的输入,因此我们要进行对输入的坐标进行判断,坐标是否在字符串内,同时该坐标下的元素是空格(同时要注意由于C语言中的数组开头是从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);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x-1][y-1] != ' ')
{
printf("坐标被占用,请重新输入!\n");
}
else
{
board[x-1][y-1] = '*';
break;
}
}
else
{
printf("坐标非法,请重新输入!\n");
}
}
}
(6)进行电脑下棋,为了确保随机下棋的进行,我们通过rand()形式产生随机数,再通过时间戳来作为随机数产生的起点,因此我们在main函数中进行一次随机数起点的进行,因此我们利用下面进行随机数起点
srand((unsigned int)time(NULL));
同时在game.h头文件中包含头文件
#include <time.h>
#include <stdlib.h>
电脑下棋代码如下:
void ComputerMove(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;
}
}
}
(7)现在可以下棋了,最后进行判断输赢情况:
(1)一种是输赢出来了
(2)一种是还没有结束,继续比赛
(3)最后就是打成平局
通过一个字符变量ret来控制判断输赢情况。
这里我们依旧使用一个函数CheckWin()来进行,函数声明就不写下了,代码如下:
//判断输赢
char CheckWin(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][0] != ' ')
{
return board[i][0];
}
}
//三列
for (i = 0; i < row; i++)
{
if (board[0][i] == board[1][i] && board[1][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[1][1] != ' ')
return board[1][1];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
return board[1][1];
//平局
if (IsFull(board, row, col) == 1)
{
return 'Q';
}
return 'C';
}
在判断平局的时候,通过引用IsFull()函数来判断是否应该结束游戏
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;
}
经过以上的代码设计,game()内部基本上达成
void game()
{
char ret = '0';
//数组的存储是二维数组
char board[ROW][COL];//初始化为空格
//初始化棋盘
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
while (1)
{
//玩家下棋
PlayerMove(board,ROW,COL);
ret = CheckWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisplayBoard(board, ROW, COL);
//电脑下棋
ComputerMove(board,ROW,COL);//随机下棋
ret = CheckWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisplayBoard(board, ROW, COL);
}
if (ret == '*')
printf("玩家赢了\n");
else if (ret == '#')
printf("电脑赢了\n");
else if (ret == 'Q')
printf("平局\n");
DisplayBoard(board, ROW, COL);
}
现在我们进行一次三子棋游戏吧!
经过与电脑进行一番PK,终于在棋盘填满的时候赢得胜利!(▽)
感谢大家的观看,作为小白,写的不是很透彻,希望大家多多包涵指点,谢谢大家!