三子棋>>
三子棋也称作井字棋,OX棋。游戏规则是 两个玩家轮流在一个3*3的棋盘上落子,谁的3个棋子率先连成一条直线,那么他就获胜了。如果棋盘下满了双方棋子都没有连成一条线,那么就定为平局。
根据游戏规则下面我们将用c语言来写一个三子棋小游戏。这里我们将运用c语言中的二维数组,循坏控制语句,函数封装的内容,过程中为大家详细解释最后为大家附上整个游戏实现的代码,那就开始吧!
一. 实现三子棋的基本思路
1.创建选择菜单
2.设置循环框架
3.初始化棋盘
4.打印棋盘
5.玩家下棋
6.电脑下棋
7.判断输赢
要成功实现三子棋,要做好前期准备工作,在实际应用软件中,往往会有数以万计行代码甚至更多,为提升效率也为增加代码的可读性就要通过功能分解实现函数的模块化思想实现程序设计,这里我们将代码分别写到game.h,game.c,test.c里面去,game.h专门用来声明我们定义的函数,game.c里实现我们各个函数的功能,test.c来测试我们的游戏代码,这种分块思想也方便大家理解。
二.三子棋实现详解
1.创建选择菜单
这里我们可以定义一个菜单函数menu,每次要开始游戏我们就调用menu函数,打印菜单选择。
void menu()
{
printf("************************\n");
printf("****** 1.play ********\n");
printf("****** 0.exit ********\n");
printf("************************\n");
}
2.设置循环结构
我们要想多次玩游戏,就要用do-while循环,这里给出菜单上两个选择,如果输入了其他数字,也可以重新选择。可以看到这里输入1进入case 1,调用game()函数,这个game()函数里放的就是我们各种功能函数,能进行我们的游戏。这样我们的框架就搭建好了,接下来开始具体游戏部分的实现。
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);
return 0;
}
3.初始化棋盘
我们要想得到一个标准的棋盘,就要先初始化棋盘,我们封装一个函数InitBoard()专门用来初始化棋盘。这里通过循坏可以我们给一个二维数组初始化。一开始我们希望上什么都没有就全部初始成空格。
()
void Initboard(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] = ' ';
}
}
}
注意:我们参数这里没有固定写成33,目的是代码量大的情况下方便后续更改,我们使用宏定义 ,不仅可以得到33棋盘,要想得到55或者1010只需改变这里的数字即可,是不是很方便?
4.打印棋盘
自然我们要打印棋盘,也需要一个打印棋盘的函数DisplayBoard(),我们一开始把二维数组全部初始化成0,如果直接打印什么也看不到的,如最上面给出的图。这里分割线有多种实现方法,这里推荐大家一种写法,就是用循环分别控制打印出横线和竖线,而不是循环打印一行的横线和竖线,这样不论几乘几的棋盘都能灵活的打印出来,使之构成我们想要棋盘。
void DisplayBoard(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)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
printf("\n");
}
}
}
初始化好棋盘,我们就打印出来看看效果。十分对称整洁,没有多余的线条,直观清晰。
5.玩家下棋
下面是重头戏,我们要玩游戏,怎么做能把棋下在这个棋盘上呢?对,坐标,用二维数组的下标来表示坐标。我们输入两个代表着坐标数字,就能在这个位置上落子。那我们不能随便输入两个数字吧,如果误一个输入的坐标压根不存在在棋盘上呢?这里我们就要判断坐标的合法性需要考虑两点:一是只有在棋盘范围内我们才能落子,二是该位置已经有子,我们要换个没有落子的地方。我们给一个判断语句实现,用星号代表执子的玩家,如果坐标合法就落子。
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋>:\n");
scanf("%d %d", &x, &y);
//判断合法性
while (1)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
printf("该位置被占用,重新落子\n");
break;
}
else
{
printf("坐标非法,重新输入\n");
}
}
}
玩家落子后需要看到棋盘的状况,我们打印一下看看效果:成功落子。
6.电脑下棋
玩家落子后,就轮到电脑了,用#号代表电脑。电脑下棋也需要考虑两点:一是只有在棋盘范围内我们才能落子,二是该位置已经有子,要换个没有落子的地方落子。那电脑是如何移动呢?这里使用的是专门生成随机数的rand函数,在调用rand函数之前要先调用srand函数。srand函数用于设置时间戳,每次运行代码会调动一次。让随机数x模row就能生成到0到row-1的数,y模col就能产生0到col-1的数,这样就能顺利进行下去。
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
while (1)
{
//生成随机
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
我们需要看电脑落子落在了哪里,我们打印一下看看:
注意:这里提一下设置时间戳的方法是srand((unsigned)time(NULL))。
7.判断输赢
总共就有三种情况,玩家赢,电脑赢,平局。根据规则要判断棋盘上哪方棋子先连成一条线,这里一条线也分为三种情况,竖着连成线,横着连成线和对角线,我们就按照这三种情况来判断。行和列for循环判断即可,对角线上if来判断。判断赢的函数这里设置的返回一个char类型字符,如果玩家赢返回*,如果电脑赢返回#。
那我们说平局是什么情况呢?就是这个棋盘已经无处落子,但是没有分出胜负的情况,我们这里设置一个函数先判断棋盘是否满了。
int IsFull(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++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
这里我们设置如果返回1,则代表棋盘已满,在下面输赢判断函数里会返回字符Q,也代表这局游戏结束;返回0,就不满足平局条件可以继续玩游戏。
这里我们成功实现了平局的判断。
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][0] != ' ')
{
return board[i][0];
}
}
//列
for (i = 0; i< col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[1][1];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[1][1];
//平局,棋盘满了
if (IsFull(board,row,col) == 1)
{
return 'Q';
}
//继续
return 'C';
}
好啦,到这里我们整个的游戏实现就全部完成了,那就试试先玩一把,说明我们这个游戏已经可以运行了。
三.总体代码实现
在文章开头告诉了大家这个三子棋小游戏分别用三个文件实现,为了方便修改和理解,也提升了效率,下面给大家分享一下完整的代码:
首先是game.h
#pragma once
#include<stdio.h>
#define ROW 3
#define COL 3
//初始化棋盘
void Initboard(char board[ROW][COL], int row, int col);
//打印棋盘
void DisplayBoard(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int col);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//判断输赢
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;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
void DisplayBoard(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)
{
int j = 0;
for (j = 0; j < col; 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;
printf("玩家下棋>:\n");
scanf("%d %d", &x, &y);
//判断合法性
while (1)
{
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
printf("该位置被占用,重新落子\n");
break;
}
else
{
printf("坐标非法,重新输入\n");
}
}
}
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("电脑下棋:>\n");
while (1)
{
//生成随机
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
int IsFull(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++)
{
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][0] != ' ')
{
return board[i][0];
}
}
//列
for (i = 0; i< col; i++)
{
if (board[0][i] == board[1][i] && board[1][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
}
//对角线
if (board[0][0] == board[1][1] && board[1][1] == board[2][2] && board[0][0] != ' ')
return board[1][1];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[1][1];
//平局,棋盘满了
if (IsFull(board,row,col) == 1)
{
return 'Q';
}
//继续
return 'C';
}
test.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include "game.h"
void menu()
{
printf("************************\n");
printf("****** 1.play ********\n");
printf("****** 0.exit ********\n");
printf("************************\n");
}
void game()
{
char board[3][3] = { 0 };
//初始化
Initboard(board, ROW, COL);
//打印棋盘
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
//电脑下棋
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
printf("玩家赢\n");
else if (ret == '#')
printf("电脑赢\n");
else
printf("平局\n");
}
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);
return 0;
}
最后,就完成了一个小游戏的程序,博主是个初学者,但是也很热爱计算机编程,个人认为这个编程从无到有的实现过程真的很有意思,也很奇妙的,欢迎能大家一起交流进步,希望每个热爱计算机小伙伴都能越来越好。