1.前言
三子棋是一种民间传统游戏,又叫九宫棋、圈圈叉叉棋、一条龙、井字棋等。游戏分为双方对战,双方依次在9宫格棋盘上摆放棋子,率先将自己的三个棋子走成一条线就视为胜利,而对方就算输了,但是三子棋在很多时候会出现和棋的局面。
2.游戏设计思路
2.1设计布局
为了增强程序的可读性,我们将该游戏程序分为三个模块。
1.test.c – 测试游戏运行。
2.game.c – 游戏函数的实现。
3.game.h – 游戏函数的声明。
2.2菜单设计
通过定义一个菜单函数,来实现程序的页面。
void menu()
{
printf("********************\n");
printf("****** 1.play ******\n");
printf("****** 0.exit ******\n");
printf("********************\n");
}
进入页面,让玩家自主选择,是否游玩游戏。
引入switch 多分支选择语句,来完成这一功能
switch (input)
{
case 1:
printf("开始游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新输入\n");
break;
为了增加游戏的可玩性,让玩家能够多次游玩游戏。
我们通过使用do while循环语句,来完成该功能;
(do while循环的特点是先进行一次循环,再判断循环条件,所以它至少要进行一次循环,符合当前程序的逻辑。)
do
{
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新输入\n");
break;
}
} while (input);
2.3棋盘设计
游戏在运行的时候,要进行数据的存储,应使用3*3的二维数组存储数据。
为了更便捷的修改数据,我们引入宏定义来固定行列数。
#define ROW 3
#define COL 3
char board[ROW][COL];
在玩家未下棋时,棋盘内应填充空格。
这里我们定义一个初始化棋盘函数,来填充棋盘。
void InitBoard(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] = ' ';
}
}
}
在填充完棋盘后,为了让我们的棋盘更beautiful。
我们开始设计棋盘格式。
在DisplayBoard函数中,先以空格+数据+空格;完成一格的填充。
第一行 元素|元素|元素
第二行 ----- | ----- | -----
以两行交替的形式,完成打印。
代码实现如下。
void DisplayBoard(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");
}
}
2.4玩家下棋
首先,玩家输入的坐标应在棋盘内存在。
所以(x >= 1 && x <= col && y >= 1 && y <= col)
数组的下标是从0开始,所以第一行第一列的元素应为board[0][0],对玩家而言,并不知道数组下标的含义,所以我们应将输入的坐标改为 行-1,列-1 的坐标。
若输入的位置为空格,合法输入。
若输入的位置以被占用,则为非法输入。应该循环,直到输入正确的坐标。
void PlayerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
printf("玩家下棋\n");
while (1)
{
printf("请输入下棋坐标,中间应有空格\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= col && y >= 1 && y <= col)
{
if (board[x - 1][y - 1] == ' ')
{
board[x - 1][y - 1] = '*';
break;
}
else
{
printf("该坐标已被占用,请重新落子\n");
}
}
else
{
printf("落子范围错误,请重新下棋\n");
}
}
}
2.5电脑输入
首先,电脑应该先生成一个随机的坐标。
在这里,我们应该调用rand函数,先生产随机值,再通过%的方法,限制随机值的范围。
调用rand函数时,应该在main函数内部补充。
srand((unsigned int)time(NULL));
补充相应的头文件。
#include<stdlib.h>
#include<time.h>
代码实现如下。
void ComputerMove(char board[ROW][COL], int row, int col)
{
int x = 0;
int y = 0;
while (1)
{
printf("电脑下棋\n");
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
2.6胜负判断
三种胜负关系:1.赢。2.输。3.平局。
赢:三个棋子连成一条线。
平局:棋盘下满,依旧没有三子连成一条线。
赢的情况:三行,三列,两条对角线。
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 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[2][2] && board[0][0] != ' ')
return board[0][0];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[0][2];
if(IsFull(board, row, col)==1)//判断是否是平局
{
return 'Q';
}
return 'C';
}
平局的情况:棋盘的所有坐标都被填满。(应在判断完是否产生胜负关系后判断)
int IsFull(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
若条件都满足,则return返回值。
若条件不满足,则继续游戏。
在main函数中判断胜负结果。
void game()
{
char ret = 0;
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);//填充棋盘
DisplayBoard(board, ROW, COL);//制作棋盘
while (1)
{
PlayerMove(board, ROW, COL);//玩家下棋.(注意落子的范围是否合理)
DisplayBoard(board, ROW, COL);
ret = Iswin(board, ROW, COL);//判断输赢
if (ret != 'C')
break;
ComputerMove(board, ROW, COL);//电脑下棋(坐标随机,应调用rand函数)
DisplayBoard(board, ROW, COL);
ret = Iswin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
printf("玩家赢\n");
if (ret == '#')
printf("电脑赢\n");
if (ret == 'Q')
printf("平局\n");
}
3.完整代码分享
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);
char Iswin(char board[ROW][COL], int row, int col);
int IsFull(char board[ROW][COL], int row, int col);
game.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"game.h"
void InitBoard(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] = ' ';
}
}
}
void DisplayBoard(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;
printf("玩家下棋\n");
while (1)
{
printf("请输入下棋坐标,中间应有空格\n");
scanf("%d %d", &x, &y);
if (x >= 1 && x <= col && 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;
while (1)
{
printf("电脑下棋\n");
x = rand() % row;
y = rand() % col;
if (board[x][y] == ' ')
{
board[x][y] = '#';
break;
}
}
}
int IsFull(char board[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (board[i][j] == ' ')
return 0;
}
}
return 1;
}
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 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[2][2] && board[0][0] != ' ')
return board[0][0];
if (board[0][2] == board[1][1] && board[1][1] == board[2][0] && board[0][2] != ' ')
return board[0][2];
if(IsFull(board, row, col)==1)//判断是否是平局
{
return 'Q';
}
return 'C';
}
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 ret = 0;
char board[ROW][COL] = { 0 };
InitBoard(board, ROW, COL);//填充棋盘
DisplayBoard(board, ROW, COL);//制作棋盘
while (1)
{
PlayerMove(board, ROW, COL);//玩家下棋.(注意落子的范围是否合理)
DisplayBoard(board, ROW, COL);
ret = Iswin(board, ROW, COL);//判断输赢
if (ret != 'C')
break;
ComputerMove(board, ROW, COL);//电脑下棋(坐标随机,应调用rand函数)
DisplayBoard(board, ROW, COL);
ret = Iswin(board, ROW, COL);
if (ret != 'C')
break;
}
if (ret == '*')
printf("玩家赢\n");
if (ret == '#')
printf("电脑赢\n");
if (ret == 'Q')
printf("平局\n");
}
int main()
{
srand((unsigned int)time(NULL));
int input = 0;
do
{
menu();
printf("请选择>:");
scanf("%d", &input);
switch (input)
{
case 1:
printf("开始游戏\n");
game();
break;
case 0:
printf("退出游戏\n");
break;
default:
printf("选择错误,请重新输入\n");
break;
}
} while (input);
return 0;
}