Münzwurf Zeitreisende


19

In der Zukunft, in der Time Travel (abgekürzt als TT) weit verbreitet sein wird, wird das Werfen von Münzen ein ernstzunehmender Gedankensport. Um uns auf die Zukunft vorzubereiten, veranstalten wir einen Wettbewerb für Programme, bei denen Zeitreisen aus Sicht der Beiträge wirklich stattfinden.

Der Wettbewerb ist im Round-Robin-Stil und besteht aus Münzwurfspielen zwischen Java-Klassen.

Regeln des Münzwurfspiels

  • Es gibt zwei Spieler und 100 Runden.
  • In jeder Runde wird eine Münze geworfen und basierend auf dem Ergebnis erhält einer der Spieler 1 Punkt. Jeder Spieler hat eine 50% ige Chance, einen Punkt zu erzielen.
  • Nach dem Werfen haben beide Spieler die Möglichkeit, die Zeit durch Ziehen der Hebel zu kontrollieren.
  • Wenn Sie einen blauen Hebel (Revert Stopper) ziehen, ist kein TT mehr möglich, um den Hebel oder eine frühere Runde zu drehen. Der Versuch von TT, an diesen Runden teilzunehmen, hat keine Wirkung.
  • Wenn Sie einen roten Hebel ziehen , versuchen Sie, die Zeit auf eine frühere Runde zurückzustellen. Bei Erfolg wird das Gedächtnis des Gegners vor der gewählten Runde auf sein Gedächtnis zurückgesetzt und die Münzwurfergebnisse ab der gewählten Runde werden ebenfalls gelöscht . Das einzig mögliche Zeichen für Ihren Gegner in Bezug auf den TT ist die Anzahl der nicht verwendeten Hebel, die nicht zurückgesetzt werden.
  • Jeder Spieler hat zu Beginn des Spiels 5 blaue und 20 rote, nicht benutzte Hebel. Diese Hebel werden von TTs nicht beeinflusst.
  • Wenn am Ende einer 100. Runde kein TT stattfindet, endet das Spiel und der Spieler mit der höheren Punktzahl gewinnt.

Einzelheiten

  • Runden haben eine 1-basierte Indizierung (Form 1 bis 100).
  • Vor der Runde erhalten xSie die Anzahl der verfügbaren blauen und roten Hebel, die Münzwurfergebnisse bis zum Zug x(einschließlich) und die Erinnerung an Ihren (letzten)x-1 Runde.
  • Das Ziehen eines blauen Hebels in der Runde xstoppt alle TTs, die ein Ziel in der Runde xoder davor haben (es blockiert eine TT, wenn es genau in dieser Runde auch passiert).
  • Zurück zur Runde xbedeutet, dass die nächste Runde rund ist x.
  • Wenn beide Spieler am Ende einer Runde zurückkehren, wird die Zeit auf das frühere Ziel zurückgesetzt, das nicht gesperrt ist. Die Spieler, die versucht haben, zu dieser Zeit zurückzukehren, behalten ihr Gedächtnis.

Technische Details

  • Sie sollten eine Java-Klasse schreiben, die die bereitgestellte Bot-Schnittstelle implementiert.
  • Fügen Sie Ihren Bot zum Projekt hinzu.
  • Fügen Sie eine Instanz Ihres Bots zu der Botin der Datei hinzuController.java .
  • Ihre Klasse sollte keine Informationen zwischen Anrufen speichern . (In den meisten Fällen wird finaldiese Anforderung erfüllt, wenn nur Variablen außerhalb von Funktionen vorhanden sind.)
  • Sie können dem Controller im memoryFeld Ihres zurückgegebenen ActionObjekts Informationen geben . Dies wird dir in der nächsten Runde zurückgegeben, wenn kein TT passiert ist. Wenn ein TT passiert, erhalten Sie die entsprechende frühere Erinnerung von Ihnen.
  • Sie können die totalScore()Methode der GameKlasse verwenden, um die Bewertung einer Verlaufszeichenfolge abzurufen.

Protokoll

  • An jeder Ecke wird Ihre takeTurn(...)Methode mit 5 Argumenten aufgerufen:

    • die Anzahl der nicht verwendeten blauen Hebel
    • die Anzahl der nicht verwendeten roten Hebel
    • Die Münzwurfhistorie ist eine Zeichenfolge aus 1 und 0, die Ihre Gewinne und Verluste in den vorherigen Runden kennzeichnet. Das erste Zeichen entspricht dem ersten Münzwurf. (In der ersten Runde beträgt die Länge der Saite1 .)
    • eine Zeichenfolge, Ihre gespeicherte Erinnerung aus der vorherigen Runde
    • der 1-basierte Index dieser Runde
  • Bei jedem Zug gibt Ihre Methode ein ActionObjekt zurück, das enthält

    • eine Ganzzahl in dem moveFeld, das Ihre Aktion beschreibt:

      • 0 für keine aktion
      • -1 einen blauen Hebel zu ziehen und TTs zu blockieren, die diese Runde durchlaufen
      • Eine positive ganze Zahl x, die nicht größer als die aktuelle Runde ist, um einen roten Hebel zu ziehen und zu versuchen, wieder zur Runde zurückzukehrenx
      • Ungültige Ganzzahlen werden als behandelt 0.
    • eine Zeichenfolge mit Ihrem Gedächtnis aus dieser Runde, die Sie beibehalten möchten. Beachten Sie, dass das Speichern von Speicherplatz kein wesentlicher Bestandteil der Herausforderung ist . Sie können gute Eingaben machen, ohne nützliche Daten in der Zeichenfolge zu speichern. In der ersten Runde ist die Zeichenfolge eine leere Zeichenfolge.

  • Ihre Methode sollte im Durchschnitt nicht länger als 10 ms pro Runde dauern.

  • Regelmäßiges Nichteinhalten der Frist führt zur Disqualifikation.

Wertung

  • Wenn Sie ein Match gewinnen, erhalten Sie 2 Punkte und ein Unentschieden 1 Punkt für beide Spieler. Verlust verdient keine Punkte.
  • Die Punktzahl eines Bots ist die Gesamtzahl der gesammelten Punkte.
  • Die Anzahl der Matches, die zwischen jedem Teilnehmerpaar ausgetragen werden, hängt von der Anzahl der Einsendungen und ihrer Geschwindigkeit ab.

Zwei einfache Beispiel-Bots werden als Antworten gepostet.

Der Controller und die ersten paar Bots sind hier verfügbar .

Testergebnisse mit bis zum 3. November eingereichten Bots:

Gesamtpunktzahl:

Oldschool: 3163
Random: 5871
RegretBot: 5269
Nostalgia: 8601
Little Ten: 8772
Analyzer: 17746
NoRegretsBot: 5833
Oracle: 15539
Deja Vu: 5491
Bad Loser: 13715

(Der Controller basiert auf dem Controller der Cat Catcher Challenge . Vielen Dank, dass @flawr ihn als Basis für diesen verwendet hat.)

Bonus: Ein schöner 6-minütiger Film, der auf einem ähnlichen Konzept basiert.


1
Ich verstehe nicht, was diese Regel bedeutet. If you pull a blue lever (revert stopper) no TT is possible through that round anymore. TT's attempting to go through the round will have no effect.Was ist "eine Runde durchmachen"?
Feersum

@feersum Wenn ich das richtig verstehe, wird durch dauerhaftes Ziehen des blauen Hebels die aktuelle Runde (und damit alle vorherigen Runden) "verriegelt", sodass die Ergebnisse nicht durch Zeitreisen verändert werden können. Wenn jemand versucht, eine Zeit vor dem Betätigen des blauen Hebels zu messen, kann er dies nicht.
PhiNotPi

@feersum @PhiNotPi ist richtig, ist diese Version klarer? If you pull a blue lever (revert stopper) no TT is possible to the round the lever was used or any earlier round anymore. TT's attempting to go to these rounds will have no effect.
Randomra

Wenn Sie den roten Hebel ziehen, können Sie dann dieselbe Runde wählen, in der Sie sich gerade befinden, um den Münzwurf für diese Runde zu wiederholen?
TheNumberOne

@TheNumberOne Ja, das macht der Zufalls-Beispiel-Bot .
Randomra

Antworten:


12

Analyzer

Dabei wird die Vergangenheit analysiert, um die besten Vorhersagen für die Zukunft zu treffen.

BEARBEITEN : Vermeidet blaue Hebelzeiten. Nutzt die blauen Hebel effektiv. Verwendet die roten Hebel effektiver. Für die Halloween-Saison wurde die Knappheit erhöht.

EDIT: um 1 Fehler behoben.

EDIT: Verbesserte computeWinningProbabilityFunktion. Verwendet jetzt rote Hebel und blaue Hebel aggressiver.

//Boo!
package bots;

import main.Action;
import main.Game;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Created 10/24/15
 *
 * @author TheNumberOne
 */
public class Analyzer implements Bot{

    @Override
    public String getName(){
        return "Analyzer";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history,
                           String memory, int roundNumber) {
        /*System.out.println(Game.totalScore(history) + " : " + history);
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }*/
        int roundsLeft = 100 - roundNumber;
        int myScore = (Game.totalScore(history) + roundNumber) / 2; //My number of wins.
        int enemyScore = roundNumber - myScore;                     //Enemy's number of wins.
        Map<Integer, Double> bestRounds = new HashMap<>();
        int timeLimit = 0;

        Scanner scanner = new Scanner(memory);
        if (scanner.hasNext()){     //No memory, first turn.
            boolean triedTimeTravel = scanner.nextBoolean();
            if (triedTimeTravel){
                int time = scanner.nextInt();
                if (roundNumber > time) {     //Failed.
                    timeLimit = time;
                }
            }
            timeLimit = Math.max(timeLimit, scanner.nextInt());
            int size = scanner.nextInt();
            for (int i = 0; i < size; i++) {
                bestRounds.put(scanner.nextInt(), scanner.nextDouble());
            }
        } else {
            bestRounds.put(1, 0.5);
        }

        clean(bestRounds, roundNumber, timeLimit);
        double winningProb = computeWinningProbability(myScore, enemyScore, roundsLeft);
        String newMemory = computeMemory(bestRounds, roundNumber, winningProb);

        if (winningProb >= new double[]{1.5, .75, .7, .65, .6, .55}[blue_levers]){ //Ensure success ... slowly.
            return getAction(-1, newMemory, timeLimit, roundNumber);
        }

        int bestRound = bestRound(bestRounds);
        double bestRoundProb = bestRounds.get(bestRound);

        if ((winningProb <= bestRoundProb - .05 || winningProb < .5 && bestRoundProb > winningProb) && red_levers > 0){
            return getAction(bestRound, newMemory, timeLimit, roundNumber);  //Let's find the best past.
        } else {
            return getAction(0, newMemory, timeLimit, roundNumber); //Let's wait it out :)
        }
    }

    //Should be combined with computeMemory.
    private static Action getAction(int actionNum, String newMemory, int timeLimit, int roundNumber){
        if (actionNum == -1){
            timeLimit = Math.max(timeLimit, roundNumber);
            newMemory = "false " + timeLimit + " " + newMemory;
            return new Action(actionNum, newMemory);
        }
        if (actionNum == 0){
            return new Action(actionNum, "false " + timeLimit + " " + newMemory);
        }
        if (actionNum > 0){
            return new Action(actionNum, "true " + actionNum + " " + timeLimit + " " + newMemory);
        }
        return null;
    }

    private static int bestRound(Map<Integer, Double> bestRounds) {
        int best = 0;           //If no previous rounds ... just go forward a round.
        double bestScore = -1;
        for (Map.Entry<Integer, Double> entry : bestRounds.entrySet()){
            if (entry.getValue() > bestScore){
                best = entry.getKey();
                bestScore = entry.getValue();
            }
        }
        return best;
    }

    private static String computeMemory(Map<Integer, Double> map, int roundNumber, double winningProb) {
        StringBuilder builder = new StringBuilder();
        builder.append(map.size() + 1).append(" ");
        for (Map.Entry<Integer, Double> entry : map.entrySet()){
            builder.append(entry.getKey()).append(" ").append(entry.getValue()).append(" ");
        }
        builder.append(roundNumber + 1).append(" ").append(winningProb);
        return builder.toString();
    }

    private static void clean(Map<Integer, Double> data, int round, int timeLimit) {
        data
                .entrySet()
                .stream()
                .filter(entry -> entry.getKey() > round || entry.getKey() <= timeLimit)
                .map(Map.Entry::getKey)
                .collect(Collectors.toList()).forEach(data::remove);
    }

    private static double computeWinningProbability(int myScore, int enemyScore, int roundsLeft){ //Too complex for IntelliJ
        int height = myScore - enemyScore;
        double total = 0.0;
        for (int i = Math.max(height - roundsLeft, 2); i <= height + roundsLeft; i += 2){
            total += prob(roundsLeft, height, i);
        }
        total += prob(roundsLeft, height, 0) / 2;
        return total;
    }

    private static double prob(int roundsLeft, int height, int i){
        double prob = 1;
        int up = i - height + (roundsLeft - Math.abs(i - height))/2;
        int down = roundsLeft - up;
        int r = roundsLeft;
        int p = roundsLeft;
        while (up > 1 || down > 1 || r > 1 || p > 0){  //Weird algorithm to avoid loss of precision.
            //Computes roundsLeft!/(2**roundsLeft*up!*down!)

            if ((prob >= 1.0 || r <= 1) && (up > 1 || down > 1 || p > 1)){
                if (p > 0){
                    p--;
                    prob /= 2;
                    continue;
                } else if (up > 1){
                    prob /= up--;
                    continue;
                } else if (down > 1){
                    prob /= down--;
                    continue;
                } else {
                    break;
                }
            }
            if (r > 1) {
                prob *= r--;
                continue;
            }
            break;
        }
        return prob;
    }

}

Ergebnis (seit dem 2. November):

Total Scores:
Oldschool: 3096
Random: 5756
RegretBot: 5362
Nostalgia: 8843
Little Ten: 8929
Analyzer: 17764
NoRegretsBot: 5621
Oracle: 15528
Deja Vu: 5281
Bad Loser: 13820

1
Beeindruckend! Ihr Bot blockt effektiv und kehrt zu optimalen Zeiten zurück. Es wird sehr schwierig sein, einen Bot zu entwickeln, der diesen toppen kann.
TNT

Ich bin mir nicht sicher, ob dieser Bot gestoppt werden kann, ohne eine Reihe von Einträgen zu verwenden, die speziell entwickelt wurden, um sich mit diesem Bot herumzuschlagen und einen anderen Bot zu stärken.
Mego

4

Nostalgie

package bots;

import main.Action;
import main.Game;

public class Nostalgia implements Bot {

    @Override
    public String getName() {
        return "Nostalgia";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history,
            String memory, int roundNumber) {

        int current_score = Game.totalScore(history);

        // wait until the end to use blue levers
        if (current_score > 0 && blue_levers >= (100 - roundNumber)) {
            return new Action(-1, memory);
        }

        // become increasingly likely to go back as the gap between the good old days
        // and the horrible present increases
        if (current_score < 0 && red_levers > 0) {
            //identify the best time to travel back to
            int best_score = -100;
            int good_old_days = 1;
            int past_score = 0;

            int unreachable_past = 0;
            if(memory != "") {
              unreachable_past = Integer.parseInt(memory, 10);
            }

            for(int i = unreachable_past; i<roundNumber ; i++) {
              if(history.charAt(i) == '1') {
                past_score += 1;
                if(past_score > best_score) {
                  best_score = past_score;
                  good_old_days = i + 1;
                }
              }
              else {
                past_score -= 1;
              }
            }
            if(roundNumber >= 95 || Math.random() < (best_score - current_score) / 100.0) {
              return new Action(good_old_days, Integer.toString(good_old_days));
            }
        }

        // if neither action was needed do nothing
        return new Action(0, memory);
    }
}

Nicht getestet, nur ein kurzer Versuch, einen Bot zu machen, der schwer zu blocken ist (weil er entscheidet, wann er den roten Hebel zieht, meistens nach dem Zufallsprinzip), aber das trifft vernünftige Entscheidungen.

Bearbeiten: Ich habe diese Regel verpasst:

Wenn Sie einen blauen Hebel ziehen (Revert Stopper), ist in dieser Runde kein TT mehr möglich

Das scheint ein guter Grund zu sein, den Speicher zu nutzen. Wenn Sie sich daran erinnern, dass Sie versucht haben, eine bestimmte Runde zu absolvieren, sind Sie möglicherweise gescheitert. Versuchen Sie also nicht, die Runde erneut zu absolvieren. Habe meinen Bot bearbeitet, um dies zu vermeiden.


4

Orakel

Ich habe schamlos Code von Analyzer kopiert (zum Parsen des Speichers). Diese Submission versucht, frühzeitig einen blauen Hebel zu ziehen und baut dann langsam seine Führung auf. Ich denke, die Leistung dieses Bots gleicht den hässlichen Code aus :)

package bots;

import java.util.*;
import java.util.Map.Entry;
import main.*;

public class Oracle implements Bot {

    @Override
    public String getName() {
        return "Oracle";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        int roundsLeft = 100 - roundNumber;
        Map<Integer, Integer> rounds = new HashMap<>();
        int myScore = (Game.totalScore(history) + roundNumber) / 2;
        int difference = myScore*2 - roundNumber;
        int highestBlockedRound = -1;
        int bestScore = 0;
        boolean hasUsedBlueLever = false;

        Scanner scanner = new Scanner(memory);
        if (scanner.hasNext()) {
            //timeTravel toRound highestBlockedRound hasUsedBlueLever bestScore rounds round1 percent1 round2 percent2 round3 percent3...
            boolean triedTravel = scanner.nextBoolean();
            int time = scanner.nextInt();
            if (triedTravel){
                if (roundNumber > time) {
                    highestBlockedRound = time;
                }
            }
            highestBlockedRound = Math.max(highestBlockedRound, scanner.nextInt());

            hasUsedBlueLever = scanner.nextBoolean();
            bestScore = scanner.nextInt();

            int size = scanner.nextInt();
            for (int i = 0; i < size && i < roundNumber; i++) {
                int number = scanner.nextInt();
                int diff = scanner.nextInt();
                if (number < roundNumber) {
                    rounds.put(number, diff);
                }
            }
        }
        rounds.put(roundNumber, difference);
        final int blockedRound = highestBlockedRound;

        int roundToRevert = 0;
        if (rounds.size() > 2) {
            Optional<Entry<Integer, Integer>> bestRound = rounds.entrySet()
                    .stream()
                    .filter(x -> x.getKey() >= blockedRound && x.getKey() <= roundNumber)
                    .sorted(Comparator
                        .comparingInt((Entry<Integer, Integer> x) -> x.getValue()*-1)
                        .thenComparingInt(x -> x.getKey()))
                    .findFirst();
            if (bestRound.isPresent()) {
                roundToRevert = bestRound.get().getKey();
            }
        }

        if (roundsLeft + Game.totalScore(history) <= 0 && red_levers > 0) {
            roundToRevert = highestBlockedRound+1;
        } else if (blue_levers > 0 && roundToRevert == roundNumber && ((hasUsedBlueLever && difference >= bestScore*1.5) || (!hasUsedBlueLever && difference > 1))) {
            roundToRevert = -1;
            hasUsedBlueLever = true;
            bestScore = difference;
            highestBlockedRound = roundNumber;
        } else if (red_levers > 0 && roundToRevert > 0 && rounds.get(roundToRevert) > difference+2) {
            roundToRevert += 1;
        } else {
            roundToRevert = 0;
        }

        StringBuilder sb = new StringBuilder();
        sb.append(roundToRevert > 0).append(' ');
        sb.append(roundToRevert).append(' ');
        sb.append(highestBlockedRound).append(' ');
        sb.append(hasUsedBlueLever).append(' ');
        sb.append(bestScore).append(' ');
        sb.append(rounds.size()).append(' ');
        rounds.entrySet().stream().forEach((entry) -> {
            sb.append(entry.getKey()).append(' ').append(entry.getValue()).append(' ');
        });
        String mem = sb.toString().trim();
        scanner.close();
        return new Action(roundToRevert, mem);
    }
}

Gut gemacht! Ich wusste, dass ich mit meinen roten Hebeln nicht aggressiv genug war. Jetzt soll der Analyzer verbessert werden. ;)
TheNumberOne

