目录
简易版
主函数部分
我们先创建两个头文件,一个test.c, 一个game.c, 一个源文件game.h。
我们的主函数和游戏实现的函数引用放再test.c。
函数的声明放在game.h。
函数的实现放在game.c。
第一步主函数:
要实现游戏我们要先让他运行一次,然后我们输入选择玩还是不玩。
打印一个菜单,然后选择1 / 0,选择错误,提示一下,然后重新选择。
这样写一个是方便别人看,有时候代码太长了阅读感不是很好,所以分模块封装,一个是也可以当知识产权的保护。
游戏部分
主函数部分写完了下面就是游戏部分的实现。
首先我们创建一个数组字符数组char board[3][3],因为我们下棋里面要放*和#,所以使用字符数组,然后三子棋嘛,就创建一个3 * 3 的格子。
然后将这个二维数组全部初识化为空格,再把棋盘打印出来。
初识化棋盘
打印棋盘
代码实现
玩家输入
玩家要输入两个值,所以先创建整型的X Y变量,然后用scanf读取。
玩家习惯的应该第一个坐标是1 1,但是数组的坐标是0 0, 所以再读取完后我们再给他加个1。
然后判断玩家输入的是不是再1~3之间,也就是判断合法性。
再判断玩家输入的这个坐标是否为空格,也就是是否被占用。
这些判断如果不成立就需要重新输入,所以这里应该是一个循环
电脑输入
电脑输入就要生成随机数,我们会用到srand,只要调用一次,所以我们在主函数里面加上。
生成的是0~2的数字,表示数组代表的坐标,所以不用判断合法性。
这里也要判断是否被占用。
判断条件失败的话要重新产生随机数,所以这里也是个循环。
判断输赢
下完一次棋无非有四种情况:
- 玩家赢了
- 电脑赢了
- 平局
- 游戏继续
我们写一个函数,判断玩家赢了输出*。
电脑赢了输出#。
平局输出“Q”。
游戏继续输出“C”。
判断输赢:
三行是否相等:board[0][0] 和 board[0][1] 和 board[0][2] 这是第一行,用for循环3次,把三行都遍历一遍。
三列是否相等:board[0][0] 和 board[1][0] 和board[2][0] 这是第一列,用for循环3次,把三列都遍历一遍。
对角线是否相等: board[0][0] 和 board[1][1] 和 board[2][2]这是正对角,board[0][2] 和 board[1][1]
和board[2][0] 这是反对角是否相等。
上面判断完相等之后并且不能等于空格。
判断平局:
将整个数组遍历一遍,看看数组里面是否还有空格,没有了就是平局。
如果以上三个都不成立就是游戏继续。
我们在玩家下完后和电脑下完后都判断一下,输出的是C就继续游戏,不是C就跳出循环,打印结果。
当判断结果是C的时候,要继续游戏,所以应该是个循环。
完整代码如下:
test.c部分
#include "game.h"
void game()
{
char ret = 0;
char board[3][3];
initialization(board, 3, 3); //初识化数组
print(board, 3, 3); //打印棋盘
while (1)
{
player_move(board, 3, 3); //玩家输入
ret = judge_win_or_lose_board(board, 3, 3); //判断输赢
if (ret != 'C')
{
break;
}
computer_move(board, 3, 3); //电脑输入
ret = judge_win_or_lose_board(board, 3, 3); //判断输赢
if (ret != 'C')
{
break;
}
}
if (ret == '*')
{
printf("玩家赢了!\n");
}
else if (ret == '#')
{
printf("电脑赢了!\n");
}
else if (ret == 'Q')
{
printf("平局!\n");
}
}
game.c部分
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void meun()
{
printf("*******************\n");
printf("**** 1. play ****\n");
printf("**** 0. exit ****\n");
printf("*******************\n");
}
void initialization(char board[3][3], int row, int col)
{
for (int i = 0; i < 3; i++) //通过两层for循环遍历整个数组,然后全部初识化为空格
{
for (int j = 0; j < 3; j++)
{
board[i][j] = ' ';
}
}
}
void print(char board[3][3], 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) //最后一个 | 不用打印, 所以减1
{
printf("|");
}
}
printf("\n"); //第一行打印完换行
}
}
}
void player_move(char board[3][3], int row, int col)
{
int x, y; //创建两个变量用来储存要输入的值
while (1)
{
printf("(第一个坐标为1 1,后面依次类推) 玩家输入:<\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= 3 && y >= 1 && y <= 3) //判断合法性
{
if (board[x - 1][y - 1] == ' ') // 判断坐标是否被占用
{
board[x - 1][y - 1] = '*';
break; //替换成功跳出循环
}
else
{
printf("此坐标被占用,请重新选择!\n"); //被占用提示一下重新输入
}
}
else
{
printf("输入错误,请重新输入!\n"); //坐标不合法提示一下,重新输入
}
}
}
void computer_move(char board[3][3], int row, int col)
{
printf("电脑输入!\n");
while (1)
{
int x = rand() % row; //产生0~2的数字
int y = rand() % col; //产生0~2的数字
if (board[x][y] == ' ')//判断是否被占用
{
board[x][y] = '#';
break;
}
}
}
int already_expired(char board[3][3], 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; //还有空格返回0
}
}
return 1; //如果没空格了返回1
}
char judge_win_or_lose_board(char board[3][3], 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][2] != ' ')
{
return board[i][0];
}
}
for (i = 0; i < row; i++) //判断三列
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[2][i] != ' ')
{
return board[0][i];
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[1][1]; //判断对角
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[1][1]; //判断对角
if (already_expired(board, row, col) == 1)
{
return 'Q'; //判断平局
}
return 'C'; //游戏继续
}
game.h部分
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//打印菜单
void meun();
//初始化数组
void initialization(char board[3][3], int row, int col);
//打印棋盘
void print(char board[3][3], int row, int col);
//玩家下棋
void player_move(char board[3][3], int row, int col);
//电脑下棋
void computer_move(char board[3][3], int row, int col);
//判断输赢
char judge_win_or_lose_board(char board[3][3], int row, int col);
//判断平局
int already_expired(char board[3][3], int row, int col);
优化版
主函数部分
主函数部分和基础版的一样,其中肯定也要产生随机数和菜单,我们直接将基础版的复制过来。
我们要优化的部分是玩家不仅仅限于三个格子,还可以产生更大的格子,所以我们的棋盘要改为可以变换的,判断方式也要改。
主函数部分还是一样。
游戏部分
第一步肯定也是创建一个字符数组,然后初识化,我们的数组不能直接写死,所以在game.h部分定义两个常量,来决定数组的大小。
然后我们创建数组的时候把数组创大一点,在ROW的基础上加个4,到判断的时候用的上。
一:初始化数组
这个和基础版也是一样,将整个数组都初识化为空格。
就是注意在游戏传参的时候要传ROW+4这样才是整个数组。
二:打印棋盘
黑色部分是我们需要用到的格子,红色部分是我们留着后面判断用的,所以我们要把棋盘打印出来,并且要将对应的数组放入格子中,我们在基础版上要进行一定的更改。
可以看出我们第一个格子的位置是2-2, 最后一个是6-6,在基础版上我们是从0开始打印的,所以在这里我们要从二开始,然后传进去的是5,但是最后一个是6,所以后面要在ROW的基础上加个2
其他的打印空格+字符+空格+ | 是一行的第一部分不变,--- + |是第一行的第二部分也不变。
三:玩家输入
玩家输入的第一个肯定是1 1,我们的下标指向的却是2 2,所以我们在玩家输入的基础上还要加上一个1,。
在判断他的合法性,是否在2 到 ROW+1中。
在判断是否是空格。
输入错误或者被占用要重新输入,所以也是个循环。
四:电脑输入
电脑输入我们让他产生随机数是2~6就行,所以合法性不用判断,只需要判断是否被占用。
五:判断输赢
这次我们不能像之前一样把把所有可以赢的格子都表示出来,那么我们怎么判断呢。
我们可以从玩家和电脑输入的坐标去找,上下左右对角是否相等。如图:
大上下左右:
大对角:
小上下左右:
小对角:
然后用if语句把他们都写进去就行,那么问题来了,怎么知道玩家和电脑下的坐标呢,出来电脑和玩家的输入函数就消失了,那么我们直接写一个函数,然后再输入函数内调用他,那么我们的输入函数不能再使用void类型了,要改为char型。
上面是玩家输赢,接下来就是平局了,和之前一样把整个数组遍历一遍看看有没有空格。
以上情况都不是就是平局。
然后再玩家和电脑输入后都判断一下,将判断结果返回。所以改完之后变这样。
后面再判断输出的是 # 、 * 、 Q 、C中的哪一个,然后进行选择。
完整代码如下:
test.c部分:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void game()
{
char ret = 0;
char board[ROW + 4][COL + 4];
init_board(board, ROW + 4, COL + 4); //初识化整个数组
print_borad(board, ROW, COL); //打印棋盘
while (1)
{
ret = player_move(board, ROW, COL); //玩家输入
if (ret != 'C')
{
break;
}
ret = computer_move(board, ROW, COL); //电脑输入
if (ret != 'C')
{
break;
}
}
if (ret == '#')
{
printf("电脑赢了!!\n");
print_borad(board, ROW, COL);
}
else if (ret == '*')
{
printf("玩家赢了!!\n");
print_borad(board, ROW, COL);
}
else if (ret == 'Q')
{
printf("平局!!\n");
print_borad(board, ROW, COL);
}
}
int main()
{
int input = 0;
srand((unsigned int)(time(NULL)));
do {
meun();
printf("请选择是否游戏\n");
scanf("%d", &input);
printf("\n");
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏");
break;
default:
printf("选择错误请重新选择\n");
break;
}
} while (input);
return 0;
}
game.c部分:
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void meun()
{
printf("*******************\n");
printf("**** 1. play ****\n");
printf("**** 0. exit ****\n");
printf("*******************\n");
}
void init_board(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 print_borad(char board[ROW][COL], int row, int col)
{
int i = 2;
int j = 2;
for (i = 2; i < row + 2; i++) //传入的是5,下标从2开始放入,到7停止,
{
//打印第一行第一部分
for (j = 2; j < col + 2; j++)
{
printf(" %c ", board[i][j]);//此时第一个下标为2 - 2
if (j < col + 1) //跟基础版一样,最后一列的 | 不用打印,本来+2现在-1就变成+1.
{
printf("|");
}
}
printf("\n");
if (i < row + 1) //跟基础版一样,最后一行的 --- 不用打印,本来+2现在-1就变成+1.
{
//打印第一行第二部分--- + |
for (j = 2; j < col + 2; j++)
{
printf("---");
if (j < col + 1) //同上
{
printf("|");
}
}
printf("\n");
}
}
}
int already_expired(char board[ROW][COL], int row, int col)
{
int i = 2;
int j = 2;
//遍历的数组是我们使用的数组,不是整个,所以是从2-ROW+2中
for (i = 2; i < row + 2; i++)
{
for (j = 2; j < col + 2; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
char judge(char board[ROW][COL], int x, int y)
{
if (board[x][y] == board[x][y + 1] && board[x][y] == board[x][y + 2] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x][y - 1] && board[x][y] == board[x][y - 2] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x + 1][y] && board[x][y] == board[x + 2][y] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x - 1][y] && board[x][y] == board[x - 2][y] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x + 1][y + 1] && board[x][y] == board[x + 2][y + 2] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x - 1][y - 1] && board[x][y] == board[x - 2][y - 2] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x - 1][y + 1] && board[x][y] == board[x - 2][y + 2] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x + 1][y - 1] && board[x][y] == board[x + 2][y - 2] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x - 1][y] && board[x][y] == board[x + 1][y] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x][y - 1] && board[x][y] == board[x][y + 1] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x + 1][y - 1] && board[x][y] == board[x - 1][y + 1] && board[x][y] != ' ')
return board[x][y];
if (board[x][y] == board[x - 1][y - 1] && board[x][y] == board[x + 1][y + 1] && board[x][y] != ' ')
return board[x][y];
if (already_expired(board, ROW, COL))
{
return 'Q';
}
return 'C';
}
char player_move(char board[ROW][COL], int row, int col)
{
printf("玩家下棋:<"); //提示玩家可以下棋了
int x = 0;
int y = 0;
while (1)
{
scanf("%d %d", &x, &y);
x = x + 1; //在玩家输入的基础上+1
y = y + 1;
//判断玩家输入的是否正确
if (x >= 2 && x <= col + 1 && y >= 2 && y <= col + 1)
{
//判断玩家输入是否被占用
if (board[x][y] == ' ')
{
board[x][y] = '*';
break;
}
else
{
printf("此坐标被占用,请重新选择!\n");
}
}
else
{
printf("输入错误,请重新输入!\n");
}
}
print_borad(board, ROW, COL); //输入完打印一下棋盘。
return judge(board, x, y);
}
char computer_move(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑输入!\n");
while (1)
{
x = rand() % row + 2; //+2表示产生从0-4的数字变成2-6。
y = rand() % col + 2;
//判断是否被占用
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
print_borad(board, ROW, COL); //输入完打印一下棋盘。
return judge(board, x, y);
}
game.h部分:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 5
#define COL 5
void meun();
void init_board(char board[ROW][COL], int row, int col);
void print_borad(char board[ROW][COL], int row, int col);
int already_expired(char board[ROW][COL], int row, int col);
char judge(char board[ROW][COL], int x, int y);
char player_move(char board[ROW][COL], int row, int col);
char computer_move(char board[ROW][COL], int row, int col);