使用C语言编写井字游戏的程序
本文已参与「新人创作礼」活动,一起开启掘金创作之路。
一、基本思路
1.用一个简易的菜单来选择开始或退出游戏 2.打印初始棋盘(没有落子的棋盘) 3.玩家下棋 4.电脑下棋 5.上述两步循环进行,直到有一方胜利或双方达成平局 6.说明哪方获胜或者说明平局 (注:以上代码较多,所以我将代码分为三块:test.c用来测试,game.c用来放需要的函数,game.h引头文件和放函数声明)
二、代码实现
1.用一个简易的菜单来选择开始或退出游戏
首先可以设想一个简易的菜单(这里的菜单不必太过复杂,只要能实现开始和退出即可) 由于不论玩家是否想继续游戏,菜单都必须出现,所以使用do……while循环 代码如下(示例):
void menu()
{
printf("*************************\n");
printf("****** 1、开始 ******\n");
printf("****** 0、退出 ******\n");
printf("*************************\n");
}
int main()
{
int input;
do
{
menu();
printf("请选择\n");
scanf("%d", &input);
switch (input)
{
case 1:
{
game();//开始游戏
}
case 0:
{
break;//退出游戏
}
default:
{
printf("输入错误,请重新输入\n");
break;
}
}
} while (input);
//如果input为0,结束循环,如果为其他,仍需进入循环
//所以可将while(input!=0)简化为while(input)
return 0;
}
2.打印初始棋盘(没有落子的棋盘)
(1)一个简易的棋盘
把下面的图形看做一个单元,每次循环打印这样呀一个单元。但要注意在最后一次打印时不需要打印下面的一行‘-’。
代码如下(示例):
#define ROW 3
#define COL 3
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
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("---", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
printf("\n");
}
(2)将数组的内容初始化为' '
初始化较为简单,只要遍历数组,设置为' '即可 代码如下(示例):
void InitBoard(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
(注:由于三子棋游戏中棋盘只能是3*3,所以在该代码中可直接设置行和列都是3,但方便起见,通过宏定义ROW和COL来调整行和列,这样如果想实现五子棋等游戏时会更方便,在该代码实现过程中也更利于修改)。
3.玩家下棋
我们希望玩家通过输入一对数来表示下棋的坐标(默认先输入横坐标,在输入纵坐标)。 但玩家输入的坐标一定在合法范围内吗?这就需要我们对输入的坐标进行检查:正常输入、输入的位置已经有棋子、输入的坐标不在范围内。这里需要一个循环,只有当玩家的输入合法时才能停止。
由于大多数人考虑的坐标范围是[1,ROW]、[1,COL],处理输入的坐标时应注意到这一点。 代码如下(示例):
void PlayerMove(char board[ROW][COL], int row, int col)
{
printf("您下棋,请输入坐标\n");
while (1)
{
int x, y;
scanf("%d%d", &x, &y);//输入坐标
if (x >= 1 && x <= row && y >= 1 && y <= col)
{//对输入的坐标做检查
if (board[x - 1][y - 1] != ' ')
{
printf("该位置已被占用,请重新输入\n");
}
else
{
board[x - 1][y - 1] = '*';
//玩家下的棋用字符'*'表示
break;//坐标合法时跳出循环
}
}
else
{
printf("输入非法,请重新输入\n");
}
}
}
4.电脑下棋
在简易的三子棋中,我们只需要让电脑生成的坐标合法即可(这里用随机数来产生,不考虑电脑对对玩家进行堵截或者在能赢的情况下优先选择赢) 随机数的生成可用下面的代码实现 代码如下(示例):
srand((unsigned int)time(NULL));//建议放在main函数刚开始的位置
x = rand();//这样得到的x就是随机数
注意time()要引<time.h>头文件,而srand()要引<stdlib.h>头文件
下面是电脑下棋的代码 代码如下(示例):
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
int x, y;
while (1)
{
x = rand() % ROW;//通过取模运算恰好得到[0,ROW)的随机数
y = rand() % COL;
if (board[x][y] == ' ')
//棋盘未落子坐标才合法,否则重新生成坐标
{
board[x][y] = '#';
//电脑下的棋用字符'#'表示
break;
}
}
}
5.上述两步循环进行,直到有一方胜利或双方达成平局
这两步的循环很容易实现,且方便起见,在每次下棋后打印出新的棋盘 代码如下(示例):
while (1)
{
PlayerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
ComputerMove(board, ROW, COL);
DisplayBoard(board, ROW, COL);
}
那么如何判断获胜或平局呢? 获胜的判断较为简单,只需要某行或某列或对角线三个棋相同即可 代码如下(示例):
char CheckWinner(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][2] == board[i][1] && board[i][0] != ' ')
//注意架上该位置不为' '的判断
{
return board[i][0];//某一行三个棋相同
//这里的return直接返回该位置的字符
//用字符代表玩家更加方便,不需要判断是电脑还是玩家
//以下同理
}
}
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')
{
return board[0][j];//某一列三个棋相同
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[3][3] && 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 IsFull(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{//遍历数组即可
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
如果棋盘已满,有不满足某一方获胜的条件,则为平局,这一部分可放如上面判断输赢的函数中 代码如下(示例):
if (IsFull(board, ROW, COL) == 1)
{
return 'Q';
}
return 'C';
将该代码补在CheckWinner函数最后即可
6.说明哪方获胜或者说明平局
这一部分在game()函数中实现,将第五步刚开始的while循环中更改为
while (1)
{
PlayerMove(board, ROW, COL);
ret = CheckWinner(board, ROW, COL);
//用ret接受chechwinner的返回值来判断游戏是否继续
if (ret != 'C')
//如果return 'C'则说明没有任何一方获胜且此时棋盘未满
//所以继续游戏
{
break;
}
DisplayBoard(board, ROW, COL);
ComputerMove(board, ROW, COL);
ret = CheckWinner(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisplayBoard(board, ROW, COL);
}
最后在循环外面打印结果即可
if (ret == '*')
{
printf("你赢了\n");
}
else if (ret == '#')
{
printf("电脑赢了\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
DisplayBoard(board, ROW, COL);
三、全部代码
game.h
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
//打印菜单
void menu();
//初始化棋盘
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 CheckWinner(char board[ROW][COL], int row, int col);
//判断棋盘是否满了(即全部不是' ')
int IsFull(char board[ROW][COL], int row, int col);
test.c
#include "game.h"
void game()
{
char ret;
char board[ROW][COL];
InitBoard(board, ROW, COL);//将棋盘每个元素初始化为' '
DisplayBoard(board, ROW, COL);//打印初始棋盘
while (1)
{
PlayerMove(board, ROW, COL);
ret = CheckWinner(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisplayBoard(board, ROW, COL);
ComputerMove(board, ROW, COL);
ret = CheckWinner(board, ROW, COL);
if (ret != 'C')
{
break;
}
DisplayBoard(board, ROW, COL);
}
if (ret == '*')
{
printf("你赢了\n");
}
else if (ret == '#')
{
printf("电脑赢了\n");
}
else if (ret == 'Q')
{
printf("平局\n");
}
DisplayBoard(board, ROW, COL);
}
int main()
{
srand((unsigned int)time(NULL));
int input;
do
{
menu();
printf("请选择\n");
scanf("%d", &input);
switch (input)
{
case 1:
{
game();
}
case 0:
{
break;
}
default:
{
printf("输入错误,请重新输入\n");
break;
}
}
} while (input);
return 0;
}
game.c
#include "game.h"
//打印菜单
void menu()
{
printf("*************************\n");
printf("****** 1、开始 ******\n");
printf("****** 0、退出 ******\n");
printf("*************************\n");
}
//初始化棋盘
void InitBoard(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
board[i][j] = ' ';
}
}
}
//打印初始棋盘
void DisplayBoard(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
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("---", board[i][j]);
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
printf("\n");
}
//玩家下棋,用'*'表示玩家下的棋
void PlayerMove(char board[ROW][COL], int row, int col)
{
printf("您下棋,请输入坐标\n");
while (1)
{
int x, y;
scanf("%d%d", &x, &y);
if (x >= 1 && x <= row && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] != ' ')
{
printf("该位置已被占用,请重新输入\n");
}
else
{
board[x - 1][y - 1] = '*';
break;
}
}
else
{
printf("输入非法,请重新输入\n");
}
}
}
//电脑下棋,用'#'表示电脑下的棋
void ComputerMove(char board[ROW][COL], int row, int col)
{
printf("电脑下棋\n");
int x, y;
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, j;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
if (board[i][j] == ' ')
{
return 0;
}
}
}
return 1;
}
//判断胜负
char CheckWinner(char board[ROW][COL], int row, int col)
{
int i, j;
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][2] == board[i][1] && board[i][0] != ' ')
{
return board[i][0];//某一行三个棋相同
}
}
for (j = 0; j < col; j++)
{
if (board[0][j] == board[1][j] && board[1][j] == board[2][j] && board[0][j] != ' ')
{
return board[0][j];//某一列三个棋相同
}
}
if (board[0][0] == board[1][1] && board[1][1] == board[3][3] && 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) == 1)
{
return 'Q';
}
return 'C';
}
感谢阅读,如有错误请批评指正
上一篇: 猜数字游戏实现:使用C语言进行编写
下一篇: 猜数字游戏的C语言实现(完整分析)
推荐阅读
-
C语言编写的2048游戏实现
-
Java 8新特性探究(十三)JavaFX 8新特性以及开发2048游戏-JavaFX历史## 跟java在服务器端和web端成绩相比,桌面一直是java的软肋,于是Sun公司在2008年推出JavaFX,弥补桌面软件的缺陷,请看下图JavaFX一路走过来的改进 从上图看出,一开始推出时候,开发者需使用一种名为JavaFX Script的静态的、声明式的编程语言来开发JavaFX应用程序。因为JavaFX Script将会被编译为Java bytecode,程序员可以使用Java代码代替。 JavaFX 2.0之后的版本摒弃了JavaFX Script语言,而作为一个Java API来使用。因此使用JavaFX平台实现的应用程序将直接通过标准Java代码来实现。 JavaFX 2.0 包含非常丰富的 UI 控件、图形和多媒体特性用于简化可视化应用的开发,WebView可直接在应用中嵌入网页;另外 2.0 版本允许使用 FXML 进行 UI 定义,这是一个脚本化基于 XML 的标识语言。 从JDK 7u6开始,JavaFx就与JDK捆绑在一起了,JavaFX团队称,下一个版本将是8.0,目前所有的工作都已经围绕8.0库进行。这是因为JavaFX将捆绑在Java 8中,因此该团队决定跳过几个版本号,迎头赶上Java 8。 ##JavaFx8的新特性 ## ###全新现代主题:Modena 新的Modena主题来替换原来的Caspian主题。不过在Application的start方法中,可以通过setUserAgentStylesheet(STYLESHEET_CASPIAN)来继续使用Caspian主题。 参考http://fxexperience.com/2013/03/modena-theme-update/ ###JavaFX 3D 在JavaFX8中提供了3D图像处理API,包括Shape3D (Box, Cylinder, MeshView, Sphere子类),SubScene, Material, PickResult, LightBase (AmbientLight 和PointLight子类),SceneAntialiasing等。Camera类也得到了更新。从JavaDoc中可以找到更多信息。 ###富文本 强化了富文本的支持 ###TreeTableView ###日期控件DatePicker 增加日期控件 ###用于 CSS 结构的公共 API
-
C语言编写的“猜数字“小游戏
-
使用C语言编写的易懂猜数字游戏
-
用C语言编写一个简单的猜数字游戏
-
用C语言编写的数字猜测游戏
-
用C语言编写的猜数字小游戏
-
使用C++编写的五子棋小游戏及其源代码
-
使用C语言编写的基于1-100数字的简易猜数游戏
-
详解:使用C语言实现的猜数字小游戏