📄 testbot.java
字号:
int friends = entities.size() - enemy_array.size(); move_array = secondPass(self, friends, enemy_array, entities); //top balanced filterMoves(move_array, self.pass, new MoveOption.WeightedComparator(1, 1), 50); //top damage filterMoves(move_array, self.pass, new MoveOption.WeightedComparator(.5, 1), 50); move_array = thirdPass(self, enemy_array); //top balanced filterMoves(move_array, self.pass, new MoveOption.WeightedComparator(1, 1), 30); //top damage filterMoves(move_array, self.pass, new MoveOption.WeightedComparator(.5, 1), 30); //reduce self threat, and add bonus for terrain for (Iterator i = self.pass.values().iterator(); i.hasNext();) { MoveOption option = (MoveOption) i.next(); option.setState(); option.self_damage *= .5; option.self_threat *= .5; //TODO: should scale to the unit bv double terrain = 2 * ((double) Compute.getTargetTerrainModifier(game, option.getEntity()).getValue()); if(debug) option.tv.add(terrain + " Terrain Adjusment " + "\n"); option.self_threat -= terrain; } move_array = fourthPass(self, enemy_array); //top balanced filterMoves(move_array, self.pass, new MoveOption.WeightedComparator(1, 1), 20); //top damage filterMoves(move_array, self.pass, new MoveOption.WeightedComparator(.5, 1), 20); //reduce transient damage estimates for (Iterator i = self.pass.values().iterator(); i.hasNext();) { MoveOption option = (MoveOption) i.next(); option.self_threat *= .5; option.self_damage *= .5; } move_array = fifthPass(self, enemy_array); /*********************************************************************** * Return top twenty moves to the lance algorithm **********************************************************************/ MoveOption[] result = new MoveOption[Math.min(move_array.length, 20)]; int offset = 0; for (int i = 0; i < Math.min(move_array.length, 20); i++) { MoveOption next = move_array[i]; if (next.isPhysical && self.range_damages[CEntity.RANGE_SHORT] > 5 && next.doomed) { if (offset + 20 < move_array.length) { next = move_array[offset + 20]; offset++; } } result[i] = next; } return result; } /** * ************************************************************************ * first pass, filter moves based upon present case * ************************************************************************ */ public void firstPass(CEntity self) { ArrayList enemies = getEnemyEntities(); MoveOption[] move_array; if (self.getEntity().isSelectableThisTurn() && !self.moved) { move_array = self.getAllMoves().values().toArray(new MoveOption[0]); } else { move_array = new MoveOption[]{self.current}; } System.out.println(self.getEntity().getShortName() + " has " + move_array.length + " moves" ); for (int i = 0; i < move_array.length; i++) { MoveOption option = move_array[i]; option.setState(); for (int e = 0; e < enemies.size(); e++) { // for each enemy Entity en = (Entity) enemies.get(e); // ignore loaded units if (en.getPosition() == null) { continue; } CEntity enemy = centities.get(en); int[] modifiers = option.getModifiers(enemy.getEntity()); if (modifiers[MoveOption.DEFENCE_MOD] == ToHitData.IMPOSSIBLE && modifiers[MoveOption.ATTACK_MOD] == ToHitData.IMPOSSIBLE) { continue; } int enemy_hit_arc = CEntity.getThreatHitArc(enemy.current.getFinalCoords(), enemy.current.getFinalFacing(), option.getFinalCoords()); int self_hit_arc = CEntity.getThreatHitArc(option.getFinalCoords(), option.getFinalFacing(), enemy.current.getFinalCoords()); if (!enemy.getEntity().isImmobile() && modifiers[MoveOption.DEFENCE_MOD] != ToHitData.IMPOSSIBLE) { self.engaged = true; int mod = modifiers[MoveOption.DEFENCE_MOD]; double max = option.getMaxModifiedDamage(enemy.current, mod, modifiers[MoveOption.DEFENCE_PC]); if (en.isSelectableThisTurn()) { enemy.current.addStep(MovePath.STEP_TURN_RIGHT); max = Math.max(option.getMaxModifiedDamage(enemy.current, mod + 1, modifiers[MoveOption.DEFENCE_PC]), max); enemy.current.removeLastStep(); enemy.current.addStep(MovePath.STEP_TURN_LEFT); max = Math.max(option.getMaxModifiedDamage(enemy.current, mod + 1, modifiers[MoveOption.DEFENCE_PC]), max); //return to original facing enemy.current.removeLastStep(); } max = self.getThreatUtility(max, self_hit_arc); if (enemy.getEntity().isProne()) max *= enemy.base_psr_odds; MoveOption.DamageInfo di = option.getDamageInfo(enemy, true); di.threat = max; di.max_threat = max; option.threat += max; if(debug) option.tv.add(max + " Threat " + e + "\n"); } /* * As a first approximation, take the maximum to a single * target */ if (!option.isPhysical) { if (modifiers[MoveOption.ATTACK_MOD] != ToHitData.IMPOSSIBLE) { self.engaged = true; double max = enemy.current.getMaxModifiedDamage(option, modifiers[0], modifiers[MoveOption.ATTACK_PC]); max = enemy.getThreatUtility(max, enemy_hit_arc); MoveOption.DamageInfo di = option.getDamageInfo(enemy, true); di.damage = max; di.min_damage = max; if(debug) option.tv.add(max + " Damage " + e + "\n"); option.damage = Math.max(max, option.damage); } } else { CEntity target = centities.get(option.getPhysicalTargetId()); try { if (target.getEntity().getId() == enemy.getEntity().getId()) { if (!target.isPhysicalTarget) { ToHitData toHit = null; double self_threat = 0; double damage = 0; if (option.isJumping()) { self.current.setState(); toHit = DfaAttackAction.toHit(game, option.getEntity().getId(), target.getEntity(), option); damage = 2 * DfaAttackAction.getDamageFor(option.getEntity()); self_threat = option.getCEntity().getThreatUtility(DfaAttackAction.getDamageTakenBy(option.getEntity()), ToHitData.SIDE_REAR) * Compute.oddsAbove(toHit.getValue()) / 100; self_threat += option.getCEntity().getThreatUtility(.1 * self.getEntity().getWeight(), ToHitData.SIDE_REAR); self_threat *= 100 / option.getCEntity().getEntity().getWeight(); } else { self.current.setState(); toHit = new ChargeAttackAction(option.getEntity(), target.getEntity()).toHit(game, option); damage = ChargeAttackAction.getDamageFor(option.getEntity(), option.getHexesMoved()); self_threat = option.getCEntity().getThreatUtility(ChargeAttackAction.getDamageTakenBy(option.getEntity(), target.getEntity()), ToHitData.SIDE_FRONT) * (Compute.oddsAbove(toHit.getValue()) / 100); option.setState(); } damage = target.getThreatUtility(damage, toHit.getSideTable()) * Compute.oddsAbove(toHit.getValue()) / 100; //charging is a good tactic against larger // mechs if (!option.isJumping()) damage *= Math.sqrt((double) enemy.bv / (double) self.bv); //these are always risky, just don't on 11 or // 12 if (toHit.getValue() > 10) damage = 0; //7 or less is good if (toHit.getValue() < 8) damage *= 1.5; //this is all you are good for if (self.range_damages[CEntity.RANGE_SHORT] < 5) damage *= 2; MoveOption.DamageInfo di = option.getDamageInfo(enemy, true); di.damage = damage; di.min_damage = damage; option.damage = damage; option.movement_threat += self_threat; } else { option.threat += Integer.MAX_VALUE; } } } catch (Exception e1) { e1.printStackTrace(); option.threat += Integer.MAX_VALUE; } } } //-- end while of each enemy self.current.setState(); } //-- end while of first pass //top balanced filterMoves(move_array, self.pass, new MoveOption.WeightedComparator(1, 1), 100); //top damage filterMoves(move_array, self.pass, new MoveOption.WeightedComparator(.5, 1), 100); } /** * ******************************************************************** * Second pass, combination moves/firing based only on the present * case, since only one mech moves at a time * ******************************************************************** */ private MoveOption[] secondPass(CEntity self, int friends, ArrayList enemy_array, ArrayList<Entity> entities) { MoveOption[] move_array = self.pass.values().toArray(new MoveOption[0]); self.pass.clear(); for (int j = 0; j < move_array.length && friends > 2; j++) { MoveOption option = move_array[j]; for (int e = 0; e < enemy_array.size(); e++) { Entity en = (Entity) enemy_array.get(e); CEntity enemy = centities.get(en); for (Entity other : entities) { if (other.isEnemyOf(self.entity)) { continue; } MoveOption foption = centities.get(other).current; double threat_divisor = 1; MoveOption.DamageInfo di = option.getDamageInfo(enemy, true); if (foption.getDamageInfo(enemy, false) != null) { option.damage += (enemy.canMove() ? .1 : .2) * di.damage; threat_divisor += foption.getCEntity().canMove() ? .4 : .6; } option.threat -= di.threat; di.threat /= threat_divisor; option.threat += di.threat; } } } return move_array; } /** * ******************************************************************** * third pass, (not so bad) oppurtunistic planner gives preference to * good ranges/defensive positions based upon the mech characterization * ******************************************************************** */ private MoveOption[] thirdPass(CEntity self, ArrayList enemy_array) { MoveOption[] move_array = self.pass.values().toArray(new MoveOption[0]); self.pass.clear(); for (int j = 0; j < move_array.length; j++) { MoveOption option = move_array[j]; option.setState(); double adjustment = 0; double temp_adjustment = 0; for (int e = 0; e < enemy_array.size(); e++) { // for each enemy
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -