想用C语言实现一个五子棋或者N子棋的玩法,我们首先就要从最简单的三子棋开始学习起来。本文一步一步介绍了如何写出一个三子棋的程序和有关人机智能下棋(有电脑进攻,防守形式)的代码,希望大家能够看完,对自己有所帮助!
首先作为玩家我们需要有所选择,打开程序应该有我们可以选择的选项。
void menu()
{
printf("*******************************\n");
printf("***********三子棋游戏**********\n");
printf("************1. play************\n");
printf("************2. exit************\n");
printf("*******************************\n");
}
这是一个比较简单的菜单选项,我们把重心放在接下来的游戏功能上面,下面是一个简单的游戏开始的场景,根据选择来进行程序的功能。
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:->");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏三子棋\n");
game();
break;
case 2:
printf("游戏退出");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input != 2);
}
我们现在假设棋盘是3x3的棋盘,并且创建一个3x3的棋盘
#define ROW 3
#define COL 3
char board[ROW][COL] = { '0','0','0','0','0','0' ,'0','0','0' };
接下来我们需要初始化棋盘,将棋盘元素全部初始化为空,也就是可以用字符空格 ' ' 来初始化,并且打印出我们需要下棋的棋盘,最好是可以让使用者观看更方便的棋盘。
void InitBoard(char board[ROW][COL], int row, int col) //初始化棋盘
{
int i, 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;
for ( i = 0; i < col; i++)
{
printf(" %d ", i + 1);
}
printf("\n");
printf("\n");
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf(" %d", i + 1);
printf("\n");
if (i < row - 1)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
棋盘打印出来之后我们就要决定是我们先手还是电脑先手,我们可以引用随机数的概念来帮助我们,记得使用rand()函数前不要忘记给种子一个随机数,也不要忘记包括头文件:#include<stdlib.h>和#include<time.h>。
代码如下
int qa;
qa = rand() % 2;
if (qa == 0)
{
printf("玩家先手!\n");
Sleep(2000);
//游戏部分
}
else
{
printf("电脑先手");
Sleep(2000);
//游戏部分
}
我们接下来把重点放在游戏下棋上,假如玩家先走,那我们需要玩家输入坐标并且判断此坐标的合法性告诉用户是下棋成功还是失败。
注意玩游戏的人不知道数组的下标是从0开始的,所以我们设计函数时需要用到x-1和y-1.
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家走:\n");
printf("请输入要移动的坐标");
while (1)
{
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] = '*';
break;
}
else
{
printf("该坐标被占用\n");
}
}
else
{
printf("坐标错误,不合法\n");
}
}
}
最难的设计部分就是电脑如何下棋了,我们需要思考,假如是电脑下棋,他需要和我们的人一样,首先判断一下局面是否有利于进攻?如果不利于进攻那就要进行防守,如果即没有需要进攻的点和防守的点,那就可以随机下一个棋。当然在电脑先手下棋的时候优先占领最中心的位置!
我们用result来代表函数判断是否需要进攻,如果为1则进攻,不满足进攻条件就去判断放守,都为0则执行随机下棋。
void ComputerMove(char board[ROW][COL], int row, int col)
{
int result = computer_attack(board, ROW, COL);
if (!result)result = computer_defend(board, ROW, COL);
if (!result) computer_random(board, ROW, COL);
}
下面时三个函数的实现
首先是进攻函数,看起来比较长,实际上就是判断一下电脑下过的棋中,有没有可以直接使电脑赢的游戏的位置,如果有则直接下棋,并返回q=1,也就是进攻成立,如果没有适合的进攻,则返回0,判断接下来的防守条件。
int computer_attack(char board[ROW][COL], int row, int col)
{
int q = 0;
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][0] == '#' && board[i][2] == ' ')
{
board[i][2] = '#';
q = 1;
return q;
}
if (board[i][0] == board[i][2] && board[i][0] == '#' && board[i][1] == ' ')
{
board[i][1] = '#';
q = 1;
return q;
}
if (board[i][1] == board[i][2] && board[i][1] == '#' && board[i][0] == ' ')
{
board[i][0] = '#';
q = 1;
return q;
}
}
for (int i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[0][i] == '#' && board[2][i] == ' ')
{
board[2][i] = '#';
q = 1;
return q;
}
if (board[0][i] == board[2][i] && board[0][i] == '#' && board[1][i] == ' ')
{
board[1][i] = '#';
q = 1;
return q;
}
if (board[1][i] == board[2][i] && board[1][i] == '#' && board[0][i] == ' ')
{
board[0][i] = '#';
q = 1;
return q;
}
}
if (board[0][0] == board[1][1] && board[0][0] == '#' && board[2][2] == ' ')
{
board[2][2] = '#';
q = 1;
return q;
}
if (board[0][0] == board[2][2] && board[0][0] == '#' && board[1][1] == ' ')
{
board[1][1] = '#';
q = 1;
return q;
}
if (board[2][2] == board[1][1] && board[1][1] == '#' && board[0][0] == ' ')
{
board[0][0] = '#';
q = 1;
return q;
}
if (board[0][2] == board[1][1] && board[0][2] == '#' && board[2][0] == ' ')
{
board[2][0] = '#';
q = 1;
return q;
}
if (board[2][0] == board[1][1] && board[2][0] == '#' && board[0][2] == ' ')
{
board[0][2] = '#';
q = 1;
return q;
}
if (board[2][0] == board[0][2] && board[0][2] == '#' && board[1][1] == ' ')
{
board[1][1] = '#';
q = 1;
return q;
}
return q;
}
接下里是防守函数:此函数主要判断依据是看看玩家有没有可以直接赢得游戏的位置,如果有,则优先抢占此位置,并返回1,如果没有,则返回0,函数执行下面的随机下棋。
int computer_defend(char board[ROW][COL], int row, int col)
{
int q = 0;
for (int i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][0] == '*' && board[i][2] == ' ')
{
board[i][2] = '#';
q = 1;
return q;
}
if (board[i][0] == board[i][2] && board[i][0] == '*' && board[i][1] == ' ')
{
board[i][1] = '#';
q = 1;
return q;
}
if (board[i][1] == board[i][2] && board[i][1] == '*' && board[i][0] == ' ')
{
board[i][0] = '#';
q = 1;
return q;
}
}
for (int i = 0; i < col; i++)
{
if (board[0][i] == board[1][i] && board[0][i] == '*' && board[2][i] == ' ')
{
board[2][i] = '#';
q = 1;
return q;
}
if (board[0][i] == board[2][i] && board[0][i] == '*' && board[1][i] == ' ')
{
board[1][i] = '#';
q = 1;
return q;
}
if (board[1][i] == board[2][i] && board[1][i] == '*' && board[0][i] == ' ')
{
board[0][i] = '#';
q = 1;
return q;
}
}
if (board[0][0] == board[1][1] && board[0][0] == '*' && board[2][2] == ' ')
{
board[2][2] = '#';
q = 1;
return q;
}
if (board[0][0] == board[2][2] && board[0][0] == '*' && board[1][1] == ' ')
{
board[1][1] = '#';
q = 1;
return q;
}
if (board[2][2] == board[1][1] && board[1][1] == '*' && board[0][0] == ' ')
{
board[0][0] = '#';
q = 1;
return q;
}
if (board[0][2] == board[1][1] && board[0][2] == '*' && board[2][0] == ' ')
{
board[2][0] = '#';
q = 1;
return q;
}
if (board[2][0] == board[1][1] && board[2][0] == '*' && board[0][2] == ' ')
{
board[0][2] = '#';
q = 1;
return q;
}
if (board[2][0] == board[0][2] && board[0][2] == '*' && board[1][1] == ' ')
{
board[1][1] = '#';
q = 1;
return q;
}
return q;
}
下面是电脑随机下棋:
int computer_random(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑走\n");
x = rand() % row;
y = rand() % col;
while (board[x][y] != ' ')
{
x = rand() % row;
y = rand() % col;
}
board[x][y] = '#';
return 0;
}
其实玩家和电脑没下一步,系统都要判断一次是否比赛结束,如果没有,则游戏继续,如果棋盘下满了也没有赢得游戏的一方,则游戏结束,输出平局!那我们要设置标记,设置一个返回值,根据返回值来判断现在游戏的进程。我们规定如下:
ret='*'则玩家赢
ret='#'则电脑赢
ret='O’则平局
ret='C‘则继续
首先我们需要定义一下,棋盘是否是满的(此时不考虑有人赢得比赛),只要有一个位置是空字符那么就说明棋盘没有满,如果遍历完了发现没有空字符则说明棋盘满了,返回1.
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[2][0] == board[1][1] && board[1][1] == board[0][2] && board[1][1] != ' ')
{
return board[1][1];
} //反对角线赢
if (1 == IsFull(board, ROW, COL))
{
return 'O';
} //满了平局
return 'C'; //游戏继续
}
如果有一方获得了游戏胜利,则返回各方获胜的标记,如果棋盘满了,则返回O,如果没有人获得胜利并且棋盘没满,则返回C。接下来是判断标记告诉玩家哪方获胜的函数:
可以选择是否清屏或者打印一次游戏棋盘告诉玩家是怎么获得游戏胜率的
int judge_win(char board[ROW][COL], int row, int col)
{
char ret = IsWin(board, ROW, COL);
if (ret == '*')
{
//system("cls");
printf("玩家赢了!\n");
//DisplayBoard(board, ROW, COL);
}
if (ret == '#')
{
//system("cls");
printf("电脑赢了!\n");
//DisplayBoard(board, ROW, COL);
}
if (ret == 'C')
{
//system("cls");
printf("游戏继续!\n");
//DisplayBoard(board, ROW, COL);
}
if (ret == 'O')
{
//system("cls");
printf("平局!\n游戏结束.\n");
//DisplayBoard(board, ROW, COL);
}
if (ret != 'C') return 1;
return 0;
}
下面就是整个程序的主要逻辑部分
void player_do_major(char board[ROW][COL], int row, int col) { while (1) { PlayerMove(board, row, col); system("cls"); DisplayBoard(board, row, col); if (judge_win(board, row, col)) break; int i = computer_attack(board, row, col); if (i == 0) //进攻不成立,去判断防守条件 { //printf("h\n"); int z = computer_defend(board, row, col); if (z == 0) //不满足防守条件 { //printf("hhh\n"); computer_random(board, row, col); system("cls"); DisplayBoard(board, row, col); if (judge_win(board, row, col)) break; } else//满足防守条件 { //system("cls"); DisplayBoard(board, row, col); if (judge_win(board, row, col)) break; } } else //满足进攻条件 { //printf("hh"); //system("cls"); DisplayBoard(board, row, col); if (judge_win(board, row, col)) break; } } }
如果是多文件编译的话,头文件一定要声明好所使用的函数,函数实现部分我已经都完整的写出来了,函数主体部分如下
void game()
{
char ret = ' ';
char board[ROW][COL] = { '0','0','0','0','0','0' ,'0','0','0' };
//printf("%c", board[0][0]);
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
int qa;
qa = rand() % 2;
if (qa == 0)
{
printf("玩家先手!\n");
Sleep(2000);
player_do_major(board, ROW, COL);
}
else
{
printf("电脑先手!你可以多准备准备!");
Sleep(5000);
printf("\n");
board[1][1] = '#';
system("cls");
DisplayBoard(board, ROW, COL);
player_do_major(board, ROW, COL);
}
return;
}
void menu()
{
printf("*******************************\n");
printf("***********三子棋游戏**********\n");
printf("************1. play************\n");
printf("************2. exit************\n");
printf("*******************************\n");
}
void test()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择:->");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏三子棋\n");
game();
break;
case 2:
printf("游戏退出");
break;
default:
printf("选择错误,请重新选择\n");
break;
}
} while (input != 2);
}
int main()
{
test();
return 0;
}
其实只要学会了三子棋,五子棋等等无非是将行和列进行变换,判断游戏输赢(五行,五列,对角线)部分作出相应的改变,最关键的是电脑下棋可能会更加高级和思考全面一些,相信大家的聪明才智应该可以完成!
如果大家觉得文章有帮助的话,麻烦动动小手点个赞,期待下一篇更好的文章!