一、游戏描述
1.游戏名称
三子棋(又称井字棋),顾名思义,三子连线为胜。
2.基本流程
(1):显示菜单,可以开始游戏或者退出游戏
(2):创建3*3棋盘,并初始化
(3):打印棋盘状态
(4):放水电脑下棋(电脑执“ X ”)
(5):判定胜负(电脑赢、平局、继续下棋)
打印棋盘状态
(6):愚蠢玩家下棋(玩家执“ O ”)
(7):判定胜负(玩家赢、继续下棋)
打印棋盘状态
(8):返回步骤(1)
二、代码实现
1.主函数main()
(1):使用srand函数为后续rand函数能正常使用
(2):switch通过choice的值决定 1.开始游戏 or 0.退出游戏 or 重新选择
(3):do-while允许重复开始游戏
int main()
{
srand((unsigned int)time(NULL));
int choice;
do
{
menu();
printf("请选择\n");
scanf("%d", &choice);
switch (choice)
{
case 1:
game();
break;
case 0:
printf("退出成功\n");
return 0;
default:
printf("无效选择\n");
}
} while (1);
}
2.游戏总函数———game函数
函数功能:通过调用其他游戏步骤的函数实现一次完整的游戏
void game()
{
char index = 0; //index的功能:接收WhoWin函数的返回值:O(玩家赢)、X(电脑赢)、
=(平局)、K(游戏继续)
//初始化棋盘,使其全为空格
BeginBoard(board, ROW, COL);
system("cls");
printf("注意:玩家执“O”,电脑执“X”\n");
DisplayBoard(board, ROW, COL);
Sleep(2000);
//下棋,每有一方落子后,打印棋盘状态,并判断游戏是否结束
while (1)
{
ComputerMove(board, ROW, COL); //电脑下棋
DisplayBoard(board, ROW, COL);
//判断平局与否
index = WhoWin(board, ROW, COL);
if (index != 'K') //index为K时,表示游戏没有结束,继续下棋
{
break;
}
PlayerMove(board, ROW, COL); //玩家下棋
DisplayBoard(board, ROW, COL);
//判断平局与否
index = WhoWin(board, ROW, COL);
if (index != 'K')
{
break;
}
}
if (index == 'O')
{
printf("你赢了!\n");
}
else if (index == 'X')
{
printf("你输了!\n");
}
else
{
printf("这局平局,再来吗?\n");
}
}
3.菜单menu函数
给玩家提示:扣1开始游戏;扣0退出游戏
void menu()
{
printf("**************************\n");
printf("*******1.<开始游戏>*******\n");
printf("*******0.<退出游戏>*******\n");
}
运行结果
4.初始化棋盘IniBoard函数
函数功能:将棋盘中的落棋点初始化为空格
void IniBoard(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] = ' ';
}
}
}
5.显示棋盘状态DisplayBoard函数
函数功能:显示当前棋盘中各个棋子的位置
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i;
int j;
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) //每两个---间打印 +
printf("+");
}
}
printf("\n"); //打印一行分隔符后进行换行
}
}
运行结果:
注意: ①第一行的“注意:玩家执O,电脑执X”是game()函数中打印的,下面会有具体的代码
②当前显示的棋盘是经过IniBoard函数初始化的,故全是空格
6.放水人机下棋ComputerMove函数
函数功能:通过rand函数生成指定范围的随机数实现下棋。(所以你猜为什么叫放水人机)在此基础上添加了避免在已有棋子的位置下棋的功能。
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑思考中...");
Sleep(2000); //为了观赏性,此处使用延时和清屏函数
system("cls");
printf("电脑已下棋:\n");
int i = 0;
int j = 0;
while (1)
{
i = rand() % row; //产生棋盘范围内的随机数,防止越界访问
j = rand() % col;
if (board[i][j] == ' ') //寻找空位置下棋
{
board[i][j] = 'X';
break;
}
}
}
运行结果:上述函数只能打印实现落子功能,打印棋盘是借助DisplayBoard函数打印的
7.玩家下棋PlayerMove函数
函数功能:由玩家选择第几行、第几列的坐标,实现在对应位置落子。实现该功能的基础上添加了处理不合理的坐标的操作。
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); //输入坐标
if (x >= 1 && x <= row && y >= 1 && y <= col) //如果坐标在棋盘内
{
if (board[x - 1][y - 1] == ' ') //该坐标正好是空格,则下棋O
{
board[x - 1][y - 1] = 'O';
break;
}
else
{
printf("该坐标已有棋子,请重新选择\n");
}
}
else //坐标不在棋盘范围内,重新输入坐标
{
printf("坐标无效,请重新选择\n");
}
}
}
运行结果:
8.判定胜负WhoWin函数
函数功能:当任意一方下棋后,对棋局进行判断,是否有一方胜出,或者达成平局。
①玩家赢---返回 V
②电脑赢---返回 X
③平局----返回 =
④继续----返回 K注意:判断平局是一个单独的函数
//玩家赢---返回 V
//电脑赢---返回 X
//平局----返回 =
//继续----返回 K
char WhoWin(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];
}
}
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 (IfFull(board, row, col)) //返回值为1,返回'=',表示平局
{
return '=';
}
return 'K'; //其余情况,继续下棋
}
9.判断平局IfFull函数
函数功能:判断棋盘是否已经下满,没下满返回0,下满了返回1
int IfFull(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
if (board[i][j] == ' ') //棋盘未满,返回0
return 0;
}
return 1; //棋盘满了返回1
}
三、 程序运行示例:
1.电脑赢
玩家得多愚蠢才会让放水人机赢啊(抱拳)
2.玩家赢
3.平局
这个还有点难!!!
四、完整代码
1.注意
出于对代码更容易管理的考虑:
(1)将①主要函数声明;②棋盘数组,棋盘的大小;③相关库函数放到game.h文件中
(2)将主要函数的定义放在game.c文件中
(3)将游戏运行部分的代码放在play.c文件
(4)在.c文件中包含game.h文件即可
当然也可以将以下所有代码放进一个.c文件中,不影响运行
2.game.h
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <Windows.h>
#define ROW 3
#define COL 3
char board[ROW][COL];
//初始化棋盘
void BeginBoard(char board[ROW][COL], int row, int col);
//打印棋盘状态
void DisplayBoard(char board[ROW][COL], int row, int col);
//电脑随机下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//判断输赢
char WhoWin(char board[ROW][COL], int row, int col);
3.game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void BeginBoard(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;
int j;
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) //每两个---间打印 +
printf("+");
}
}
printf("\n"); //打印一行分隔符后进行换行
}
}
//电脑随机下棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑思考中...");
Sleep(2000);
system("cls");
printf("电脑已下棋\n");
int i = 0;
int j = 0;
while (1)
{
i = rand() % row;
j = rand() % col;
if (board[i][j] == ' ')
{
board[i][j] = 'X';
break;
}
}
}
//玩家下棋
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);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = 'O';
break;
}
else
{
printf("该坐标已有棋子,请重新选择\n");
}
}
else
{
printf("坐标无效,请重新选择\n");
}
}
}
//棋盘是否已满
int IfFull(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
if (board[i][j] == ' ') //存在空,则棋盘未满,返回0
return 0;
}
return 1;
}
//判断输赢
//玩家赢---返回 V
//电脑赢---返回 X
//平局----返回 =
//继续----返回 K
char WhoWin(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];
}
}
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 (IfFull(board, row, col)) //返回值为1(非0),返回'=',表示平局
{
return '=';
}
return 'K'; //其余情况,继续下棋
}
4.play.c
#include "game.h"
void menu()
{
printf("**************************\n");
printf("*******1.<开始游戏>*******\n");
printf("*******0.<退出游戏>*******\n");
}
void game()
{
char index = 0;
//初始化棋盘,使其全为空格
BeginBoard(board, ROW, COL);
system("cls");
printf("注意:玩家执“O”,电脑执“X”\n");
DisplayBoard(board, ROW, COL);
Sleep(2000);
//下棋,每有一方落子后,打印棋盘状态,并判断游戏是否结束
while (1)
{
ComputerMove(board, ROW, COL); //电脑下棋
DisplayBoard(board, ROW, COL);
//判断平局与否
index = WhoWin(board, ROW, COL);
if (index != 'K') //index为K时,表示游戏没有结束,继续下棋
{
break;
}
PlayerMove(board, ROW, COL); //玩家下棋
DisplayBoard(board, ROW, COL);
//判断平局与否
index = WhoWin(board, ROW, COL);
if (index != 'K')
{
break;
}
}
if (index == 'O')
{
printf("你赢了!\n");
}
else if (index == 'X')
{
printf("你输了!\n");
}
else
{
printf("这局平局,再来吗?\n");
}
}
int main()
{
srand((unsigned int)time(NULL));
int choice;
do
{
menu();
printf("请选择\n");
scanf("%d", &choice);
switch (choice)
{
case 1:
game();
break;
case 0:
printf("退出成功\n");
return 0;
default:
printf("无效选择\n");
}
} while (1);
}