一、初生棋盘
一生二,二生三,三生万物.....想成为好的执棋人就得从最小的棋盘操手——“三子棋”
下手思路且听笔者娓娓道来:
- 如何进入棋盘?
- 执棋顺序为何?
- 棋盘模型如何?
- 如何呈现对决?
- 如何裁定胜负?
二、基础页面
在这种庞杂(起码对我而言)的项目上我们通常使用多文件形式进行代码编写,一般写为三个:
game.h——代码所包含的头文件和各功能模块的函数声明
game.c——实现游戏各功能模块的函数
sanziqi.c——测试游戏的实现
1.任何游戏都需要登录界面不是吗?(也有可能是我玩的少),我们开始使用(menu())作为菜单函数,它大致需要满足三个基本功能:
1.进入游戏 2.退出游戏 3.输入不符规则的提醒.
其代码模块如下:
例如:void menu() { printf("**** 1.游戏开始 ****\n"); printf("**** 0.退出游戏 ****\n"); } int main() { int input = 0; do{ menu(); srand((unsigned)time(NULL)); 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; }
运行截图如下
三、游戏核心
1.在初始情况下,我们应该对棋盘初始化,实现清空操作。我们来使用“Initchess”函数来进行棋盘初始化。
void initchess(char chess[ROW][COL], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
chess[i][j] = ' ';
}
}
}
2.棋盘的展现,我们使用”displaychess“函数来实现,代码如下:
void displaychess(char chess[ROW][COL], int row, int col)
{
int i = 0;
//按照规律打印表格
for (i = 0; i < row; i++)
{
int j = 0;
//将一行表格打出
for (j = 0; j < col; j++)
{
printf(" %c ", chess[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");
}
}
运行结果:
ps:笔者使用了全局变量ROW和COL来进行编写,即只需要改变此二值即可操作棋盘格局。
#define ROW 3
#define COL 3
3.棋手对决
这一模块也就是需要去实现两个功能:
1.棋盘能够表现出玩家输入的位置(人类认知由一行与一列开始,而机器是零行零列起始,所以我们需要思考怎样让输入既是人类所想,也可为机器所懂。)
2.在已有子时我们不可下。
void self(char chess[ROW][COL], int row, int col)
{
int x, y;
printf("玩家请走棋:>");
while(1)
{
scanf("%d %d", &x, &y);
if (x > 0 && x <= row&&y > 0 && y <= col)
{
if (chess[x - 1][y - 1] == ' ')
{
chess[x - 1][y - 1] = '#';
break;
}
else
printf("该位置已经被占用");
}
else
{
printf("输入位置不合规则\n");
}
}
}
运行效果;
4.电脑”打假赛“
在这一功能里,电脑自动下棋,因此我们要使用rand来生成随机数。
srand((unsigned)time(NULL));初始化rand生成数
x=rand()%row;y=rand()%col——坐标随机数
注意在此同时需要引用两个头文件:
1.<time.h>
2.<stdlib.h>
在这一模块里也需要判断是否棋盘已有落子
void computer(char chess[ROW][COL], int row, int col)
{
printf("电脑下棋:>\n");
while (1)
{
int x = rand() % row;
int y = rand() % col;
if (chess[x][y] == ' ')
{
chess[x][y] = '*';
break;
}
}
}
运行结果
5.裁决胜负
在这一模块里我们设计的函数需要对电脑和玩家每一步棋下完后结果进行判断
返回'#',玩家胜利
返回'*',电脑胜利
返回'q',双方平局
返回'c',继续比赛
因此这一模块在主函数的的位置如下:
while (1)
{
computer(chess, ROW, COL);//电脑执旗
displaychess(chess, ROW, COL);//打印棋盘
ret = IsWin(chess, ROW, COL);//判断输赢
if (ret != 'c')
break;
self(chess, ROW, COL);//玩家执棋
displaychess(chess, ROW, COL);//打印棋盘
ret = IsWin(chess, ROW, COL);
if (ret != 'c')
break;
}
switch (ret)
{
case '*':
printf("电脑胜利\n");
break;
case '#':
printf("玩家胜利\n");
break;
case 'q':
printf("平局\n");
}
break;
我们借”Iswin“这一函数实现以上所述功能
1.判断行是否成型
2.判断列是否成型
3.判断主副对角线是否成型
4.判断棋盘是否已经”棋满为患“
char Iswin(char chess[ROW][COL], int row, int col)
{
//行成型
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
if (chess[i][0] == chess[i][1] && chess[i][1] == chess[i][2] && chess[i][0] != ' ')
return chess[i][0];
}
//列成型
for (i = 0; i< col; i++)
{
if (chess[0][i] == chess[1][i] && chess[1][i] == chess[2][i] && chess[0][i] != ' ')
return chess[0][i];
}
int k = 0, l = 0;
for (i = 0, j = 0; i < row&&j < col; i++, j++)
{
if (chess[i][j] == '#')
k++;
if (k==3)
return '#';
}
for (i = 2, j = 2; i >0 && j >0; i--, j--)
{
if (chess[i][j] == '*')
l++;
if (l == 3)
return '*';
}
if (Isfull(chess, row, col))
return 'q';
else
return 'c';
}
int Isfull(char chess[ROW][COL], int row, int col)
{
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
if (chess[i][j] == ' ')
return 0;
}
}
return 1;
}
我们在里面嵌套使用了”Isfull"函数对棋盘是否满格进行判断。
5.最后的最后
游戏整体逻辑或者说正式运行检测部分(sanziqi.c)如下;
#define _CRT_SECURE_NO_WARNINGS
#include "game.h"
void game(){
char chess[ROW][COL] = { 0 };
char ret;
initchess(chess, ROW, COL);//初始化棋盘
int m = 0;
printf("请选择是电脑先下还是玩家先下\n");
printf("***** 1 电脑**************\n");
printf("***** 2 玩家**************\n");
scanf("%d", &m);
switch (m)
{
case 1:
while (1)
{
computer(chess, ROW, COL);//电脑执旗
displaychess(chess, ROW, COL);//打印棋盘
ret = Iswin(chess, ROW, COL);//判断输赢
if (ret != 'c')
break;
self(chess, ROW, COL);//玩家执棋
displaychess(chess, ROW, COL);//打印棋盘
ret = Iswin(chess, ROW, COL);
if (ret != 'c')
break;
}
switch (ret)
{
case '*':
printf("电脑胜利\n");
break;
case '#':
printf("玩家胜利\n");
break;
case 'q':
printf("平局\n");
}
break;
case 2:
while (1){
self(chess, ROW, COL);
displaychess(chess, ROW, COL);
ret = Iswin(chess, ROW, COL);
if (ret != 'c')
break;
computer(chess, ROW, COL);
displaychess(chess, ROW, COL);
ret = Iswin(chess, ROW, COL);
if (ret != 'c')
break;
}
switch (ret)
{
case '*':
printf("电脑胜利\n");
break;
case '#':
printf("玩家胜利\n");
break;
case 'q':
printf("平局\n");
}
break;
default:
printf("输入无效\n");
break;
}
}
void menu()
{
printf("**** 1.游戏开始 ****\n");
printf("**** 0.退出游戏 ****\n");
}
int main()
{
int input = 0;
do{
menu();
srand((unsigned)time(NULL));
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;
}
四.棋盘成,天地显
运行结果如下
五.体会
这个游戏缺点还是蛮多的,比如判断胜负时,若是棋盘更大,我们应该怎么样判断输赢呢?当然笔者已经有所理解了,只待明天再去尝试。像笔者一样的萌新们也可以多多尝试。
ps:感冒真的难受,可以说是病里努力敲码了
c路漫漫,你我做伴!!爱你们么么哒
Tips