这是我学习编程的第12天,今天我完成了一个简单的三子棋游戏,如果作者有哪里写的不对或者不好的地方,大家可以指出来,话不多说我们开始吧!
建立大体的框架,创建了一个头文件和两个源文件,创建的头文件来声明各类功能函数,一个源文件用来定义函数,另一个用来测试代码。
我所标记的是需要创建的三个文件,文件添加好后我们来完成其大体的框架。
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
void InItboard(char board[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);
这是头文件需要包含的库以及需要声明的函数,我将所有需要的头文件都包含在game1.h这个头文件中,在其他源文件使用的时候就只需包含这个头文件就可以。
首先,我们要分析这个游戏的玩法,棋盘打印在屏幕上大概就是这个样子,简易版的一个棋盘,玩家走一步,电脑就会走一步,当有一方的棋子一列或一行或是对角线上有三个棋子相同了,那么这方会获胜。
接下来,游戏菜单选择的基本功能
分析游戏菜单功能应该是一个选择功能,并且可以一直进行你想要的选择,那么就需要将其写进一个循环。这里我使用了do while循环每次进行选择都会有菜单的打印,之后就是选择对应的功能
1.玩游戏0.退出游戏。这里我用到了switch循环。
void Menu()
{
printf("******************\n");
printf("******1.play *****\n");
printf("******0.exit *****\n");
printf("******************\n");
}
int main()
{
int input = 0;
do
{
Menu();
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("输入有误,请重新选择:");
break;
}
} while (input);
return 0;
}
菜单选择的功能就很好的完成了,接下来是设计各类函数来完成游戏的各类功能。
将各类函数放在一个函数中去调用,这里我将每个功能函数放在了game()这个函数中去调用。
并且在头文件包含每个函数的声明。
void InItboard(char board[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);
首先,棋盘的创建和初始化。其中棋盘我们可以很容易的将其抽象成一个二维字符数组,二维数组的行列我们可以用宏来定义方便以后进行修改,这里也是一样在头文件中定义就可,
#define ROW 3
#define COL 3
接下来就是创建以及初始化,这里我们设计了一个InItboard()的函数用其来初始化数组,这个过程是很容易的,只需遍历到二维数组的每一个元素将其赋值’ ‘ ,代码如下:
void InItboard(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++)
{
board[i][j] = ' ';
}
}
棋盘初始化后我们需要将棋盘打印出来,设计了函数DisplayBoard()考虑到未来代码修改后的可操作性,将打印棋盘写活代码如下:
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");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
棋盘展示后,需要设计人和电脑下棋的功能,首先要设计人和电脑的下棋函数,我们先来设计人的下棋功能,设计一个函数PlayerMove()这个函数中要实现,玩家输入一个坐标,将坐标赋值给这个二维数组,即棋盘,需要注意的是:要判断坐标是否在规定范围内,以及所输入的坐标是否已经被占用。代码如下:
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");
}
}
}
接下来,我们要设计电脑下棋的函数ComputerMove(),由于作者是初学者能力有限,我们就色痕迹一个简单随机功能来实现电脑的动作,首先我们需要一个生成随机值的函数rand()这个函数会生成一个随机值,我们用到这个函数就必须要引用其所需的头文件,<stdlib.h>并要借助这个函数实现srand((unsigned int)time(NULL));其中time函数也需引用头文件<time.h>,我们还需要生成的随机值在3以内,只需将生成的值%row或col即可,代码如下:
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;
}
}
}
电脑和人的动作函数都完成后,在游戏时候应该是人和电脑每走一步就会现实一遍现在的棋盘,所以在调用这两个函数后要再调用打印棋盘函数。
然后我们需要设计一个判断输赢以及平局的函数来,这个函数需要在每次人或者电脑动作完成后都要被调用,首先,我们来设计这个函数,函数所要实现的功能有,如果有某一行或者某一列或者是对角线上有三个元素相同,若为’*‘则玩家获胜,若为’#‘则为电脑获胜,如果棋盘满了,没有以上情况,即为平局。代码如下:
char IsWin(char board[ROW][COL], int row, int col)
{
//1. 判断输赢
int i = 0;
int j = 0;
int flag = 0;
for (i = 0; i < row; i++) //判断行是否有三个相同元素 如果有直接结束函数并返回相应的值
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
{
if (board[i][0] == '*')
{
return '*';
}
else if (board[i][0] == '#')
{
return '#';
}
}
}
for (i = 0; i < row; i++) //判断对角线是否有三个相同元素 如果有直接结束函数并返回相应的值
{
if( (board[0][0] == board[1][1] && board[1][1] == board[2][2])||(board[0][2])==board[1][1]&&board[1][1]==board[2][0] )
{
if (board[1][1] == '*')
{
return '*';
}
else if (board[1][1] == '#')
{
return '#';
}
}
}
for (j = 0; j < col; j++) //判断列是否有三个相同元素 如果有直接结束函数并返回相应的值
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j])
{
if (board[0][j] == '*')
{
return '*';
}
else if (board[0][j] == '#')
{
return '#';
}
}
}
for (int i = 0; i < row; i++) //判断棋盘是否已满
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
flag = 1;
}
}
}
if (flag)
{
return 'C';
}
else
return '\0';
}
这三个函数的功能设计好后,将它们整合到一个循环当中实现下棋。
while (1) //下棋
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
ComputerMove(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");
}
}
当返回值不是’C‘时终止循环,并将返回值进行判断输赢情况。游戏结束后,即调用一次game()函数,之后跳出switch继续进行游戏的选择。
测试文件中代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include"game1.h"
//打印菜单
void Menu()
{
printf("******************\n");
printf("******1.play *****\n");
printf("******0.exit *****\n");
printf("******************\n");
}
void game()
{
char board[ROW][COL];
//初始化棋盘
InItboard(board,ROW,COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
int ret = 0;
while (1) //下棋
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
ComputerMove(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");
}
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
Menu();
printf("请选择:\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("输入有误,请重新选择:");
break;
}
} while (input);
return 0;
}
游戏源文件中,代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include"game1.h"
void InItboard(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++)
{
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("|");
}
printf("\n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
printf("\n");
}
}
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");
}
}
}
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;
}
}
}
char IsWin(char board[ROW][COL], int row, int col)
{
//1. 判断输赢
int i = 0;
int j = 0;
int flag = 0;
for (i = 0; i < row; i++) //判断行是否有三个相同元素 如果有直接结束函数并返回相应的值
{
if (board[i][0] == board[i][1] && board[i][1] == board[i][2])
{
if (board[i][0] == '*')
{
return '*';
}
else if (board[i][0] == '#')
{
return '#';
}
}
}
for (i = 0; i < row; i++) //判断对角线是否有三个相同元素 如果有直接结束函数并返回相应的值
{
if( (board[0][0] == board[1][1] && board[1][1] == board[2][2])||(board[0][2])==board[1][1]&&board[1][1]==board[2][0] )
{
if (board[1][1] == '*')
{
return '*';
}
else if (board[1][1] == '#')
{
return '#';
}
}
}
for (j = 0; j < col; j++) //判断列是否有三个相同元素 如果有直接结束函数并返回相应的值
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j])
{
if (board[0][j] == '*')
{
return '*';
}
else if (board[0][j] == '#')
{
return '#';
}
}
}
for (int i = 0; i < row; i++) //判断棋盘是否已满
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
flag = 1;
}
}
}
if (flag)
{
return 'C';
}
else
return '\0';
}
头文件中的代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3
void InItboard(char board[ROW][COL], int row, int col);
void DisplayBoard(char board[ROW][COL], int row, int col);
void PlayerMove(char board[ROW][COL], int row, int col);
void ComputerMove(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);
在最后编译时,这三个文件会整合到一起。
我们来测试一下:
由于作者初学,能力还有限,这个电脑动作功能不是很智能,在未来作者能力提升后,会对游戏进行改进。希望大家理解,如果我的代码哪里有问题,希望大家指出来!让我们共同进步,这次的三子棋就到这里了,以后我会陆续更新其他的文章,感谢大家支持!