 前言:今天我们来用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:
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("输入有误\n");
break;
}
} while (input);
return 0;
}
然后我们要补充好game()的部分:
按照构思,我们先要把初始化的棋盘给写出来,那初始化棋盘如何写呢,一个九宫格的棋盘可以看作为九个空格和一个井字合起来,而且空格中需要输入东西,所以我们可以用一个二维数组了表示,如何横竖的井字,我们可以用符号" — " 和符号 " | "在二维数组的缝隙中接入。
那么直接写?不不不,还记得我们区分板块吗,在这里我们只需要命名几个函数,然后在game.c上写就可以啦
void game()
{
char board[ROW][COL];
InitBoard(board, ROW, COL);
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);
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");
}
}
以上就是我们test.c的代码。
3.game.h
写好主函数之后,那么头文件game.h中的函数声明就很容易写好了。 部分说明直接在代码中注释就可以了。
#pragma once
#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);
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[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
int ret = IsFull(board, row, col);
if (ret == 1)
{
return 'Q';
}
return 'C';
}
到此就把game.c中需要的函数都实现了。
三、完整代码
完整代码如下:
1.test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include "game.h"
void menu()
{
printf("***********************************\n");
printf("*********** 1. play *********\n");
printf("*********** 0. exit *********\n");
printf("***********************************\n");
}
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);
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;
srand((unsigned int)time(NULL));
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;
}
2.game.h
#pragma once
#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);
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);
int IsFull(char board[ROW][COL], int row, int col);
char IsWin(char board[ROW][COL], int row, int col);
3.game.c
#define _CRT_SECURE_NO_WARNINGS 1
#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)
{
for (j = 0; j < col; j++)
{
printf("---");
if (j < col - 1)
printf("|");
}
}
printf("\n");
}
}
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);
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)
{
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;
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[1][1] == board[2][0] && board[1][1] != ' ')
{
return board[1][1];
}
int ret = IsFull(board, row, col);
if (ret == 1)
{
return 'Q';
}
return 'C';
}
这就是三子棋小游戏的C语言写法啦,小白制作不易,有错的地方还请xdm指正,互相关注,共同进步。
|