Difference between revisions of "Twin Duel/Tourney Runner"

From Robowiki
Jump to navigation Jump to search
m (fix some white space)
m (Using <syntaxhighlight>.)
Line 19: Line 19:
  
 
== RunTwinTourney.java ==
 
== RunTwinTourney.java ==
<pre>
+
<syntaxhighlight>
 
package twinduel;
 
package twinduel;
  
Line 419: Line 419:
 
     }
 
     }
 
}
 
}
</pre>
+
</syntaxhighlight>
 
== TwinListener.java ==
 
== TwinListener.java ==
<pre>
+
<syntaxhighlight>
 
package twinduel;
 
package twinduel;
  
Line 508: Line 508:
 
     }
 
     }
 
}
 
}
</pre>
+
</syntaxhighlight>
  
 
[[Category:Source Code]]
 
[[Category:Source Code]]
 
[[Category:Utilities]]
 
[[Category:Utilities]]

Revision as of 09:32, 1 July 2010

Twin Duel Sub-pages:
Twin DuelParticipants - Results - Strategy Guide - Tourney Runner - Origin Discussion - Archived Talk 20090807

This is the latest automation code for the Twin Duel tournament. It's currently written to the Robocode 1.7+ control API, so it unfortunately does not work with 1.6.1.4. Especially unfortunate because 1.7.1.1 introduces a bug with onRobotDeath events. The 1.7.1.4 alphas 8 and 9 have that bug fixed, so they are the best versions to use it with until the real 1.7.1.4 comes - sorry. Get them here.

This code includes a round robin, collecting results from round robin to rank the bots, and running a single elimination tourney based on that seeding. It would be a good base for any new tournaments anyone wants to try and run. It is also a good utility for testing Twin Duel battles in batch, since RoboResearch doesn't support that yet: you'd just use the round robin method and tweak the one "if" to only run battles that include a certain bot (like the commented out line).

I think the old code would be closer to what 1.6.1.4 needs, if you want to try and adapt it: TwinDuelUtil_003.zip.

Lastly, the portion that restarts the Robocode engine when a battle errors is untested.

RunTwinTourney.java

package twinduel;

import robocode.control.*;

import java.io.File;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Collections;

public class RunTwinTourney {
    public static final String ROBOCODE_PATH = "/PATH/TO/ROBOCODE";
    static final int NUM_ROUNDS = 75;
    static final int NUM_ITERATIONS = 1;
    static final int BATTLEFIELD_WIDTH = 800;
    static final int BATTLEFIELD_HEIGHT = 800;
    static final String[] competitors = {
        "ags.lunartwins.LunarTwins 1.2",
        "bvh.two.Ravens 0.2",
        "bvh.two.Valkiries 0.44t_mk3",
        "chase.twin.SurroundingTeam 1.0",
        "davidalves.twin.YinYang 1.2",
        "gh.GruwelTwins 0.1",
        "gh.twin.GrauwuarG 0.41",
        "jk.team.NightAndDay 1.6",
        "kawigi.micro.ShizPair 1.1",
        "kawigi.twin.MarioBros 1.0",
        "kc.twins.GeminiTeam 2.1",
        "kinsen.twin.SelcouthTeam 1.1",
        "krillr.mini.JointStrikeForce 2.0",
        "voidious.team.LuminariousDuo 1.0591",
        "wcsv.Coyote.CoyotePair .1",
        "whind.TwintelligenceTeam 1.0",
        "wiki.twin.InevitableTeam 0.1",
        "wiki.twin.KomariousTeam 1.0"

    };

    static final boolean WAIT_UNTIL_OVER = true;
    
    private TwinListener _twinListener;
    private BattlefieldSpecification _battlefield; 
    private RobocodeEngine _roboEngine;

    public RunTwinTourney() { 
        _twinListener = new TwinListener();
        _roboEngine = new RobocodeEngine(new File(ROBOCODE_PATH));
        _roboEngine.addBattleListener(_twinListener);
        _roboEngine.setVisible(false);
        _battlefield = 
            new BattlefieldSpecification(BATTLEFIELD_WIDTH, BATTLEFIELD_HEIGHT);
    }
    
    public void runTwinDuel() {
        ArrayList<CompetitorData> competitorList = processRoundRobin();
        ArrayList<CompetitorData> sortedCompetitorList = 
            (ArrayList<CompetitorData>)competitorList.clone();
        Collections.sort(sortedCompetitorList, new CompetitorSort());
        
        System.out.println("----");
        System.out.println();
        System.out.println("Round Robin Results: ");
        printCompetitorStats(sortedCompetitorList);

        processBracketTourney(sortedCompetitorList);
    }
    
