/*
* MegaMek -
* Copyright (C) 2006 Ben Mazur (bmazur@sev.org)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package megamek.common.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import megamek.common.Compute;
import megamek.common.MechSummary;
import megamek.common.MechSummaryCache;
import megamek.common.TechConstants;
import megamek.common.UnitType;
public class RandomArmyCreator {
/**
* Parameters for the random army generator
*/
public static class Parameters {
/**
* Number of mechs to include in the army
*/
public int mechs;
/**
* Number of combat vehicles to include
*/
public int tanks;
/**
* Number of battle armor infantry to include
*/
public int ba;
/**
* Number of conventional infantry to include
*/
public int infantry;
/**
* Maximum battle value
*/
public int maxBV;
/**
* Minimum battle value
*/
public int minBV;
/**
* Latest design year
*/
public int maxYear = 9999;
/**
* Earliest design year
*/
public int minYear = 0;
/**
* A value from TechConstants, which will filter the units
*/
public int tech;
/**
* Canon units only?
*/
public boolean canon;
/**
* If true, add extra infantry to pad out the BV and get closer to
* maximum
*/
public boolean padWithInfantry;
}
/**
* Sorting MechSummary by BV
*/
static Comparator<MechSummary> bvComparator = new Comparator<MechSummary>() {
public int compare(MechSummary a, MechSummary b) {
if (a.getBV() > b.getBV()) {
return 1;
} else if (b.getBV() > a.getBV()) {
return -1;
} else {
return 0;
}
}
};
private static ArrayList<MechSummary> generateArmy(
ArrayList<MechSummary> unitList, int count, int targetBV,
int allowedVariance) {
ArrayList<MechSummary> units = new ArrayList<MechSummary>();
if ((count < 1) || (unitList.size() < 1)) {
return units;
}
// first pick any random mechs
int selection[] = new int[count];
int currentBV = 0;
for (int i = 0; i < count; i++) {
selection[i] = Compute.randomInt(unitList.size());
currentBV += unitList.get(selection[i]).getBV();
}
Arrays.sort(selection);
// now try and bring into range
int bottom, top;
bottom = 0;
top = unitList.size() - 1;
int giveUp = 0;
while (((currentBV < targetBV - allowedVariance) || (currentBV > targetBV))
&& (giveUp++ < 40000)) {
if (top == bottom) {
break;
}
if (currentBV < targetBV - allowedVariance) {
// under BV, reroll above the weakest unit
bottom = Math.max(bottom, selection[0]);
currentBV = 0;
for (int i = 0; i < count; i++) {
selection[i] = Compute.randomInt(top - bottom) + bottom;
currentBV += unitList.get(selection[i]).getBV();
}
} else if (currentBV > targetBV) {
// over BV, reroll below the highest unit
top = Math.min(top, selection[selection.length - 1]);
currentBV = 0;
for (int i = 0; i < count; i++) {
selection[i] = Compute.randomInt(top - bottom) + bottom;
currentBV += unitList.get(selection[i]).getBV();
}
}
Arrays.sort(selection);
}
for (int i = 0; i < count; i++) {
MechSummary m = unitList.get(selection[i]);
units.add(m);
}
return units;
}
private static int countBV(ArrayList<MechSummary> units) {
int bv = 0;
for (MechSummary m : units) {
bv += m.getBV();
}
return bv;
}
public static void main(String[] args) {
Parameters p = new Parameters();
p.mechs = 4;
p.tanks = 4;
p.infantry = 0;
p.ba = 4;
p.maxBV = 8000;
p.minBV = 7600;
p.minYear = 3050;
p.maxYear = 3055;
p.tech = TechConstants.T_IS_TW_NON_BOX;
p.canon = true;
p.padWithInfantry = true;
ArrayList<MechSummary> units = generateArmy(p);
int totalBV = 0;
for (MechSummary m : units) {
totalBV += m.getBV();
System.out.print(m.getChassis());
System.out.print(" ");
System.out.print(m.getModel());
System.out.print(" ");
System.out.println(m.getBV());
}
System.out.print("Total: ");
System.out.println(totalBV);
}
public static ArrayList<MechSummary> generateArmy(Parameters p) {
int allowedVariance = java.lang.Math.abs(p.maxBV - p.minBV);
MechSummary[] all = MechSummaryCache.getInstance().getAllMechs();
ArrayList<MechSummary> allMechs = new ArrayList<MechSummary>();
ArrayList<MechSummary> allTanks = new ArrayList<MechSummary>();
ArrayList<MechSummary> allInfantry = new ArrayList<MechSummary>();
ArrayList<MechSummary> allBA = new ArrayList<MechSummary>();
for (MechSummary m : all) {
if ((p.tech != TechConstants.T_ALL) && (p.tech != m.getType())) {
// advanced rules includes basic too
if (p.tech == TechConstants.T_CLAN_ADVANCED) {
if (m.getType() != TechConstants.T_CLAN_TW) {
continue;
}
} else if (p.tech == TechConstants.T_IS_ADVANCED) {
if ((m.getType() != TechConstants.T_INTRO_BOXSET)
&& (m.getType() != TechConstants.T_IS_TW_NON_BOX)) {
continue;
}
} else if (p.tech == TechConstants.T_IS_TW_NON_BOX) {
if (m.getType() != TechConstants.T_INTRO_BOXSET) {
continue;
}
} else if (p.tech == TechConstants.T_TW_ALL) {
if ((m.getType() != TechConstants.T_INTRO_BOXSET)
&& (m.getType() != TechConstants.T_IS_TW_NON_BOX)
&& (m.getType() != TechConstants.T_CLAN_TW)) {
continue;
}
} else if (p.tech == TechConstants.T_IS_TW_ALL) {
if ((m.getType() != TechConstants.T_INTRO_BOXSET)
&& (m.getType() != TechConstants.T_IS_TW_NON_BOX)) {
continue;
}
} else {
continue;
}
}
if (((m.getYear() < p.minYear) || (m.getYear() > p.maxYear))
&& !m.getUnitType().equals(
UnitType.getTypeName(UnitType.INFANTRY))) {
continue;
}
if (p.canon && !m.isCanon()) {
continue;
}
// Unit accepted, add to the appropriate list
if (m.getUnitType().equals(UnitType.getTypeName(UnitType.MEK))) {
allMechs.add(m);
} else if (m.getUnitType()
.equals(UnitType.getTypeName(UnitType.TANK))
|| m.getUnitType().equals(
UnitType.getTypeName(UnitType.VTOL))) {
allTanks.add(m);
} else if (m.getUnitType().equals(
UnitType.getTypeName(UnitType.BATTLE_ARMOR))) {
allBA.add(m);
} else if (m.getUnitType().equals(
UnitType.getTypeName(UnitType.INFANTRY))) {
allInfantry.add(m);
}
}
Collections.<MechSummary> sort(allMechs, bvComparator);
Collections.<MechSummary> sort(allTanks, bvComparator);
Collections.<MechSummary> sort(allInfantry, bvComparator);
Collections.<MechSummary> sort(allBA, bvComparator);
// get the average BV for each unit class, to determine how to split up
// the total
int averageMechBV = countBV(allMechs) / Math.max(1, allMechs.size());
int averageTankBV = countBV(allTanks) / Math.max(1, allTanks.size());
int averageInfBV = countBV(allInfantry) / Math.max(1, allInfantry.size());
int averageBaBV = countBV(allBA) / Math.max(1, allBA.size());
int helpWeight = Math.max(1, p.mechs * averageMechBV + p.tanks
* averageTankBV + p.infantry * averageInfBV + p.ba * averageBaBV);
int baBV = (p.ba * averageBaBV * p.maxBV) / helpWeight;
if ((p.ba > 0) && (allBA.size() > 0)) {
baBV = Math.max(baBV, p.ba * allBA.get(0).getBV());
baBV = Math.min(baBV, p.ba * allBA.get(allBA.size() - 1).getBV());
} else {
baBV = 0;
}
int mechBV = (p.mechs * averageMechBV * p.maxBV) / helpWeight;
if ((p.mechs > 0) && (allMechs.size() > 0)) {
mechBV = Math.max(mechBV, p.mechs * allMechs.get(0).getBV());
mechBV = Math.min(mechBV, p.mechs
* allMechs.get(allMechs.size() - 1).getBV());
} else {
mechBV = 0;
}
int tankBV = (p.tanks * averageTankBV * p.maxBV) / helpWeight;
if ((p.tanks > 0) && (allTanks.size() > 0)) {
tankBV = Math.max(tankBV, p.tanks * allTanks.get(0).getBV());
tankBV = Math.min(tankBV, p.tanks
* allTanks.get(allTanks.size() - 1).getBV());
} else {
tankBV = 0;
}
// add the units in roughly increasing BV order
ArrayList<MechSummary> units = generateArmy(allBA, p.ba, baBV,
allowedVariance);
units.addAll(generateArmy(allTanks, p.tanks, tankBV + baBV
- countBV(units), allowedVariance));
units.addAll(generateArmy(allMechs, p.mechs, mechBV + tankBV + baBV
- countBV(units), allowedVariance));
if (p.padWithInfantry) {
int inf = (p.maxBV - countBV(units)) / averageInfBV;
units.addAll(generateArmy(allInfantry, inf, p.maxBV
- countBV(units), allowedVariance));
} else {
units.addAll(generateArmy(allInfantry, p.infantry, p.maxBV
- countBV(units), allowedVariance));
}
return units;
}
}