在该项目当中,首先我们要分析应该用什么文件存放什么功能的代码:
1.我们分析得出要用 test.c 来测试游戏逻辑是否正确,main函数写在 test.c 中。
2.用 game.c 来对游戏中功能代码的实现。
3.用 game.h 来存放游戏代码函数的声明,库函数的声明,宏常量的定义。
1.该项目我们首先要写出一个菜单界面来显示逻辑选项,我们要通过不同的选项写不同的代码。可以分为进入游戏,退出游戏两大版块。
2.我们通过菜单界面选择进入游戏后,应该编写一个游戏的函数。我们的三字棋棋盘界面应该长这样子的:
应该用一个二维数组来实现该棋盘。
3.有了棋盘后,我们就应该写一个玩家下棋的代码,实现玩家下棋,还要写出一个下棋后打印的代码,实现下棋后可以打印在屏幕上的功能。
4.然后我们还要写一个电脑下棋的代码,因为本人技术有限,所以只能写出电脑随机下棋的笨代码。
5.最后我们还要对下棋后的棋局进行判断,判断是否有一方胜利或者平局亦或者还没有决出胜负,并进行相应的处理。
思路理清楚了,接下来就让我们一步一步来实现这一个三字棋项目。
我们先写出自己喜欢的菜单界面函数 menu,将写好的代码放在main函数里头,因为我们不只想玩一局游戏,所以将 menu 放进 do { } while 循环里面。并用switch语句来对逻辑的判断,定义一个变量 input 来作为 switch 语句的判断常量,并且 input 也可以用作while 循环的判断成分,因为 我们在 meun 函数中设置 0 为退出游戏,是为了后面只定义一个变量input ,巧妙的作为循环判断与 switch 语句的判断。
void menu() {
printf("******************************\n");
printf("********** 1 . play **********\n");
printf("********** 0 . exit **********\n");//选择 0 退出是为了后面只定义一个变量input ,可以作为循环判断与switch
printf("******************************\n");
}
int main() {
int input = 0;
do {
menu();//菜单
printf("请选择:>");
scanf("%d", &input);
switch (input) {
case 0:
printf("退出游戏成功\n");
break;
case 1:
break;
default:
printf("输入错误\n");
}
} while (input);
return 0;
}
当我们在菜单界面中选择 1 进入游戏后,这个时候就要写一个 游戏函数 game 来补充逻辑,
进入 game 函数后,我选择了用二维数组来存放该棋盘 ,创建数组后,就要对该数组进行初始化并把棋盘打印出来,用 InitBoard 函数来对数组初始化,DispalyBoard 函数来打印数组。
并且因为二维数组的行和列在该项目中会广泛用到,所以我们将他定为宏常量,存放在 game.h 中。
void game() {
char board[ROW][COL] = { 0 };
//棋盘初始化
InitBoard(board, ROW, COL);
DispalyBoard(board, ROW, COL);
}
InitBoard 函数是属于来实现游戏功能的代码,所以我打算将他写在 play.c 文件中,
我选择用 ‘空格’ 来实现对数组的初始化,用嵌套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] = ' ';
}
}
}
我将要在 DispalyBoard 函数中打印出棋盘的形状 ,预览图如下:
分析得,我可以把这个棋盘分为三个部分,一个部分包含三个空格两条竖线,加上分割线,最后一部分不需要分割线。
所以写得代码如下:
void DispalyBoard(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");
int j = 0;
for (j = 0; j < col; j++) {
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
数组初始化与棋盘打印完后,我们就要来考虑怎么让玩家下棋的代码了。将代码写在PlayMove函数内,
先让玩家输入想下的棋子的位置,再用一个for循环来判断,该位置是否为 ‘空格’ ,如果为 ‘空格’ 表示该位置已经有人落子了不可以再落到该位置,所以要重新输入位置,所以把判断存放在 while 循环中。如果该位置不为 ‘空格’ 就落子到该位置,如果玩家输入的坐标超出棋盘的范围,就提升输入错误重新输入 。我规定玩家的棋子用 ‘*’ 来表示。
void PlayMove(char board[ROW][COL], int row, int col) {
int i = 0;
int j = 0;
while (1) {
printf("玩家请输入:>\n");
printf("请输入坐标:>");
scanf("%d %d", &i, &j);
if (i <= ROW && i > 0 && j <= COL && j > 0) {
if (board[i - 1][j - 1] == ' ') {
board[i - 1][j - 1] = '*';
break;
}
else {
printf("坐标被占用不能下该位置,请选择其他位置\n");
printf("\n");
}
}
else {
printf("坐标非法请重新输入\n");
}
printf("\n");
}
}
在玩家下棋后,我们要顺便用 DispalyBoard 函数棋与棋盘打印出来,在继续考虑电脑下棋的代码。
电脑下棋我们可以写个低配版,让电脑随机下棋,不考虑算法在内。用到 rand()函数 ,电脑生成随机数,然后需要在main函数设定随机数起点,srand((unsigned int)time(NULL));//设置生成随机数的起点
。将生成的随机数模上 行和列 就会生成在 0 ~ 2 之内的随机数。下棋的判断与玩家一致。
void ComputerMove(char board[ROW][COL], int row, int col) {
printf("电脑下棋:>\n");
int i = 0;
int j = 0;
while (1) {
i = rand() % row;//0 ~ 2
j = rand() % col;//0 ~ 2
if (board[i][j] == ' ') {
board[i][j] = '#';
break;
}
}
}
在玩家和电脑都下棋后,我们需要对这时候的棋局进行判断,看是否有决出胜负,我们可以先规定 如果是玩家赢 返回 * ,电脑赢 返回 # , 平局 返回 Q ,游戏继续 返回 A 。
判断思路:
先对行进行判断,判断是否有三个棋子连在一起的情况,然后再对列判断,最后对对角线判断。我先将判断的代码写死,之后有时间再来将他写活。
char Iswin(char board[ROW][COL] , int row,int col) {
//判断数组
//先判断行,再来列,再来对角线
int i = 0;
int j = 0;
int indxtx = 0;
int indxty = 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 (j = 0; j < COL; j++) {
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[2][j] != ' ')
return board[0][j];
}
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)) {
return 'Q';
}
return 'A';
}
当判断没有人赢的情况下,就来判断是否平局,我们来写个平局的代码 IsFull()。如果为平局返回 Q
如果不是平局的话返回 A
判断平局要判断该数组是否满了,如果满了且元素不为 ‘空格’ ,则为平局,返回 1 。 反之 ,返回 0 。
//判断数组是否满了,满了返回 1,不满返回 0
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 函数里,将上面写到的游戏函数给调用,将游戏函数串起来,并且在game 函数 末尾,对判断输赢的 Iswin 函数返回值进行判断,打印出结果。
void game() {
char board[ROW][COL] = { 0 };
//棋盘初始化
InitBoard(board, ROW, COL);
DispalyBoard(board, ROW, COL);
char ret = ' ';
while (1) {
PlayMove(board,ROW,COL);
DispalyBoard(board, ROW, COL);//下棋后打印
printf("\n");
//判断输赢
ret = Iswin(board , ROW,COL);
if (ret != 'A') {//有结果了先跳出循环,再来判断结果什么
break;
}
ComputerMove(board, ROW, COL);//电脑下棋
DispalyBoard(board, ROW, COL);
printf("\n");
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'A') {
break;
}
}
if (ret == '*') {
printf("玩家赢了...\n\n");
}
else if (ret == '#') {
printf("电脑赢了...\n\n");
}
else if (ret == 'Q') {
printf("平局...\n\n");
}
}
在这个项目中会有不少函数的声明,所以我把所有函数声明写在一个 game.h 头文件里,直接调用该头文件即可。
#pragma once
#include
#include
#include
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayMove( char board[ROW][COL],int row,int col);
//打印棋盘
void DispalyBoard(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);
//判断数组是否满了
int IsFull(char board[ROW][COL], int row, int col);
因为本人技术
#pragma once
#include
#include
#include
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayMove( char board[ROW][COL],int row,int col);
//打印棋盘
void DispalyBoard(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);
//判断数组是否满了
int IsFull(char board[ROW][COL], int row, int col);
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
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 DispalyBoard(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 DispalyBoard(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");
int j = 0;
for (j = 0; j < col; j++) {
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
//玩家下棋
void PlayMove(char board[ROW][COL], int row, int col) {
int i = 0;
int j = 0;
while (1) {
printf("玩家请输入:>\n");
printf("请输入坐标:>");
scanf("%d %d", &i, &j);
if (i <= ROW && i > 0 && j <= COL && j > 0) {
if (board[i - 1][j - 1] == ' ') {
board[i - 1][j - 1] = '*';
break;
}
else {
printf("坐标被占用不能下该位置,请选择其他位置\n");
printf("\n");
}
}
else {
printf("坐标非法请重新输入\n");
}
printf("\n");
}
}
void ComputerMove(char board[ROW][COL], int row, int col) {
printf("电脑下棋:>\n");
int i = 0;
int j = 0;
while (1) {
i = rand() % row;//0 ~ 2
j = rand() % col;//0 ~ 2
if (board[i][j] == ' ') {
board[i][j] = '#';
break;
}
}
}
//玩家赢 - *
//电脑赢 - #
//平局 - Q
//游戏继续 - A
char Iswin(char board[ROW][COL] , int row,int col) {
//判断数组
//先判断行,再来列,再来对角线
int i = 0;
int j = 0;
int indxtx = 0;
int indxty = 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 (j = 0; j < COL; j++) {
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[2][j] != ' ')
return board[0][j];
}
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)) {
return 'Q';
}
return 'A';
}
//判断数组是否满了,满了返回 1,不满返回 0
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;
}
#define _CRT_SECURE_NO_WARNINGS
#include
#include "game.h"
//创建数组,数组初始化 : 空 格 ,打印表格
void menu() {
printf("******************************\n");
printf("********** 1 . play **********\n");
printf("********** 0 . exit **********\n");//选择 0 退出是为了后面只定义一个变量input ,可以作为循环判断与switch
printf("******************************\n");
}
void game() {
char board[ROW][COL] = { 0 };
//棋盘初始化
InitBoard(board, ROW, COL);
DispalyBoard(board, ROW, COL);
char ret = ' ';
while (1) {
PlayMove(board,ROW,COL);
DispalyBoard(board, ROW, COL);//下棋后打印
printf("\n");
//判断输赢
ret = Iswin(board , ROW,COL);
if (ret != 'A') {//有结果了先跳出循环,再来判断结果什么
break;
}
ComputerMove(board, ROW, COL);//电脑下棋
DispalyBoard(board, ROW, COL);
printf("\n");
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'A') {
break;
}
}
if (ret == '*') {
printf("玩家赢了...\n\n");
}
else if (ret == '#') {
printf("电脑赢了...\n\n");
}
else if (ret == 'Q') {
printf("平局...\n\n");
}
}
int main() {
srand((unsigned int)time(NULL));//设置生成随机数的起点
int input = 0;
do {
menu();//菜单
printf("请选择:>");
scanf("%d", &input);
switch (input) {
case 0:
printf("退出游戏成功\n");
break;
case 1:
game();
break;
default:
printf("输入错误\n");
}
} while (input);
return 0;
}