C语言虽然是最基础的语言,但是功能无比强大,用C语言可以写出很多有趣的东西,今天就给大家介绍一种三子棋小游戏,这个游戏目前还没有加复杂的算法来提高电脑的智力,只是实现了一些最基本的东西,整体是用数组来完成的,但是后期我会不断地去完善。
1.设置菜单及选项界面
因为是游戏的初期,菜单设置的比较简单,就是1和0,选择1玩游戏,选择0退出游戏
void menu()
{
printf("****************************************\n");
printf("*********1.play 0.return **********\n");
printf("****************************************\n");
//用户输入并执行
}
void test()
{
int x = 0;
printf("请输入想要进行的操作:");
do{
menu();
scanf("%d", &x);
printf("\n");
switch (x)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("请重新输入\n");
break;
}
} while (x);
}
选项的执行放在switch语句中完成,case1就执行玩游戏的函数,case0就退出,其他的输入就重新输入,用do-while循环的原因就是游戏至少要玩一次,正好适合do-while循环的使用场景,判断条件除了0之外都不会跳出循环,因此将输入作为判断循环条件即可,只要不输入0就继续游戏。
2.游戏界面
(1)设置棋盘
将棋盘设置为如图所示的界面,用for循环就可以完成。
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] = ' ';
}
}
}
void DisplayBoard(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++)
{
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");
}
}
}
为了将棋盘界面最开始保持为空的界面,在数组存放的位置先初始化为空格,这样子既可以保证界面的客观性,也不影响后面的改动。
(2)玩家下棋
玩家下棋在现在这个基础的阶段,是通过输入棋盘的坐标来进行选择的。因此,在编写代码的时候要注意以下几个问题:
1.如果玩家输入的坐标超出棋盘所在的位置,应该有所提示并重新选择。
2.如果玩家输入的坐标已经下过棋子,不可能用新的值覆盖,这样就应该提醒玩家并重新选择。
3.因为玩家不全是程序员,因此不是所有人都知道数组的起始是从0开始的,因此要使玩家输入的是正常值,而我们在编写程序的时候要将输入的坐标减一。、
根据上面的三个需要注意的问题,整个玩家输入坐标的过程需要用循环完成,如果输入的不是正确值就重新输入,如果输入正确,就用break跳出。代码实现如下:
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("玩家下棋->\n");
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("坐标被占用,请重新输入\n");
}
}
else
{
printf("输入超出棋盘,请重新输入\n");
}
}
}
(3)电脑下棋
电脑下棋的方式是可以多变的,算法的不同可以使电脑下棋的方式不断改变,可以使电脑的智力不断提高。但是现在的初级阶段,我对一些算法还不够了解,因此先用最基础的随机数来让电脑进行下棋,在后面我会多查查资料,使整个结构更加完善。
由于电脑的走棋是用随机数规定好的,因此不需要考虑坐标越界的情况,只需要考虑坐标是不是被占用了即可,同样采用循环的方法来实现每一次电脑的输入,输入正确用break跳出。
代码实现如下:
void ComputerMove(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;
}
}
}
(3)判断棋局结果
既然是下棋游戏,就必然会有一个结果,是输、是赢、还是打平了,因此在每次玩家和电脑输入之后我们都要对整个棋盘进行一次判断,如果有一方赢了或者平局,就结束游戏,开始下一次的选择。判断的条件我用的是返回“ * ”、返回“ # ” 、返回Q和返回C来分别代表不同的意思。返回“ * ”表示玩家赢。返回“ # ”代表电脑赢,返回Q表示平局、返回C表示游戏继续。
代码实现:
char IsWin(char board[ROW][COL], int row, int col)
{
int q = 0;
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 (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' ')
{
return board[1][i];
}
}
if (board[1][1] == board[2][2] && board[2][2] == board[3][3] && board[1][1] != ' ')
return board[1][1];
if (board[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
return board[1][1];
q = IsFull(board, ROW, COL);
if (q == 1)
return 'Q';
return 'C';
}
判断谁赢就是根据有没有一行或者一列或者两个对角线有连起来的进行判断,因为是初阶的算法,所以判断输赢这一块只用了if来判断,所以就只能限制在三子棋。这里有一个巧妙的地方,就是返回“ * ”和“ # ”是直接用哪一个连成线就返回那一条线上的任意一个坐标元素,这样子就返回就不需要在进行判断是谁赢了,再返回对应的标志。
平局的判断就是遍历整个棋盘,如果没有一个人赢并且棋盘上全部满了,就是平局。
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;
}
代码效果
玩家赢
电脑赢
平局
整体的代码实现还是很成功的,但是还有很多能够改进的地方,比如可以给电脑加入一些算法,使电脑落子能够根据棋盘的状况选择最佳的落子位置,比如现在输入是根据坐标来进行输入的,可以改进为用鼠标点击下棋等等,这些都需要更多的思考。
我后面会去查找资料,将整体更加优化,希望大家能够给我更多的鼓励和支持。