Viajantes no tempo jogando moedas


19

No futuro, quando a Viagem no tempo (abreviada como TT) for comum, o lançamento de moedas se tornará um esporte mental sério. Para nos prepararmos para o futuro, criamos uma competição para programas em que a viagem no tempo estará realmente acontecendo do ponto de vista das entradas.

A competição é um King of the Hill do estilo round-robin, que consiste em partidas de sorteio entre as classes Java.

Regras da partida de lançamento de moedas

  • Existem dois jogadores e 100 rodadas.
  • Em cada rodada, uma moeda é lançada e, com base no resultado, um dos jogadores ganha 1 ponto. Cada jogador tem 50% de chance de marcar um ponto.
  • Após o lançamento, os dois jogadores têm a chance de controlar o tempo puxando as alavancas.
  • Se você puxar uma alavanca azul (tampa de reversão), nenhum TT é possível para a rodada em que a alavanca foi usada ou em qualquer rodada anterior. A tentativa de TT de ir a essas rodadas não terá efeito.
  • Se você puxar uma alavanca vermelha (reverter), tenta reverter o tempo para uma rodada anterior. Se for bem-sucedida, a memória do oponente será revertida para a memória antes da rodada escolhida e os resultados do sorteio a partir da rodada escolhida também serão excluídos . O único sinal possível para o seu oponente sobre o TT será o número de suas alavancas não utilizadas que não serão revertidas.
  • Cada jogador tem 5 alavancas azuis e 20 vermelhas não utilizadas no início da partida. Essas alavancas não são afetadas pelos TTs.
  • Se nenhum TT acontecer no final de uma centésima rodada, o jogo termina e o jogador com a pontuação mais alta vence.

Detalhes

  • As rodadas têm uma indexação baseada em 1 (formulário 1 a 100).
  • Antes da rodada, xvocê recebe o número de alavancas azuis e vermelhas disponíveis, o lançamento da moeda resulta até o turno x(inclusive) e a memória da (última) x-1quinta rodada.
  • Puxar uma alavanca azul na rodada xinterrompe todos os TTs que têm um destino na rodada xou antes (ele bloqueia um TT se ocorrer também na mesma rodada exata).
  • Reverter para a rodada xsignifica que a próxima rodada será rodada x.
  • Se ambos os jogadores optarem por reverter no final de uma rodada, o tempo será revertido para o destino anterior que não está bloqueado. O (s) jogador (es) que tentaram reverter para este momento manterão sua memória.

Detalhes técnicos

  • Você deve escrever uma classe Java implementando a interface Bot fornecida.
  • Adicione seu bot ao projeto.
  • Adicione uma instância do seu Bot ao Botarquivo Controller.java.
  • Sua turma não deve manter informações entre as chamadas . (Na maioria dos casos, ter apenas finalvariáveis ​​fora das funções atende a esse requisito.)
  • Você pode fornecer informações ao controlador no memorycampo do seu Actionobjeto retornado . Este valor será devolvido a você no próximo turno, se não houver TT. Se um TT acontecer, você receberá a memória anterior correspondente.
  • Você pode usar o totalScore()método da Gameclasse para obter a pontuação de uma sequência do histórico.

Protocolo

  • A cada passo, seu takeTurn(...)método é chamado com 5 argumentos:

    • o número de alavancas azuis não utilizadas
    • o número de alavancas vermelhas não utilizadas
    • o histórico de lançamento de moedas, uma sequência de 1 e 0 marcando suas vitórias e derrotas nas rodadas anteriores. O primeiro caractere corresponde ao primeiro lançamento da moeda. (Na primeira rodada, o comprimento da corda será 1.)
    • uma string, sua memória armazenada da rodada anterior
    • o índice baseado em 1 desta rodada
  • A cada passo, seu método retorna um Actionobjeto que contém

    • um número inteiro no movecampo que descreve sua ação:

      • 0 para nenhuma ação
      • -1 puxar uma alavanca azul e bloquear TT está passando por esta rodada
      • um número inteiro positivo x, não maior que a rodada atual, para puxar uma alavanca vermelha e tentar voltar à rodadax
      • Inteiros inválidos são tratados como 0.
    • uma string contendo sua memória desta rodada que você deseja preservar. Observe que armazenar memória não é uma parte crucial do desafio . Você pode fazer boas entradas sem armazenar dados úteis na string. Na primeira rodada, a sequência será uma sequência vazia.

  • Seu método não deve demorar mais que 10 ms por rodada, em média, em uma partida.

  • A falha regular do prazo resulta na desqualificação.

