Spads -- WangXP
游戏对象(上阵)缘分触发条件表达式解析
本文分为 6 个部分
---------- ---------- ---------- ----------
1、简要
2、应用背景
3、问题提出
4、解决方案
5、测试程序
6、测试结果
---------- ---------- ---------- ----------
1.简要
对问题透彻分析,能够帮助我们快速、高效的解决它。下文中引用的名词简称会做相应的说明。
如:游戏对象 -> GameObject
2.应用背景
当某个游戏对象被放到战斗阵容上时, 因其自身的缘分Buff(也可称之为 属性)会对其他阵中的游
戏对象的某些属性值提供加成。此举目的希望能够提供玩家新的游戏方式。通过对阵容上的游戏对象进
行不同方式的组合达到调整阵容战斗属性以应对不同的对手。
例如:
阵容中现有:[GameObjct1, GameObjct40]
GameObjct1 = { "itemId": 1, "health": 530, "attack": 73 ... } GameObjct40 = { "itemId": 40, "health": 335, "attack": 90 ... }
触发条件定义:
<config> <buff itemId="1" targetId="12_40" effectProp="health" value="10"/> <buff itemId="23" targetId="1" effectProp="attack" value="15"/> ... <buff .../> </config>
综上定义, 当游戏对象 23 上阵时,若阵中已存在 buff 目标 1 则会导致游戏对象 1 的某些战斗属
性值有一定幅度的增加(attack), 其具体增加方式此处就不再熬述。
GameObjct23 = { "itemId": 23, "health": 700, "attack": 60 ... }
阵容:[GameObjct1, GameObjct40, GameObjct23]
此时的 GameObject1 的 attack 属性值将发生变化。如下:
GameObjct1 = { "itemId": 1, "health": 530, "attack": 88 ... }
反之,阵中不存在目标游戏对象时此 buff 将不会触发任何游戏对象的属性发生变化。
大家可能发现 targetId 有这样的 "12_40"格式, 其指的含义是。 阵容中必须同时出现游戏对象 12
与 40 时此缘分才能触发。
3.问题提出
为了应对游戏新版某些功能;上述缘分触发方式已不满足功能需求。游戏对象在新版功能中能够繁殖
同类型新的游戏对象, 其缘分 Buff 定义继续沿用老游戏对象的缘分。
例如:
GameObject1 繁殖出新的游戏对象: GameObject101
上述定义的触发条件定义中的 itemId="23" 应修改为
<buff itemId="23" targetId="1#101" effectProp="attack" value="15"/> ...
如果其他的缘分触发表达式原先是这样 "12_40" 时, 则新的表达式就会是 "12_40#101"。
那么,问题来了。下面的解决方案就是针对此问题中的表达式进行解析。
4.解决方案
// 常量定义
private static final String ONE = "1";
private static final String ZERO = "0";
private static final String OR = "#";
private static final String AND = "_";
/***
* <b>判定缘分触发</b><br/>
* 对指定条件表达式与集中中元素的关系进行匹配。其核心算法阐述如下:<br/>
* 首先,对表达式字符串解析成字符串数组,根据表达式关系运算符优先级关系,将加入队列的数值进行排序已便后期计算。<br/>
* 在后期计算中有两种, 分为<code>#</code>逻辑或运算和<code>_</code>逻辑与运算。优先级关系是:
* <pre>
* # 高于 _
* </pre>
* 当计算过程中从队列中获取的值若非运算符则将其以链表结构保存,否则判定运算符以对应的逻辑或 或者 逻辑与对链表中的数据进行计算。<br/>
* 并将结果保存在栈中。对于某些特定格式的表达式,在进行与逻辑运算时会从链表中获取数据并计算结果。<br/>
* 已通过测试的表达式格式如下所示:
* <pre>
* "",
* "10",
* "56",
* "210_10",
* "10_210",
* "210_99",
* "41_23",
* "41#210_56",
* "210#41_56",
* "188#210_41",
* "41#210_56#78_23",
* "41#210_56#78#99",
* "41#210",
* "41_56",
* "41_2_78_10_23",
* "56#78_41_99",
* "41_99_56#78",
* "99#210#56#77#41",
* "41_56#78_99"
* </pre>
* 若以条件表达式 2_10#78 , 匹配集合 [2, 10, 78, 41, 23], 那么得到的接触来的运算队列应该是
* 1, 1, 1, 2, #, 2, _,
* 结果: true
* @see Util
* @param exp 条件表达式
* @param assemble 集合
* @return true: 符合缘分触发, false: 不符合
* @exception null
*/
static public boolean matchFates(String expression, List<Integer> assemble)
{
if (expression == null || expression.length() == 0)
return false;
int length = expression.length();
Queue<String> result = new LinkedList<String>();
List<String> tempResult = new LinkedList<String>();
StringBuilder builder = new StringBuilder();
boolean isNum = Character.isDigit(expression.charAt(0));
int enableEvaCount = 0;
boolean cOrExist = false;
boolean cContinuFlag = false;
int cOrAppearCount = 0;
char c;
char lastC = 'o';
byte cAndCount = 0;
for (int charIndex = -1; ++charIndex != length; )
{
c = expression.charAt(charIndex);
if (isNum ^ Character.isDigit(c)) {
if (builder.length() != 0)
tempResult.add(builder.toString());
if (!Character.isDigit(c)) {
if (lastC != 'o' && lastC == c)
cContinuFlag = true;
else cContinuFlag = false;
if (c == '_') {
if (lastC != 'o' && lastC == '#') {
if (tempResult.size() > 0) {
Integer intValue = Integer.valueOf(tempResult.get(tempResult.size() - 1));
if (assemble.contains(intValue)) result.add(ONE);
else result.add(ZERO);
tempResult.remove(tempResult.size() - 1);
++enableEvaCount;
}
if (((++ cOrAppearCount + 1) <= enableEvaCount) && cContinuFlag)
enableEvaCount = cOrAppearCount + 1;
result.add(String.valueOf(enableEvaCount));
enableEvaCount = 0;
result.add(OR);
lastC = 'o';
}
else if (lastC == 'o') {
if (tempResult.size() > 0) {
Integer intValue = Integer.valueOf(tempResult.get(tempResult.size() - 1));
if (assemble.contains(intValue)) result.add(ONE);
else result.add(ZERO);
tempResult.remove(tempResult.size() - 1);
++enableEvaCount;
}
}
if (++cAndCount == 2) {
if (tempResult.size() > 0) {
Integer intValue = Integer.valueOf(tempResult.get(tempResult.size() - 1));
if (assemble.contains(intValue)) result.add(ONE);
else result.add(ZERO);
tempResult.remove(tempResult.size() - 1);
++enableEvaCount;
}
if (cOrExist) {
enableEvaCount = cOrAppearCount;
cOrAppearCount = 0;
}
enableEvaCount = enableEvaCount <= 1 ? 2 : enableEvaCount;
result.add(String.valueOf(enableEvaCount));
enableEvaCount = 0;
result.add(AND);
-- cAndCount;
}
lastC = '_';
}
else if (c == '#') {
if (lastC != 'o' && lastC == '_') enableEvaCount = 0;
if (tempResult.size() > 0) {
Integer intValue = Integer.valueOf(tempResult.get(tempResult.size() - 1));
if (assemble.contains(intValue)) result.add(ONE);
else result.add(ZERO);
tempResult.remove(tempResult.size() - 1);
++enableEvaCount;
}
lastC = '#';
cOrExist = true;
}
}
else
{
// 数 至 符 || (符 至 数 && (是最后一个数字 || 下个字符不是数字了))
if ((isNum && !Character.isDigit(c)) || ((!isNum && Character.isDigit(c))
&& (charIndex + 1 == length || !Character.isDigit(expression.charAt(charIndex + 1))
)))
{
if (tempResult.size() != 0)
{
Integer intValue = Integer.valueOf(tempResult.get(tempResult.size() - 1));
if (assemble.contains(intValue)) result.add(ONE);
else result.add(ZERO);
tempResult.remove(tempResult.size() - 1);
++enableEvaCount;
}
}
}
builder = new StringBuilder();
isNum = !isNum;
}
if (Character.isDigit(c)) builder.append(c);
if (charIndex + 1 == length)
{
// 数
if (builder.length() != 0) {
Integer intValue = Integer.valueOf(builder.toString());
if (assemble.contains(intValue)) result.add(ONE);
else result.add(ZERO);
++enableEvaCount;
}
// #
if (lastC == '#') {
result.add(String.valueOf(enableEvaCount));
enableEvaCount = 0;
result.add(OR);
++ cOrAppearCount;
}
// _
if (cAndCount == 1) {
if (cOrExist)
enableEvaCount = 2;
else enableEvaCount = enableEvaCount <= 1 ? 2 : enableEvaCount;
result.add(String.valueOf(enableEvaCount));
enableEvaCount = 0;
result.add(AND);
}
}
}
return eval(result);
}
/**
* 计算队列中值
* @param oprCodeQue 操作码队列
* @return 是否触发缘分
*/
public static boolean eval(Queue<String> oprCodeQue)
{
Stack<String> oprStack = new Stack<String>();
int size = oprCodeQue.size();
if (size == 1) return oprCodeQue.poll().equals(ONE);
List<String> nums = new LinkedList<String>();
int evalNumCount = 0;
for(String code: oprCodeQue)
{
if (ONE.equals(code) || ZERO.equals(code))
{
oprStack.add(code);
}
else if (OR.equals(code))
{
while (evalNumCount-- != 0)
{
nums.add(oprStack.pop());
}
if (nums.contains(ONE))
oprStack.add(ONE);
else oprStack.add(ZERO);
nums.clear();
}
else if (AND.equals(code))
{
try {
while (evalNumCount-- != 0)
{
nums.add(oprStack.pop());
}
} catch (Exception e) {
e.printStackTrace();
}
if (nums.contains(ZERO))
oprStack.add(ZERO);
else oprStack.add(ONE);
nums.clear();
}
else
{
evalNumCount = Integer.valueOf(code);
}
}
return oprStack.pop().equals(ONE);
}
5.测试程序
List<Integer> battleDiscipleItems = new ArrayList<Integer>();
battleDiscipleItems.add(2);
battleDiscipleItems.add(10);
battleDiscipleItems.add(78);
battleDiscipleItems.add(41);
battleDiscipleItems.add(23);
List<Integer> requireList = new ArrayList<Integer>();
Map<Integer, Integer> fatestatus = new HashMap<Integer, Integer>();
String[] abc = {
"2_17_93#186_150_19#83#76#188#179_69",
"2_10#78#99#100",
"2_10#78",
"10",
"56",
"210_10",
"10_210",
"210_99",
"41_23",
"41#210_56",
"210#41_56",
"188#210_41",
"41#210_56#78_23",
"41#210_56#78#99",
"41#210",
"41_56",
"41_2_78_10_23",
"56#78_41_99",
"41_99_56#78",
"99#210#56#77#41",
"41_56#78_99",
"41_99_56#78"
};
int length = abc.length;
StringBuilder assBuilder = new StringBuilder();
for (int j = 0; j < battleDiscipleItems.size(); j++)
{
if (j == 0) assBuilder.append("[");
assBuilder.append(battleDiscipleItems.get(j));
if (j + 1 == battleDiscipleItems.size())
{
assBuilder.append("]\t");
}
else {
assBuilder.append(", ");
}
}
for (int i = 0 ; i < length; i ++)
{
Record record = new Record(assBuilder.toString(), abc[i]+ "\t");
long sTime = System.nanoTime();
record.setResult(matchFates(abc[i], battleDiscipleItems, record));
record.setcTime(System.nanoTime(), sTime);
RecordTimeUtil.inst.put(record);
}
RecordTimeUtil.inst.printfAll();
6.测试结果:
关于本程序,有错误地方请大家指正。
转载于:https://blog.51cto.com/coffe/1333644