3

RegretBot

Am Ende unseres Lebens bereuen wir unsere Fehler in der Vergangenheit und versuchen, sie zu beheben.

package bots;

import main.Action;
import main.Game;

public final class RegretBot implements Bot {

    @Override
    public String getName() {
        return "RegretBot";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        int actionNum = 0;
        if(roundNumber == 100) {
            // if it's the end of the game and we're losing, go back
            //  in time to the first loss, in hopes of doing better
            if(Game.totalScore(history)<=0 && red_levers > 0) {
                actionNum = history.indexOf("0")+1;
            }
            // if we're winning at the end, pull a blue lever if we can,
            //  to prevent our opponent from undoing our victory
            else if(blue_levers > 0) {
                actionNum = -1;
            }
        }
        // we don't need no stinkin' memory!
        return new Action(actionNum, null);
    }

}

2

Kleine Zehn

Little Ten multipliziert und dividiert viel durch 10, verwendet Zahlen, die ein Vielfaches von 10 sind, und geht zurück zu Runden, die ein Vielfaches von 10 sind.

package bots;

import main.Action;
import main.Game;

public class LittleTen implements Bot {

    @Override
    public String getName() {
        return "Little Ten";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        int score = Game.totalScore(history);
        char c = history.charAt(history.length() - 1);
        if (memory.isEmpty())
            memory = "1";

        if (roundNumber == 100) {
            if (score >= 0)
                // We're tied or ahead by the end of the match. Prevent time
                // travel if we can; otherwise whatever happens happens.
                return new Action(blue_levers > 0 ? -1 : 0, memory);
            else {
                // Travel to earlier rounds the farther behind we are if we can
                // (of course using 10 as a reference)
                if (red_levers > 0) {
                    int i = Integer.parseInt(memory);
                    int round = score <= -10 ? i : 100 - ((100 - i) / (11 + (score <= -10 ? -10 : score)));
                    return new Action(round, memory);
                }
            }
        }
        else if (score >= 7 + roundNumber / 20 && blue_levers > 0) {
            // We're ahead; we don't want to lose our lead, especially if the
            // match is close to ending. But we don't want to use up our blue
            // levers too quickly.
            int choice = (int) (Math.random() * 100),
                bound = (roundNumber / 10 + 1) * 5 - ((6 - blue_levers) * 5 - 2);
            if (choice < bound) {
                memory = String.valueOf(roundNumber);
                return new Action(-1, memory);
            }
        }
        else if (score <= -3) {
            // Possibly use a red lever if we're falling too far behind
            if (red_levers > 0) {
                int choice = (int) (Math.random() * 100),
                    bound = score <= -11 ? 90 : 10 * (-3 - score + 1);
                if (choice < bound) {
                    // Check the first round that is the lower multiple of ten
                    // and decide if we've been successful up to that point; if
                    // so, travel back to that round, otherwise go back 10 more
                    int round = roundNumber / 10 * 10;
                    if (round < 10)
                        return new Action(1, memory);
                    String seq = history.substring(0, round-1);
                    int minRound = Integer.parseInt(memory);
                    while (Game.totalScore(seq) <= 0 && round > 10 && round > minRound) {
                        round -= 10;
                        seq = history.substring(0, round-1);
                    }
                    if (round == 0)
                        round = 1;
                    return new Action(round, memory);
                }
            }
        }
        return new Action(0, memory);
    }
}

Bearbeiten: Die Mechanik wurde ein wenig geändert, da die Erklärung, was passiert, wenn ein blauer Hebel gezogen wird, klarer ist. Hat auch ein bisschen nachgeglichen.


1

Zufällig

Die Strategie von Random ist folgende:

  • Block mit einer Chance von 10%, wenn er in Führung liegt und noch blaue Hebel hat
  • Reise eine Runde zurück (die letzte Runde wird wiederholt), mit einer Chance von 10%, wenn du in der Wertung zurückbleibst und rote Hebel übrig hast
package bots;

import main.Action;
import main.Game;

public class RandomBot implements Bot {

