[Home]Simonton/RoboleagueSeasonAverages

Robo Home | Simonton | Changes | Preferences | AllPages

I don't know the best place to do this, so here goes: I hacked together some mods for Roboleague to let me see the overall averages of my bot over several seasons in a division. It isn't pretty, but it works. I can't find licencing info on Roboleague, so I'm just going to paste my mods on here & let you paste them into the soure & compile. Please treat this code as "open source" & share any improvements you make!

This is in roboleague.XmlIO. At the top of storeDivisionSeasons(...), add this line:

		storeDivisionSeasonsAverages(parent, seasons);

Now make that work by adding these functions:

	protected void storeDivisionSeasonsAverages(Element parent,
			DivisionSeason[] seasons) {
		Element element = parent.getOwnerDocument().createElement("SEASON");
		parent.appendChild(element);
		element.setAttribute("number", "Overall Averages");
		element
				.setAttribute("finished", isFinished(seasons) ? "true"
						: "false");
		storeCompetitorTotals(element, getTotalsAverages(seasons));
		storeGroupings(element, getGroupingsAverages(seasons));
	}

	private boolean isFinished(DivisionSeason[] seasons) {
		for (DivisionSeason season : seasons) {
			if (!season.getCompleted()) {
				return false;
			}
		}
		return true;
	}

	private CompetitorResults[] getTotalsAverages(DivisionSeason[] seasons) {
		TallySet tallies = new TallySet();
		for (DivisionSeason season : seasons) {
			CompetitorResults[] finalTotals = season.getFinalTotals();
			if (finalTotals != null) {
				for (CompetitorResults results : finalTotals) {
					tallies.tally(results);
				}
			}
		}
		return tallies.getAverages();
	}

	private Collection getGroupingsAverages(DivisionSeason[] seasons) {
		Map<Grouping, TallySet> tallies = new HashMap<Grouping, TallySet>();
		for (DivisionSeason season : seasons) {
			Collection groupings = season.getGroupings();
			for (Object resultsObj : groupings) {
				Grouping grouping = (Grouping) resultsObj;
				if (grouping.getTerminated()) {
					TallySet tally;
					Grouping key = findGrouping(grouping, tallies.keySet());
					if (key == null) {
						tally = new TallySet();
						tallies.put(grouping, tally);
					} else {
						tally = tallies.get(key);
					}
					for (CompetitorResults results : grouping.competitorResults) {
						tally.tally(results);
					}
				}
			}
		}
		Collection<Grouping> avgs = new ArrayList<Grouping>();
		for (TallySet tally : tallies.values()) {
			avgs.add(new Grouping(tally.getAverages()));
		}
		return avgs;
	}

	private Grouping findGrouping(Grouping grouping, Iterable<Grouping> space) {
		for (Grouping g : space) {
			if (isMatch(grouping, g)) {
				return g;
			}
		}
		return null;
	}
	
	private boolean isMatch(Grouping g1, Grouping g2) {
		if (g1.competitors.length != g2.competitors.length) {
			return false;
		}
		for (Competitor c : g1.competitors) {
			if (!contains(g2, c)) {
				return false;
			}
		}
		return true;
	}
	
	private boolean contains(Grouping grouping, Competitor competitor) {
		for (Competitor c2 : grouping.competitors) {
			if (competitor.id.equals(c2.id)) {
				return true;
			}
		}
		return false;
	}

	private Collection<CompetitorResults> average(
			Map<Competitor, CompetitorResults> avgs,
			Map<Competitor, Integer> numSeasons) {
		List<CompetitorResults> results = new ArrayList<CompetitorResults>(avgs
				.values());
		for (int i = 0; i < results.size(); ++i) {
			CompetitorResults result = results.get(i);
			int seasonCount = numSeasons.get(result.competitor);
			result.score /= seasonCount;
			result.survival /= seasonCount;
			result.lastSurvivorBonus /= seasonCount;
			result.bulletDamage /= seasonCount;
			result.bulletDamageBonus /= seasonCount;
			result.ramDamage /= seasonCount;
			result.ramDamageBonus /= seasonCount;
			result.firsts /= seasonCount;
			result.seconds /= seasonCount;
			result.thirds /= seasonCount;
		}
		Collections.sort(results);
		for (int i = 0; i < results.size(); ++i) {
			results.get(i).rank = i + i;
		}
		return results;
	}

	class TallySet {
		Map<Competitor, ResultsTally> tallies = new HashMap<Competitor, ResultsTally>();
		void tally(CompetitorResults results) {
			ResultsTally tally = tallies.get(results.competitor);
			if (tally == null) {
				tally = new ResultsTally(results.competitor);
				tallies.put(results.competitor, tally);
			}
			tally.tally(results);
		}
		public CompetitorResults[] getAverages() {
			CompetitorResults[] avgs = new CompetitorResults[tallies.size()];
			int i = 0;
			for (ResultsTally tally : tallies.values()) {
				avgs[i++] = tally.getAvg();
			}
			Arrays.sort(avgs);
			for (i = 0; i < avgs.length; ++i) {
				avgs[i].rank = i + 1;
			}
			return avgs;
		}
	}

	class ResultsTally {
		CompetitorResults tally;
		int numTallied = 0;
		ResultsTally(Competitor competitor) {
			tally = new CompetitorResults(competitor);
		}
		void tally(CompetitorResults results) {
			assert results.competitor == tally.competitor;
			tally.score += results.score;
			tally.survival += results.survival;
			tally.lastSurvivorBonus += results.lastSurvivorBonus;
			tally.bulletDamage += results.bulletDamage;
			tally.bulletDamageBonus += results.bulletDamageBonus;
			tally.ramDamage += results.ramDamage;
			tally.ramDamageBonus += results.ramDamageBonus;
			tally.firsts += results.firsts;
			tally.seconds += results.seconds;
			tally.thirds += results.thirds;
			++numTallied;
		}
		CompetitorResults getAvg() {
			CompetitorResults avg = new CompetitorResults(tally.competitor);
			avg.score = tally.score / numTallied;
			avg.survival = tally.survival / numTallied;
			avg.lastSurvivorBonus = tally.lastSurvivorBonus / numTallied;
			avg.bulletDamage = tally.bulletDamage / numTallied;
			avg.bulletDamageBonus = tally.bulletDamageBonus / numTallied;
			avg.ramDamage = tally.ramDamage / numTallied;
			avg.ramDamageBonus = tally.ramDamageBonus / numTallied;
			avg.firsts = tally.firsts / numTallied;
			avg.seconds = tally.seconds / numTallied;
			avg.thirds = tally.thirds / numTallied;
			return avg;
		}
	}

Finally make sure next time we load this Roboleague doesn't try to read in our new avarages & do strange things with them as a season of their own by modifying restoreDivisionSeasons()'s for loop to be:

		for (int i = 0; i < nodeList.getLength(); i++) {
			Element element = (Element) nodeList.item(i);
			String numebrAttribute = element.getAttribute("number");
			try {
				int number = Integer.valueOf(numebrAttribute).intValue();
				Collection groupings = restoreGroupings(element, allCompetitors);
				boolean completed = element.getAttribute("finished").equals(
						"true");
				result.add(new DivisionSeason(number, groupings, completed));
			} catch (NumberFormatException err) {
				assert numebrAttribute.contains("Overall Averages");
			}
		}

Now the next time a Division's html results are created, you have overal averages at the bottom! (B.t.w., if someone can get these to show up at the top it would be awesome!).


Robo Home | Simonton | Changes | Preferences | AllPages
Edit text of this page | View other revisions
Last edited September 28, 2006 1:15 EST by Simonton (diff)
Search: