Монети, кидаючи мандрівників у часі


19

У майбутньому, коли подорож у часі (скорочено - TT) буде загальним, кидання монет стане серйозним спортом. Щоб підготуватися до майбутнього, ми створюємо конкурс програм, де подорож у часі дійсно відбуватиметься з точки зору публікацій.

Змагання є королем у стилі короля пагорба, що складається з підкидання монет між класами Java.

Правила поєднання монети

  • Є два гравці та 100 турів.
  • У кожному раунді кидається монета і за результатом один з гравців набирає 1 бал. Кожен гравець має 50% шансів набрати очко.
  • Після жеребкування обидва гравці мають шанс контролювати час, потягнувши важелі.
  • Якщо ви потягнете синій важіль (зворотний стопор), жоден TT не можливий до раунду, коли важіль був використаний або будь-який попередній раунд. Спроба TT пройти в ці раунди не дасть ефекту.
  • Якщо ви тягнете червоний важіль (ревертер), ви намагаєтеся повернути час назад до колишнього раунду. Якщо це вдалося , пам'ять суперника буде повернуто до пам'яті перед обраним раундом, а результати монети монети, починаючи з обраного раунду, також будуть видалені . Єдиним можливим знаком для опонента щодо TT буде кількість невикористаних важелів, які не будуть повернені назад.
  • У кожного гравця є 5 синіх та 20 червоних невикористаних важелів на початку матчу. Ці важелі не впливають на ТТ.
  • Якщо в кінці 100-го раунду не трапляється жодної TT, гра закінчується, і виграє гравець з більшим балом.

Деталі

  • Раунти мають індексацію на основі 1 (форма 1 до 100).
  • Перед раундом xвам надається кількість доступних синіх та червоних важелів, викидання монети до повороту x(включно) та пам’ять про ваш (останній) x-1раунд.
  • Потягнення синього важеля в круглі xзупиняє будь-які TT, які мають місце призначення в раунді xабо раніше (він блокує TT, якщо він трапляється і в тому ж точному раунді).
  • Повернення до раунду xозначає, що наступний раунд буде круглим x.
  • Якщо обидва гравці вирішать повернути в кінці раунду, час повертається до попереднього пункту призначення, який не блокується. Гравець, який намагався повернутися до цього часу, збереже пам'ять.

Технічні деталі

  • Вам слід написати клас Java, що реалізує наданий інтерфейс Bot.
  • Додайте свого бота до проекту.
  • Додайте Botдо файлу екземпляр свого Bot Controller.java.
  • Ваш клас не повинен зберігати інформацію між дзвінками . (У більшості випадків наявність лише finalзмінних поза функціями задовольняє цю вимогу.)
  • Ви можете надати інформацію контролеру в memoryполі повернутого Actionоб'єкта. Це буде повернуто вам у наступній черзі, якщо жодного TT не відбулося. Якщо 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 . Дякую за те, що @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 Якщо я правильно розумію, тягнення синього важеля назавжди "фіксується" в поточному раунді (і, таким чином, у всіх попередніх раундах), щоб результати не могли бути змінені за часом руху. Якщо хтось спробує TT на час раніше, ніж коли ви потягнули синій важіль, вони не зможуть.
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.
randomra

Коли ви потягнете червоний важіль, чи можете ви вибрати той же раунд, в який ви зараз перебуваєте, щоб переробити викидання монети за цей раунд?
TheNumberOne

@TheNumberOne Так, саме це робить бот Random Example .
randomra

Відповіді:


12

Аналізатор

Це аналізує минуле, щоб зробити найкращі прогнози на майбутнє.

РЕДАКТУВАННЯ. Уникайте синього часу. Ефективно використовує сині важелі. Ефективніше використовувати червоні важелі. Додано дефіцит на сезон Хеллоуїна.

EDIT: Виправлено 1 помилкою.

EDIT: Покращена 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
Вражає! Ваш бот ефективно блокує і повертається в оптимальний час. Буде дуже важко створити бота, який зможе очолити цього.
ТНТ

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

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

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

Редагувати: я пропустив це правило:

Якщо ви потягнете синій важіль (зворотний стопор), то через цей раунд вже не можливий TT

Це здається вагомим приводом для використання пам’яті - якщо ви пам’ятаєте, що намагалися TT до заданого раунду, ви, можливо, не вдалися, тому не слід повторювати спробу TT до цього раунду. Відредагував мого бота, щоб спробувати цього уникнути.


4

Oracle

Я безсоромно скопіював якийсь код з 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);
    }
}

Хороша робота! Я знав, що я недостатньо агресивний зі своїми червоними важелями. Тепер для вдосконалення Analyzer. ;)
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

Маленька Десять

Маленький Десять робить багато множення і ділення на 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

Випадкові

Стратегія Random полягає в наступному:

  • блокувати з 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.