Путешественники, подбрасывающие монеты


19

В будущем, когда Time Travel (сокращенно TT) станет обычным явлением, подбрасывание монет станет серьезным интеллектуальным спортом. Чтобы подготовиться к будущему, мы создаем конкурс для программ, в которых путешествие во времени будет действительно происходить с точки зрения заявок.

Соревнование проводится в стиле «круговой малиновый король горы», состоящем из подбрасывания монет между классами Java.

Правила жеребьевки

  • Есть два игрока и 100 раундов.
  • В каждом раунде подбрасывается монета, и в зависимости от результата один из игроков получает 1 очко. Каждый игрок имеет 50% шанс набрать очко.
  • После броска у обоих игроков есть возможность контролировать время, потянув за рычаги.
  • Если вы потянете синий рычаг (отведите стопор), TT не будет возможен для раунда, в котором использовался рычаг, или для любого более раннего раунда. ТТ, пытающиеся пойти на эти раунды, не будут иметь никакого эффекта.
  • Если вы потянете красный рычаг (ревертер), вы попытаетесь вернуть время назад к предыдущему раунду. В случае успеха память противника будет возвращена к его памяти до выбранного раунда, и результаты броска монеты, начиная с выбранного раунда, также будут удалены . Единственный возможный знак для вашего оппонента о ТТ - это количество его неиспользованных рычагов, которые не будут возвращены назад.
  • Каждый игрок имеет 5 синих и 20 красных неиспользованных рычагов в начале матча. Эти рычаги не подвержены влиянию ТТ.
  • Если в конце 100-го раунда ТТ не происходит, игра заканчивается, и побеждает игрок с более высоким счетом.

Детали

  • Раунды имеют индексирование на основе 1 (от 1 до 100).
  • Перед раундом xвам предоставляется количество доступных синих и красных рычагов, результаты подбрасывания монеты до хода x(включительно) и память о вашем (последнем) x-1раунде.
  • Нажатие синего рычага в раунде xостанавливает все ТТ, которые имеют пункт назначения в раунде xили раньше (он блокирует ТТ, если это произойдет и в тот же самый раунд).
  • Возвращение к раунду xозначает, что следующий раунд будет круглым x.
  • Если оба игрока решают вернуться в конце раунда, время возвращается к более раннему месту назначения, которое не блокируется. Игроки, которые попытались вернуться к этому времени, сохранят свою память.

Технические детали

  • Вы должны написать класс Java, реализующий предоставленный интерфейс Bot.
  • Добавьте своего бота в проект.
  • Добавьте экземпляр вашего бота Botв файл Controller.java.
  • Ваш класс не должен хранить информацию между звонками . (В большинстве случаев наличие только finalпеременных вне функций удовлетворяет этому требованию.)
  • Вы можете предоставить информацию контроллеру в memoryполе вашего возвращаемого Actionобъекта. Это будет возвращено вам в следующем ходу, если ТТ не произошло. Если произойдет TT, вы получите соответствующую более раннюю память о себе.
  • Вы можете использовать totalScore()метод Gameкласса, чтобы получить оценку строки истории.

протокол

  • На каждом шагу ваш takeTurn(...)метод вызывается с 5 аргументами:

    • количество неиспользованных синих рычагов
    • количество неиспользованных красных рычагов
    • история бросания монеты, строка, состоящая из 1 и 0, отмечающая ваши победы и поражения в предыдущих раундах. Первый символ соответствует первому бросанию монеты. (В первом раунде длина строки будет 1.)
    • строка, ваша сохраненная память из предыдущего раунда
    • основанный на 1 индекс этого раунда
  • На каждом шагу ваш метод возвращает Actionобъект, содержащий

    • целое число в moveполе, описывающем ваше действие:

      • 0 бездействовать
      • -1 потянуть синий рычаг и блокировать ТТ, проходящие через этот раунд
      • положительное целое число x, не больше текущего раунда, чтобы потянуть красный рычаг и попытаться вернуться к раундуx
      • Неверные целые числа рассматриваются как 0.
    • строка, содержащая вашу память из этого раунда, которую вы хотите сохранить. Обратите внимание, что хранение памяти не является важной частью задачи . Вы можете делать хорошие записи без сохранения каких-либо полезных данных в строке. В первом раунде строка будет пустой строкой.

  • Ваш метод должен занимать в среднем не более 10 мс на раунд в матче.

  • Регулярное нарушение сроков приводит к дисквалификации.

