目录
一、前言
二、头文件
四、初始化棋盘Initboard函数
五、显示棋盘Displayboard函数
六、落子函数
七、判断输赢ifwin
八、人机、人人模式的选择
九、作者遇到的坑点
十、完整的代码
本文将先介绍五子棋运行所需要的函数,最后串联成完整代码。
我们需要实现的功能有:1.菜单menu函数
2.初始化棋盘Initboard函数
3.显示棋盘Displayboard函数
4.实现人机、人人模式的选择
5.落子函数 playermove computermove
6.判断输赢ifwin函数
先来看看运行效果吧!
#define _CRT_SECURE_NO_WARNINGS
#include
#include
#include
#include
#include
#define ROW 10 //定义棋盘的宽
#define COL 10 //定义棋盘的长
//定义常量方便全局的修改
void Initboard(char board[ROW][COL], int row, int col);
//初始化棋盘
void Displayboard(char board[ROW][COL], int row, int col);
//展示棋盘
void Playermove_1(char board[ROW][COL], int row, int col,int*px,int *py);
//玩家一下棋
void Playermove_2(char board[ROW][COL], int row, int col,int*px, int *py);
//玩家二下棋
void computermove(char board[ROW][COL], int row, int col);
//电脑下棋
void game1(char board[ROW][COL], int row, int col);
//人机模式
void game2(char board[ROW][COL], int row, int col);
//人人模式
int Ifwin(char board[ROW][COL], int row, int col, int x, int y);
//判断输赢
int check_x(char board[ROW][COL], int row, int col, int x, int y);
//判断竖直五子
int check_y(char board[ROW][COL], int row, int col, int x, int y);
//判断水平五子
int check_xy_up(char board[ROW][COL], int row, int col, int x, int y);
//判断斜上五子
int check_xy_down(char board[ROW][COL], int row, int col, int x, int y);
//判断斜下五子
void menu()
{ //完成菜单的初始化
printf("***********************\n");
printf("***********************\n");
printf("*****1.play 0.exit****\n");
printf("***********************\n");
printf("***********************\n");
printf("请输入:");
}
很简单,就不多说了
初始化棋盘,为数组一一存入空格
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;
int j = 0;
for (j = 0; j < col; j++)//打印横向y坐标
{
if (j == 0)//考虑到x轴所占的一格
{
printf(" %d ", j + 1);
}
else
{
printf(" %d ", j + 1);
}
}
printf("\n");
for (i = 0; i < row; i++)//打印数据
{
for (j = 0; j < col; j++)
{
if (j == 0)//顺带打印竖向x坐标
{
printf("%2d",i+1);//%md表示域宽为m
printf(" %c ",board[i][j]);
}
else
{
printf(" %c ", board[i][j]);
}
if (j < col - 1)
printf("|");
}
printf("\n");
//打印分割行
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
if (j == 0)//同样考虑到y轴
printf(" ---");
else
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
玩家一落子——playermove_1
void Playermove_1(char board[ROW][COL], int row, int col, int *px, int*py)//ROW可以省,COL不行
{
int x = *px;
int y = *py;
while (1)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入坐标的合法性
{
if (board[x -1][y- 1] == ' ')//保证落子点为空
{
board[x-1 ][y -1] = '*';
*px = x; *py = y;//如果开始xy输入不合法,则要对外部xy修改,所以选择传址操作
break;
}
else
{
printf("你不能在此处落子\n");
printf("玩家1落子,请重新输入x y坐标: ");
scanf("%d%d", &x, &y);
}
}
else
{
printf("输入坐标不合法\n");
printf("玩家落子,请重新输入x y坐标: ");
scanf("%d%d", &x, &y);
}
}
}
玩家2落子完全相同,就不赘叙了
电脑落子
void computermove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
//rand函数的使用需要srand函数的初始化,但srand不可以被重复调用,所以放在外部
while (1)
{
x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')//x的范围在0~row-1,所以这里x不用-1了
{
board[x][y] = '#';
break;
}
}
}
根据我们下五子棋的经验,能获胜的地方必定是最后落子的水平线、竖直线、和两个斜对角线,我们只需对其进行检索即可。ifwin的返回值决定之后的switch语句
弱弱的说一句,虽然看起来多,但很多都是重复的。若要优化就使用函数指针
int Ifwin(char board[ROW][COL], int row, int col, int x, int y)
{
int ret;
{
ret = check_x(board, row, col, x, y);
if (ret >= 5)
return 0;
ret = check_y(board, row, col, x, y);
if (ret >= 5)
return 0;
ret = check_xy_up(board, row, col, x, y);
if (ret >= 5)
return 0;
ret = check_xy_down(board, row, col, x, y);
if (ret >= 5)
return 0;
}
return 3;
}
int check_x(char board[ROW][COL], int row, int col, int x, int y)//检查x轴竖直方向
{
int sum = 1;
int old_x = x;
while (x < row && board[x - 1][y - 1] == board[x][y - 1])
{
sum++;
x++;
}
x = old_x;
while (x-2>= 0 && board[x - 1][y - 1] == board[x - 2][y - 1] )
{
sum++;
x--;
}
return sum;
}
int check_y(char board[ROW][COL], int row, int col, int x, int y)//检查y轴水平方向
{
int sum = 1;
int old_y = y;
while (y = 0 && board[x-1][y-1] == board[x-1][y -2] )
{
sum++;
y--;
}
return sum;
}
int check_xy_up(char board[ROW][COL], int row, int col, int x, int y)//检查斜上45度
{
int sum = 1;
int old_x = x;
int old_y = y;
while (x= 0 && board[x - 1][y - 1] == board[x][y - 2])
{
sum++;
x++;
y--;
}
x = old_x;
y = old_y;
while (x - 2 >= 0 && y =0 && y-2 >=0)
{
sum++;
x--;
y--;
}
return sum;
}
初始选择界面
void game()
{
int input;
char board[ROW][COL] = { 0 };
Initboard(board, ROW, COL);
//初始化棋盘
Displayboard(board, ROW, COL);
//展示棋盘
printf("请选择模式:1.人机;2.玩家对战\n");
printf("请选择:");
do{
scanf("%d", &input);
printf("\n");
switch (input)
{
case 1:printf("游戏模式1开始!(注意:竖为x轴,横为y轴)\n"); game1(board, ROW, COL); break;
case 2:printf("游戏模式2开始!(注意:竖为x轴,横为y轴)\n"); ; game2(board, ROW, COL); break;
default:printf("请重新输入\n"); break;
}
} while (input != 1 && input != 2);//do while语句在输入错误时反复输入
}
game1的具体实现
void game1(char board[ROW][COL], int row, int col)
{
srand((unsigned int)time(NULL));//srand只要设置一次就可以,所以要放在while循环外
while (1)
{
int ret;
int count = 0;
int flag = 0;
//判读玩家的下棋
int x; int y;
printf("玩家落子,请依次输入x y坐标: ");
scanf("%d%d", &x, &y);
Playermove_1(board, row, col,&x, &y);
count++;
Displayboard(board, ROW, COL);
if (count == ROW*COL)//全下满则认为平局
ret = 1;
else
ret = Ifwin(board, ROW, COL, x, y);
switch (ret)
{
case 0:printf("玩家获胜\n"); flag = 1; break;
case 1:printf("平局\n"); flag = 1; break;
default: break;
}
if (flag == 1)//用flag跳出while循环
break;
//判断计算机的下棋
computermove(board, row, col);
count++;
Displayboard(board, ROW, COL);
if (count == ROW*COL)
ret = 1;
else
ret = Ifwin(board, ROW, COL, x, y);
switch (ret)
{
case 0:printf("电脑获胜\n"); flag = 1; break;
case 1:printf("平局\n"); flag = 1; break;
default: break;
}
if (flag == 1)
break;
}
}
作者觉得写的是挺啰嗦,欢迎留言建议。game2和game1玩家一的内容很相近,就不赘述
1.输入的坐标和存在数组里的下标有减一的关系,在写的时候不要写忘记了
2.传址操作才能改变函数外的变量值
头文件就省了
int main()
{
int input;
do{
system("cls");//清屏
menu();
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n\n"); game(); break;
case 0:
printf("退出游戏\n"); break;
default:
printf("请重新输入\n"); break;
}
Sleep(3000);//暂停3秒
} while (input);//do while语句实现可以反复玩
return 0;
}
void menu()
{ //完成菜单的初始化
printf("***********************\n");
printf("***********************\n");
printf("*****1.play 0.exit****\n");
printf("***********************\n");
printf("***********************\n");
printf("请输入:");
}
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;
int j = 0;
for (j = 0; j < col; j++)//打印横向y坐标
{
if (j == 0)//考虑到x轴所占的一格
{
printf(" %d ", j + 1);
}
else
{
printf(" %d ", j + 1);
}
}
printf("\n");
for (i = 0; i < row; i++)//打印数据
{
for (j = 0; j < col; j++)
{
if (j == 0)//顺带打印竖向x坐标
{
printf("%2d",i+1);//%md表示域宽为m
printf(" %c ",board[i][j]);
}
else
{
printf(" %c ", board[i][j]);
}
//数字表示坐标
if (j < col - 1)
printf("|");
}
printf("\n");
//打印分割行
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
if (j == 0)//同样考虑到y轴
printf(" ---");
else
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");//别忘记这里也要换行
}
}
}
void game()
{
int input;
char board[ROW][COL] = { 0 };
Initboard(board, ROW, COL);
//初始化棋盘
Displayboard(board, ROW, COL);
//展示棋盘
printf("请选择模式:1.人机;2.玩家对战\n");
printf("请选择:");
do{
scanf("%d", &input);
printf("\n");
switch (input)
{
case 1:printf("游戏模式1开始!(注意:竖为x轴,横为y轴)\n"); game1(board, ROW, COL); break;
case 2:printf("游戏模式2开始!(注意:竖为x轴,横为y轴)\n"); ; game2(board, ROW, COL); break;
default:printf("请重新输入\n"); break;
}
} while (input != 1 && input != 2);//do while语句在输入错误时反复输入
}
void game1(char board[ROW][COL], int row, int col)
{
srand((unsigned int)time(NULL));//srand只要设置一次就可以,所以要放在while循环外
while (1)
{
int ret;
int count = 0;
int flag = 0;
//判读玩家的下棋
int x; int y;
printf("玩家落子,请依次输入x y坐标: ");
scanf("%d%d", &x, &y);
Playermove_1(board, row, col,&x, &y);
count++;
Displayboard(board, ROW, COL);
if (count == ROW*COL)//全下满则认为平局
ret = 1;
else
ret = Ifwin(board, ROW, COL, x, y);
switch (ret)
{
case 0:printf("玩家获胜\n"); flag = 1; break;
case 1:printf("平局\n"); flag = 1; break;
default: break;
}
if (flag == 1)//用flag跳出while循环
break;
//判断计算机的下棋
computermove(board, row, col);
count++;
Displayboard(board, ROW, COL);
if (count == ROW*COL)
ret = 1;
else
ret = Ifwin(board, ROW, COL, x, y);
switch (ret)
{
case 0:printf("电脑获胜\n"); flag = 1; break;
case 1:printf("平局\n"); flag = 1; break;
default: break;
}
if (flag == 1)
break;
}
}
void game2(char board[ROW][COL], int row, int col)
{
while (1)
{
int ret;
int count = 0;
int flag = 0;
int x; int y;
//判读玩家1的下棋
printf("玩家1落子,请输入坐标:(注意:竖为x轴,横为y轴)");
scanf("%d%d", &x, &y);
Playermove_1(board, row, col, &x, &y);
count++;
Displayboard(board, ROW, COL);
if (count == ROW*COL)
ret = 1;
else
ret = Ifwin(board, ROW, COL, x, y);
switch (ret)
{
case 0:printf("玩家1获胜\n"); flag = 1; break;
case 1:printf("平局\n"); flag = 1; break;
default: break;
}
if (flag == 1)
break;
//判断玩家2的下棋
printf("玩家2落子,请输入坐标:(注意:竖为x轴,横为y轴)");
scanf("%d%d", &x, &y);
Playermove_2(board, row, col, &x, &y);
count++;
Displayboard(board, ROW, COL);
if (count == ROW*COL)
ret = 1;
else
ret = Ifwin(board, ROW, COL, x, y);
switch (ret)
{
case 0:printf("玩家2获胜\n"); flag = 1; break;
case 1:printf("平局\n"); flag = 1; break;
default: break;
}
if (flag == 1)
break;
}
}
void Playermove_1(char board[ROW][COL], int row, int col, int *px, int*py)//ROW可以省,COL不行
{
int x = *px;
int y = *py;
while (1)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入坐标的合法性
{
if (board[x -1][y- 1] == ' ')//保证落子点为空
{
board[x-1 ][y -1] = '*';
*px = x; *py = y;//如果开始xy输入不合法,要对外部xy修改,所以要传址操作
break;
}
else
{
printf("你不能在此处落子\n");
printf("玩家1落子,请重新输入x y坐标: ");
scanf("%d%d", &x, &y);
}
}
else
{
printf("输入坐标不合法\n");
printf("玩家落子,请重新输入x y坐标: ");
scanf("%d%d", &x, &y);
}
}
}
void Playermove_2(char board[ROW][COL], int row, int col, int *px, int*py)
{
int x = *px;
int y = *py;
while (1)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)//判断输入坐标的合法性
{
if (board[x - 1][y - 1] == ' ')//保证落子点为空
{
board[x - 1][y - 1] = '#';
*px = x; *py = y;
break;
}
else
{
printf("你不能在此处落子\n");
printf("玩家2落子,请重新输入x y坐标: ");
scanf("%d%d", &x, &y);
}
}
else
{
printf("输入坐标不合法\n");
printf("玩家落子,请重新输入x y坐标: ");
scanf("%d%d", &x, &y);
}
}
}
void computermove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
x = rand() % ROW;
y = rand() % COL;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
int Ifwin(char board[ROW][COL], int row, int col, int x, int y)
{
int ret;
{
ret = check_x(board, row, col, x, y);
if (ret >= 5)
return 0;
ret = check_y(board, row, col, x, y);
if (ret >= 5)
return 0;
ret = check_xy_up(board, row, col, x, y);
if (ret >= 5)
return 0;
ret = check_xy_down(board, row, col, x, y);
if (ret >= 5)
return 0;
}
return 3;
}
int check_x(char board[ROW][COL], int row, int col, int x, int y)//检查x轴竖直方向
{
int sum = 1;
int old_x = x;
while (x < row && board[x - 1][y - 1] == board[x][y - 1])
{
sum++;
x++;
}
x = old_x;
while (x-2>= 0 && board[x - 1][y - 1] == board[x - 2][y - 1] )
{
sum++;
x--;
}
return sum;
}
int check_y(char board[ROW][COL], int row, int col, int x, int y)//检查y轴水平方向
{
int sum = 1;
int old_y = y;
while (y = 0 && board[x-1][y-1] == board[x-1][y -2] )
{
sum++;
y--;
}
return sum;
}
int check_xy_up(char board[ROW][COL], int row, int col, int x, int y)//检查斜上45度
{
int sum = 1;
int old_x = x;
int old_y = y;
while (x= 0 && board[x - 1][y - 1] == board[x][y - 2])
{
sum++;
x++;
y--;
}
x = old_x;
y = old_y;
while (x - 2 >= 0 && y =0 && y-2 >=0)
{
sum++;
x--;
y--;
}
return sum;
}