Podróżujący w czasie rzucania monetą


19

W przyszłości, gdy podróżowanie w czasie (w skrócie TT) będzie powszechne, rzucanie monetami stanie się poważnym sportem umysłowym. Aby przygotować się na przyszłość, tworzymy konkurs na programy, w których podróże w czasie będą się naprawdę działo z punktu widzenia zgłoszeń.

Konkurs jest królem wzgórza w stylu robota okrągłego, polegającym na rzucaniu monetami między klasami Java.

Zasady losowania monet

  • Jest dwóch graczy i 100 rund.
  • W każdej rundzie rzuca się monetą i na podstawie wyniku jeden z graczy zdobywa 1 punkt. Każdy gracz ma 50% szans na zdobycie punktu.
  • Po podrzuceniu obaj gracze mają szansę kontrolować czas, pociągając za dźwignie.
  • Jeśli pociągniesz niebieską dźwignię (cofnij korek) TT nie będzie możliwe w rundzie, w której użyto dźwigni ani w żadnej wcześniejszej rundzie. Próby przejścia do tych rund TT nie przyniosą efektu.
  • Jeśli pociągniesz czerwoną dźwignię (rewerter) , spróbujesz cofnąć czas do poprzedniej rundy. Jeśli się powiedzie , pamięć przeciwnika zostanie przywrócona do pamięci przed wybraną rundą, a wyniki losowania rozpoczynające się od wybranej rundy również zostaną usunięte . Jedynym możliwym znakiem dla przeciwnika na temat TT będzie liczba niewykorzystanych dźwigni, które nie zostaną cofnięte.
  • Każdy gracz ma 5 niebieskich i 20 czerwonych nieużywanych dźwigni na początku meczu. TT nie wpływają na te dźwignie.
  • Jeśli na końcu setnej rundy nie wydarzy się TT, gra się kończy, a gracz z wyższym wynikiem wygrywa.

Detale

  • Rundy mają indeksowanie 1 (od 1 do 100).
  • Przed rundą xotrzymujesz liczbę dostępnych niebieskich i czerwonych dźwigni, rzut monetą aż do tury x(włącznie) i pamięć twojej (ostatniej) x-1rundy.
  • Pociągnięcie niebieskiej dźwigni w rundzie xzatrzymuje wszystkie TT, które mają cel w rundzie xlub wcześniej (blokuje TT, jeśli zdarzy się również w tej samej dokładnej rundzie).
  • Powrót do rundy xoznacza, że ​​następna runda będzie rundą x.
  • Jeśli obaj gracze zdecydują się powrócić na koniec rundy, czas zostanie przywrócony do wcześniejszego celu, który nie jest blokowany. Gracz (y), którzy próbowali powrócić do tego czasu, zachowają swoją pamięć.

Szczegóły techniczne

  • Powinieneś napisać klasę Java implementującą dostarczony interfejs Bot.
  • Dodaj swojego bota do projektu.
  • Dodaj instancję swojego Bota do Botpliku Controller.java.
  • Twoja klasa nie powinna przechowywać informacji między rozmowami . (W większości przypadków posiadanie tylko finalzmiennych poza funkcjami spełnia to wymaganie).
  • Możesz przekazać kontrolerowi informacje w memorypolu zwracanego Actionobiektu. Zostanie ci to zwrócone w następnej turze, jeśli TT się nie wydarzyło. Jeśli zdarzy się TT, otrzymasz odpowiednią wcześniejszą pamięć.
  • Możesz użyć totalScore()metody Gameklasy, aby uzyskać wynik ciągu historii.

Protokół

  • Na każdym kroku twoja takeTurn(...)metoda jest wywoływana z 5 argumentami:

    • liczba nieużywanych niebieskich dźwigni
    • liczba nieużywanych czerwonych dźwigni
    • historia losowania monet, ciąg składający się z 1 i 0 oznaczających twoje wygrane i przegrane w poprzednich rundach. Pierwszy znak odpowiada losowaniu pierwszej monety. (W pierwszej rundzie długość łańcucha będzie wynosić1 .)
    • ciąg, twoja pamięć przechowywana z poprzedniej rundy
    • indeks oparty na 1 tej rundzie
  • Za każdym razem twoja metoda zwraca Actionobiekt zawierający

    • liczba całkowita w movepolu opisującym twoje działanie:

      • 0 za brak działania
      • -1 pociągnąć niebieską dźwignię i zablokować TT przechodzące przez tę rundę
      • dodatnia liczba całkowita x, nie większa niż bieżąca runda, aby pociągnąć czerwoną dźwignię i spróbować wrócić do rundyx
      • Nieprawidłowe liczby całkowite są traktowane jako 0.
    • ciąg zawierający twoją pamięć z tej rundy, którą chcesz zachować. Pamiętaj, że przechowywanie pamięci nie jest kluczową częścią wyzwania . Możesz dokonywać dobrych wpisów bez zapisywania użytecznych danych w ciągu. W pierwszej rundzie łańcuch będzie pusty.

  • Twoja metoda nie powinna zająć średnio więcej niż 10 ms na rundę w meczu.

  • Regularne niedotrzymywanie terminu skutkuje dyskwalifikacją.