    public ArrayList<CompetitorData> processRoundRobin() {        
        HashMap<String, CompetitorData> competitorHash = 
            new HashMap<String, CompetitorData>();        

        for (int z = 0; z < NUM_ITERATIONS; z++) {
            System.out.println("Round Robin Iteration " + (z + 1) + "...");
            for (int x = 0; x < competitors.length; x++) {
                for (int y = 0; y < competitors.length; y++) {
                    if (x < y) {                              
//                    if (x == 0 && x != y) {                          
                        String botNameFirst = "", botNameSecond = "";
                        int botSurvivalFirst = -1, botSurvivalSecond = -1;
                        do {                                  
                            BattleSpecification battleSpec = 
                                new BattleSpecification(NUM_ROUNDS, 
                                    _battlefield, 
                                    _roboEngine.getLocalRepository(
                                    competitors[x] + "," + competitors[y]));
                            _twinListener.lastBattleErrored = false;
                            _roboEngine.runBattle(battleSpec, WAIT_UNTIL_OVER);

                            botNameFirst = 
                                _twinListener.lastResult1.getRobot().getTeamId();
                            botNameFirst = 
                                botNameFirst.replaceFirst("\\[.*\\]", "");
                            botSurvivalFirst = 
                                _twinListener.lastResult1.getFirsts();
                            botNameSecond = 
                                _twinListener.lastResult2.getRobot().getTeamId();
                            botNameSecond = 
                                botNameSecond.replaceFirst("\\[.*\\]", "");
                            botSurvivalSecond = 
                                _twinListener.lastResult2.getFirsts();
                            if (botSurvivalFirst == botSurvivalSecond) {
                            System.out.println(botNameFirst + " tied with " + 
                                botNameSecond + ": " + botSurvivalFirst + 
                                " rounds won each. Rerunning...");
                            }
                            if (_twinListener.lastBattleErrored) {
                                System.out.println("Encountered a Robocode " +
                                    "error. Re-initializing Robocode engine " +
                                    "and rerunning...");
                                _roboEngine = 
                                    new RobocodeEngine(new File(ROBOCODE_PATH));
                                _roboEngine.addBattleListener(_twinListener);
                            }
                        } while (botSurvivalFirst == botSurvivalSecond ||
                                 _twinListener.lastBattleErrored);
                              
                        String winnerName, loserName;
                        int winnerSurvival, loserSurvival;
                        if (botSurvivalFirst > botSurvivalSecond) {
                            winnerName = botNameFirst;
                            winnerSurvival = botSurvivalFirst;
                            loserName = botNameSecond;
                            loserSurvival = botSurvivalSecond;
                        } else {
                            loserName = botNameFirst;
                            loserSurvival = botSurvivalFirst;
                            winnerName = botNameSecond;
                            winnerSurvival = botSurvivalSecond;
                        }
                              
                        CompetitorData winnerData, loserData;
                        if (competitorHash.containsKey(winnerName)) {
                            winnerData = competitorHash.get(winnerName);
                        } else {
                            winnerData = new CompetitorData();
                            winnerData.name = winnerName;
                            competitorHash.put(winnerName, winnerData);
                        }
                        winnerData.matchesWon++;
                        winnerData.roundsWon += winnerSurvival;
                        winnerData.roundsTotal += NUM_ROUNDS;

                        if (competitorHash.containsKey(loserName)) {
                            loserData = competitorHash.get(loserName);
                        } else {
                            loserData = new CompetitorData();
                            loserData.name = loserName;
                            competitorHash.put(loserName, loserData);
                        }
                        loserData.matchesLost++;
                        loserData.roundsWon += loserSurvival;
                        loserData.roundsTotal += NUM_ROUNDS;

                        System.out.println("RESULT = "+ winnerName +" defeats "
                            + loserName + ": " + winnerSurvival + " to " + 
                            loserSurvival);                       
                    }
                }
            }
            System.out.println();
        }
           
        return new ArrayList<CompetitorData>(competitorHash.values());
    }
    
