|
板凳

楼主 |
发表于 2020-9-5 18:54:34
|
只看该作者
有一只部队A,知道它的起点(from)和要到达目的地(to),如何...
方法一
1)计算A在from的可到达格子集合std::vector<map_location> srcdst。
2)用种近似算法,像distance_between(dst, to),逐个计算集合srcdst中元素dst到to分数。挑出个最好分数best_dst。
3)把A从from移动到best_dst。
这种方法存在问题是A只挑个座标距离最近的,而不管路途中地形。这往往会使骑兵冲进山坳,然后就傻傻的走不出山坳。
方法二
1)调用a_star_search,设个不会超过的移动阈值,搜出一条路径route。
2)用这个route调用::move_unit。即使A的移动力其实无法完成route,::move_unit自会中途退出。
程序采用方法二
设定“合适”门限
要为a_star_search设一个“适合”的门限。这个门限有几个要求:
1)尽可能绕过站了敌方部队格子。要让a_start_search尽可能绕过这些部队,因而在这些格子上的cost要比没有部队时高。
2)不能让挑选不可经过地形格子。像山岭对于骑兵。这时这个cost应该是“绝对”高,不能让a_star_search选择这条路径。
3)对于最小值,必须大于(2*站了敌方部队格子的cost)。当计划攻城时,目标格子往往就是敌方城市中心格子,中心格子加上旁边一个格子就是两格。
以上可以看出,这个门限取多少和“站了敌方部队格子”、“不可经过地形格子”消耗多少移动力密切相关。程序中对于这两个值分别是:
站了敌方部队格子:getUnitHoldValue()(424242.0)
不可经过地形格子:getNoPathValue()(42424242.0)
当前设定门限值:calc.getUnitHoldValue() * 3 + 10000.0
让最多可以穿过3个敌方部队,后面10000.0是留给“可到达”格子上消耗移动力。
ai_default::move_unit
dst_must_reachable指示此个移动是否强制要末尾格子是“可到达”格子。对于移动+攻击,移动+建造这类移动,要求要移动部队必须可以站在末尾格子。
由于传给ai_default::move_unit的to上可能就站有部队,这时需要把这些结尾站有部队格子从搜出的路径上去除掉。以最后一个“站”在的格子赋给to。- while (!dst_must_reachable) {
- to = route_.steps.back();
- if (!units_.count(to)) {
- break;
- }
- if (to == from) {
- // A(city)(city), A will enter it
- return map_location();
- }
- route_.steps.pop_back();
- }
复制代码 以上删结尾格子的while,当中if (to == from)是可能成立的。
轮到袁绍行动,曹彰被灭,鞠义站在曹彰位置。颜良认为不适合攻城,于是计划穿过鞠义到濮阳中心格子。由于鞠义是已方阵营部队,在它之上只须耗“可到达”移动力,加上要路过的濮阳两格子,但这三个格子全站有部队,导致(to == from)成立。
当城内部队无法移出城时(包括出征+战斗和只是出征)
1、只有确定移出城的部队才需要调用erase;
2、对于未能移出部队则调用un.remove_movement_ai()。这个操作对只是出征无作用,但出征+战斗时需要。- if (move_spectator.get_unit().valid() && move_spectator.get_unit()->first != from) {
- // move_unit may be not move! reside troop ratain in city.
- reside_troops.erase(reside_troops.begin() + units_.last_expedite_index());
- } else {
- un.remove_movement_ai();
- }
复制代码
在此图下,
轮到孙坚。
徐盛移到(51,28)(伏击有效),陆逊移到(50,28)。
轮到刘表。
有一个部队移动(51,29),占掉这格子。
分析攻击路径,决定采用路径是(53,30)-->(52,30)-->(51,29)-->(51,28),去攻击位在(50,28)的陆逊。
本计划到达(51,28),但在这格子上站有敌对伏击部队,而偏偏(51,29)上又有一个已方部队,致使蔡瑁只能待在城里。由于没移动,蔡瑁和未计算前一致。
下一次攻击分析时,当前状态和上一次一样,导致系统死循环。
????(51,29)上要是有已方部队,(51,28)上怎么可能还有伏击部队?——出问题时应该检查(51,28)、(51,29)上到底为什么不时移动到,是部队的话应该检查是什么部队。
如果出现此种问题,想到办法是一旦遇到这个无法移动情况就把该部队移动力置0,使得分析攻击路径时不再考虑这只城内部队。un.remove_movement_ai()实现置0操作。
当要移动部队是城内部队时,参数std::pair<unit*, int>& pair中的first为何是城市指针,而不是部队指针?
因为之前移动操作影响,部队指针可能已经失效。- unit* unit_ptr = NULL;
- if (pair.second >= 0) {
- unit_ptr = &unit_2_artifical(pair.first)->reside_troops()[pair.second];
- } else {
- unit_ptr = pair.first;
- }
复制代码 对于移动,它一般是数只部队被组成一个要移动集合,然后逐只移动。这就造成一个问题,之前移动操作会影响集合中未移动部队指针。
当城外部队移动到城内时,这只部队是添加在该城的reside_troop末尾,但这个push_back会影响已先前已在部队的内存位置,进而影响属于该城的而未移动部队指针,使这些指针的指向处于不可预知状态
这种影响不会涉及城外部队,但要注意城外部队一旦移动后,这个指针可能已经无效,像部队入城了。
对于攻击时的std::pair<unit*, int>,这个first还是城内部队指针。1)每次攻击分析时都会重新构造一个pair集合;2)攻击分析过程中用部队指针可以快速进行指针值比较。
std::vector<>.push_back、erase函数
push_back操作是在vector添加单位,要注意操作会影响先前已存在单位的内存位置!
如果先前vector中已有4个unit对象,一旦向这个vector添加一个unit,这个unit是会被放在末尾,但同时会改变之前四个unit的内存位置,导致如果程序有指向之前四个unit对象指针的话,这些指针将可能变得无效。
同样的,erase是在vector删除间接,要注意操作也会影响先前已存在单位的内存位置!(参考ai::build)
如果先前vector中已有4个unit对象,一旦向这个vector删除一个unit,删除的uniti若不是末尾,它就可能改变它自已和在它之后的unit的内存位置,导致如果程序有指向它自已和之后unit对象指针的话,这些指针将可能变得无效。
它们改为后内存位置是随机的,程序要确保不使用此时指针。即遇到过程中会删除unit时,删除之后的操作要重计算指针。 |
|