目录
学习C语言已经有一段时间了,今天学习了实现一个三子棋小游戏,结合之前学过的C语言知识做三子棋,即满足了学习C语言的好奇心,也巩固和加深了对知识的理解。
想象一下我们平时玩的五子棋,其实跟三子棋是类似的,只要三个一样的在一条线上(横的、竖的、斜的都算)就赢了,下面来具体实现一下吧!
对于这种稍大复杂的程序,我们可以建立多个源文件和头文件,目的是为了管理方便,代码的可读性也会更高,更容易使人理解,如果都写在一个源文件里,会给人一种很乱,很挤的感觉。
首先,不管三七二十一我们先创建好项目,创建一个game.h文件,用来写函数的声明的头文件的包含,创建一个game.c文件,用来写函数的具体实现,再创建一个test.c文件用来测试这个游戏。
创建如下图所示的文件:
创建好项目后,我们先把程序的框架搭起来,然后具体的功能封装成函数来实现。
做一个简易的菜单,用来提示用户输入选项,我们要写一个三子棋,首先得有棋盘,才能在棋盘上落子,通过分析,发现用二维数组存放棋盘的数据是非常合适的,那么我们得创建一个二维数组。
创建数组时,数组的大小可以用#define来定义,如果我们想玩10*10的棋盘只需要把#define定义的常量改成10即可。
整体框架代码:
//game.h 文件中,函数的声明和头文件的包含
#pragma once
#define ROW 3
#define COL 3
//头文件的包含
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
//函数的声明
//菜单函数
void menu();
//初始化棋盘
void BoardInit(char board[ROW][COL], int row, int col);
//打印棋盘
void BoardPrint(char board[ROW][COL], int row, int col);
//玩家下棋
void PlayerMove(char board[ROW][COL], int row, int clo);
//电脑下棋
void ComputerMove(char board[ROW][COL], int row, int col);
//判断输赢
char IsWin(char board[ROW][COL], int row, int col);
//test.c 文件中,主函数实现
#include "game.h"
void game()
{
//创建棋盘
char board[ROW][COL];
//初始化棋盘
BoardInit(board, ROW, COL);
//打印棋盘
BoardPrint(board, ROW, COL);
char ret = 0;
while (1)
{
//玩家下棋
PlayerMove(board, ROW, COL);
//打印棋盘
BoardPrint(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
//电脑下棋
ComputerMove(board, ROW, COL);
//打印棋盘
BoardPrint(board, ROW, COL);
//判断输赢
ret = IsWin(board, ROW, COL);
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入选项(1 or 0):");
scanf("%d", &input);
switch (input)
{
case 1:game();
break;
case 0:
printf("退出程序\n");
break;
default:
printf("输入错误,请重新输入\n");
break;
}
} while (input);
return 0;
}
//game.c 文件中,函数的具体实现
#include "game.h"
//打印菜单
void menu()
{
printf("*******************************\n");
printf("********** 1.play *********\n");
printf("********** 0.exit *********\n");
printf("*******************************\n");
}
//初始化棋盘
void BoardInit(char board[ROW][COL], int row, int col)
{
}
//打印棋盘
void BoardPrint(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)
{
}
//判断输赢
//玩家赢了,返回*
//电脑赢了,返回#
//平局, 返回Q
//继续, 返回C
char IsWin(char board[ROW][COL], int row, int col)
{
}
代码整体框架构建好后,接下来就实现每个功能。框架如下:
初始化棋盘:
//所使用的头文件已经包含
void BoardInit(char board[ROW][COL], int row, int col)//形式参数棋盘,行数,列数
{
//可以使用遍历数组的方式初始化棋盘
/*for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
board[i][j] = ' ';//将数组内容全部初始化成空格
}
}*/
//也可以使用memset函数来初始化棋盘
memset(board, ' ', sizeof(board[0][0]) * row * col);
}
打印棋盘:
//所使用的头文件已经包含
void BoardPrint(char board[ROW][COL], int row, int col)//形式参数,棋盘,行数,列数
{
//控制行
for (int i = 0; i < row; i++)
{
//控制列
for (int j = 0; j < col; j++)
{
printf(" %c ", board[i][j]);
if (j < col - 1)
printf("|");
}
printf("\n");
if (i < row - 1)
{
for (int 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;
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;
while (1)
{
//获取随机值,任何一个数模n的值的范围是 [0, n-1]
x = rand() % row;//0-2
y = rand() % col;//0-2
//判断当前坐标是否被使用
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
判断输赢:
//玩家赢了,返回*
//电脑赢了,返回#
//平局, 返回Q
//继续, 返回C
char IsWin(char board[ROW][COL], int row, int col)//形式参数,行数,列数
{
//判断每一行的三个棋子是否相同
for (int 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 (int 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[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];
}
//判断棋盘是否满了
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
//如果棋盘未满就继续下棋,返回 'C' 继续
if (board[i][j] == ' ')
return 'C';
}
}
//以上都没有返回,那么棋盘已满,但是谁都没有赢,返回 'Q' 平局
return 'Q';
}
因为判断输赢的函数有返回值,所以需要在game函数里接收它的返回值,从而判断输赢结果:
那么game函数中需要这样写:
好了,三子棋就到这里,下棋更新扫雷游戏!!!