public void newBattle(int mapWidth, int mapHeight) { mapX = mapWidth; mapY = mapHeight; lastUnit1Damage = 0; lastUnit2Damage = 0; lastU1 = -1; lastU2 = -1; lastCalc1 = ""; lastCalc2 = ""; lastResult1 = EnumResult.Nothing; lastResult2 = EnumResult.Nothing; lastMove = enumMoveType.Nothing; lastUnit1 = null; lastUnit2 = null; }
public void changeUnitStance(ref MapUnit[] playerUnits, int thisUnit, stanceEnum toStance) { lastUnit1 = (MapUnit)playerUnits[thisUnit].Clone(); lastUnit2 = null; lastMove = enumMoveType.Stance; lastU1 = thisUnit; lastU2 = -1; lastResult1 = EnumResult.Nothing; lastResult2 = EnumResult.Nothing; lastUnit1Damage = 0; lastUnit2Damage = 0; lastCalc1 = ""; lastCalc2 = ""; playerUnits[thisUnit].stanceUnit = toStance; }
public void moveUnit(ref MapUnit[] playerUnits, int moveUnit, int newX, int newY) { lastUnit1 = (MapUnit)playerUnits[moveUnit].Clone(); lastUnit2 = null; lastMove = enumMoveType.Move; lastU1 = moveUnit; lastU2 = -1; lastResult1 = EnumResult.Advance; lastResult2 = EnumResult.Nothing; lastUnit1Damage = 0; lastUnit2Damage = 0; lastCalc1 = ""; lastCalc2 = ""; playerUnits[moveUnit].x = newX; playerUnits[moveUnit].y = newY; }
public int fightUnits(ref MapUnit[] playerUnits, int fromUnit, int toUnit, int maxUnits, bool showBattle) { if (fromUnit > -1 && toUnit > -1) { if (showBattle == true) { lastUnit1 = (MapUnit)playerUnits[fromUnit].Clone(); lastUnit2 = (MapUnit)playerUnits[toUnit].Clone(); lastMove = enumMoveType.Attack; lastU1 = fromUnit; lastU2 = toUnit; lastCalc1 = ""; lastCalc2 = ""; notePlayerWeights(ref playerUnits, maxUnits); } playerUnits[fromUnit].support = calculateSupport(ref playerUnits, fromUnit, maxUnits); playerUnits[toUnit].support = calculateSupport(ref playerUnits, toUnit, maxUnits); int fireWeight1 = calculateAttackWeight(ref playerUnits, fromUnit); int defenseWeight1 = calculateDefenseWeight(ref playerUnits, fromUnit, true); if (defenseWeight1 <= 0) { defenseWeight1 = 1; } int fireWeight2 = calculateAttackWeight(ref playerUnits, toUnit); int defenseWeight2 = calculateDefenseWeight(ref playerUnits, toUnit, true); if (defenseWeight2 <= 0) { defenseWeight2 = 1; } int effectiveDamage1 = fireWeight1 / defenseWeight2; if (effectiveDamage1 == 0) { effectiveDamage1 = Constants.MINIMUM_EFFECTIVE_DAMAGE; } int effectiveDamage2 = fireWeight2 / defenseWeight1; if (effectiveDamage2 == 0) { effectiveDamage2 = Constants.MINIMUM_EFFECTIVE_DAMAGE; } // special case if artillery into infantry square if (playerUnits[fromUnit].typeUnit == unitEnum.Artillery && playerUnits[toUnit].typeUnit == unitEnum.Infantry && playerUnits[toUnit].stanceUnit == stanceEnum.Square) { defenseWeight2 = Convert.ToInt32(defenseWeight2 * Constants.WEIGHT_SQUARE_ARTILLERY); } // special case if cavalry into infantry square if (playerUnits[fromUnit].typeUnit == unitEnum.Cavalry && playerUnits[toUnit].typeUnit == unitEnum.Infantry && playerUnits[toUnit].stanceUnit == stanceEnum.Square) { defenseWeight2 = Convert.ToInt32(defenseWeight2 * Constants.WEIGHT_SQUARE_CAVALRY); } // special case if infantry into infantry square if (playerUnits[fromUnit].typeUnit == unitEnum.Infantry && playerUnits[toUnit].typeUnit == unitEnum.Infantry && playerUnits[toUnit].stanceUnit == stanceEnum.Square) { defenseWeight2 = Convert.ToInt32(defenseWeight2 * Constants.WEIGHT_SQUARE_INFANTRY); } if (showBattle == true) { lastResult1 = EnumResult.StandOff; lastResult2 = EnumResult.StandOff; lastCalc1 = fireWeight1.ToString() + "/" + defenseWeight1.ToString(); lastCalc2 = fireWeight2.ToString() + "/" + defenseWeight2.ToString(); } playerUnits[toUnit].strength -= effectiveDamage1; playerUnits[toUnit].morale -= effectiveDamage1; if (playerUnits[toUnit].morale < 0) { playerUnits[toUnit].morale = 0; } if (showBattle == true) { lastUnit2Damage = effectiveDamage1; } if (playerUnits[toUnit].strength <= 0) { if (showBattle == true) { lastResult2 = EnumResult.Destroyed; } killUnit(ref playerUnits, toUnit, fromUnit, maxUnits, showBattle); } playerUnits[fromUnit].strength -= effectiveDamage2; playerUnits[fromUnit].morale -= effectiveDamage2; if (showBattle == true) { lastUnit1Damage = effectiveDamage2; } if (playerUnits[fromUnit].morale < 0) { playerUnits[fromUnit].morale = 0; } if (playerUnits[fromUnit].strength <= 0) { if (showBattle == true) { lastResult1 = EnumResult.Destroyed; } killUnit(ref playerUnits, fromUnit, toUnit, maxUnits, showBattle); } if (showBattle == true) { if (lastResult1 == EnumResult.Destroyed && lastResult2 != EnumResult.Destroyed) { lastResult2 = EnumResult.Victory; } if (lastResult2 == EnumResult.Destroyed && lastResult1 != EnumResult.Destroyed) { lastResult1 = EnumResult.Victory; } } // Retreat or kill one of units neither already died if (isUnitDead(ref playerUnits, fromUnit) == false && isUnitDead(ref playerUnits, toUnit) == false) { if (effectiveDamage1 > effectiveDamage2) { if (showBattle == true) { lastResult1 = EnumResult.Advance; lastResult2 = EnumResult.Retreat; } retreatUnit(ref playerUnits, toUnit, fromUnit, maxUnits, showBattle); } else { if (showBattle == true) { lastResult1 = EnumResult.Retreat; lastResult2 = EnumResult.Advance; } retreatUnit(ref playerUnits, fromUnit, toUnit, maxUnits, showBattle); } } return(effectiveDamage1 + effectiveDamage2); } else { return(-1); } }
public int fireAtUnit(ref MapUnit[] playerUnits, int fromUnit, int toUnit, int maxUnits, bool showBattle) { if (fromUnit > -1 && toUnit > -1) { if (playerUnits[fromUnit].player != playerUnits[toUnit].player) { if (showBattle == true) { lastUnit1 = (MapUnit)playerUnits[fromUnit].Clone(); lastUnit2 = (MapUnit)playerUnits[toUnit].Clone(); lastMove = enumMoveType.Fire; lastU1 = fromUnit; lastU2 = toUnit; lastCalc1 = ""; lastCalc2 = ""; notePlayerWeights(ref playerUnits, maxUnits); } int distanceFire = calculateDistance(playerUnits[fromUnit].x, playerUnits[fromUnit].y, playerUnits[toUnit].x, playerUnits[toUnit].y); playerUnits[fromUnit].support = calculateSupport(ref playerUnits, fromUnit, maxUnits); playerUnits[toUnit].support = calculateSupport(ref playerUnits, toUnit, maxUnits); int fireWeight = calculateFireWeight(ref playerUnits, fromUnit); int defenseWeight = calculateDefenseWeight(ref playerUnits, toUnit, false); if (defenseWeight <= 0) { defenseWeight = 1; } if (playerUnits[fromUnit].typeUnit == unitEnum.Infantry) { fireWeight = Convert.ToInt32(fireWeight * Math.Pow(Constants.SHOOT_INFANTRY_ENERGYLOSS, distanceFire)); } if (playerUnits[fromUnit].typeUnit == unitEnum.Artillery) { fireWeight = Convert.ToInt32(fireWeight * Math.Pow(Constants.SHOOT_ARTILLERY_ENERGYLOSS, distanceFire)); } // special case if artillery into infantry square if (playerUnits[fromUnit].typeUnit == unitEnum.Artillery && playerUnits[toUnit].typeUnit == unitEnum.Infantry && playerUnits[toUnit].stanceUnit == stanceEnum.Square) { defenseWeight = Convert.ToInt32(defenseWeight * Constants.WEIGHT_FIRESQUARE_ARTILLERY); } // special case if infantry into infantry square if (playerUnits[fromUnit].typeUnit == unitEnum.Infantry && playerUnits[toUnit].typeUnit == unitEnum.Infantry && playerUnits[toUnit].stanceUnit == stanceEnum.Square) { defenseWeight = Convert.ToInt32(defenseWeight * Constants.WEIGHT_FIRESQUARE_INFANTRY); } if (showBattle == true) { lastCalc1 = fireWeight.ToString(); lastCalc2 = defenseWeight.ToString(); } int effectiveDamage = fireWeight / defenseWeight; if (effectiveDamage == 0) { effectiveDamage = Constants.MINIMUM_EFFECTIVE_DAMAGE; } if (showBattle == true) { //MessageBox.Show("TESTING: fireWeight: " + fireWeight.ToString() + " - defenseWeight: " + defenseWeight.ToString() + " - effectiveDamage: " + effectiveDamage.ToString()); } Random rand = new Random(); int chanceMorale = playerUnits[fromUnit].morale / rand.Next(5, Constants.MAX_RANDOM_MORALE_LOSS); if (chanceMorale <= 0) { chanceMorale = 1; } playerUnits[toUnit].strength -= effectiveDamage; playerUnits[toUnit].morale -= (effectiveDamage + chanceMorale); if (playerUnits[toUnit].morale < 0) { playerUnits[toUnit].morale = 0; } if (showBattle == true) { lastUnit1Damage = 0; lastUnit2Damage = effectiveDamage; lastResult1 = EnumResult.StandOff; lastResult2 = EnumResult.Damaged; } if (playerUnits[toUnit].strength <= 0) { if (showBattle == true) { lastResult1 = EnumResult.Victory; lastResult2 = EnumResult.Destroyed; } killUnit(ref playerUnits, toUnit, fromUnit, maxUnits, showBattle); } return(effectiveDamage); } else { return(-1); } } else { return(-1); } }
// using minimax type of algorithm public int makeMove(ref MapUnit[] playerUnits, playerEnum player, int maxUnits, int thisDepth, int maxDepth, int bestWeight) { traceProgress("makeMove() - *** DEPTH *** " + thisDepth.ToString() + " bestweight:" + bestWeight.ToString()); // already got end-condition, then this recurse not needed if (bestWeight == Constants.MAXIMUM_WEIGHT) { return(Constants.MINIMUM_WEIGHT); } if (modelBattleEngine == null) { modelBattleEngine = new BattleEngine(); modelBattleEngine.newBattle(mapX, mapY); } MapUnit[] modelUnits = new MapUnit[maxUnits]; for (int mu = 0; mu < maxUnits; mu++) { modelUnits[mu] = (MapUnit)playerUnits[mu].Clone(); } if (thisDepth == 0) { movesConsidered = 0; deadUnits = modelBattleEngine.countDeadUnits(ref modelUnits, player, maxUnits); bestU = -1; bestF = -1; bestX = -1; bestY = -1; bestMoveType = enumMoveType.Nothing; bestStance = stanceEnum.Nothing; traceProgress("makeMove() - *** INITIALISE *** max:" + mapX.ToString() + "," + mapY.ToString()); } int startingWeight = calculateWeight(ref modelUnits, ref modelBattleEngine, player, maxUnits); traceProgress("makeMove() - startingWeight:" + startingWeight.ToString()); int u = 0; while (u < maxUnits && bestWeight != Constants.MAXIMUM_WEIGHT) { if (player == modelUnits[u].player && modelUnits[u].strength > 0) { traceProgress("makeMove() - UNIT:" + modelUnits[u].description); // Moves int moveOffset = modelBattleEngine.possibleMoves(modelUnits[u].typeUnit, modelUnits[u].stanceUnit); int startX = modelUnits[u].x - moveOffset; int endX = modelUnits[u].x + moveOffset; if (startX < 0) { startX = 0; } if (endX >= mapX) { endX = mapX - 1; } for (int i = startX; i <= endX; i++) { int startY = modelUnits[u].y - moveOffset; int endY = modelUnits[u].y + moveOffset; if (startY < 0) { startY = 0; } if (endY >= mapY) { endY = mapY - 1; } for (int j = startY; j <= endY; j++) { if (bestWeight != Constants.MAXIMUM_WEIGHT) { playerEnum enemyPlayer = (player == playerEnum.Red)? playerEnum.Blue : playerEnum.Red; int livingEnemyBefore = modelBattleEngine.countLivingUnits(ref modelUnits, enemyPlayer, maxUnits); MapUnit oldUnit = (MapUnit)modelUnits[u].Clone(); MapUnit oldAttackedUnit = null; int nearestEnemyBefore = modelBattleEngine.findNearestFriend(ref modelUnits, u, maxUnits, true); int nearestEnemyDistanceBefore = modelBattleEngine.calculateDistance(ref modelUnits, nearestEnemyBefore, u); int f = modelBattleEngine.findUnit(ref modelUnits, i, j, maxUnits); int playerWeight = Constants.MINIMUM_WEIGHT; bool noChange = false; if (f > -1) { if (f != u && modelUnits[f].player != modelUnits[u].player && modelUnits[f].strength > 0) { movesConsidered++; // nearby enemy unit, try attacking oldAttackedUnit = (MapUnit)modelUnits[f].Clone(); modelUnits[u].x = i; modelUnits[u].y = j; modelBattleEngine.fightUnits(ref modelUnits, u, f, maxUnits, false); traceProgress("makeMove() - Attack:" + modelUnits[f].description); } else { noChange = true; } } else { movesConsidered++; // empty square, so try moving modelUnits[u].x = i; modelUnits[u].y = j; traceProgress("makeMove() - Move:" + i.ToString() + "," + j.ToString()); } if (noChange == false) { if (thisDepth < maxDepth) { if (pruneFar == true) { // stop moves away from enemy int nearestEnemyAfter = modelBattleEngine.findNearestFriend(ref modelUnits, u, maxUnits, true); int nearestEnemyDistanceAfter = modelBattleEngine.calculateDistance(ref modelUnits, nearestEnemyAfter, u); if (nearestEnemyDistanceAfter > nearestEnemyDistanceBefore) { playerWeight = Constants.MINIMUM_WEIGHT; } else { // if not at maxDepth, then recurse for unpruned tree playerWeight = makeMove(ref modelUnits, player, maxUnits, thisDepth + 1, maxDepth, bestWeight); } } else { // if all enemy dead, then this is end condition! int livingEnemyAfter = modelBattleEngine.countLivingUnits(ref modelUnits, enemyPlayer, maxUnits); if (livingEnemyAfter <= 0) { playerWeight = Constants.MAXIMUM_WEIGHT; } else { // if not at maxDepth, then recurse playerWeight = makeMove(ref modelUnits, player, maxUnits, thisDepth + 1, maxDepth, bestWeight); if (livingEnemyAfter < livingEnemyBefore) { playerWeight++; } } } traceProgress("makeMove() - RecursedWeight:" + playerWeight.ToString()); } else { // finally at max depth, what is the weighting? playerWeight = calculateWeight(ref modelUnits, ref modelBattleEngine, player, maxUnits); traceProgress("makeMove() - playerWeight:" + playerWeight.ToString()); } if (playerWeight > bestWeight) { if (f > -1) { if (modelUnits[u].player != modelUnits[f].player) { bestWeight = playerWeight; bestX = i; bestY = j; bestU = u; bestF = f; bestMoveType = enumMoveType.Attack; traceProgress("makeMove() - Set bestWeight:" + playerWeight.ToString()); traceProgress("makeMove() - To Attack:" + modelUnits[f].description); } } else { bestWeight = playerWeight; bestX = i; bestY = j; bestU = u; bestF = -1; bestMoveType = enumMoveType.Move; traceProgress("makeMove() - Set bestWeight:" + playerWeight.ToString()); traceProgress("makeMove() - To Move:" + i.ToString() + "," + j.ToString()); } } } // undo hypothetical move modelUnits[u] = (MapUnit)oldUnit.Clone(); // undo hypothetical attack if (f > -1 && oldAttackedUnit != null) { modelUnits[f] = (MapUnit)oldAttackedUnit.Clone(); } } } // try changing stance int stanceWeight = Constants.MINIMUM_WEIGHT; int numberStances = 0; MapUnit oldStanceUnit = (MapUnit)modelUnits[u].Clone(); switch (modelUnits[u].typeUnit) { case (unitEnum.Artillery): numberStances = 2; break; case (unitEnum.Cavalry): numberStances = 2; break; case (unitEnum.Infantry): numberStances = 3; break; default: numberStances = 0; break; } int us = 1; while (us <= numberStances) { bool stanceChange = false; stanceEnum currentStance = stanceEnum.Nothing; switch (us) { case (1): if (modelUnits[u].stanceUnit != stanceEnum.Line) { modelUnits[u].stanceUnit = stanceEnum.Line; currentStance = stanceEnum.Line; stanceChange = true; } break; case (2): if (modelUnits[u].stanceUnit != stanceEnum.Column) { //modelUnits[u].stanceUnit = stanceEnum.Column; //currentStance = stanceEnum.Column; //stanceChange = true; } break; case (3): if (modelUnits[u].stanceUnit != stanceEnum.Square) { modelUnits[u].stanceUnit = stanceEnum.Square; currentStance = stanceEnum.Square; stanceChange = true; } break; } if (stanceChange == false) { stanceWeight = Constants.MINIMUM_WEIGHT; } else { traceProgress("makeMove() - Set stance:" + currentStance.ToString()); movesConsidered++; if (thisDepth < maxDepth) { stanceWeight = makeMove(ref modelUnits, player, maxUnits, thisDepth + 1, maxDepth, bestWeight); traceProgress("makeMove() - recursedWeight:" + stanceWeight.ToString()); } else { stanceWeight = calculateWeight(ref modelUnits, ref modelBattleEngine, player, maxUnits); traceProgress("makeMove() - stanceWeight:" + stanceWeight.ToString()); } } if (stanceWeight > bestWeight && currentStance != stanceEnum.Nothing) { bestWeight = stanceWeight; bestU = u; bestStance = currentStance; bestMoveType = enumMoveType.Stance; traceProgress("makeMove() - Set bestWeight:" + stanceWeight.ToString()); traceProgress("makeMove() - stance:" + currentStance.ToString()); } // undo hypothetical stance change modelUnits[u] = (MapUnit)oldStanceUnit.Clone(); us++; } // try firing at all nearby units int fireWeight = Constants.MINIMUM_WEIGHT; int fireOffset = modelBattleEngine.possibleFire(modelUnits[u].typeUnit, modelUnits[u].stanceUnit); if (fireOffset > 0) { int uf = 0; while (uf < maxUnits && bestWeight != Constants.MAXIMUM_WEIGHT) { if (modelUnits[u].player != modelUnits[uf].player && modelUnits[uf].strength > 0) { playerEnum enemyPlayer = (player == playerEnum.Red)? playerEnum.Blue : playerEnum.Red; int livingEnemyBefore = modelBattleEngine.countLivingUnits(ref modelUnits, enemyPlayer, maxUnits); MapUnit oldFireUnit = (MapUnit)modelUnits[uf].Clone(); movesConsidered++; traceProgress("makeMove() - Fire At:" + modelUnits[uf].description); int distanceFire = modelBattleEngine.calculateDistance(ref modelUnits, uf, u); if (distanceFire <= fireOffset) { traceProgress("makeMove() - Distance:" + distanceFire.ToString()); modelBattleEngine.fireAtUnit(ref modelUnits, u, uf, maxUnits, false); if (thisDepth < maxDepth) { // if all enemy dead, then this is end condition! int livingEnemyAfter = modelBattleEngine.countLivingUnits(ref modelUnits, enemyPlayer, maxUnits); if (livingEnemyAfter <= 0) { fireWeight = Constants.MAXIMUM_WEIGHT; } else { // if not at maxDepth, then recurse fireWeight = makeMove(ref modelUnits, player, maxUnits, thisDepth + 1, maxDepth, bestWeight); if (livingEnemyAfter < livingEnemyBefore) { fireWeight++; } } traceProgress("makeMove() - recursedWeight:" + fireWeight.ToString()); } else { fireWeight = calculateWeight(ref modelUnits, ref modelBattleEngine, player, maxUnits); traceProgress("makeMove() - fireWeight:" + fireWeight.ToString()); } if (fireWeight > bestWeight) { bestWeight = fireWeight; bestU = u; bestF = uf; bestMoveType = enumMoveType.Fire; traceProgress("makeMove() - Set Fire:" + modelUnits[uf].description); } // undo hypothetical fire modelUnits[uf] = (MapUnit)oldFireUnit.Clone(); } } uf++; } } } } u++; } if (bestU > -1 && thisDepth == 0) { bool moveMade = false; traceProgress("makeMove() - *** MAKE COMPUTER MOVE ***"); switch (bestMoveType) { case (enumMoveType.Move): if (bestX > -1 && bestY > -1) { modelBattleEngine.moveUnit(ref playerUnits, bestU, bestX, bestY); moveMade = true; traceProgress("makeMove() - *** MOVE UNIT ***"); traceProgress("makeMove() - " + playerUnits[bestU].description + " to " + bestX.ToString() + "," + bestY.ToString()); } break; case (enumMoveType.Attack): if (bestX > -1 && bestY > -1) { playerUnits[bestU].x = bestX; playerUnits[bestU].y = bestY; modelBattleEngine.fightUnits(ref playerUnits, bestU, bestF, maxUnits, true); moveMade = true; traceProgress("makeMove() - *** ATTACK UNIT ***"); traceProgress("makeMove() - " + playerUnits[bestU].description + " to " + playerUnits[bestF].description); } break; case (enumMoveType.Fire): modelBattleEngine.fireAtUnit(ref playerUnits, bestU, bestF, maxUnits, true); moveMade = true; traceProgress("makeMove() - *** FIRE ON UNIT ***"); traceProgress("makeMove() - " + playerUnits[bestU].description + " to " + playerUnits[bestF].description); break; case (enumMoveType.Stance): modelBattleEngine.changeUnitStance(ref playerUnits, bestU, bestStance); moveMade = true; traceProgress("makeMove() - *** CHANGE STANCE ***"); traceProgress("makeMove() - " + playerUnits[bestU].description + " to " + bestStance.ToString()); break; default: traceProgress("makeMove() - *** ERROR - DEFAULT CASE ***"); moveMade = false; break; } traceProgress("makeMove() - moves considered:" + movesConsidered.ToString()); Debug.Assert(moveMade == true, "No move made", "madeMove() failed to create a move!"); if (moveMade == false) { bestWeight = Constants.MINIMUM_WEIGHT; } } traceProgress("makeMove() - return weight:" + bestWeight.ToString()); return(bestWeight); }