C语言三字棋小游戏详解
Posted Persistence_i
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言三字棋小游戏详解相关的知识,希望对你有一定的参考价值。
前言:今天我们来用C语言写一个三子棋小游戏,三子棋,是黑白棋的一种。三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉、一条龙、井字棋等。这里我们写的是玩家与电脑对战的一个代码,如果想跟朋友一起玩也可以自己稍作修改噢。
让我们往下看吧
目录:
C语言简单三字棋小游戏:
一、想法与构思
1.想法
首先想要做一个游戏就先明白游戏的规则和玩法,三子棋,就是在一个九宫格里面下子,两个人对战,每一个人每一轮下一子,当任意一方有横竖斜其中一种三子连线,即该方获胜。若九宫格填满,仍无连线,则为平局。
没错,这就是我们想写出来的游戏,那么接下来就是构思了↓
2.构思
有了想法构思就很容易啦。
首先我们要确定我们代码中要实现的:
- 在初始状态下出现一个九宫格。
- 玩家和电脑轮流进行输入。
- 每一轮可在里面输入一个字符标记。
- 判断游戏继续、平局或谁胜谁负。
完成构思接下来就进入我们的代码领域了。
二、代码与实现
1.代码分块
为了让整个代码更加可观,我们首先把代码分为三个板块:
1.test.c源文件
测试游戏和一些细节的补充。
2.game.h头文件
存放游戏函数的声明。
3.game.c源文件
整个游戏的实现。
2.test.c
首先我们来将代码的整体框架给写出来:
//先写一个菜单函数,让我们选择是否进入游戏
void menu()
{
printf("***********************************\\n");
printf("*********** 1. play *********\\n");
printf("*********** 0. exit *********\\n");
printf("***********************************\\n");
}
void game()//游戏主体的代码
{
}
int main()//主函数
{
int input = 0;
do
{
menu();//引用上面的菜单函数
printf("请选择>");
scanf("%d", &input);//选择是否进入游戏
switch (input)
{
case 1://输入1进入游戏
game();
break;
case 0://输入0退出游戏
printf("退出游戏\\n");
break;
default://输入其他会提示输入有误
printf("输入有误\\n");
break;
}
} while (input);
return 0;
}
然后我们要补充好game()的部分:
按照构思,我们先要把初始化的棋盘给写出来,那初始化棋盘如何写呢,一个九宫格的棋盘可以看作为九个空格和一个井字合起来,而且空格中需要输入东西,所以我们可以用一个二维数组了表示,如何横竖的井字,我们可以用符号" — " 和符号 " | "在二维数组的缝隙中接入。
那么直接写?不不不,还记得我们区分板块吗,在这里我们只需要命名几个函数,然后在game.c上写就可以啦
void game()//三子棋游戏的过程
{
char board[ROW][COL];//创建一个二维数组作为棋盘
//ROW为行,COL为列
InitBoard(board, ROW, COL);//初始化棋盘 - board的元素都给成空格
//将二维数组和行列传进函数
DisplayBoard(board, ROW, COL);//打印横竖的棋盘
//将二维数组和行列传进函数
}
然后接下来就是下棋的部分了。
再看回我们的构思,玩家和电脑轮流下棋。所以我们得写两个函数分别描述玩家下棋和电脑下棋。
void game()//三子棋游戏的过程
{
char board[ROW][COL];
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
PlayerMove(board, ROW, COL);//玩家下棋
DisplayBoard(board, ROW, COL);//打印玩家下棋后的棋盘
ComputerMove(board, ROW, COL);//电脑下棋
DisplayBoard(board, ROW, COL);//打印电脑下棋后的棋盘
}
然后我们需要是第三个构思。每一轮! 我们不可能一轮就分出胜负,所以我们要在玩家和电脑下棋之间放一个循环,同时我们再看第四个构思,当循环出来那么就是胜负已分了。
所以我们要在game()中添加一个循环和一个胜负条件还有平局条件:
这里我们可以设置一个判断胜负函数 IsWin,然后 给 IsWin函数设置返回值,结果为
- 如果胜负未分,游戏继续,则返回值为C(continue)
- 如果玩家赢了,返回玩家的符号,反之返回电脑的符号。
- 什么都不返回就平局。
void game()//三子棋游戏的过程
{
char board[ROW][COL];
InitBoard(board, ROW, COL);
DisplayBoard(board, ROW, COL);
char ret = 0;
while (1)//设置循环,当判断平局或胜负就跳出
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
//设置一个判断胜负函数 IsWin
//在这里设置一个变量ret,接收IsWin返回的结果
ret = IsWin(board, ROW, COL);
if (ret != 'C')
{
break;//如果不等于C(continue),就是平局或胜负已分
//直接跳出循环
}
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");
}
}
以上就是我们test.c的代码。
3.game.h
写好主函数之后,那么头文件game.h中的函数声明就很容易写好了。
部分说明直接在代码中注释就可以了。
#pragma once //作用:让引头文件只引一次,防止头文件被多次包含。
//在这里我们几个模块需要的头文件的放这里就可以了
//到时候再在另外两个中直接引用 "game.h"就可以使用game.h中引用的头文件了。
#include <stdio.h>
#include <stdlib.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);
4.game.c
重头戏来了,整个代码的灵魂,也是最难写的部分来了。
前面写了那么多也仅仅是把构思的框架实现了而已,这里才是真正把游戏写出来的地方。
那我们一个一个来吧:
1.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] = ' ';
}
}
}
2.DisplayBoard(横竖划分)
在这里,我们可以先想像棋盘是什么样子的:
那我们打印的时候呢(要用 — 和 | ):
我们可以看到先 — 再 | ,而且是三次打印 — 两次打印 |
所以整体是分为:
- 打印玩家或电脑输入字符+竖杠分割线
- 横杠分割线+竖杠分割线
代码:
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)//打印两次
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)//比横少一次打印
printf("|");
}
}
printf("\\n");
}
}
3. PlayerMove(玩家进行游戏)
首先我们要提示到玩家进行游戏,然后为了统一和简化玩家操作,我们直接把玩家想画的地方改为坐标指示。比如1 1就是画第一行第一列。
然后我们也要判断玩家输入的坐标是否有效,要考虑坐标存不存在,坐标里面是否已经被画。
代码:
void PlayerMove(char board[ROW][COL], int row, int col)
{
printf("轮到玩家进行操作:>\\n");
int x = 0;
int y = 0;
while (1)//设定一个死循环,直到玩家输对坐标才跳出去
{
printf("请输入坐标:>");
scanf("%d%d", &x, &y);//定义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.ComputerMove(电脑进行操作)
电脑操作就比玩家简单多了,直接设定一个符合坐标的随机值,再判断这个坐标为空格就可以了。
代码:
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;
}
}
}
5. IsWin(判断胜负)
判断胜负的条件也很简单,我们可以分别写出来:
- 横上有三个相同的符号
- 竖上有三个相同的符号
- 对角线有三个相同的符号
代码:
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[0][2] == board[1][1] && board[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
}
然后还有平局和继续游戏这两个情况还没有,我们可以写一个IsFull函数来决定是否结束游戏,:
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[0][2] == board[1][1] && board[[C语言]三字棋游戏