一、项目背景

       此游戏是笔者大二第一学期时受好友之托,重拾c语言编写的小程序,这篇文章主要介绍Game中的游主体逻辑部分。程序主体多用if-elsewhilefor等关键字,适合c语言初学者阅读,若有疑问或bug或建议可评论指出。

用java编写斗兽棋 我想玩斗兽棋_游戏

 

二、编程环境

笔者用的是  Visual Studio 2019,调用库有:

#include <iostream>
#include <windows.h>    
#include <conio.h>

三、规则介绍

用java编写斗兽棋 我想玩斗兽棋_游戏_02

四、程序主体

1、chess结构体

struct chess {
    int player;  // 1  A电脑   2  B人类    0   棋盘
    int ani;     // 8方块  7象(E)  6虎(T)  5狮(L)  4狼(W)  3狗(D)  2猫(C)  1鼠(M)  0空  
}Board[Vol * Vol], PlayB;

PlayB使用户控制可以移动的方块棋子,Board是组成棋盘的各个棋子。

player的值代表这个棋子属于哪一方,ani的值代表这个棋子是空还是动物还是方块(方块的player为0)。

2、主要函数:

用java编写斗兽棋 我想玩斗兽棋_c语言_03

       其中关于UI设计的六个函数分别有着隐藏光标定位绘制棋盘绘制方框绘制棋子展示提示的作用;Init部分的三个函数重绘棋盘,让数据初始化,便于重新开始;Game部分的三个函数分别是游戏主体逻辑比较棋子大小游戏结束

3、游戏主体逻辑

(1)结构

用java编写斗兽棋 我想玩斗兽棋_用java编写斗兽棋_04

       可以观察到,当数据初始化完成后,就进入了循环输入反馈的游戏主体中。而根据输入,有三种反馈,分别是方块棋子的移动空格选中或取消棋子召唤己方动物。在反馈结束后,根据f(判断棋子互动有无的标志)判断是否进行棋子互动。若达到结束条件,则结束游戏。

(2)小键盘移动