    @Override
    public String getName() {
        return "Random";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history,
            String memory, int roundNumber) {

        // if in the lead and has blocks left, blocks with a 10% chance
        if (Game.totalScore(history) > 0 && blue_levers > 0
                && Math.random() > 0.9) {
            return new Action(-1, null);
        }

        // if behind and has travels left, travel back the current step to
        // replay it with a 10% chance
        if (Game.totalScore(history) < 0 && red_levers > 0
                && Math.random() > 0.9) {
            return new Action(roundNumber, null);
        }

        // if neither action were needed do nothing
        return new Action(0, null);
    }
}

1

NoRegretsBot

package bots;

import main.Action;
import main.Game;

public final class NoRegretsBot implements Bot {

    @Override
    public String getName() {
        return "NoRegretsBot";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        // every 20 turns, pull a blue lever to lock in the past
        // hopefully this will thwart some of those pesky time-travelers
        return new Action(roundNumber%20==0?-1:0, null);
    }

}

1

Schlechter Verlierer

Dieser Bot benötigt keinen Speicher und ist überraschend gut (aber er schlägt Analyzer oder Oracle nicht).

package main;

import bots.Bot;

/**
 * Created 11/2/15
 *
 * @author TheNumberOne
 */
public class BadLoser implements Bot{
    @Override
    public String getName() {
        return "Bad Loser";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history, String memory, int roundNumber) {
        if (history.contains("00") && red_levers > 0){       //Subtract a zero for better performance against
            return new Action(history.indexOf("00") + 1, "");// Analyzer and Nostalgia, and worse performance 
                                                             // against everything else.
        }
        int wins = 0;
        for (char c : history.toCharArray()){
            wins += c - '0';
        }
        if (wins >= new int[]{101, 51, 40, 30, 20, 10}[blue_levers]){
            return new Action(-1, "");
        }
        return new Action(0, "");
    }
}

0

Alte Schule

Dieser Bot tut niemals etwas, da Oldschool nicht an Zeitreisen glaubt.

package bots;

import main.Action;

public class OldschoolBot implements Bot {

    @Override
    public String getName() {
        return "Oldschool";
    }

    @Override
    public Action takeTurn(int blue_levers, int red_levers, String history,
            String memory, int roundNumber) {       
        // never tries to block or travel at all
        return new Action(0, null);
    }
}

0

Deja Vu Bot

Dieser Bot versucht zu verfolgen, wann er das Blau zieht, um zu vermeiden, dass Rot in diesen Bereich zieht. Zieht nur rote Hebel, wenn er in der Wertung deutlich zurückliegt.

package bots;

import main.*;

public class Dejavu implements Bot
{
    @Override
    public String getName()
    {
        return "Deja Vu";
    }

@Override
public Action takeTurn(int blue_levers, int red_levers, String history,
                       String memory, int roundNumber) {

    if(roundNumber == 1)
    {
        memory = "-1";
    }
    int[] blevers = getBlueLevers(memory);
    char[] hist = history.toCharArray();
    int ms = 0;
    int ts = 0;
    int rl = -1;
    boolean bl = false;
    boolean url = false;

    for(int i = 0; i < hist.length; i++)
    {
        switch(hist[i])
        {
            case '1':
            ms++;
            break;
            case '0':
            ts++;
            break;
        }
    }

    if(ts - ms >= 10)
    {   
        for(rl = hist.length - 1; ts - ms <= 5 && rl >= 0; rl--)
        {
            switch(hist[rl])
            {
                case '1':
                ms--;
                break;
                case '0':
                ts--;
                break;
            }
        }
        url = true;
    }

    if(ms - ts >= 7)
    {
        bl = true;
        url = false;
        memory += "," + roundNumber;
    }

    for(int i = 0; i < blevers.length; i++)
    {
        if(rl <= blevers[i])
        {
            rl = blevers[i] + 1;
        }
    }

    if(url)
    {
        return new Action(rl, memory);
    }
    else if(bl)
    {
        return new Action(-1, memory);
    }
    else
    {
        return new Action(0, memory);
    }              
}

private int[] getBlueLevers(String s)
{
    String[] b = s.split(",");

    int[] bl = new int[b.length];
    for(int i = 0; i < b.length; i++)
    {
        bl[i] = Integer.parseInt(b[i]);
    }

    return bl;
}

}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.