文章目录
三子棋游戏就是玩家和电脑之间轮流下棋,首先它的棋盘为3X3,我们玩家先下棋,然后到电脑,只要其中一方下的棋子连成了一条线即为胜利。 那么要实现游戏的前提首先是得有一个棋盘显示出来,然后把我们每一次下的棋到显示在屏幕上直到一方胜利或者和局。所以
我们第一步是要打印棋盘:
打印棋盘的前提是有数据可以打印,所以我们需要用到一个3X3的二维数组,刚开始里面没有数据,我们先初始化成空格,这样打印出来就是空白的形式,为了方便区分玩家和电脑下棋,我们可以规定
玩家下棋就用符号" *"填补
电脑下棋就用符号"# "填补
那么第二步:
棋盘打印出来屏幕后,就是玩家下棋,那么我们需要一个玩家下棋的独立函数,用来接收玩家输入的坐标,而且要判断坐标是否合法
第三步:
玩家下完棋后,就是电脑下棋,电脑下棋我们可以用随机值进行下棋
此时我们又可以实现一个电脑下棋的独立函数
第四步:
玩家和电脑每下一次棋,我们都需要判断一下是否有一方已经胜利了,或者棋盘是否满了,所以我们又需要一个独立函数用来判断
第五步:
把上述的所有函数用循环连接起来即可,下面直接看我操作
下面的图就是我们要实现的棋盘,首先要创建一个3X3的二维数组
#define ROW 3 //行
#define COL 3 //列
char board[ROW][COL]
我们用宏定义来定义行列,方便以后要打印成其他4X4,10X10的棋盘
而且我们要把它初始化成空格
//初始化成空格
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] = ' ';
}
}
}
可以看一个下的棋下面都有三个“-”符号,因为我们的“ # ”,和“ * ”都只占一个位置,所以我们打印的时候要用空格隔开
用宏定义的好处,如果把ROW和COL改成10,那么它可以直接打印成下面的10X10格子 注意我们下面是基于3X3格子进行实现的三子棋,只适用于3x3格子
下面我们就实现一下打印棋盘的代码
实现代码:
//打印棋盘
void BoardPrint(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++)
{
printf(" %c ",board[i][j]);
//可以看到图片里的最后一列是没有竖杆的,所以这里要判断一下
//如果是最后一列就不必打印竖杆
if(j<col-1)
printf("|");
}
printf("\n");
for (j = 0; j < col; j++)
{
printf("---");
//这里跟上面用一个意思
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
玩家下棋的方式是输入坐标 ,所以需要接收玩家输入的数据,我们要考虑到
**用户友好性** |
因为我们使用的是二维数组,下标都是从0开始的,而玩家不一定是程序员,是不知道的这件事的,所以用户输入的数据时要注意处理
处理用户输入的数据只需将它-1即可,
比如玩家输入坐标"3 3",在后台改变数组的时候就将它减1变成“2 2”
同时还有判断当前坐标是否已经被占用了,如果被占用了还需要提醒玩家重新输入,直到输入正确为止,所以我们要使用到循环结构 坐标没有被占用,我们就可以将数组对应的位置放字符“ * ”
void PlayerMove(char board[ROW][COL], int row, int col)
{
while (1)
{
printf("请输入坐标>:");
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
//判断坐标是否合法
if (x <= 3 && x > 0 && y <= 3 && y > 0)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("坐标被占用,不能下棋,请选择其他位置\n");
}
}
else
{
printf("坐标非法,请重新输入\n");
}
}
}
电脑下棋使用rand函数获取随机值,将它坐标按行和列取模,比如随机值是100,那么取模行row之后,就为1,
电脑下棋就不用判断坐标是否合法了,只需要确定它取模后的数字范围在0~2之间即可
还需要注意获取的坐标是否被占用即可
因为我们是使用随机值的方式让电脑下棋,使用这样的方式下棋,电脑是很“笨”的,不会对我们下的棋进行拦截,简而言之就是不够“智能”,当然如果, 你感兴趣的话,可以对它进行一些算法处理,比如穷举一些玩家可能性下的棋,对它进行预判等等,让它变得更加“智能”一些,但本文章就不做优化了,留给你们自行处理!
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
判断输赢大概就以下几种,我们可以使用枚举的方式,也可以使用循环的方式去判断,下面我给出两个版本,一个是枚举的,一个是循环的
我们规定玩家赢返回“ * ”,电脑赢返回“ # ”,平局返回“Q”,进行游戏返回“0” |
枚举
//版本1.0枚举
//玩家赢返回"*",电脑赢返回""#,棋盘满了返回"Q"
char DetermineEnd1(char board[ROW][COL])
{
//玩家赢的情况
if ((board[0][0] == board[0][1] && board[0][1] == board[0][2]&&board[0][0]=='*')
|| (board[1][0] == board[1][1] && board[1][1] == board[1][2] && board[1][0] == '*')
|| (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '*')
|| (board[0][0] == board[1][0] && board[1][0] == board[2][0]&&board[0][0] == '*')
|| (board[0][1] == board[1][1] && board[1][1] == board[2][1] && board[0][1] == '*')
|| (board[0][2] == board[1][2] && board[1][2] == board[2][2] && board[0][2] == '*')
|| (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] == '*')
|| (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] == '*'))
{
return '*';
}
//电脑赢的情况
else if ((board[0][0] == board[0][1] && board[0][1] == board[0][2]&&board[0][0]=='#')
|| (board[1][0] == board[1][1] && board[1][1] == board[1][2] && board[1][0] == '#')
|| (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '#')
|| (board[0][0] == board[1][0] && board[1][0] == board[2][0]&&board[0][0] == '#')
|| (board[0][1] == board[1][1] && board[1][1] == board[2][1] && board[0][1] == '#')
|| (board[0][2] == board[1][2] && board[1][2] == board[2][2] && board[0][2] == '#')
|| (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] == '#')
|| (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][02] == '#'))
{
return '#';
}
else
{
//判断棋盘是否满了
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
if (board[i][j] == ' ')
return '0';
}
}
}
//程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
return 'Q';
}
其实循环和枚举在这里都是大同小异。 |
循环
//版本2.0循环
// 判断游戏是否结束 玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char DetermineEnd2(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];
}
}
//判断列
for (i = 0; i < row; i++)
{
if ((board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '))
{
return board[1][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];
}
//判断棋盘是否满了
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
//其中有一个空格就说明还没满,返回"0"
if (board[i][j] == ' ')
return '0';
}
}
//程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
return 'Q';
}
其实不管是猜数字小游戏,还是前面实现的顺序表和单链表,看似代码很大,其实如果理解其中的思想,就知道他们都有一个共同点,都是一些基本操作组装起来。 |
接下来才是最关键的一步,就是将它们组装起来,形成一个可以运行的程序
我把它实现在text.c文件中。
text.c为工程测试文件 |
#define _CRT_SECURE_NO_WARNINGS
#include"game.h"
void menu()
{
printf("******************************\n");
printf("******* 1. play 0. exit*****\n");
printf("******************************\n");
}
void game()
{
char board[ROW][COL] = { 0 };
//先初始化棋盘
InitBoard(board, ROW, COL);
//打印棋盘让玩家下棋
BoardPrint(board, ROW, COL);
char ret;
while (1)
{
printf("玩家下棋\n");
PlayerMove(board, ROW, COL);
ret= DetermineEnd2(board,ROW,COL);
if (ret != '0')
{
break;
}
BoardPrint(board, ROW, COL);
printf("电脑下棋\n");
ComputerMove(board, ROW, COL);
ret = DetermineEnd2(board, ROW, COL);
if (ret != '0')
{
break;
}
BoardPrint(board, ROW, COL);
}
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else
{
printf("平局\n");
}
BoardPrint(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.c为工程函数实现文件 |
#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 BoardPrint(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++)
{
printf(" %c ",board[i][j]);
if(j<col-1)
printf("|");
}
printf("\n");
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
void PlayerMove(char board[ROW][COL], int row, int col)
{
while (1)
{
printf("请输入坐标>:");
int x = 0;
int y = 0;
scanf("%d %d", &x, &y);
//判断坐标是否合法
if (x <= 3 && x > 0 && y <= 3 && y > 0)
{
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)
{
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
//}
////版本1.0
////玩家赢返回"*",电脑赢返回""#,棋盘满了返回"Q"
//char DetermineEnd1(char board[ROW][COL])
//{
// //玩家赢的情况
// if ((board[0][0] == board[0][1] && board[0][1] == board[0][2]&&board[0][0]=='*')
// || (board[1][0] == board[1][1] && board[1][1] == board[1][2] && board[1][0] == '*')
// || (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '*')
// || (board[0][0] == board[1][0] && board[1][0] == board[2][0]&&board[0][0] == '*')
// || (board[0][1] == board[1][1] && board[1][1] == board[2][1] && board[0][1] == '*')
// || (board[0][2] == board[1][2] && board[1][2] == board[2][2] && board[0][2] == '*')
// || (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] == '*')
// || (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] == '*'))
// {
//
// return '*';
// }
// //电脑赢的情况
// else if ((board[0][0] == board[0][1] && board[0][1] == board[0][2]&&board[0][0]=='#')
// || (board[1][0] == board[1][1] && board[1][1] == board[1][2] && board[1][0] == '#')
// || (board[2][0] == board[2][1] && board[2][1] == board[2][2] && board[2][0] == '#')
// || (board[0][0] == board[1][0] && board[1][0] == board[2][0]&&board[0][0] == '#')
// || (board[0][1] == board[1][1] && board[1][1] == board[2][1] && board[0][1] == '#')
// || (board[0][2] == board[1][2] && board[1][2] == board[2][2] && board[0][2] == '#')
// || (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] == '#')
// || (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][02] == '#'))
// {
//
// return '#';
// }
// else
// {
// //判断棋盘是否满了
// for (int i = 0; i < ROW; i++)
// {
// for (int j = 0; j < COL; j++)
// {
// if (board[i][j] == ' ')
// return '0';
// }
// }
// }
// //程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
// return 'Q';
//}
//版本2.0
// 判断游戏是否结束 玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char DetermineEnd2(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];
}
}
//判断列
for (i = 0; i < row; i++)
{
if ((board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[1][i] != ' '))
{
return board[1][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];
}
//判断棋盘是否满了
for (int i = 0; i < ROW; i++)
{
for (int j = 0; j < COL; j++)
{
//其中有一个空格就说明还没满,返回"0"
if (board[i][j] == ' ')
return '0';
}
}
//程序走到这里就说明没有分出胜负,而且棋盘已经满了,故为和局
return 'Q';
}
game.h为工程的函数和变量声明的头文件 |
#pragma once
#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 BoardPrint(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);
// 版本1.0 判断游戏是否结束 玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char DetermineEnd1(char board[ROW][COL]);
//版本2.0 判断游戏是否结束 玩家赢返回"*",电脑赢返回"#",棋盘满了返回"Q"
char DetermineEnd2(char board[ROW][COL],int row,int col);
不要让舒适夺走了你本可以拥有的东西!! |