// 上下左右移动
if (ch_1 == -32) {
	ch_2 = _getch();
	switch (ch_2) {
	case 72:y == 1 ? y = Vol : y--; break;
	case 75:x == 1 ? x = Vol : x--; break;
	case 80:y == Vol ? y = 1 : y++; break;
	case 77:x == Vol ? x = 1 : x++; break;
	default:break;}

       在用_getch()(在头文件conio.h)获得上下左右键的键值时候,他们是双键值,会返回高八位和低八位的int型数值。经测试,返回的第一个数值为-32,第二个数值上72左75下80右77。这里采用的是碰壁返回另一边的碰壁逻辑。

(3)空格选中棋子

else if (ch_1 == ' ') {
    if (PlayB.player == 0) {//手上无棋子,需拿起棋子
	    if (Board[(x - 1) * Vol + y - 1].player == 2) {
		    PlayB.ani = Board[(x - 1) * Vol + y - 1].ani;
		    PlayB.player = Board[(x - 1) * Vol + y - 1].player;
		    Board[(x - 1) * Vol + y - 1].player = Board[(x - 1) * Vol + y - 1].ani = 0;
		    Chess(x, y, PlayB);
		    tips = 4;
	    }
    }
    else if (PlayB.player == 2) {
	    if (Board[(x - 1) * Vol + y - 1].player == 2)
		    tips = 5;
	    else if (Board[(x - 1) * Vol + y - 1].player == 0) {
		    Board[(x - 1) * Vol + y - 1].ani = PlayB.ani;
	    	Board[(x - 1) * Vol + y - 1].player = PlayB.player;
		    PlayB.ani = 8;
	    	PlayB.player = 0;
	    	Chess(x, y, PlayB);
	    	tips = 6;
	    }
	    else if (Board[(x - 1) * Vol + y - 1].player == 1) {
	    	f = PlayB.ani;
	    	PlayB.ani = 8;
		    PlayB.player = 0;
	    }
    }
}

       首先判断手上是否有棋子,根据方块棋子的player属性判断其为方块还是己方动物,否则不响应。若为方块,则可以拿起棋子,当落点所属玩家为人类时,落点棋盘上的棋子属性变为空(皆0),手上方块属性变为己方动物属性。若为己方动物,则按下空格视为落子,若落子处为,则直接落子,与提子为反逻辑;若落子处为敌方动物,则成功落子并进行棋子互动;若落子处为己方动物,则会提示无法落子

(4)召唤棋子

// 召唤己方棋子
switch (ch_1) {
case 'e':case 'E':Allchess[6] = Allchess[6] > 0 ? Allchess[6] - 1 : -1; f = 7; break;
case 't':case 'T':Allchess[5] = Allchess[5] > 0 ? Allchess[5] - 1 : -1; f = 6; break;
case 'l':case 'L':Allchess[4] = Allchess[4] > 0 ? Allchess[4] - 1 : -1; f = 5; break;
case 'w':case 'W':Allchess[3] = Allchess[3] > 0 ? Allchess[3] - 1 : -1; f = 4; break;
case 'd':case 'D':Allchess[2] = Allchess[2] > 0 ? Allchess[2] - 1 : -1; f = 3; break;
case 'c':case 'C':Allchess[1] = Allchess[1] > 0 ? Allchess[1] - 1 : -1; f = 2; break;
case 'm':case 'M':Allchess[0] = Allchess[0] > 0 ? Allchess[0] - 1 : -1; f = 1; break;
case 'g':case 'G':end = 1; break;
default:break;
}

     召唤棋子即召唤手中动物到棋盘上,因手中动物每种各两只,所以需要进行计数处理,并赋值f,进行棋子互动。其中按下G键游戏提前结束。

(5)棋子互动

if (f) 
{
	if (Allchess[f - 1] > -1) {//手上还有棋子吗?
		if (Board[(x - 1) * Vol + y - 1].player == 1) {//该位置有敌方棋子
			int flag = Compare(f, Board[(x - 1) * Vol + y - 1].ani);
			if (flag == 2) { //两子皆亡
				Achess[Board[(x - 1) * Vol + y - 1].ani - 1]--;
				Bchess[f - 1]--;
				Board[(x - 1) * Vol + y - 1].ani = Board[(x - 1) * Vol + y - 1].player = 0;
				tips = 2;
				sumA--; sumB--;
			}
			else if (flag == 1) {//人类获胜!
				Achess[Board[(x - 1) * Vol + y - 1].ani - 1]--;
				Board[(x - 1) * Vol + y - 1].ani = f;
				Board[(x - 1) * Vol + y - 1].player = 2;
				tips = 3;
				sumA--;
			}
			else {//电脑获胜
				Bchess[f - 1]--;
				tips = 1;
				sumB--;
			}
		}
		else if (Board[(x - 1) * Vol + y - 1].player == 0) { //该地无棋子
			Board[(x - 1) * Vol + y - 1].ani = f;
			Board[(x - 1) * Vol + y - 1].player = 2;
			tips = 6;
		}
		else if (Board[(x - 1) * Vol + y - 1].player == 2) { //该地有己方棋子
			Allchess[f - 1]++;
			tips = 5;
		}
	}
	else
		tips = 9;
	f = 0;
	Chess(x, y, Board[(x - 1) * Vol + y - 1]);
}

        棋子互动首先判定手中是否有棋子,若无则f=0,跳出互动;

       若手中有棋子,则根据落点棋子player属性互动。若落点棋子为,则直接落子;若落点棋子为己方棋子,则因该位置已满,无法放入,棋子回到手中,计数器+1;若落点棋子为敌方棋子,则进行比较,有以下三种结果:被吃,吃,同归于尽。同时相应计数器-1。

4、cheat处理及颜色

if (cheat)
	switch (board.ani) {
	case 7:printf(RED"E " NONE); break;
	case 6:printf(RED"T " NONE); break;
	case 5:printf(RED"L " NONE); break;
	case 4:printf(RED"W " NONE); break;
	case 3:printf(RED"D " NONE); break;
	case 2:printf(RED"C " NONE); break;
	case 1:printf(RED"M " NONE); break;
	default:break;
	}
else
	printf(RED"●" NONE);

若cheat为1,则敌方棋子为已知,否则为未知。(方便测试时用)

加上如下宏定义,可以输出不同颜色的字体:

#define RED  "\033[0;32;31m"                      //字体红色
#define NONE "\033[m"                             //字体无色

五、结语

难度中规中矩,适合c语言初学者新手上路,该题另有复盘要求:

用java编写斗兽棋 我想玩斗兽棋_#include_05

 可作为读者的小练习。代码放在评论区。