三子棋
前言
一、游戏规则
二、所需文件
三、创建菜单栏
四、游戏的内容与实现
1.棋盘的初始化
2.棋盘的展示
3.玩家下棋
4.电脑下棋
5.判断输赢
6.game()函数的实现
五、游戏运行的结果
前言
用C语言实现三子棋是考验大家对二维数组、函数、循环分支语句等内容的考验。通过本片文章教会大家如何有思路的写出三子棋游戏,试着自己去理解然后想着框架再去敲代码会事半功倍,相信大家一定会掌握三子棋的精髓
一、游戏规则
在我们写代码之前,相信我们大家都在小学或者初中的课堂上和同桌玩过,了解过游戏的玩法 那么我们就围绕着规则用c语言去实现一下
1.人机双方用不同的棋子轮流在规定的棋盘里落子,先连成一线者获胜
2.棋盘若被摆满棋子还未有人获胜则视为平局
二、所需文件
写三子棋的代码如果都放在一起的话会显得及其杂乱,不易自己理解和修改,所以我们要分文件编写。
什么是分文件编写?
就是把我们的程序代码划分成多个文件,这样就不会把所有的代码都放在test.c里面,采用分模块的编程思想,进行功能划分,把每个功能不一样的单独放在一个.c文件里,然后写头文件把它封装成可调用的一个函数,在主函数中调用这个封装好的函数,编译的时候一起编译即可
它的好处是什么:
1.功能分化(有助更加清晰的理解)
2.方便调试和修改数值
3.主程序简洁
让我们来看看怎么操作:
先在源文件中创建一个test.c文件用来存放主程序/再创建一个game.c文件用来函数的具体实现
在头文件中创建一个game.h的文件用来函数的声明
三、创建菜单栏
首先我们的第一步就是在屏幕上打印菜单栏
void menu()
{
printf("******************************\n");
printf("***** 1.play *****\n");
printf("***** 0.exit *****\n");
printf("******************************\n");
}
打印完菜单栏上面有两个选择,所以我们用switch语句用来进行菜单的选择,要是我们还想继续再接着玩怎么办
所以我们用do......while循环
int main()
{
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误请重新选择!\n");
break;
}
} while (input);
}
四、游戏的内容与实现
game()函数 中的内容实现整个游戏,因为我们玩的是三子棋先创建一个二维数组用来表示行和列
1.棋盘的初始化
char board[3][3];//因为我们下棋用的是*和#所以用char类型来接收
但是这样初始化的话,我们要是觉得棋盘太小想玩更大的棋盘就得修改每一个二维数组的值很不方便
所以我们直接在game.h中定义行和列
#define ROW 3
#define COL 3
在game.h中声明并初始化函数Initboard
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);//row是行 col是列
随后我们观察一下棋盘发现它三个横线(---)上并没有任何东西所以上面一个是空格
在game.c中实现初始化函数,创造三行三列并都放上空格
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] = ' ';
}
}
}
2.棋盘的展示
初始化完棋盘需要将棋盘打印在键盘上
在game.h文件中声明打印棋盘
//打印棋盘
void DispalyBoard(char board[ROW][COL], int row, int col);
在game.c文件中实现棋盘打印函数
void DispalyBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)//外面决定了我打印几行数据
{
//打印数据
/*printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);*/
int j = 0;
for (j = 0; j < col; j++)//列的数据
{
printf(" %c ", board[i][j]);
if (j < col - 1)//限制一个区域如果不限制会多打出一列‘|’
printf("|");
}
printf("\n");
//打印分割线
//printf("---|---|---\n");
if (i < row - 1)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if(j<col-1)
printf("|");
}
printf("\n");
}
}
}
棋盘打印完成
3.玩家下棋
在game.h中声明玩家下棋的函数
//玩家下棋
void PlayMove(char board[ROW][COL], int row, int col);
在game.h中实现玩家下棋函数。
我们定义一下 玩家的棋子‘*’ 电脑的棋子‘#’
我们要作为玩家的角度去玩我们自己知道数组要从0开始但是玩家不知道所以我们这边
x和y的值要减去1
玩家所在下棋子不能出棋盘否则坐标非法重新下,所下棋子必须在有空格的格子中否则坐标被占有重新下,while实现玩家下错棋子重新下直到下正确退出循环
void PlayMove(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");
}
}
}
玩家下棋完成。
4. 电脑下棋
在game.h声明电脑下棋函数
//电脑下棋
//找没有下棋的位置随机下
void ComputerMove(char board[ROW][COL], int row, int col);
在game.c文件中实现电脑下棋函数。电脑随机下棋需要srand()函数生成随机数,所以要引头文件#include <stdlib.h>,随机数生成需要时间戳time()函数要引用头文件#include <time.h>。将电脑所下棋控制在棋盘内然后判断是否下在空棋盘内否则重下,while实现玩家下错棋子重新下直到下正确退出循环
srand()函数生成的随机值是0~32767
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:>\n");
int x = 0;
int y = 0;
x = rand() % row;//0~2
y = rand() % col;//0~2
while (1)
{
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
5.判断游戏的输赢
在game.h中声明胜负判断函数。
//玩家赢 -‘*’
//电脑赢 - ‘#’
//平局 - ‘Q’
//继续 - ‘C’
char Iswin(char board[ROW][COL], int row, int col);
在game.c中实现胜负判断函数。每次下棋结果共有四种1.玩家嬴2.电脑嬴3.平局4.继续游戏,
for循环实现行列三点成直线,if判断玩家或电脑三点成直线打印‘ * ’或‘ # ’
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];
}
}
//判断列
int j = 0;
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
{
return board[1][j];
}
}
//判断对角线
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(board, row, col))
{
return 'Q';
}
else
//没人赢也没有平局那就游戏继续
return 'C';
}
平局函数在game.h中。若所有坐标被占满(坐标都不为空)平局函数返回真,判断胜负函数返回Q平局。若坐标不满有空,函数返回假,在判断胜负函数中返回C继续游戏
//如果满了就返回1,不满返回0
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;
}
6.game()函数的实现
创建数组 char board[ROW][COL]; 并用char类型来接收
调用并初始化棋盘InitBoard(char board[ROW][COL]);
和打印棋盘DispalyBoard(char board[ROW][COL])函数,while循环实现电脑和玩家相互下棋用ret接收胜负结果,如果不是继续游戏(C)则跳出循环。若结果为玩家(*)则玩家嬴,若结果为电脑(#)则电脑赢,否则结果为平局。
void game()
{
char ret = 0;
char board[ROW][COL] = {0};
//初始化棋盘的函数
InitBoard(board,ROW,COL);
DispalyBoard(board,ROW,COL);
//开始下棋
while (1)
{
PlayMove(board,ROW,COL);
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DispalyBoard(board, ROW, COL);
ComputerMove(board,ROW,COL);
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DispalyBoard(board, ROW, COL);
}
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else
{
printf("平局\n");
}
DispalyBoard(board, ROW, COL);
}
五、游戏运行结果
1.运行程序,屏幕上打印菜单栏
2.选择1开始游戏,出现棋盘
![]()
3.输入下棋的坐标 开始下棋
4.电脑紧跟其后就开始下棋了
![]()
后面就直接展示全部了
![]()
出现三点成线程序结束
![]()
若棋盘下满则平局
完整代码如下:
game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col);//row是行 col是列
//打印棋盘
void DispalyBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayMove(char board[ROW][COL], int row, int col);
//电脑下棋
//找没有下棋的位置随机下
void ComputerMove(char board[ROW][COL], int row, int col);
//玩家赢 -‘*’
//电脑赢 - ‘#’
//平局 - ‘Q’
//继续 - ‘C’
char Iswin(char board[ROW][COL], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
//棋盘的清除(初始化棋盘)
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 DispalyBoard(char board[ROW][COL], int row, int col)
//{
// int i = 0;
// for (i = 0; i < row; i++)
// {
// //打印数据
// printf(" %c | %c | %c \n",board[i][0],board[i][1],board[i][2]);
// //打印分割线
// if(i<row-1)
// printf("---|---|---\n");
// }
//}
void DispalyBoard(char board[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)//外面决定了我打印几行数据
{
//打印数据
/*printf(" %c | %c | %c \n", board[i][0], board[i][1], board[i][2]);*/
int j = 0;
for (j = 0; j < col; j++)//列的数据
{
printf(" %c ", board[i][j]);
if (j < col - 1)//限制一个区域如果不限制会多打出一列‘|’
printf("|");
}
printf("\n");
//打印分割线
//printf("---|---|---\n");
if (i < row - 1)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if(j<col-1)
printf("|");
}
printf("\n");
}
}
}
void PlayMove(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");
}
}
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋:>\n");
int x = 0;
int y = 0;
x = rand() % row;//0~2
y = rand() % col;//0~2
while (1)
{
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
//如果满了就返回1,不满返回0
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];
}
}
//判断列
int j = 0;
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[1][j] != ' ')
{
return board[1][j];
}
}
//判断对角线
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(board, row, col))
{
return 'Q';
}
else
//没人赢也没有平局那就游戏继续
return 'C';
}
test.c
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void menu()
{
printf("******************************\n");
printf("***** 1.play *****\n");
printf("***** 0.exit *****\n");
printf("******************************\n");
}
void game()
{
char ret = 0;
char board[ROW][COL] = {0};
//初始化棋盘的函数
InitBoard(board,ROW,COL);
DispalyBoard(board,ROW,COL);
//开始下棋
while (1)
{
PlayMove(board,ROW,COL);
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DispalyBoard(board, ROW, COL);
ComputerMove(board,ROW,COL);
//判断输赢
ret = Iswin(board, ROW, COL);
if (ret != 'C')
{
break;
}
DispalyBoard(board, ROW, COL);
}
if (ret == '*')
{
printf("玩家赢\n");
}
else if (ret == '#')
{
printf("电脑赢\n");
}
else
{
printf("平局\n");
}
DispalyBoard(board, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));//设置随机数的生成起点
int input = 0;
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch (input)
{
case 1:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误请重新选择!\n");
break;
}
} while (input);
return 0;
}