学习了C语言中的二维数组,本照着学以致用的原则,现在利用对二维数组的操作来实现一个简单版的三子棋游戏。
三子棋其实我们都玩过,在我们这边又叫"一条龙"。就是一个九空格,下棋的双方依次在九个空格里面下棋,直到有一方在九宫格的某一行或者某一列,或者对角线下了同样的棋,那么这一方就会取得胜利。
如下图:
创建文件
这里需要三个文件:
- test.c 用于测试游戏的逻辑
- game.c 用于游戏代码的实现
- game.h 用于游戏代码的声明(函数声明、符号定义)
游戏逻辑分析
1、写出游戏主逻辑
2、创建并初始化棋盘
3、打印棋盘
4、玩家下棋
5、电脑下棋
6、判断输赢
第一步:写出游戏主逻辑(test.c)
首先需要创建个menu()菜单,菜单里面包含三子棋游戏。玩家选择1表示玩游戏,玩家选择0表示退出游戏,所以需要switch语句。如果玩家玩了一次,感觉不过瘾,继续选择1,然后接着玩游戏,所以这里需要do...while语句。
代码实现:
game.h文件
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
test.c
#include "game.h"
void menu()
{
printf("**********************************\n");
printf("********* 1. 玩游戏 *************\n");
printf("********* 0.退出游戏 *************\n");
printf("**********************************\n");
}
void game()
{
printf("玩游戏\n");
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
//这里是整个游戏的函数。
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误!\n");
break;
}
} while(input);
return 0;
}
测试:
第二步:创建并初始化棋盘
棋盘的样子:
创建棋盘,很简单,无非就是创建一个3行3列的二维数组。那如何初始化棋盘呢?如上图,其实也很简单就是在每一个格格里面用空格填充就可以了。
代码实现:
test.c
#include "game.h"
void menu()
{
printf("**********************************\n");
printf("********* 1. 玩游戏 *************\n");
printf("********* 0.退出游戏 *************\n");
printf("**********************************\n");
}
void game()
{
char board[ROW][COL] = {
0 };
InitBoard(board,ROW,COL);
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 2:
printf("退出游戏\n");
break;
default:
printf("选择错误!\n");
break;
}
} while(input);
return 0;
}
game.c
#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] = " ";
}
}
}
game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define ROW 3
#define COL 3
//声明初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);
第三步:打印棋盘(版本一:代码有局限性,但是可以使用)
test.c
#include "game.h"
void menu()
{
printf("**********************************\n");
printf("********* 1. 玩游戏 *************\n");
printf("********* 0.退出游戏 *************\n");
printf("**********************************\n");
}
void game()
{
char board[ROW][COL] = {
0 };
//初始化棋盘
InitBoard(board,ROW,COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
}
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误!\n");
break;
}
} while(input);
return 0;
}
game.c
#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 DisplayBoard(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");
}
}
}
game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.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);
其实可以发现,这里的打印期盼是有局限形的。因为输出的格式我们是写死的,不灵活,所以这个是个思路,但是不完美。我们可以按照下面的第二版本的来写。
第三步:打印棋盘(版本二:具有灵活性,推荐使用)
game.c
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)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
}
第四步:玩家下棋
这一步实现玩家下棋,并且玩家每下一步棋后需要在打印棋盘。我们想一想下棋是两个人游戏,玩家下过之后,就需要电脑下棋,然后玩家下,电脑下...一直循环往复,直到判断出一方输赢然后停止游戏。那这个就需要在一个while循环语句中。
代码如下:(重复代码已省略)
test.c
//玩家下棋
while (1)
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
}
game.h
//玩家下棋
void PlayerMove(char baord[ROW][COL], int row, int col);
game.c
//玩家下棋
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
//判断坐标输入是否合法
while (1)
{
printf("玩家下棋:>\n");
printf("请输入坐标:>");
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");
}
}
}
第五步:电脑下棋
这里实现电脑下棋采用随机的方式进行下棋。所以说需要引入几个关于时间,生成随机数的库函数。除此之外其它思路和玩家下棋思路一样。
代码如下:(重复代码已省略)
test.c
...
int main()
{
srand((unsigned int)time(NULL));
...
return 0;
}
game.h
...
#include <stdlib.h>
#include <time.h>
...
//声明电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
game.c
//电脑下棋
...
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:>\n");
int x = 0;
int y = 0;
while (1)
{
//随机生成横坐标 ,范围是0~2
x = rand() % row;
//随机生成纵坐标 ,范围是0~2
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
第六步:判断输赢
判断输赢的动作应该在玩家或者电脑下过棋之后的动作。
判断输赢有以下几个内容:
- 玩家赢
- 电脑赢
- 平局
- 继续游戏
其中赢,又分为几部分:
任意一列全部一样为赢
任意一行全部一样为赢
对角线全部一样为赢
test.c
#include "game.h"
void menu()
{
printf("**********************************\n");
printf("********* 1. 玩游戏 *************\n");
printf("********* 0.退出游戏 *************\n");
printf("**********************************\n");
}
void game()
{
char ret = 0;
char board[ROW][COL] = {
0 };
//初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisplayBoard(board, ROW, COL);
//电脑下棋
ComputerMove(board, ROW, COL);
//判断输赢
if (ret != 'C')
{
break;
}
DisplayBoard(board, ROW, COL);
}
if (ret == '*')
{
printf("玩家赢\n");
DisplayBoard(board, ROW, COL);
}
else if (ret == '#')
{
printf("电脑赢\n");
DisplayBoard(board, ROW, COL);
}
else
{
printf("平局\n");
DisplayBoard(board, ROW, COL);
}
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误!\n");
break;
}
} while(input);
return 0;
}
game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#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 baord[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);
game.c
#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 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)
{
int j = 0;
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");
printf("请输入坐标:>");
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)
{
printf("电脑下棋:>\n");
int x = 0;
int y = 0;
while (1)
{
//随机生成横坐标 ,范围是0~2
x = rand() % row;
//随机生成纵坐标 ,范围是0~2
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//如果棋盘满了返回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;
}
//判断输赢
char IsWin(char board[ROW][COL], 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][1] != ' ')
{
return board[i][1];
}
}
//判断是否为列的赢
int j = 0;
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
{
return board[1][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 'C';
}
全部代码展示
test.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu()
{
printf("*****************************\n");
printf("******1. 进入游戏 0. 退出****\n");
printf("*****************************\n");
}
void game()
{
char ret = 0;
char board[ROW][COL] = {
0 };
//初始化棋盘的函数
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//下棋
while (1)
{
//玩家下棋
PlayerMove(board,ROW,COL);
//判断输赢
ret = IsWin(board,ROW,COL);
if (ret != 'C')
{
break;
}
DisplayBoard(board, ROW, COL);
//电脑下棋
ComputeMove(board,ROW,COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisplayBoard(board, ROW, COL);
}
if (ret == '*')
{
printf("玩家赢\n");
DisplayBoard(board, ROW, COL);
}
else if (ret == '#')
{
printf("电脑赢\n");
DisplayBoard(board, ROW, COL);
}
else
{
printf("平局\n");
DisplayBoard(board, ROW, COL);
}
}
int main()
{
srand((unsigned int)time(NULL));//设置随机数的生成起点
int input = 0;
do
{
menu();
printf("请选择>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误\n");
break;
}
} while (input);
return 0;
}
game.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define ROW 3
#define COL 3
#include <stdlib.h>
#include <time.h>
//初始化棋盘
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 ComputeMove(char board[ROW][COL], int row, int col);
//判断输赢,包含四种情况:
//玩家赢-'*'
//电脑赢-'#'
//平局-'Q'
//继续-'C'
char IsWin(char board[ROW][COL], int row, int col);
game.c
#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 DisplayBoard(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 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");
printf("请输入坐标:>");
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 ComputeMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:>\n");
int x = 0;
int y = 0;
while (1)
{
x = rand() % row; //0~2
y = rand() % col; //0~2
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//平局的函数,返回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;
}
//判断输赢
char IsWin(char board[ROW][COL], 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][1] != ' ')
{
return board[i][1];
}
}
//判断在列中赢的
int j = 0;
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
{
return board[1][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 'C';
}
效果展示:
总结
三子棋游戏可以很好的锻炼二维数组的知识。此游戏的根本就是对二维数组的操作。此代码只是实现了最基本的游戏功能,部分代码还可以优化,还可以更加灵活,比如说:可以让电脑玩家更加智能。从而是游戏增加难度等等。