Punktacja

  • Zwycięstwo w meczu daje 2 punkty, a remis - 1 punkt dla obu graczy. Strata nie daje punktów.
  • Wynik bota będzie łączną liczbą punktów, które zebrał.
  • Liczba meczów rozegranych między każdą parą zawodników będzie zależeć od liczby zgłoszeń i ich prędkości.

Dwa proste boty przykładowe są publikowane jako odpowiedzi.

Kontroler i kilka pierwszych botów są dostępne tutaj .

Wyniki testu z botami przesłanymi do 3 listopada .:

Wyniki ogółem:

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

(Kontroler jest oparty na Cat Catcher Challenge . Dziękujemy za @flawr, który jest dla niego bazą.)

Bonus: ładny 6-minutowy film oparty na podobnej koncepcji.


1
Nie rozumiem, co oznacza ta zasada. 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.Co „przechodzi przez rundę”?
feersum

@feersum Jeśli dobrze rozumiem, pociągnięcie niebieskiej dźwigni na stałe „blokuje” bieżącą rundę (a więc wszystkie poprzednie rundy), aby wyników nie można było modyfikować w czasie podróży. Jeśli ktoś podejmie TT do czasu wcześniejszego niż pociągnięcie niebieskiej dźwigni, nie będzie w stanie tego zrobić.
PhiNotPi

@feersum @PhiNotPi ma rację, czy ta wersja jest bardziej przejrzysta? 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

Czy pociągając czerwoną dźwignię, możesz wybrać tę samą rundę, na której aktualnie jesteś, aby powtórzyć rzut monetą w tej rundzie?
TheNumberOne

@TheNumberOne Tak, właśnie tak robi przypadkowy przykładowy bot .
randomra

Odpowiedzi:


12

Analizator

Analizuje przeszłość, aby uzyskać najlepsze prognozy na przyszłość.

EDYTOWAĆ: Unika niebieskich czasów wylewania. Skutecznie wykorzystuje niebieskie dźwignie. Bardziej efektywnie wykorzystuje czerwone dźwignie. Dodano rzadkość na sezon Halloween.

EDYCJA: Wyłączone przez 1 błąd.

EDYCJA: Ulepszona computeWinningProbabilityfunkcja. Teraz bardziej agresywnie używa czerwonych dźwigni i niebieskiej dźwigni.

//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;
    }

}

Ocena (od 2 listopada):

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
Imponujący! Twój bot blokuje się skutecznie i cofa się w optymalnych momentach. Stworzenie bota, który da sobie radę, będzie bardzo trudne.
TNT

Nie jestem pewien, czy tego bota można zatrzymać, bez użycia szeregu wpisów specjalnie zaprojektowanych do zepsucia tego bota i ulepszenia innego bota.
Mego

4

Nostalgia

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);
    }
}

Nie testowano, wystarczy szybkie dźgnięcie w próbę stworzenia bota, który trudno jest zablokować (ponieważ decyduje, kiedy pociągnąć czerwoną dźwignię głównie losowo), ale to podejmuje dobre decyzje.

Edycja: brakowało mi tej reguły:

Jeśli pociągniesz niebieską dźwignię (korek cofania), TT nie będzie już możliwe w tej rundzie

Wydaje się, że to dobry powód, aby użyć pamięci - jeśli pamiętasz próbę przejścia do danej rundy, być może nie udało ci się, więc nie powinieneś próbować ponownie przejść do tej rundy. Edytowałem mojego bota, aby tego uniknąć.


4

Wyrocznia

Bezwstydnie skopiowałem jakiś kod z Analyzera (do parsowania pamięci). To poddanie próbuje wcześnie pociągnąć niebieską dźwignię, a następnie powoli buduje swoją przewagę. Myślę, że wydajność tego bota rekompensuje brzydki kod :)

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);
    }
}

Dobra robota! Wiedziałem, że nie jestem wystarczająco agresywny z moimi czerwonymi dźwigniami. Teraz, aby ulepszyć Analizator. ;)
TheNumberOne

3

RegretBot

Pod koniec naszego życia żałujemy naszych porażek z przeszłości i staramy się je cofnąć i naprawić.

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

Little Ten

Mała Dziesiątka często mnoży i dzieli przez 10, używając liczb, które są wielokrotnościami 10, i wraca do rund, które są wielokrotnościami 10.

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);
    }
}

Edycja: Zmieniłem nieco mechanikę teraz, gdy wyjaśnienie tego, co dzieje się po pociągnięciu niebieskiej dźwigni, jest jaśniejsze. Trochę też przywróciłem równowagę.


1

Losowy

Strategia Randoma jest następująca:

  • blokuj z 10% szansą, jeśli jesteś na prowadzeniu i ma niebieskie dźwignie
  • cofnij się o jedną turę (odtwarzanie ostatniej rundy) z 10% szansą, jeśli zaliczysz wynik i pozostaną czerwone dźwignie
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

Zły przegrany

Ten bot nie używa pamięci i jest zaskakująco dobry (ale nie pokonuje Analyzera ani Oracle).

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

Stara szkoła

Ten bot nigdy nie wykonuje żadnej akcji, ponieważ Oldschool nie wierzy w podróże w czasie.

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

Ten bot próbuje śledzić, kiedy ściąga niebieski, aby uniknąć czerwonych pociągnięć w tym regionie. Przyciąga czerwone dźwignie tylko wtedy, gdy jest znacznie w tyle w wyniku.

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;
}

}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.