三子棋小游戏-c语言实现
要实现三子棋游戏,在直接动手打代码之前,首先要考虑的是,三子棋的大致框架。如三子棋的棋盘、用户是否可以选择进入或者退出游戏、玩家用何种方式玩游戏等等
一、搭建基本框架
void menu()//打印菜单
{
printf("*****************************\n");
printf("******* 1.play *********\n");
printf("******* 0.exit *********\n");
printf("*****************************\n");
printf("*****************************\n");
}
void test()
{
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);
}
int main()
{
test();
return 0;
}
二、实现核心代码-game()
这一部分代码是此游戏的核心,玩家输入的信息应该保存在什么地方呢?棋盘又怎么实现呢?
如图:
我可以发现,这个棋盘与二维数组非常相似,且用二维数组来保存玩家下棋的位置和电脑下棋的位置也是非常适合的。
char board[ROW][COL] = { 0 };
- 初始化棋盘
下棋之前,棋盘上应该是空空如也。
//初始化棋盘
InitBoard(board, ROW, COL);
//函数实现
void InitBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)//二维数组常有套路啦,双层for循环
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
- 打印棋盘(不打印出来,就只能靠想象了)
关键是如何打印,直接打印,no no no。直接打印就是一大堆空格啦,需要修饰一下。每一个数据都一个分隔符(|),且每一个数据下方也有一个分隔符(——|)。在打印数据之后,处理好分隔符。
//打印棋盘
DisplayBoard(board, ROW, COL);
//函数实现
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("|");
}
printf("\n");
for (j = 0; j < col; j++)
{
//打印分隔符
if (i < row - 1)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
- 玩家下棋
玩家输入坐标,输入之后,程序员要考虑用户输入的坐标是否合理,输入的坐标是否被占用。
player_move(board, ROW, COL);
void player_move(char board[ROW][COL],int row,int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("玩家下棋\n");
printf("请输入坐标->");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row, y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')//不能苛求玩家知道坐标是从0开始
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("该坐标已被占用,请重新输入\n");
}
}
else
{
printf("输入错误,请重新输入\n");
}
}
}
- 电脑下棋
电脑下棋,其实就是产生在0-row/col之间的随机数,那么就需要考虑怎么产生随机数呢?可以想到rand()函数需要配合srand()使用,不然每次产生的随机数都是一样的。
computer_move(board, ROW, COL);
void computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋\n");
while (1)
{
x = rand() % row;//余数不会大于除数
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
srand((unsigned int)time(NULL));//因为只需要调用一次就放在其他函数中
5. 整理代码
写到现在,我们可以已经实现玩家下棋和电脑下棋了,但是下完一步就不懂了。我们需要交互式的,这时我们可以将写好的代码放入循环当中。
while ()
{
//玩家下
player_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//电脑下
computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
}
- 判断输赢
这时代码到了尾声,如何判断输赢。我们每下一步,都会有四种情况。1. 玩家赢了 2.电脑赢了 3. 平局 4.游戏继续。那怎么判断赢了呢?三行中有一行或者三列中有一列具有相同的字符,若为*则玩家赢,反之是电脑赢。其中若是对角线相同,同上。
如何判断平局呢 ?棋盘全满,谁也没赢也没输则平局。
//判断输赢
//返回'*',代表玩家赢
//返回'#',代表电脑赢
//返回'Q',代表平局
//返回'C',代表游戏继续
static int is_full(char board[ROW][COL], int row, int col)
{//static修饰函数,这个函数就只能在这个源文件使用
//这个函数是用来判断棋盘是否满啦
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 is_win(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[i][0];
}
}
//对角线
for (i = 0; i < row; i++)
{
if (board[0][0] == board[1][1]&& board[1][1] == board[2][2] && board[0][0] != ' ')
{
return board[0][0];
}
}
//判断平局
if (is_full(board,row,col) == 1)
{
return 'Q';
}
//继续
return 'C';
}
- 整理上述代码
根据逻辑,整理代码,每走一步都需要判断输赢。
while (1)
{
//玩家下
player_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
//电脑下
computer_move(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else
{
printf("平局\n");
}
三、总结
我的难点是什么?
我自己写,我可能理不清游戏的需求是什么,一脸懵
产生随机数的部分,有困惑的地方
判断输赢的部分,自己不会写。感觉写死了,但是又不是怎么改