三子棋项目
一:项目目的
实现基本的三子棋操作,玩家或者电脑谁先满足同一条线上有3颗己方的棋子,谁就获胜。
二:设计思路
在实现一个项目时,应该考虑到项目的基本构成要素有哪些。
1.需要实现三子棋必须先有一个三子棋特定的棋盘,我们可以使用二维数组来实现。
2.作为游戏的开始,应该有主菜单,显示开始游戏和退出游戏。
3.提供给用户在游戏过程中想要占领三子棋的地方。由程序先判断此位置是否已经被占用,被占用时向用户提醒此操作无效并重新输入。未被占用时,将此位置占用。电脑和人脑轮番占用位置,这时就会出现三种情况:
(1)玩家所占位置练成一条线,玩家获胜,游戏结束;
(2)电脑居然赢了!!!游戏结束;
(3)稀里糊涂的二人组居然将棋盘占满都没有分出胜负,真是旗鼓相当的对手啊>.<!
4.回到初始菜单界面,询问用户是否开始下一把PK。
三:项目主要函数
本人是将项目的主要函数和参数都放在同一个 game.h 头文件当中,既能够节省主函数的空间,也便于后续对程序的维护。例如对于有#define所定义的常量能够方便修改。
#ifndef __GAME_H__
#define __GAME_H__
#include <stdio.h>
//调用rand()和srand()函数的头文件
#include <stdlib.h>
#include <time.h>
#define ROW 3
#define COL 3
// 初始化棋盘
void InitBoard(char board[][ROW], int row, int col, char set);
// 打印棋盘
void ShowBoard(char board[][ROW], int row, int col);
// 玩家移动
void PlayerMove(char board[][ROW], int row, int col);
// 电脑移动
void ComputerMove(char board[][ROW], int row, int col);
// 判断谁赢了比赛
char IsWin(char board[][ROW], int row, int col);
#endif //!__GAME_H__
再此说明
#ifndef __GAME_H__
#define __GAME_H__
//函数声明
#endif
这三个主要作用是为了防止头文件重复引用。
四:函数代码功能详解
将函数如何实现的放入game.c中,只要在含有main() 函数源文件中引入game.h,通过函数调用就能够实现整个游戏的运行。
1.初始化棋盘
初始化需要知道数组的地址、行数、列数以及需要将整个数组的值赋值为‘ ’(空格)。使用for循环将这个数组统一赋值为set值。
void InitBoard(char board[][ROW], int row, int col, char set)
{
int i = 0;
int j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < row; j++)
{
board[i][j] = set;
}
}
}
2.打印棋盘
传入数组名称 ,行和列,利用for输出数组。
为了输出一个明显分割的二维数组。如下图1所示,在每次输出参数时,在行添加“|”,以标示出列。在每一行输出结束后添加“—”和“|”以区分出列。
void ShowBoard(char board[][ROW], int row, int col)
{
int i = 0;
int j = 0;
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("---");
if (j < col - 1)
{
printf("|");
}
}
printf("\n");
}
}
}
3.玩家移动和电脑移动
在玩家和电脑输入需要占用的位置时,站在游戏玩家的思想上考虑,输入的数值应该从第一行到第三行需要先判断此位置是否在三子棋的位置上,在录入位置后,程序应该自行处理行列与数组的位置关系,即x- -和y- -,之后再判断此位置是否已经被占用,所以在占用前先添加判断条件。
//代码块---玩家
//1.坐标合法 -》坐标被占用
if (x >= 1 && x <= 3 && y >= 1 && y <= 3)
{
x--;
y--;
if (board[x][y] == ' ')
{
board[x][y] = 'X';
//退出循环:位置合法,并且没有被占用,break
break;
}
else if (board[x][y] == 'X' || board[x][y] == 'O')
{
printf("输入的坐标被占用,请重新输入!!\n");
}
}
//2.坐标不合法
else
{
printf("输入错误!!\n");
}
3.1玩家移动
玩家的移动需要通过键盘来获取,此外再将位置进行判断和占用就可以了。玩家占领位置代码如下:
void PlayerMove(char board[][ROW], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("玩家移动\n");
printf("请输入1-3的坐标:\n");
scanf("%d %d", &x, &y);
//代码块--玩家
}
}
3.2电脑移动
电脑占据位置是通过随机数来占用位置的,此处就需要用到rand()和srand(),调用它们需要引用头文件stdlib.h和time.h。为了产生1-3的随机值,令x=rand()%3和y=rand()%3。此时就表现了#define定义的常量的好处,如果变成五子棋就需要将两个参数都改变,这时由define定义的常量就能避免在函数体频繁更改的麻烦,还避免了将参数改错的情况。
电脑占位置代码如下:
void ComputerMove(char board[][ROW], 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] = 'O';
break;
}
}
}
4. 判断比赛结果
如下图2所示三子棋赢的条件有八种情况:
char IsWin(char board[][ROW], int row, int col)
{
int i = 0;
ShowBoard(board, ROW, COL);
for (i = 0; i < row; i++)
{
if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != ' ')
{
return board[i][0];
}
else if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != ' ')
{
return board[0][i];
}
else if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != ' ')
{
return board[1][1];
}
else if (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] != ' ')
{
return board[1][1];
}
if (IsFull(board, ROW, COL))
{
return 'Q';//平局
}
}
return '1';
}
IsFull(board,ROW,COL)判断是否为平局的函数,如果双方都将棋盘下满了,则为平局。即整个二维数组中没有初始化的set值(此处初始化set值为空格字符)。while()循环语句为非0数均为真,所以整个数组还有空格字符时,返回0。反之,返回1,表示三子棋已经下满了。
int IsFull(char board[][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;
}
五:主函数
将main()函数的内容存放在源文件当中,至此文件目录如下:
主函数中,主要通过对函数的调用来实现三子棋游戏。
代码如下:
#include "game.h"
void menu()
{
printf("****************************\n");
printf("**********0.exit************\n");
printf("**********1.play************\n");
printf("****************************\n");
}
void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL, ' ');
ShowBoard(board, ROW, COL);
while (1)//只要有一方胜利,就结束循环
{
PlayerMove(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != '1')
{
//可能平局,可能一方胜出;
break;
}
//ShowBoard(board, ROW, COL);
ComputerMove(board, ROW, COL);
ret = IsWin(board, ROW, COL);
if (ret != '1')
{
//可能平局,可能一方胜出;
break;
}
//ShowBoard(board, ROW, COL);
}
if (ret == 'X')
{
printf("玩家赢了!!");
}
else if (ret == 'O')
{
printf("电脑赢了!!");
}
else
{
printf("平局");
}
}
int main()
{
int input = 0;
srand((unsigned int)time(NULL));
do
{
menu();
printf("请输入你的选择: ");
scanf("%d", &input);
switch (input)
{
case 1:
printf("游戏开始\n");
game();
case 0:
printf("游戏退出!\n");
break;
default:
printf("请输入正确的数字!\n");
break;
}
} while (input);
return 0;
}