счет

  • Победа в матче приносит 2 очка, а ничья - 1 очко для обоих игроков. Потеря не приносит очков.
  • Оценка бота будет равна общему количеству набранных им очков.
  • Количество матчей между каждой парой участников будет зависеть от количества участников и их скорости.

Два простых примера ботов публикуются в качестве ответов.

Контроллер и первая пара ботов доступны здесь .

Результаты теста с ботами представлены до 3 ноября.

Всего очков:

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

(Контроллер основан на контроллере Cat Catcher Challenge . Спасибо, что @flawr предоставил его в качестве основы для этого.)

Бонус: хороший 6-минутный фильм, основанный на аналогичной концепции.


1
Я не понимаю, что означает это правило. 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.Что такое "прохождение раунда"?
feersum

@feersum Если я правильно понимаю, нажатие синего рычага навсегда «фиксирует» текущий раунд (и, следовательно, все предыдущие раунды), чтобы результаты не могли быть изменены путешествием во времени. Если кто-то попытается выполнить ТТ на какое-то время раньше, чем когда вы нажмете синий рычаг, он не сможет этого сделать.
PhiNotPi

@feersum @PhiNotPi прав, эта версия понятнее? 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.
Рандомра

Когда вы нажимаете на красный рычаг, можете ли вы выбрать тот же раунд, в котором вы сейчас находитесь, чтобы повторить бросок монеты для этого раунда?
TheNumberOne

@TheNumberOne Да, это то, что делает бот случайного примера .
Рандомра

Ответы:


12

анализатор

Это анализирует прошлое, чтобы сделать лучшие прогнозы на будущее.

РЕДАКТИРОВАТЬ: Избегает синих многоуровневых раз. Эффективно использует синие рычаги. Использует красные рычаги более эффективно. Добавлен шрам на сезон Хэллоуина.

РЕДАКТИРОВАТЬ: исправлено 1 ошибка.

РЕДАКТИРОВАТЬ: улучшенная computeWinningProbabilityфункция. Теперь используются красные рычаги и синий рычаг более агрессивно.

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

}

Оценка (со 2 ноября):

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
Впечатляет! Ваш бот блокирует эффективно и возвращается в оптимальное время. Будет очень сложно создать бота, который сможет превзойти этого.
TNT

Я не уверен, что этого бота можно остановить, не используя кучу записей, специально предназначенных для того, чтобы связываться с этим ботом и усиливать другого бота.
Мего

4

Ностальгия

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

Не проверено, просто быстрый удар по попытке сделать бота, которого трудно заблокировать (потому что он решает, когда тянуть красный рычаг в основном случайным образом), но это принимает достойные решения.

Изменить: я пропустил это правило:

Если вы потянете синий рычаг (откиньте стопор), то через этот раунд ТТ больше не возможен

Это кажется хорошей причиной для использования памяти - если вы помните, что пытались провести ТТ до данного раунда, возможно, вы потерпели неудачу, поэтому вам не следует пытаться снова провести ТТ до этого раунда. Отредактировал мой бот, чтобы попытаться избежать этого.


4

оракул

Я беззастенчиво скопировал некоторый код из Analyzer (для анализа памяти). Это представление пытается вытащить синий рычаг рано, а затем медленно наращивает свое лидерство. Я думаю, что производительность этого бота компенсирует уродливый код :)

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

Молодец! Я знал, что я недостаточно агрессивен с моими красными рычагами. Теперь, чтобы улучшить анализатор. ;)
TheNumberOne

3

RegretBot

В конце нашей жизни матча мы сожалеем о наших прошлых неудачах и пытаемся вернуться и исправить их.

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 много умножает и делит на 10, используя числа, кратные 10, и возвращаясь к раундам, кратным 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);
    }
}

Изменить: Немного изменили механику теперь, когда объяснение того, что происходит, когда синий рычаг нажал, стало более понятным. Также сделал немного ребалансировки.


1

случайный

Стратегия Рэндома заключается в следующем:

  • блокировать с вероятностью 10%, если лидирует и у него остались синие рычаги
  • Пройдите назад на один ход (переиграв последний раунд) с вероятностью 10%, если отставали в счете и остались красные рычаги
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

Плохой неудачник

Этот бот не использует память и на удивление хорош (но он не побеждает Analyzer или 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

Старая школа

Этот бот никогда не делает никаких действий, так как Oldschool не верит в путешествия во времени.

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

Этот бот пытается отследить, когда он тянет синих, чтобы избежать красных тянет в эту область. Тянет только красные рычаги, когда значительно отстают в счете.

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

}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.