Pontuação

  • Ganhar uma partida ganha 2 pontos e um empate ganha 1 ponto para ambos os jogadores. A perda não ganha pontos.
  • A pontuação de um bot será o número total de pontos coletados.
  • O número de partidas disputadas entre cada par de participantes dependerá do número de participações e de sua velocidade.

Dois exemplos simples de bots são postados como respostas.

O controlador e o primeiro par de robôs estão disponíveis aqui .

Resultados dos testes com bots enviados até 3 de novembro:

Total de pontuações:

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

(O controlador é baseado no controlador do desafio Cat catcher . Obrigado por @flawr fornecê-lo como base para este).

Bônus: um belo filme de 6 minutos baseado em um conceito semelhante.


11
Não entendo o que essa regra significa. 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.O que é "passar por uma rodada"?
feersum

@feersum Se bem entendi, puxar permanentemente a alavanca azul "trava" a rodada atual (e, portanto, todas as rodadas anteriores), para que os resultados não possam ser modificados pela viagem no tempo. Se alguém tentar fazer TT um tempo antes do que quando você puxou a alavanca azul, não será possível.
PhiNotPi 24/10/2015

@feersum @PhiNotPi está certo, esta versão é mais clara? 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.
Random #

Quando você puxa a alavanca vermelha, pode escolher a mesma rodada em que está atualmente para refazer o sorteio dessa rodada?
TheNumberOne

@TheNumberOne Sim, é isso que o bot de exemplo aleatório faz.
Random #

Respostas:


12

Analisador

Isso analisa o passado para fazer as melhores previsões para o futuro.

EDIT: Evita tempos de alavanca azuis. Usa alavancas azuis efetivamente. Usa alavancas vermelhas de forma mais eficaz. Adicionado medo para a temporada de Halloween.

EDIT: Corrigido por 1 erro.

EDIT:computeWinningProbability Função aprimorada . Agora usa alavancas vermelhas e alavanca azul de forma mais agressiva.

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

}

Pontuação (desde 2 de novembro):

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

11
Impressionante! Seu bot bloqueia efetivamente e reverte nos horários ideais. Vai ser muito difícil criar um bot que possa superar esse.
TNT

Não tenho certeza de que este bot possa ser interrompido, sem usar um monte de entradas projetadas especificamente para mexer com esse bot e aumentar outro bot.
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);
    }
}

Não testado, apenas uma tentativa rápida de criar um bot difícil de bloquear (porque decide quando puxar a alavanca vermelha aleatoriamente), mas que toma decisões decentes.

Edit: Eu perdi esta regra:

Se você puxar uma alavanca azul (rolha de reversão), o TT não será mais possível nessa rodada

Essa parece ser uma boa razão para usar a memória - se você se lembrar de tentar fazer o TT em uma determinada rodada, pode ter falhado; portanto, não deve tentar fazer o TT novamente nessa rodada. Editou meu bot para tentar evitar isso.


4

Oráculo

Copiei descaradamente algum código do Analyzer (para analisar a memória). Essa finalização tenta puxar uma alavanca azul mais cedo e, lentamente, aumenta sua liderança. Eu acho que o desempenho desse bot compensa o código feio :)

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

Bom trabalho! Eu sabia que não estava sendo agressivo o suficiente com minhas alavancas vermelhas. Agora, para melhorar o Analyzer. ;)
TheNumberOne

3

RegretBot

No final de nossa vida, a partida, lamentamos nossas falhas passadas e tentamos voltar e corrigi-las.

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

O Little Ten faz muita multiplicação e divisão por 10, usando números que são múltiplos de 10 e voltando às rodadas que são múltiplos de 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);
    }
}

Edit: Mudou a mecânica um pouco agora que a explicação do que acontece quando uma alavanca azul é puxada é mais clara. Também fez um pouco de reequilíbrio.


1

Aleatória

A estratégia da Random é a seguinte:

  • bloqueie com 10% de chance se estiver na liderança e ainda houver alavancas azuis
  • viaje de volta uma vez (repetindo a última rodada) com 10% de chance se estiver atrasado na pontuação e tiver as alavancas vermelhas
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

Mau perdedor

Esse bot não usa memória e é surpreendentemente bom (mas não supera o Analyzer ou o 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

Moda antiga

Esse bot nunca realiza nenhuma ação, pois o Oldschool não acredita em viagens no tempo.

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

Este bot tenta rastrear quando puxa o azul para evitar puxar o vermelho para aquela região. Só puxará alavancas vermelhas quando estiver significativamente atrasado na pontuação.

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

}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.