主要知识点:数组,判断语句,函数,循环
目录
一.三子棋游戏规则
三子棋是一种双人对弈游戏,玩家使用不同的符号(本文章是“ * ”和“#”)在一个3×3的棋盘上交替落子。 游戏的目标是在棋盘上连成一条直线的三个符号,可以是横线、竖线或者对角线。 游戏开始时,棋盘是空的。 首先由先手玩家选择一个符号,并在棋盘上落子,接下来是后手玩家的回合,也在棋盘上落子。 双方轮流进行,直到有一方玩家连成一条直线或者棋盘下满,游戏结束。 如果棋盘下满而没有玩家连成直线,那么游戏以平局结束。
二.代码模块介绍
本文所使用代码对代码采用了分装,进而达到使代码更加简练和易读,便于观察和理解。
共分为三个模块,头文件game.h,源文件game.c和test.c
game.h:封装游戏函数的声明
game.c:游戏函数的实现
test.c :测试游戏
三. 游戏具体实现思路
1.游戏界面的实现(选择玩游戏还是退出游戏)
2.创建棋盘并打印棋盘
3.玩家以输入坐标的形式表示落子
4.电脑落子
5.判断输赢(赢,输,平局)
6.结束游戏
四.游戏界面的实现
//开始界面,进入时的菜单
void menu()
{
printf("*******************************\n");
printf("************1. play ***********\n");
printf("************0. exit ***********\n");
printf("*******************************\n");
}
编写一个menu( ) 函数,用来显示玩家进入的初始界面。
利用print( ) 函数实现对于游戏界面的打印。
和用户交互的代码如下(主要判断用户是否需要进入游戏。用户输入错误怎么办,用户选择进入游戏如何进入,拒绝进入游戏如何拒绝)
int main()
{
int input = 0;//input不能放到do语句里面
srand((unsigned int)time(NULL));
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;
}
在此段代码中,我们首先调用了menu() 函数,对于 开始的菜单页面进行打印,我们利用scanf()函数邀请用户输入一个数字,来进行交互操作,以便后续代码的运行。
我们可以观察到,用户输入0时,退出游戏。输入其他数字时,会显示输入错误,让用户重新选择。输入1时会继续游戏。
五.创建棋盘并打印棋盘
接下来是对于棋盘的创建和打印:
一个首先的知识点:在game.h头文件中,我们进行了宏定义
#define ROW 3 #define COL 3 //利用这个,避免以后写五子棋等进行多次更改,直接在此处进行
1.提高代码可读性
2.提高效率,直接在此处更改就行
我们创建了两个函数 InitBoard() 和 DisplayBoard()
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] = ' '; } } }
利用for 循环进行对棋盘的打印,我们写的是三子棋,则此处row = 3且col = 3。初始化了一个3*3的空格。
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]); } printf("\n"); } }
//版本二带边界,问题是不能打印10*10,只能打印10*3,在打印数据那里出现了问题 void DisplayBoard(char board[ROW][COL], int row, int col) { int i = 0; for (i = 0; i < row; i++) { //1.打印数据 printf("| %c | %c | %c | \n", board[i][0], board[i][1], board[i][2]); //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++) { //1.打印数据 int j = 0; for (j = 0; j < col; j++) { printf(" %c ", board[i][j]); if (j < col - 1) printf("|"); } printf("\n"); //2.打印分割线 if (i < row - 1)//不打印最后一行 { int j = 0; for (j = 0; j < col; j++) { printf("---"); if (j < col - 1) printf("|"); } printf("\n"); } } }
我们来仔细分析一下棋盘的打印。
如上图所示,分析版本三代码,我们利用" %c " 对每一个空格进行打印,利用"---"进行每一行分割线的打印,利用if语句if (j < col - 1) printf("|");进行每一列分割线的打印。
六.玩家下棋
我们定义了一个函数PlayerMove( ) 进行玩家下棋。
我们需要先让玩家输入下棋坐标,判断坐标的合法性与否,合法就下在玩家输入的位置并进行棋盘打印,不合法就对玩家进行提醒。
同时需要利用循环语句 while 对于代码进行循环,使得游戏可以继续进行下去。
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋>:\n");
while (1)
{
printf("请输入下棋的坐标,中间使用空格>:");
scanf("%d %d", &x, &y);
//坐标合法,3*3时玩家会输入1-3之间的数,所以保证输入数据的合理性
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");
}
}
}
七.电脑下棋
和玩家下棋的运行逻辑类似。
结合简单的while循环和 if 语句。
//电脑随机下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;//0~row-1
int y = 0;//0~col-1
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
八.判断输赢(赢,输,平局)
分析什么时候存在输赢局面,当一行三个符号全一致或者对角线一致时,判断一方赢。
IsFull()函数进行3*3棋盘是否填满的判断
IsWin()函数进行输赢判断
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < row; j++)
if (board[i][j] == ' ')
{
return 0;
}
}
}
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][0] != ' ')
{
return board[i][0];
}
}
//判断列
// int i = 0;
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//对角线
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) == 1)
{
return 'Q';
}
//继续
return 'C';
}
九.运行结果部分展示
十.所有代码汇总
头文件game.h
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define ROW 3
#define COL 3 //利用这个,避免以后写五子棋等进行多次更改,直接在此处进行
//.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 ComputerMove(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;
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]);
// }
// printf("\n");
// }
//}
版本二带边界,问题是不能打印10*10,只能打印10*3,在打印数据那里出现了问题
//void DisplayBoard(char board[ROW][COL], int row, int col)
//{
// int i = 0;
// for (i = 0; i < row; i++)
// {
// //1.打印数据
// printf("| %c | %c | %c | \n", board[i][0], board[i][1], board[i][2]);
// //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++)
{
//1.打印数据
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
//2.打印分割线
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;
printf("玩家下棋>:\n");
while (1)
{
printf("请输入下棋的坐标,中间使用空格>:");
scanf("%d %d", &x, &y);
//坐标合法,3*3时玩家会输入1-3之间的数,所以保证输入数据的合理性
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;//0~row-1
int y = 0;//0~col-1
printf("电脑下棋:>\n");
while (1)
{
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
int IsFull(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < row; j++)
if (board[i][j] == ' ')
{
return 0;
}
}
}
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][0] != ' ')
{
return board[i][0];
}
}
//判断列
// int i = 0;
for (i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//对角线
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) == 1)
{
return 'Q';
}
//继续
return 'C';
}
源文件test.c
#include "game.h"
//开始界面,进入时的菜单
void menu()
{
printf("*******************************\n");
printf("************1. play ***********\n");
printf("************0. exit ***********\n");
printf("*******************************\n");
}
void game()
{
char board[ROW][COL] = { 0 };
//初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
//下棋
char 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()
{
int input = 0;//input不能放到do语句里面
srand((unsigned int)time(NULL));
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;
}