三子棋
目录
一、问题介绍
? ? ? ? 三子棋,在民间又叫井字棋。因为人们在游玩时常常不画棋盘的边框,正如汉字中的“井”字,多称为“井字棋”。
三子棋的游戏规则十分的简单:
在3×3的棋盘双方轮流下棋(先手一般的棋子为“X”,后手为“O”),当有一方所下的棋子连成一条直线即为胜利!
?
二、实现思路
- ?创建游戏菜单
- 初始化棋盘
- 打印棋盘
- 玩家下棋(判断是否胜利)
- 电脑下棋(判断是否胜利)
- 游戏结束
三、实现流程
1.创建游戏菜单
//菜单函数
void menu(void)
{
printf("|---------------|\n");
printf("|--- 1.START ---|\n");
printf("|--- 0.EXIT ---|\n");
printf("|---------------|\n");
}
1.开始游戏? ? ? 0.退出游戏
2.初始化棋盘
使用全局变量创建3×3的棋盘
使用全局变量的原因:
- 后续修改棋盘大小更为便捷
- 代码可读性加强
//定义行、列
#define ROW 3
#define COL 3
//初始化棋盘函数
void InitChessBoard(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] = ' ';
}
}
}
3.打印棋盘
在这里,为了后续棋盘的大小方便改变,将分割行分别打印
//打印棋盘函数
void DisplayChessBoard(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");
if (i <row-1)
{
//打印“---|---|---”
for (j = 0; j < row; j++)
{
printf("---");
if (j < col - 1)
{
printf("|");
}
}
}
//打印完一行之后换行
printf("\n");
}
}
4.玩家下棋
玩家需通过输入[1,3]区间内的数字来落子“x”
- 当玩家输入超出棋盘大小的坐标时,提醒玩家输入坐标错误并重新输入
- 当玩家输入已被占用的棋盘坐标时,提醒玩家输入坐标错误并重新输入
//玩家下棋函数
void PlayerMove(char Board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("player(行 列):>");
//玩家输入坐标
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//玩家输入区间为[1, 3]
if (Board[x - 1][y - 1] == ' ')
{
Board[x - 1][y - 1] = 'x';
break;
}
else
{
printf("该坐标已被占用,请重新输入!\a\n\n");
}
}
else
{
printf("输入坐标非法,请重新输入!\a\n\n");
}
}
}
5.电脑下棋
电脑下棋需要使用生成随机数种子,并且保证电脑在空的坐标上落子
在主调函数中使用生成随机数函数,?确保生成的随机数为随机:
srand((unsigned int)time(NULL));
//time的函数返回类型是time_t
//在这里使用强制转换类型(unsigned int)
//电脑下棋函数
void ComputerMove(char Board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("computer:\n");
while (1)
{
//获取时间随机数
x = rand() % row;
y = rand() % col;
if (Board[x][y] == ' ')
{
Board[x][y] = 'o';
break;
}
}
}
6.判断游戏胜利
在这一步我们需要定义两个函数:
- IsWin函数(判断是否胜利)
- IsFull函数(判断棋盘是否下满)
我们约定当返回“x”时玩家胜利
返回“o”时电脑胜利
返回“q”时代表平局
返回“c”时代表棋盘未被填满游戏继续
//判断是否胜利函数
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];
}
}
//判断列
for (i = 0; i < col; 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];
}
//检查棋盘是否填满
if (IsFull == 1)
{
//返回平局
return 'q';
}
//返回继续
return 'c';
}
//判断棋盘是否被填满函数
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;
}
7.游戏函数和主调函数
//游戏实现函数
void Game(char Board[ROW][COL], int row, int col)
{
InitChessBoard(Board, ROW, COL);
DisplayChessBoard(Board, ROW, COL);
while (1)
{
PlayerMove(Board, ROW, COL);
DisplayChessBoard(Board, ROW, COL);
if (IsWin(Board, ROW, COL) != 'c')
break;
ComputerMove(Board, ROW, COL);
DisplayChessBoard(Board, ROW, COL);
if (IsWin(Board, ROW, COL) != 'c')
break;
}
if (IsWin(Board, ROW, COL) == 'x')
printf("PLAYER WIN!\n\n");
else if (IsWin(Board, ROW, COL) == 'o')
printf("COMPUTER WIN!\n\n");
else
printf("平局!\n\n");
}
//主调函数
int main(void)
{
srand((unsigned int)time(NULL));
char Board[ROW][COL] = { 0 };
int input = 0;
do
{
menu();
printf("please enter:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("GAME START\n");
Game(Board, ROW, COL);
break;
case 0:
printf("GAME EXIT\n\a");
break;
default:
printf("ERROR!\n\a");
}
} while (input);
return 0;
}
四、代码总览
#define _CRT_SECURE_NO_WARNINGS 1
//程序所需头文件
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
//定义行、列
#define ROW 3
#define COL 3
//菜单函数
void menu(void)
{
printf("|---------------|\n");
printf("|--- 1.START ---|\n");
printf("|--- 0.EXIT ---|\n");
printf("|---------------|\n");
}
//初始化棋盘函数
void InitChessBoard(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 DisplayChessBoard(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");//打印完一行之后换行
if (i <row-1)
{
for (j = 0; j < row; 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("player(行 列):>");
//玩家输入坐标
scanf("%d %d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
//玩家输入区间为[1, 3]
if (Board[x - 1][y - 1] == ' ')
{
Board[x - 1][y - 1] = 'x';
break;
}
else
{
printf("该坐标已被占用,请重新输入!\a\n\n");
}
}
else
{
printf("输入坐标非法,请重新输入!\a\n\n");
}
}
}
//电脑下棋函数
void ComputerMove(char Board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("computer:\n");
while (1)
{
//获取时间随机数
x = rand() % row;
y = rand() % col;
if (Board[x][y] == ' ')
{
Board[x][y] = 'o';
break;
}
}
}
//判断棋盘是否被填满函数
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];
}
}
//判断列
for (i = 0; i < col; 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];
}
//检查棋盘是否填满
if (IsFull == 1)
{
//返回平局
return 'q';
}
//返回继续
return 'c';
}
//游戏实现函数
void Game(char Board[ROW][COL], int row, int col)
{
InitChessBoard(Board, ROW, COL);
DisplayChessBoard(Board, ROW, COL);
while (1)
{
PlayerMove(Board, ROW, COL);
DisplayChessBoard(Board, ROW, COL);
if (IsWin(Board, ROW, COL) != 'c')
break;
ComputerMove(Board, ROW, COL);
DisplayChessBoard(Board, ROW, COL);
if (IsWin(Board, ROW, COL) != 'c')
break;
}
if (IsWin(Board, ROW, COL) == 'x')
printf("PLAYER WIN!\n\n");
else if (IsWin(Board, ROW, COL) == 'o')
printf("COMPUTER WIN!\n\n");
else
printf("平局!\n\n");
}
//主调函数
int main(void)
{
srand((unsigned int)time(NULL));
char Board[ROW][COL] = { 0 };
int input = 0;
do
{
menu();
printf("please enter:>");
scanf("%d", &input);
switch (input)
{
case 1:
printf("GAME START\n");
Game(Board, ROW, COL);
break;
case 0:
printf("GAME EXIT\n\a");
break;
default:
printf("ERROR!\n\a");
}
} while (input);
return 0;
}
五、代码注意事项
- 程序中哪里需要使用循环,哪里不需要使用循环应仔细分清
- Game()函数中,每当玩家下棋或是电脑下棋都需要判断是否胜利
|