    public void processBracketTourney(ArrayList<CompetitorData> competitorList) {
        for (int x = 0; x < competitorList.size(); x++) {
            CompetitorData competitor = competitorList.get(x);
            competitor.tourneySeed = (x + 1);
        }

        int rounds = 1, slots = 2;
        
        while (slots < competitorList.size()) {
            rounds++;
            slots *= 2;
        }
        
        for (int x = 0; x < rounds; x++) {
            System.out.println();
            System.out.println("----");
            System.out.println();
            if (x < rounds - 1) {
                System.out.println("Bracket Tourney Round " + (x + 1));
            } else {
                System.out.println("Tourney Finals");
            }
            System.out.println();

            boolean needExtraNewline = false;
            
            for (int y = 0; y < (slots / 2); y++) {
                int effectiveSeed1 = (y + 1);
                int effectiveSeed2 = slots - y;
                
                if (competitorList.size() < effectiveSeed2) {
                    System.out.println("Seed " + effectiveSeed1 
                        + " gets a bye");
                    needExtraNewline = true;
                } else {
                    if (needExtraNewline) {
                        System.out.println();
                        needExtraNewline = false;
                    }
                    
                    CompetitorData higherSeed = 
                        competitorList.get(effectiveSeed1 - 1);
                    CompetitorData lowerSeed =
                        competitorList.get(effectiveSeed2 - 1);

                    System.out.println(
                            higherSeed.tourneySeed + " " + higherSeed.name);
                    System.out.println(
                            lowerSeed.tourneySeed + " " + lowerSeed.name);
                    
                    String tourneyResultString = tourneyBattleResult(
                        higherSeed, lowerSeed, (slots == 2));
                    System.out.println("\t" + tourneyResultString);
                    
                    if (!tourneyResultString.contains(
                            higherSeed.name + " wins")) {
                        competitorList.set(y, lowerSeed);
                    }
                    
                    needExtraNewline = true;
                }
            }
            
            slots /= 2;
        }
        
        System.out.println();
    }

    public static void printCompetitorStats(
        ArrayList<CompetitorData> competitorStats) {

        for (int x = 0; x < competitorStats.size(); x++) {
            System.out.println();
            CompetitorData stats = competitorStats.get(x);
            System.out.println("Competitor: " + stats.name);
            System.out.println("Win/loss: " + stats.matchesWon + " - " + stats.matchesLost);
            System.out.println("Rounds won: " + stats.roundsWon + 
                " (" + stats.roundWinPercentage() + "%)");
        }
    }
    
    public String tourneyBattleResult(CompetitorData firstBot, 
        CompetitorData secondBot, boolean tourneyFinals) {
        
        String botNameFirst = "", botNameSecond = "";
        int botSurvivalFirst = -1, botSurvivalSecond = -1;
        int battlesFought = 0;
        
        TwinBattleResult tourneyBattleResult = new TwinBattleResult();
        tourneyBattleResult.firstBotName = firstBot.name;
        tourneyBattleResult.secondBotName = secondBot.name;
        
        do {                                  
            BattleSpecification battleSpec = 
                new BattleSpecification(NUM_ROUNDS, _battlefield, 
                _roboEngine.getLocalRepository(firstBot.name + 
                    "," + secondBot.name));
            _twinListener.lastBattleErrored = false;
            _roboEngine.runBattle(battleSpec, WAIT_UNTIL_OVER);

            if (_twinListener.lastBattleErrored) {
                System.out.println("Encountered a Robocode error. " +
                    "Re-initializing Robocode engine and rerunning...");
                _roboEngine = new RobocodeEngine(new File(ROBOCODE_PATH));
                _roboEngine.addBattleListener(_twinListener);
            } else {
                botNameFirst = _twinListener.lastResult1.getRobot().getTeamId();
                botNameFirst = botNameFirst.replaceFirst("\\[.*\\]", "");
                botSurvivalFirst = _twinListener.lastResult1.getFirsts();
                botNameSecond = _twinListener.lastResult2.getRobot().getTeamId();
                botNameSecond = botNameSecond.replaceFirst("\\[.*\\]", "");
                botSurvivalSecond = _twinListener.lastResult2.getFirsts();

                battlesFought++;
                if (firstBot.name.equals(botNameFirst)) {
                    tourneyBattleResult.firstSurvival.add(
                        new Integer(botSurvivalFirst));
                    tourneyBattleResult.secondSurvival.add(
                        new Integer(botSurvivalSecond));             
                } else {
                    tourneyBattleResult.secondSurvival.add(
                        new Integer(botSurvivalFirst));
                    tourneyBattleResult.firstSurvival.add(
                        new Integer(botSurvivalSecond));                              
                }
                // For debugging suspected problems...
//                System.out.println("RAW TOURNEY RESULT: " + botNameFirst + 
//                    " = " + botSurvivalFirst + ", " + botNameSecond + " = " + 
//                    botSurvivalSecond);
            }
        } while ((tourneyFinals && battlesFought < 3) ||
                (!tourneyFinals && botSurvivalFirst == botSurvivalSecond) ||
                _twinListener.lastBattleErrored);
        
        return tourneyBattleResult.winString();
    }
    
