三子棋
前言
三子棋是一个经典的游戏,也是一个简单益脑的游戏,在如今的地位也是十分的受欢迎,所以我们如何用C语言去实现呢?让我们继续一探究竟
一、主要思路
如果我们想要实现一个不小的程序,我们分别用 game.h,game.c,test.c 一个头文件,两个源代码,game.h 我们用来声明函数作为接口函数和定义一些变量 game.c 主要是用来对游戏函数的实现。 test.c 就是我们整个的测试程序 把他分为3个文件,可以理清我们的思路 关于3字棋的棋盘,首先我们的思路就是去创建一个棋盘,我们创建棋盘需要怎么做呢,一上来的想法就是创建一个二维数组去用来实现。这就是我们一上来能想到的一些思路
二、代码模块
1. test.c
首先做一个菜单函数 menu()
void menu()
{
printf("********************************\n");
printf("***********1.进入游戏***********\n");
printf("***********0.退出游戏***********\n");
printf("********************************\n");
}
用do while语句使循环至少运行一次,用switch语句进行判断,此时我们把case 0设置为退出,正好判断0为假可以跳出循环
int main()
{
int input=0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请选择:>\n");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出成功\n");
break;
default:
printf("输入错误,请重新输入:\n");
break;
}
} while (input);
return 0;
}
这里是整个下棋的流程。我们创建game()函数 创建一个二维数组,把数组长度用ROW COL来定义 这样方便我们以后修改棋盘的格数
void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };
init_board(board, ROW, COL);
display_board(board, ROW, COL);
while (1)
{
//下棋
player_move(board, ROW, COL);
//打印棋盘
display_board(board, ROW, COL);
//判断是否赢得游戏
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
//电脑下棋
computer_move(board, ROW, COL);
//打印棋盘
display_board(board, ROW, COL);
ret = is_win(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*') //*玩家赢 #电脑赢 Q平局 C继续游戏
{
printf("玩家赢!\n");
}
else if (ret == '#')
{
printf("电脑赢!\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
}
这里我们在每次玩家和电脑下棋之后进行判断,用一行if进行判断是否继续这样也可以避免判断三行的输赢关系,避免了垄长的代码。
还有我们这里用*来代表玩家赢,#代表了电脑赢,一会会在game.c讲到
2. game.h
接口函数
#include<stdio.h>
#include<time.h>
#include<stdlib.h>
#define ROW 3
#define COL 3
void display_board(char board[ROW][COL], int row, int col); //展示出棋盘
void init_board(char board[ROW][COL],int row,int col); //初始化棋盘
void player_move(char board[ROW][COL], int row, int col); //玩家下棋
void computer_move(char board[ROW][COL], int row, int col); //电脑下棋
char is_win(char board[ROW][COL], int row, int col); //判断输赢
3. game.c
打印棋盘
void display_board(char board[ROW][COL], int row, int col)
{
int i = 0;
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("\n");
if (i < row - 1) //最后一行的 ---|---|--- 去掉
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
如果我们想实现出这样的棋盘,在每一列中要打印出空格%c空格和丨
为了美观在最后一列中没有丨所以要进行判断,同理打印—和丨也是一样的方法,这里要注意的是在最后一行也是没有—丨—丨—所以我们要有一个条件进行判断
初始化函数
void init_board(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
}
这里要注意的是如果把每个数组赋为\0的话会造成棋盘位置不美观,如下图
玩家下棋
void player_move(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] = '*';
break;
}
else
{
printf("该坐标被占用,请重新输入\n");
}
}
else
{
printf("该坐标非法,请重新输入\n");
}
}
}
我们都知道在数组中第一个元素是0,但是玩家认为第一行第一列是1,所以我们要以玩家考虑,并且使得玩家输入的在棋盘之中。
电脑下棋
void computer_move(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:>\n");
while (1)
{
int x = rand() % row; //放在循环内部 每次都重新赋一个值
int y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
假如我们设计的是三子棋这里我们设计一个随机值使得 x,y的范围在0-2之内
判断输赢
*代表玩家赢 #代表电脑赢 Q代表平局 C代表继续游戏
char is_win(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 (j > 0 && board[i][j] == board[i][j + 1] && board[i][j] == board[i][j - 1] && j < col - 1 && board[i][j] != ' ')
{
return board[i][j];
}
//列
if (i > 0 && board[i][j] == board[i+1][j] && board[i][j]==board[i-1][j] && i < row - 1 && board[i][j] != ' ')
{
return board[i][j];
}
//两对角线
if (i > 0 && j > 0 && board[i][j] == board[i + 1][j + 1] && board[i][j] == board[i - 1][j - 1] && i < row - 1 && j < col - 1 && board[i][j] != ' ')
{
return board[i][j];
}
if (i > 0 && j > 0 && board[i][j] == board[i + 1][j - 1] && board[i][j] == board[i - 1][j + 1] && i < row - 1 && j < col - 1 && board[i][j] != ' ')
{
return board[i][j];
}
}
}
//判断平局
if (is_full(board, row, col) == 1)
{
return 'Q';
}
//游戏继续
return 'C';
}
上面我们讲到判断胜利的条件返回值是*或者#,这样正好就在game()函数中 *和#来判断 可以直接返回任意一个数组,很方便。 不用再返回个1
判断棋盘空满
static int is_full(char board[ROW][COL],int row,int col) //满了返回1 不满返回0
{
int i = 0; //static修饰的函数 只能在本文件引用 其他文件中不能引用
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
这里我们用一个static关键字 用处是限制只能在本文件之中引用,不能被以外的代码文件调用,函数设立为静态函数,具有唯一性。
运行程序
总结
以上就是今天的内容,整的来说代码难度不大,重要的是整个流程的思路,希望发表的这篇文章可以让大家有一个明确的思路,获得一定的收获,谢谢大家!