目录
1.呈现初始菜单与玩家的选择面板
2.呈现初始棋盘
3.玩家落子
4.电脑落子
5.判断胜负
6.呈现最终结果
7.最终代码展示
8.心得体会
正文
1.呈现初始菜单
游戏初始菜单是面向玩家的第一个面板,必须让玩家清晰的知道下一步要怎么做,有什么选择,因此我搭建了如下菜单。
#include<stdio.h>
void menu()
{
printf("*************菜单*************\n");
printf("******1.Play******0.Exit******\n");
printf("******************************\n");
}
void test()
{
menu();
}
int main()
{
test();
return 0;
}
注:在主函数中进入游戏调试的test函数,再从test函数进入菜单menu函数,之后的游戏函数也是在test函数中实现的。
这里想要实现的是玩家输入1为开始游戏,输入0为退出游戏。
那么,菜单呈现之后就要实现让玩家选择的功能了。玩家可以选择开始游戏或者退出游戏,如果玩家输入了1和0以外的数字,系统则会报错并让玩家重新选择。有多种情况,可以用一个循环和判断的嵌套来实现。如下:
#include<stdio.h>
void menu()
{
printf("*************菜单*************\n");
printf("******1.Play******0.Exit******\n");
printf("******************************\n");
}
void test()
{
menu();
int input = 0;
do
{
scanf("%d", &input);
switch (input)
{
case 1:
game();//实现游戏内容
break;
case 0:
printf("退出游戏");
break;
default:
printf("输入非法,请重新输入");
}
} while (input);
}
int main()
{
test();
return 0;
}
2.呈现初始棋盘
在玩家输入1之后,游戏开始。那么,为了更直观的游戏体验,开始我想让玩家能看到一个空棋盘,并且之后能在这个空棋盘上落子。那么,这该如何实现呢?
下面是初始化棋盘函数IntialBoard 和 呈现棋盘函数DisplayBoard的定义。
#include<stdio.h>
#include "game.h"
void InitialBoard(char arr[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
arr[i][j] = ' ';
}
}//初始化棋盘, 让数组中每一个元素都为空格' '
}
#include<stdio.h>
#include "game.h"
void DisplayBoard(char arr[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 ", arr[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");
}
}//打印棋盘,玩家下子后棋盘发生变化
✔最终打印结果:
该棋盘中n行m列对于了二维数组中的元素board[n-1][m-1]
过渡~
3.玩家落子
构建玩家落子playermove()函数:
错误版本❌:
void playermove(char arr[ROW][COL], int row, int col)
{
int x, y;
scanf("%d%d", &x, &y);
while (1)
{
if ((x >= 1 && x <= row) && (y >= 1 && y <= col))
{
if (arr[x - 1][y - 1] == ' ')
{
arr[x - 1][y - 1] = 'X';
break;
}
else
{
printf("坐标已被占用,请重新输入");
continue;
}
}
else
{
printf("坐标非法,请重新输入");
continue;
}
}
}
⭕改正版本如下:
void playermove(char arr[ROW][COL], int row, int col)
{
int x, y;
printf("请输入落子坐标(行 列):");
while (1)
{
scanf("%d%d", &x, &y);
if ((x >= 1 && x <= row) && (y >= 1 && y <= col))
{
if (arr[x - 1][y - 1] == ' ')
{
arr[x - 1][y - 1] = 'X';
break;//直到玩家下入一个棋子便跳出循环,为止
}
else
{
printf("坐标已被占用,请重新输入:");
continue;
}
}
else
{
printf("坐标非法,请重新输入:");
continue;
}
}
}
测试成功:
4.电脑落子
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
srand((unsigned int)time(NULL));
int rom=rand();
}
这是生成随机数的代码,具体原理在此不展开。如果想要获得区间(a,b)内的随机数,则可通过
rom=rand()%(b-a+1)+a 来实现。
⭕下面是我对电脑落子computermove函数的定义:
void computermove(char arr[ROW][COL], int row, int col)
{
printf("电脑走\n");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (arr[x][y] == ' ')
{
arr[x][y] = 'O';
break;
}
else
continue;
}
}//若坐标占用,则重新生成一组随机坐标,直到电脑成功下子,跳出循环,回合结束。
测试结果:
5.判断输赢
因为每次判断有四种可能的结果,分别是玩家赢、电脑赢、平局、继续, 我们用四个字符 X、O、Q、C分别来表示四种结果。我们可以定义判断函数的返回值是一个字符并且该返回值的结果有X、O、Q、C四种,根据判断函数返回值来判断本回的结果。如下:
char Judge(char arr[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0;i < row;i++)
{
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
return arr[i][0];//返回值可以是'X'和'O',返回谁就是谁赢了
}
int j = 0;
for (j = 0;j < col;j++)
{
if (arr[0][j] == arr[1][j] && arr[1][j] == arr[2][j] && arr[0][j] != ' ')
return arr[0][j];
}
if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[1][1] != ' ')
return arr[1][1];
if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[1][1] != ' ')
return arr[1][1];
if (Is_full(arr, ROW, COL) == 1)
{
return 'Q';
}
return 'C';
由于棋盘下满后才有可能平局,因此我们再构建一个函数Is_full判断棋盘是否已满,用整数返回值1/0表示。
int Is_full(char arr[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0;i < row;i++)
{
int j = 0;
for (j = 0;j < col;j++)
{
if (arr[i][j] == ' ')
return 0;
}
}
return 1;
}
--------------------------------------------------------------------------------------------------------------------------------
💚优化版💚
void game()
{
int count1 = 0;
int count2 = 0;
srand((unsigned int)time(NULL));
char board[ROW][COL] = { ' ' };
InitialBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL,NULL);
while (1)
{
playermove(board, ROW, COL, &count1);//计数器在此函数外,因此需传址
DisplayBoard(board, ROW, COL);
if (count1 >= 3)
{
if (Judge(board, ROW, COL) != 'C')
break;
}
computermove(board, ROW, COL,&count2);
DisplayBoard(board, ROW, COL);
if (count2 >= 3)
{
if (Judge(board, ROW, COL) != 'C')
break;
}
}
Result(Judge(board, ROW, COL));
printf("选择继续游戏或退出:\n");
}
void computermove(char arr[ROW][COL], int row, int col,int* n)
{
printf("电脑走\n");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (arr[x][y] == ' ')
{
arr[x][y] = 'O';
(*n)++;//落子后自增加1
break;
}
else
continue;
}
}
玩家下子同理,不再贴出代码段。
6.呈现最终结果
void game()
{
srand((unsigned int)time(NULL));
char board[ROW][COL] = { ' ' };
InitialBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
while (1)
{
playermove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
if (Judge(board, ROW, COL) != 'C')
break;
computermove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
if (Judge(board, ROW, COL) != 'C')
break;
}
Result(Judge(board, ROW, COL));
printf("选择继续游戏或退出:\n");
}
最后,game()函数的总体实现如上代码块所示。每一回合中某一方落子判断一次,直到有一次判断的字符结果不为'C'(既不再继续),才跳出循环,再判断(在Result函数中实现,如下代码块)该字符为‘X’ ‘O’ 'Q'中的哪一个,从而得出最终结果。
void Result(char ch)
{
switch (ch)
{
case 'X':
printf("玩家获胜\n");
break;
case 'O':
printf("电脑获胜\n");
break;
case 'Q':
printf("平局\n");
break;
}
}
测试结果:
7.最终代码展示 (有点长,可以跳过)
test.c文件
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include"game.h"
void game()
{
int count1 = 0;
int count2 = 0;
srand((unsigned int)time(NULL));
char board[ROW][COL] = { ' ' };
InitialBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL,NULL);
while (1)
{
playermove(board, ROW, COL, &count1);
DisplayBoard(board, ROW, COL);
if (count1 >= 3)
{
if (Judge(board, ROW, COL) != 'C')
break;
}
//
computermove(board, ROW, COL,&count2);
DisplayBoard(board, ROW, COL);
if (count2 >= 3)
{
if (Judge(board, ROW, COL) != 'C')
break;
}
}
Result(Judge(board, ROW, COL));
printf("选择继续游戏或退出:\n");
}
void menu()
{
printf("*************菜单*************\n");
printf("******1.Play******0.Exit******\n");
printf("******************************\n");
}
void test()
{
int input = 0;
do
{
menu();
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入非法,请重新输入:\n");
}
} while (input);
}
int main()
{
test();
return 0;
}
game.h文件(函数声明)
#define _CRT_SECURE_NO_WARNINGS 1
#define ROW 3
#define COL 3
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void InitialBoard(char arr[ROW][COL], int row, int col);
void DisplayBoard(char arr[ROW][COL], int row, int col);
void playermove(char arr[ROW][COL], int row, int col,int* n);
void computermove(char arr[ROW][COL], int row, int col,int* n);
char Judge(char arr[ROW][COL], int row, int col);
int Is_full(char arr[ROW][COL], int row, int col);
void Result(char ch);
game.c文件(函数定义)
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void Result(char ch)
{
switch (ch)
{
case 'X':
printf("玩家获胜\n");
break;
case 'O':
printf("电脑获胜\n");
break;
case 'Q':
printf("平局\n");
break;
}
}
int Is_full(char arr[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0;i < row;i++)
{
int j = 0;
for (j = 0;j < col;j++)
{
if (arr[i][j] == ' ')
return 0;
}
}
return 1;
}
char Judge(char arr[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0;i < row;i++)
{
if (arr[i][0] == arr[i][1] && arr[i][1] == arr[i][2] && arr[i][0] != ' ')
return arr[i][0];
}
int j = 0;
for (j = 0;j < col;j++)
{
if (arr[0][j] == arr[1][j] && arr[1][j] == arr[2][j] && arr[0][j] != ' ')
return arr[0][j];
}
if (arr[0][0] == arr[1][1] && arr[1][1] == arr[2][2] && arr[1][1] != ' ')
return arr[1][1];
if (arr[0][2] == arr[1][1] && arr[1][1] == arr[2][0] && arr[1][1] != ' ')
return arr[1][1];
if (Is_full(arr, ROW, COL) == 1)
{
return 'Q';
}
return 'C';
}
void computermove(char arr[ROW][COL], int row, int col,int* n)
{
printf("电脑走\n");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row;
y = rand() % col;
if (arr[x][y] == ' ')
{
arr[x][y] = 'O';
(*n)++;
break;
}
else
continue;
}
}
void playermove(char arr[ROW][COL], int row, int col,int* n)
{
printf("玩家走\n");
int x = 0;
int y = 0;
printf("请输入落子坐标(行 列):");
while (1)
{
scanf("%d%d", &x, &y);
if ((x >= 1 && x <= row) && (y >= 1 && y <= col))
{
if (arr[x - 1][y - 1] == ' ')
{
arr[x - 1][y - 1] = 'X';
(*n)++;
break;
}
else
{
printf("坐标已被占用,请重新输入:");
continue;
}
}
else
{
printf("坐标非法,请重新输入:");
continue;
}
}
}
void DisplayBoard(char arr[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 ", arr[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 InitialBoard(char arr[ROW][COL], int row, int col)
{
int i = 0;
int j = 0;
for (i = 0;i < row;i++)
{
for (j = 0;j < col;j++)
{
arr[i][j] = ' ';
}
}
}
下面让我们跟电脑来一场酣畅淋漓的较量吧!!
很显然,这个游戏难就难在怎么让电脑赢/doge
8.心得体会 🧐
经过大概两天的学习和coding最终写出这篇博客,收获颇多,在学习完函数模块后以此巩固了对知识的掌握、加深了对知识的理解。错误和bug是在所难免的,虽然寻找它和修改它的过程很艰辛,但是每修一个bug都会十分的心情愉悦。
今天的分享到此为止啦,记得点个赞噢!