    class CompetitorData {
        String name;
        long matchesWon = 0;
        long matchesLost = 0;
        long roundsWon = 0;
        long roundsTotal = 0;
        int tourneySeed = -1;
        
        public double roundWinPercentage() {
            return (
                ((double)Math.round((((double)roundsWon)/roundsTotal)*10000))
                    / 100);            
        }
    }

    class CompetitorSort implements Comparator<CompetitorData> {
        public int compare(CompetitorData c1, CompetitorData c2) {
            if (c1.matchesWon - c1.matchesLost <
                c2.matchesWon - c2.matchesLost) {
                return 1;
            } else if (c1.matchesWon - c1.matchesLost >
                c2.matchesWon - c2.matchesLost) {
                return -1;
            } else {
                if (c1.roundWinPercentage() < c2.roundWinPercentage()) {
                    return 1;
                } else if (c1.roundWinPercentage() > c2.roundWinPercentage()) {
                    return -1;
                } else {
                    return 0;
                }
            }
        }
        
        public boolean equals(Object obj) {
            return (this == obj);
        }
    }

    class TwinBattleResult {
        String firstBotName, secondBotName;
        ArrayList<Integer> firstSurvival;
        ArrayList<Integer> secondSurvival;
        
        public TwinBattleResult() {
            firstSurvival = new ArrayList<Integer>();
            secondSurvival = new ArrayList<Integer>();
        }
        
        public String winString() {
            int firstWins = 0, secondWins = 0;
            
            for (int x = 0; x < firstSurvival.size(); x++) {
                if (((Integer)firstSurvival.get(x)).intValue() 
                        > ((Integer)secondSurvival.get(x)).intValue()) {
                    firstWins++;
                } else if (((Integer)firstSurvival.get(x)).intValue()
                        < ((Integer)secondSurvival.get(x)).intValue()) {
                    secondWins++;
                }
            }
            
            String winString = "";
            
            if (firstWins > secondWins) {
                winString += firstBotName + " wins ";
            } else if (firstWins < secondWins) {
                winString += secondBotName + " wins ";
            } else {
                winString += firstBotName + " tied with " + secondBotName
                    + " ";
            }
            
            for (int x = 0; x < firstSurvival.size(); x++) {
                if (x != 0) {
                    winString += ", ";
                }
                
                if (firstWins >= secondWins) {
                    winString += firstSurvival.get(x) + " - " 
                    + secondSurvival.get(x); 
                } else {
                    winString += secondSurvival.get(x) + " - " 
                    + firstSurvival.get(x);
                }
            }
            
            return winString;
        }
    }

    public static void main(String[] args) {
        RunTwinTourney rtt = new RunTwinTourney();
        rtt.runTwinDuel();
    }
}

TwinListener.java

package twinduel;

import robocode.control.BattleSpecification;
import robocode.control.RobotResults;
import robocode.control.events.BattleCompletedEvent;
import robocode.control.events.BattleErrorEvent;
import robocode.control.events.BattleFinishedEvent;
import robocode.control.events.BattleMessageEvent;
import robocode.control.events.BattlePausedEvent;
import robocode.control.events.BattleResumedEvent;
import robocode.control.events.BattleStartedEvent;
import robocode.control.events.RoundEndedEvent;
import robocode.control.events.RoundStartedEvent;
import robocode.control.events.TurnEndedEvent;
import robocode.control.events.TurnStartedEvent;
import robocode.BattleResults;

public class TwinListener implements robocode.control.events.IBattleListener {
    
    public RobotResults lastResult1;
    public RobotResults lastResult2;
    public boolean lastBattleErrored = false;
    
    public void battleAborted(BattleSpecification battlespecification) { }
    
    public void battleMessage(String string) { }

    public void onBattleCompleted(BattleCompletedEvent arg0) {
        RobotResults[] results = 
            RobotResults.convertResults(arg0.getIndexedResults());
            
        lastResult1 = results[0];
        lastResult2 = results[1];
    }

    public void onBattleError(BattleErrorEvent arg0) {
        System.out.println(arg0.getError());
        lastBattleErrored = true;
        
    }

    public void onBattleFinished(BattleFinishedEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    public void onBattleMessage(BattleMessageEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    public void onBattlePaused(BattlePausedEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    public void onBattleResumed(BattleResumedEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    public void onBattleStarted(BattleStartedEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    public void onRoundEnded(RoundEndedEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    public void onRoundStarted(RoundStartedEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    public void onTurnEnded(TurnEndedEvent arg0) {
        // TODO Auto-generated method stub
        
    }

    public void onTurnStarted(TurnStartedEvent arg0) {
        // TODO Auto-generated method stub
        
    }
}