井字棋算是童年课堂上的与同桌默契配合的一大乐趣...躲避着老师“关切”的目光,在眼皮底下“顶风作案”,将“灯下黑”体现的淋漓尽致!在C语言中,也算是一个小的项目,今天,我们就用C语言来实现它!!!追逐童年的一份小乐趣!
游戏介绍:
“井字棋”也称“三子棋”,需要一个3*3的棋盘。假设分为黑、白方,各执黑棋、白棋,双方各下一次,下棋位置必须在棋盘内并且不能占着已有棋子,若能将横3、竖3、斜3任意一种情况都是黑棋/白棋,那么则黑方/白方胜利。要是当棋盘下满还不能分出胜负,那么就是平局。
C语言实现逻辑:
1. 首先,需要一个3*3的棋盘,棋盘使用二维数组配合字符进行打印即可,采用循环结构可以方便我们的操作。
2. 游戏简答可分成:玩家、电脑双方,那么电脑下棋子与玩家下棋子的棋盘都需要进行打印。这是两种不同的重复操作,但大致功能相同,那么可以根据其功能写出两种打印函数。
3. 双方落子是依据在二维数组之内的,给两者不同的字符标识即可进行区分。但是落子规则需要进一步讨论,玩家所输入坐标必须在满足二维数组的要求,不能是负数、不能越界,否则应该重新进行坐标输入。还有一种情况就是,所输入坐标已经有棋子了,这时应该提示玩家重新进行输入,并且电脑应该直接避免这个情况。
4. 判断胜负是游戏很重要的一部分。这一部分也是依据在二维数组的基础上的,可以遍历二维数组的元素,要是横、竖、斜之一存在相同的棋子,那么执该棋子方取得胜利。否则当棋盘填充满的情况下,仍无胜利方,那么就是平局了。
经过上面简单的逻辑分析,为了验证我们逻辑的正确性,现在给出我们的C语言实现的源代码及结果!
测试源代码:
#include <stdio.h>
#include "game.h"
#include <time.h>
#include <stdlib.h>
void menu() //打印游戏菜单
{
printf("************************************\n");
printf("********《《 1. play 》》*********\n");
printf("********《《 0. exit 》》*********\n");
printf("************************************\n");
}
void game()
{
char board[ROW][COL] = {0}; //以行列作为二维数组的参数值
char ret = 0; //字符类型ret作为载体,便于二维数组中所传字符进行比对
InitBoard(board, ROW, COL); //定义一个ROW*COL的空棋盘
DisplayBoard(board, ROW, COL); //添加字符/特殊字符(宣扬个性),给棋盘加上边界
while(1) //死循环
{
PlayerMove(board, ROW, COL); //玩家走,定义函数
ret = IsWin(board, ROW, COL); //判定胜负
if(ret != ' ') //如果此二维数组内元素未定义,即为空,在执行下面的电脑走
{
break;
}
DisplayBoard(board, ROW, COL);//玩家走后打印棋盘
ComputerMove(board, ROW, COL);//电脑走(一定是空白可赋值,见25--28行)
ret = IsWin(board, ROW, COL); //判定胜负
if(ret != ' ')
{
break;
}
DisplayBoard(board, ROW, COL);//电脑走后,打印棋盘
}
if(ret == '0') //
{
printf("电脑赢!\n");
}
else if(ret == 'X')
{
printf("玩家赢!\n");
}
else if(ret == 'Q')
{
printf("平局!\n");
}
}
void test()
{
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");
}
}while(input); //循环结构,输错后继续,不准停!
}
int main()
{
test();
return 0;
}
游戏实现源代码:
#include "game.h"
void InitBoard(char arr[ROW][COL], int row, int col) //函数不需返回值,需要二维数组、行数、列数作为函数参数
{
int i = 0; //注:在从game.h拷贝函数名的时候需要去除 ";" 否则会提示错误:在文件范围内找到“{”(是否缺少函数头?)
int j = 0;
for(i=0; i<row; i++)
{
for(j=0; j<col; j++) //遍历二维数组
{
arr[i][j] = ' '; //初始化二维数组
}
}
}
void DisplayBoard(char arr[ROW][COL],int row, int col) //函数参数与InitBoard相同,功能为打印有边界的棋盘,即给二维数组赋值
{
int i = 0;
int j = 0;
for(i=0; i<row; i++) //遍历二维数组
{
for(j=0; j<col; j++)
{
printf(" %c ", arr[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 arr[ROW][COL],int row, int col)
{
int x = 0;
int y = 0;
printf("玩家走:\n");
while(1)
{
printf("请输入坐标:");
scanf("%d%d", &x, &y);
if((x>=1 && x<=3)&&((y>=1 && x<=3))) //保证玩家输入坐标正确性
{
if(arr[x-1][y-1] == ' ') //玩家输入坐标与二维数组下标之间相差1
{
arr[x-1][y-1] = '*'; //如果为空,即未被占用,则赋值为字符X
break;
}
else
{
printf("坐标已被占用\n"); //被占用提示
}
}
else //不在if语句限值之内即非法
{
printf("坐标非法\n");
}
}
}
void ComputerMove(char arr[ROW][COL],int row, int col) //电脑落子
{
int x = 0;
int y = 0;
printf("电脑走:>\n");
while(1)
{
x=rand() % 3; //得二维数组下标0 1 2,对3取模即可
y=rand() % 3;
if(arr[x][y] == ' ')
{
arr[x][y] = 'o'; //若为空,对其赋值
break;
}
}
printf("电脑坐标:%d %d\n", x+1, y+1);
}
//当进程没有退出时 会产生错误 1>LINK : fatal error LNK1104: 无法打开文件“E:\A-bite\A\game\Debug\game.exe”
static int IsFull(char arr[ROW][COL],int row, int col) //不为接口函数,不需要放入game.h,仅在此使用,无法进行test.c中调用
{
int i = 0;
int j = 0;
for(i=0; i<row; i++) //遍历二维数组
{
for(j=0; j<col; j++)
{
if(arr[i][j] == ' ') //判断是否仍有空值
return 0; //有空值返回0
}
}
return 1; //无空值返回1
}
char IsWin(char arr[ROW][COL],int row, int col) //判断胜负
{
int i = 0;
for(i=0; i<row; i++) //判断行 是否能胜利
{
if(arr[i][0]==arr[i][1] && arr[i][1]==arr[i][2] && arr[i][0]!=' ')
{
return arr[i][0]; //若三子相同,且不能为空,返回元素内值
}
}
for(i=0; i<col; i++) //判断列 是否能胜利
{
if(arr[0][i]==arr[1][i] && arr[1][i]==arr[2][i] && arr[1][i]!=' ')
{
return arr[1][i];
}
}
if(arr[0][0]==arr[1][1] && arr[1][1]==arr[2][2] && arr[1][1] != ' ') //判断正对角线能否胜利
{
return arr[1][1];
}
if(arr[0][2]==arr[1][1] && arr[1][1]==arr[2][0] && arr[1][1] != ' ') //判断反对角线能否胜利
{
return arr[1][1];
}
if(IsFull(arr, row, col)) //判定平局
{
return 'Q';
}
return ' '; //继续
}
头文件及函数声明:
#ifndef __GAME_H__
#define __GAME_H__
#include<stdio.h>
#define ROW 3
#define COL 3
void InitBoard(char arr[ROW][COL],int row, int col);
void DisplayBoard(char arr[ROW][COL],int row, int col);
void PlayerMove(char arr[ROW][COL],int row, int col);
void ComputerMove(char arr[ROW][COL],int row, int col);
char IsWin(char arr[ROW][COL],int row, int col);
#endif //__GAME_H__