Морра, благородная игра королей

28

Задний план

Игра Морра простая игра. В «оригинальной» версии несколько игроков одновременно выбрасывают 0-5 своими руками, угадывая общую сумму рук каждого. Версия, которую я здесь использую, была изменена, чтобы увеличить потенциал для нетривиальной стратегии, и она описана ниже:

  • Есть два игрока.
  • Как и в каменных ножницах, игроки двигаются одновременно.
  • Каждый ход каждый игрок выбирает число 0-5, а также угадывает выбор своих оппонентов 0-5. Это означает, что два числа выводятся каждый ход. Для уточнения оба выходных числа должны быть в диапазоне 0-5 включительно.
  • Если вы правильно угадали выбор своего оппонента, но оппонент не угадал правильно, вы выиграли определенное количество очков, равное сумме двух сыгранных чисел. Например, если сыграно 3 и 5, правильное предположение будет стоить 8 баллов.
  • Если оба или ни один из игроков не угадают правильно, очки не начисляются.
  • Человек с наибольшим количеством очков после 1000 раундов побеждает в этой игре.

Турнир

Турнир будет проводиться в круговом стиле и будет проводиться путем создания каждой возможной пары участников. За каждую победу участник получает 2 победных очка. Каждая ничья приводит к 1 победному очку. За потерю не набираются победные очки.

Интуитивно, победитель турнира должен быть участником с наибольшим количеством победных очков против других.


Как войти

Будет два способа подачи ботов на соревнования. Первый и наиболее предпочтительный метод заключается в реализации интерфейса Java, предоставляемого контроллером. Второй способ - написать независимую программу.

Давайте сначала рассмотрим метод Java. Интерфейс, который вам нужно реализовать, это Playerи он определяет два метода: public String getName()идентифицирует вашего бота и public int[] getMove(String[] args)принимает argsв качестве массива шесть строк mychoices myguesses myscore opponentchoices opponentguesses opponentscore. Примером является следующее:

042 045 0 324 432 6

Это означает, что я выбрал 0 в первом раунде и предположил, что мой противник собирается бросить 0. Мой противник бросил 3 и предположил, что я брошу 4. В третьем раунде мой оппонент сделал правильное предположение, что я брошу 2, что означает, что он получает 2 + 4 = 6 баллов.

Ваш метод вернет массив из двух целых чисел, которые вы выбираете и угадываете соответственно. Пример {4,2}для выбора 4 и предположения 2.

Вот пример полного Java-бота, написанного как метод. Если вы хотите, ваше представление должно включать только то, что происходит в getMoveметоде.

import java.util.Random;
/**
 * A simple example Morra bot to get you started.
 */
public class ExampleBot implements Player
{
    public String getName()
    {
        return "ExampleBot";
    }

    public int[] getMove(String [] args)
    {
        //easiest way I know to break down to create a move history
        //(just contains their throw history)
        char[] theirThrowsC = args[3].toCharArray();
        int[] theirThrows = new int[theirThrowsC.length];
        for(int i = 0; i < theirThrowsC.length; i++)
        {
            theirThrows[i] = Integer.parseInt(Character.toString(theirThrowsC[i]));
        }

        //get my score
        int myScore = Integer.parseInt(args[2]);

        Random r = new Random();
        int guess = r.nextInt(6);
        if(theirThrows.length > 0)
        {
            guess = theirThrows[theirThrows.length-1];
        }

        //throws a random number, guesses what they threw last
        return new int[] {r.nextInt(6),guess}; 
    }

    public static int otherMethod(int example) //you can write additional static methods
    {
        return 0;
    }
}

Как независимая программа

В настоящее время я ограничен в поддержке других языков. Помимо Java, я могу принимать программы, написанные на Python 3.4, Perl 5 или Ruby 2.1.5. Если есть язык, который, кажется, нужен нескольким людям, я сделаю все возможное, чтобы добавить его.

Ввод вашей программы будет аргументами в командной строке. Это может выглядеть так:

perl awesomebot.plx 042 045 0 324 432 6

Вывод вашей программы должен быть вашим выбором, за которым следует ваше предположение, за которым следует пробел.

Пожалуйста, включите в свой ответ точную команду, необходимую для его запуска. Имейте в виду, что я использую Windows 8.1.


Дополнительные правила

Сохранение состояния и тайм-ауты

Ваша программа сможет создать один текстовый файл в локальном каталоге, где вы можете хранить информацию. Эта информация будет храниться в течение всего турнира, но впоследствии будет удалена. Дайте файлу имя, которое я могу опознать.

Время ответа вашего кода составляет 500 миллисекунд. Невозможность ответить в срок (или неверный ход) приведет к конфискации этого конкретного матча. Представления Java в настоящее время имеют пассивный тайм-аут (который я могу обновить до активного), в то время как представления не-Java имеют активный тайм-аут, когда их процесс завершается через 500 миллисекунд.

Больше правил подачи

  • Вам разрешено несколько заявок, если они соблюдают правила и не помечают команду.
  • Каждая запись должна быть уникальной. Вы не можете сделать точную копию логики другого бота на другом языке.
  • Боты не могут взаимодействовать друг с другом (формировать команду любого рода).
  • Вы не можете использовать логику других ботов внутри вашего бота, например, чтобы идентифицировать вашего конкурента и предсказать его действия. Конечно, вы можете попытаться определить стратегию вашего противника.
  • Не пытайтесь связываться с контроллером, другими участниками или моим компьютером. Не подключайтесь к внешним источникам информации.

Контроллер

Текущая версия контроллера находится здесь . Он написан на Java 8. Файл «Турнир» является основным контроллером, который также содержит список участников (если вы хотите провести свои собственные соревнования).


Leaderboard

Мне не очень часто удавалось обновлять таблицу лидеров. Я довольно занят в эти выходные. Под «довольно занятым» я подразумеваю отсутствие доступа к компьютеру с 6:30 до 21:30. Вот результаты после 5 пробежек. По какой-то причине бот «Эхо» продолжал терять свои права (возможно, я виноват, я еще не исследовал).

  170 - Quinn and Valor                         
  158 - Historian                               
  142 - DeltaMax                                
  140 - MorraCowbell                            
  132 - Extrapolator                            
  115 - Rainbolt                                
  102 - Popularity                              
  100 - Interpolator                            
   83 - CounterBot                              
   80 - Basilisk                                
   76 - Erratica                                
   65 - Trendy                                  
   63 - Scholar                                 
   62 - RandomGuesser                           
   60 - KingFisher                              
   59 - NullifierBot                            
   55 - EvolvedBot                              
   48 - Confused          

кредит

Большое спасибо Rainbolt и Peter Taylor за помощь с контроллером.

PhiNotPi
источник
1
@ MartinBüttner Ruby 2.1.5 был добавлен.
PhiNotPi
Как работает Round Robin? Игрок1 против Игрока2 1000 раз, Игрок1 против Игрока3 1000 раз и т.д ... ИЛИ это Игрок1 против Игрока2 один раз, затем игрок1 против Игрока 3 один раз и т.д. ...
Ваджура
@ Ваджура Один турнир состоит из 1 битвы между каждой парой. Одна битва имеет 1000 раундов, с наибольшим общим счетом в конце битвы, определяющим, кто получит два победных очка. Текущее табло показывает общее количество победных очков после 40 турниров.
PhiNotPi
Извините за задержки в обновлении платы. Я очень занят в эти выходные. Ожидайте и обновляйте сегодня и завтра утром.
PhiNotPi
Вау, я не ожидал, что мой бот так хорошо справится! Кроме того, что означают цифры под первым набором результатов ... количество побед?
mbomb007

Ответы:

17

Морра Ковбелл

Для любого, кто ищет значение в названии этого бота, имя Morra заставляет меня думать о Space Italian , поэтому я решил, что мне нужно имя, которое сыграло на этом. Среди других кандидатов Морра дурачила тебя и Морра за меня .

Это полный класс, реализующий Playerинтерфейс. Объяснение ниже.

import java.util.Random;

public class MorraCowbell implements Player {
    private final Random rnd = new Random();

    public String getName() {
        return "MorraCowbell";
    }

    public int[] getMove(String[] args) {
        int[] prior = new int[36];
        for (int i = 0; i < 36; i++) prior[i] = 1;
        // args: myChoices myGuesses myScore opponentChoices opponentGuesses opponentScore
        if (args.length == 6 && args[3].length() == args[4].length()) {
            for (int i = 0; i < args[3].length(); i++) prior[6*(args[3].charAt(i) - '0') + (args[4].charAt(i) - '0')]++;
        }

        int[] weights = new int[6];
        for (int r = 0; r < 6; r++) {
            for (int s = 0; s < 6; s++) {
                for (int t = 0; t < 6; t++) {
                    weights[r] += (r + s) * ((r + s == 5 ? 1 : 0) + (r == t ? -1 : 0)) * prior[s * 6 + t];
                }
            }
        }

        // Find the best window.
        int[][] magic = new int[][] {
            { 7776, 6480, 5400, 4500, 3750, 3125 }, { 3125, 2500, 2000, 1600, 1280, 1024 }, { 1875, 1500, 1200, 960,
            768, 640 }, { 1125, 900, 720, 576, 480, 400 }, { 1620, 1296, 1080, 900, 750, 625 }, { 1296, 1080, 900, 750,
            625, 500 }, { 750, 625, 500, 400, 320, 256 }, { 675, 540, 432, 360, 300, 250 }, { 648, 540, 450, 375, 300,
            250 }, { 375, 300, 250, 200, 160, 128 }, { 375, 300, 240, 200, 160, 128 }, { 450, 375, 300, 240, 192, 160,
            128 }, { 324, 270, 225, 180, 150, 125 }, { 270, 225, 180, 144, 120, 100, 80 }, { 225, 180, 150, 120, 96,
            80 }, { 225, 180, 144, 120, 96, 80 }, { 324, 270, 216, 180, 150, 125, 100, 80, 64 }, { 135, 108, 90, 72, 60,
            50 }, { 135, 108, 90, 75, 60, 50, 40, 32 }, { 108, 90, 75, 60, 48, 40, 32 }, { 54, 45, 36, 30, 25, 20, 16 },
            { 54, 45, 36, 30, 24, 20, 16 }
        };
        long bestN = 0;
        int bestD = 1, bestIdx = -1, bestA[] = null;
        for (int[] A : magic) {
            for (int i = 0; i < A.length - 5; i++) {
                long n = 0;
                int d = 0;
                for (int j = 0; j < 6; j++) {
                    n += weights[j] * A[i + j];
                    d += A[i + j];
                }
                if (n * bestD > bestN * d) {
                    bestN = n;
                    bestD = d;
                    bestIdx = i;
                    bestA = A;
                }
            }
        }

        int r = rnd.nextInt(bestD);
        for (int i = 0; i < 6; i++) {
            r -= bestA[bestIdx + i];
            if (r < 0) return new int[] { i, 5 - i };
        }

        // Just a precaution: this should be unreachable.
        return new int[] { 0, 5 };
    }
}

объяснение

Я начал с анализа игр с меньшим количеством пальцев. Простейший нетривиальный способ допускает вызовы 0или 1и имеет следующую таблицу выплат (значения - это выплаты для игрока строки):

       (0,0) (0,1) (1,0) (1,1)
      +-----------------------
(0,0) |  0     0    -1     0
(0,1) |  0     0     0     1
(1,0) |  1     0     0    -1
(1,1) |  0    -1     1     0

(0,0)Стратегия доминирует (0,1), так что мы можем уменьшить таблицу

       (0,1) (1,0) (1,1)
      +-----------------
(0,1) |  0     0     1
(1,0) |  0     0    -1
(1,1) | -1     1     0

Теперь (1,0)стратегия доминирует (0,1), поэтому мы можем еще больше сократить таблицу до

       (0,1) (1,1)
      +-----------
(0,1) |  0     1
(1,1) | -1     0

И теперь (1,1)доминирует (0,1), поэтому мы в конечном итоге

       (0,1)
      +-----
(0,1) |  0  

Поэтому всегда игра (0,1)- это равновесие Нэша. Но любопытно, что это не единственный. Это симметричная игра с нулевой суммой, поэтому ожидаемый выигрыш равен 0, и любая смешанная стратегия, объединяющая (0,1)и (1,0)где (0,1)выбирается по крайней мере 50% времени, достигает этого выигрыша. Таким образом, мы имеем одномерное пространство равновесий Нэша.

Кажется, что это так, хотя я не доказал этого, что у nМорфра-пальца есть многомерный nмногогранник равновесий Нэша, которые представляют собой смешанные стратегии, n+1 (pick, guess)для которых пары pick + guess = n.

Магические числа в коде выше кодируют 32 вершины 5-мерного многогранника равновесий Нэша. Я нашел их, настроив экземпляр линейного программирования, который представлял многогранник, и затем использовал случайные целевые функции. Причина кодирования всех 32, а не выбора одного, проста: ожидаемый выигрыш равен 0, поэтому мне нужно добиться большего, чем ожидалось, чтобы получить победу. По сути, я предполагаю, что другой игрок использует смешанную стратегию, и оцениваю распределение на основе их истории выбора. Затем я выбираю многогранную вершину, которая максимизирует мой ожидаемый выигрыш по сравнению с этим предполагаемым распределением.

QuinnAndValor демонстрирует уязвимость предположения о том, что другой игрок использует смешанную стратегию. Обнаружив игрока, который использует стратегии из равновесия Нэша, он может переключиться в режим случайного блуждания, где, играя в неравновесную стратегию, он в среднем может проиграть, но ему нужно только получить преимущество один раз, а затем он может вернуться к игре пар, для которых pick + guess = n. Таким образом, равновесия Нэша для одной игры не обобщаются тривиально на равновесия Нэша для повторной игры, что позволяет применять более сложные стратегии.

Питер Тейлор
источник
4
Возможно ли, что ваша магия содержит часть чисел Хэмминга ? Это, конечно, не содержит все из них, но многие ( или все? ) Из них находятся в списке на этом сайте.
GiantTree
@GiantTree, они все числа Хэмминга. Интересное наблюдение.
Питер Тейлор
Неудивительно, что твой бот улетает. : D
mbomb007
11

Куинн и Доблесть (Обновлено)

Куинн и Валор - элитная команда рейнджеров. С помощью арбалета и когтя они разрывают каждого противника, осмелившегося бросить им вызов

import java.util.ArrayList;
import java.util.List;

interface Champion extends Player {
}

/*
 * Quinn and Valor are an elite ranger team. With crossbow and claw, they ...
 */
public class QuinnAndValor implements Champion {

    private final Champion quinn = new Quinn();
    private final Champion valor = new Valor();

    private int checker;
    private int myScore, opScore;
    private boolean ulted;
    private boolean teemoDetected;
    private boolean quinnNeverLose, valorNeverLose;
    private int quinnScore, valorScore;
    private int quinnRound, valorRound;

    public QuinnAndValor() {
        checker = check() ? 0 : 1;
    }

    // Check if is a fine use
    private static boolean check() {
        return Thread.currentThread().getStackTrace()[3].getClassName().equals(
                "Tournament");
    }

    @Override
    public String getName() {
        return quinn + " and " + valor;
    }

    @Override
    public int[] getMove(String[] args) {
        // Punish for bad usage
        switch (checker) {
        case 1:
            checker++;
            return new int[] { -1, -1 };
        case 2:
            checker++;
            return null;
        case 3:
            throw new Error("Mua he he heh!");
        default:
            if (checker > 0)
                throw new Error("Mua he he heh!");
            break;
        }

        int round = args[0].length();
        if (round == 0) {
            // Buy starting items
            myScore = opScore = 0;
            teemoDetected = false;
            quinnNeverLose = valorNeverLose = true;
            quinnScore = valorScore = quinnRound = valorRound = 0;
            ((Valor) valor).reset();
        }

        if (ulted = useUltimate(args)) {
            valorRound++;
            return valor.getMove(args);
        } else {
            quinnRound++;
            return quinn.getMove(args);
        }
    }

    /*
     * Quinn's ultimate has a lengthy cool-down, especially at lower ranks, so
     * we have to use it only when needed.
     */
    private boolean useUltimate(String[] args) {
        int round = args[0].length();
        int lastMyScore = myScore;
        int lastOpScore = opScore;
        myScore = Integer.parseInt(args[2]);
        opScore = Integer.parseInt(args[5]);
        int score = (myScore - opScore) - (lastMyScore - lastOpScore);
        if (ulted) {
            valorScore += score;
            valorNeverLose &= score >= 0;
        } else {
            quinnScore += score;
            quinnNeverLose &= score >= 0;
        }

        if (round < 100) {
            // Haven't hit level 6 yet
            return false;
        }

        if (myScore > opScore) {
            // We're already winning. Press on with strategy impossible to lose
            if (quinnNeverLose && quinnRound >= 50)
                return false;
            if (valorNeverLose && valorRound >= 50)
                return true;
        } else if (myScore < opScore) {
            // Although Quinn can blind others to counter them, she can be
            // counter be Teemo who also has blind! Don't fall for this!
            if (!teemoDetected) {
                teemoDetected = true;
                for (int i = round - 20; i < round; i++)
                    if (args[3].charAt(i) + args[4].charAt(i) != 'e')
                        teemoDetected = false;
            }
            if (teemoDetected)
                return true;
        }

        if (valorRound < 100) {
            // If we never use our ultimate, how can we know how strong it is?
            return true;
        }

        if (quinnScore < 0 && valorScore < 0)
            return valorRound < quinnRound;
        else
            return quinnScore * valorRound < valorScore * quinnRound;
    }

    @Override
    public String toString() {
        return getName();
    }

    /*
     * Quinn is a female Demacian elite ranger.
     * 
     * @see Valor
     */
    public static class Quinn implements Champion {
        @Override
        public String getName() {
            return "Quinn";
        }

        /*
         * Magic!
         */
        @Override
        public int[] getMove(String[] args) {
            int t = (int) ((Math.sqrt(Math.random() * 168 + 1) - 1) / 2);
            return new int[] { 5 - t, t };
        }

        @Override
        public String toString() {
            return getName();
        }
    }

    /*
     * Valor is Quinn's Demacian eagle.
     * 
     * @see Quinn
     */
    public static class Valor implements Champion {
        @Override
        public String getName() {
            return "Valor";
        }

        private int lastRound;
        private double[][] c;

        public void reset() {
            lastRound = 0;
            c = new double[6][6];
        }

        /*
         * Magic!
         */
        @Override
        public int[] getMove(String[] args) {
            int round = args[0].length();
            int[] b = new int[6];
            for (int i = round - 12; i < round; i++)
                b[args[0].charAt(i) - '0']++;
            {
                double deWeight = Math.pow(0.95, round - lastRound);
                for (int i = 0; i < 6; i++)
                    for (int j = 0; j < 6; j++)
                        c[i][j] *= deWeight;
                double weight = 1;
                for (int i = round - 1; i >= lastRound; i--) {
                    c[args[3].charAt(i) - '0'][args[4].charAt(i) - '0'] += weight;
                    weight *= 0.95;
                }
            }
            lastRound = round;

            List<int[]> pq = new ArrayList<>(1);
            double e = Integer.MIN_VALUE;
            for (int i = 0; i < 6; i++)
                for (int j = 0; j < 6; j++) {
                    double f = 0;
                    for (int k = 0; k < 6; k++)
                        f += (i + j) * c[j][k];
                    for (int k = 0; k < 6; k++)
                        f -= (i + k) * c[k][i];
                    // recently played moves are dangerous
                    f -= b[i] * b[i] * ((round + 11) / 12);
                    if (f >= e) {
                        if (f > e) {
                            pq.clear();
                            e = f;
                        }
                        pq.add(new int[] { i, j });
                    }
                }
            return pq.get((int) (Math.random() * pq.size()));
        }

        @Override
        public String toString() {
            return getName();
        }
    }
}

Они почти всегда побеждают все решения Java на моей машине.

Редактировать:

Я признаю, что Куинн и Доблесть не смогли дуэли с Историком, но я все еще верю в них, чтобы выиграть турнир.

Мой принцип, для любого решения choice + guess == 5, также играть с choice + guess == 5грантополучателями, сохраняя ваше преимущество.

Обновить:

Ну ... все только усложнилось.

johnchen902
источник
1
Мне нравится ссылка на League of Legends. Я действительно хочу сделать бот Teemo сейчас. :)
mbomb007
6

филолог

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

import java.util.HashMap;

public class Scholar implements Player
{
    public static int[] pm = new int[6];
    public static int[] pg = new int[6];
    public static HashMap<Integer, Integer> lm = new HashMap<>();
    public static HashMap<Integer, Integer> lg = new HashMap<>();

    public String getName()
    {
        return "Scholar";
    }

    public int[] getMove(String[] a)
    {
        int r = a[0].length();
        for (int i = 0; i < 6; i++) { pm[i]=0; pg[i]=0; }
        for (int i = 0; i < a[3].length(); i++) {
            int m = Integer.parseInt(String.valueOf(a[4].charAt(i)));
            int g = Integer.parseInt(String.valueOf(a[3].charAt(i)));
            pm[m]++; pg[g]++;
        }
        for (int i = 0; i < pm.length; i++) { lm.put(i, pm[i]); lg.put(i, pg[i]); }

        if (r < 1) {
            return new int[] { 3, 3 };
        } else {

            int mm = lm.entrySet().stream().min((x, y) -> x.getValue() > y.getValue() ? 1 : -1).get().getKey();
            int mg = lg.entrySet().stream().max((x, y) -> x.getValue() > y.getValue() ? 1 : -1).get().getKey();
            return new int[] { mm, mg };
        }   
    }
}
Thrax
источник
6

DeltaMAX

(Обновлен, чтобы не использовать файлы и добавил новый раздел. Также изменен, чтобы больше не зависать связывание в первом разделе.)

Состоит из пары стратегий, которые начинаются с простого, а затем становятся более сложными - если вы его очистите, он переместит вас в следующий раздел.

  • Раздел 1: Угадай {0, 5}последовательно
  • Раздел 2. Проверьте, формируют ли ваши последние 4 догадки постоянный, линейный или квадратичный шаблон, и продолжайте угадывать шаблон, пока он не сломается.
  • Раздел 3: Проверьте, не угадываете ли вы аномально низкое количество некоторого числа (меньше 1/13), и выберите это число
  • Раздел 4: Анализируйте биграммы по своему выбору и посмотрите, что с большей вероятностью выйдет дальше
  • Раздел 5: Посмотрите на последние 100 раундов и выберите (choice, guess)пару, которая будет иметь наилучшие ожидания, взвешенные так, чтобы последние раунды были более важными
  • Финальный раздел: Угадайте случайно, с более высокой вероятностью того, что у вас будет низкий выбор и высокие догадки. Если вы попали сюда, то DeltaMax сдалась и хотела бы сказать «хорошая игра».

Чтобы выяснить, какой слой использовался в конце, раскомментируйте

if (myChoices.length == 999) { System.out.println(strat); }

линия.

Извиняюсь за ужасную Java, я провел свой день, собирая кусочки вместе и переучивая язык :)

import java.io.*;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;

public class DeltaMax implements Player
{
    private int strat = 100;

    public String getName() { return "DeltaMax"; }

    public int[] toInts(String s) {
        char [] chars = s.toCharArray();
        int[] ints = new int[chars.length];

        for (int i = 0; i < chars.length; i++){
            ints[i] = Integer.parseInt(Character.toString(chars[i]));
        }

        return ints;
    }

    public int mod6(int n) {
        n = n % 6;
        if (n < 0) { n += 6; }
        return n;
    }

    public int[] getMove(String [] args)
    {
       int[] myChoices = toInts(args[0]);
       int[] myGuesses = toInts(args[1]);
       int myScore = Integer.parseInt(args[2]);
       int[] opponentChoices = toInts(args[3]);
       int[] opponentGuesses = toInts(args[4]);
       int opponentScore = Integer.parseInt(args[5]);

       int rounds = myChoices.length;

       if (rounds == 0) { strat = 100; }
       Random r = new Random();

       // if (myChoices.length == 999) { System.out.println(strat); }

       if (strat == 100) { // Section 1 - {0, 5}
           if (opponentScore - myScore > 21 || (opponentScore >= myScore && rounds > 100)) {
               strat = 200;
           } else {
               return new int[] {0, 5};
           }
       }

       if (strat == 200) { // Section 2 - Mini interpolator
           int w = opponentChoices[opponentChoices.length - 4];
           int x = opponentChoices[opponentChoices.length - 3];
           int y = opponentChoices[opponentChoices.length - 2];
           int z = opponentChoices[opponentChoices.length - 1];

           if (w == x && x == y && y == z) { // Constant
               return new int[] { r.nextInt(4) + 2, w };
           }

           if (mod6(x-w) == mod6(y-x) && mod6(y-x) == mod6(z-y)) { // Linear
               return new int[] { r.nextInt(4) + 2, mod6(z + (z-y)) };
           }

           if (mod6((y-x) - (x-w)) == mod6((z-y) - (y-x))) { // Quadratic
               return new int[] { r.nextInt(4) + 2, mod6((z-y) + mod6((y-x) - (x-w))) };
           }

           strat = 300;
       }

       if (strat == 300) { // Section 3 - exploit least guessed
           int [] counts = new int[6];

           for (int i = 0; i < rounds; i++) {
               counts[opponentGuesses[i]] += 1;
           }

           int minCount = rounds;

           for (int i = 0; i < 6; i++) {
               if ((counts[i] <= 1 || counts[i] * 13 < rounds) && counts[i] < minCount) {
                   minCount = counts[i];
               }
           }

           if (minCount == rounds) {
               strat = 400;
           } else {
               ArrayList<Integer> choices = new ArrayList<Integer>();

               for (int i = 0; i < 6; i++) {
                   if (counts[i] == minCount) {
                       choices.add((Integer) i);
                   }
               }

               int choice = choices.get(r.nextInt(choices.size()));

               // {0, 0} is about the worst thing you can do, so DeltaMax tries to avoid that
               if (choice == 0) {
                   return new int[] { 0, r.nextInt(4) + 2 };
               } else {
                   return new int[] { choice, r.nextInt(6) };
               }
           }
       }

       if (strat == 400) { // Section 4 - bigrams
           if (opponentScore - myScore > 42 || (opponentScore >= myScore && rounds > 300)){
               strat = 500;
           } else {
               int[] opponentScores = new int[6];
               int opponentLast = opponentChoices[opponentChoices.length - 1];

               int[] myScores = new int[6];
               int myLast = myChoices[myChoices.length - 1];

               for (int i = 0; i < opponentChoices.length - 1; i++) {
                   if (opponentChoices[i] == opponentLast) {
                       opponentScores[opponentChoices[i+1]] += 1;
                   }

                   if (myChoices[i] == myLast) {
                       myScores[myChoices[i+1]] += 1;
                   }
               }

               int maxIndex = -1;
               int maxScore = 0;

               int minIndex = -1;
               int minScore = rounds;

               for (int i = 0; i < 6; i++) {
                   if (opponentScores[i] >= maxScore) {
                       maxScore = opponentScores[i];
                       maxIndex = i;
                   }

                   if (myScores[i] <= minScore) {
                       minScore = myScores[i];
                       minIndex = i;
                   }
               }

               if (minIndex == 0 && maxIndex == 0) {
                   return new int[] { 0, r.nextInt(4) + 2 };
               } else {
                   return new int[] { minIndex, maxIndex };
               }
           }
       }

       if (strat == 500) { // Section 5 - best expectation
           if (opponentScore - myScore > 84 || (opponentScore >= myScore && rounds > 800)){
               strat = 573;
           } else {
               int minLen = Math.min(rounds, 100);

               double bestScore = 0;
               int bestGuess = 0;
               int bestChoice = 5;

               for (int guess = 0; guess < 6; guess++) {
                   for (int choice = 0; choice < 6; choice++) {
                       double score = 0;
                       int start = rounds - minLen;

                       for (int i = start; i < rounds; i++) {
                           if (opponentGuesses[i] == choice && opponentChoices[i] != guess) {
                               score -= (choice + opponentChoices[i]) * ((double) i - start) / minLen;
                           } else if (opponentGuesses[i] != choice && opponentChoices[i] == guess) {
                               score += (choice + opponentChoices[i]) * ((double) i - start) / minLen;
                           }
                       }

                       if (score > bestScore) {
                           bestScore = score;
                           bestGuess = guess;
                           bestChoice = choice;
                       }
                   }
               }

               if (bestChoice == 0 && bestGuess == 0) {
                   return new int[] { r.nextInt(4) + 2, bestGuess };
               } else {
                   return new int[] {bestChoice, bestGuess};
               }
           }
       }

       // Section final - hope for the best
       int num = (int) Math.floor(Math.sqrt(r.nextInt(35)));
       return new int[] {5 - num, num};
    }
}
Sp3000
источник
С текущей реализацией контроллера, нет необходимости сохранять вещи в файл, если данные используются только для одной игры. т.е. private int strat;достаточно хорош
johnchen902
@ johnchen902 Спасибо, я не понимал, что смогу это сделать. Это делает вещи намного проще.
Sp3000
6

Историк

(Обновлено: та же логика, более короткий код и 100 раз быстрее, но вы можете использовать только одного бота Historian на турнире.)

Использует взвешенную случайную выборку для выбора пары бросок-угадывание, основываясь на эффективности использования только этой пары против предыдущей истории противников. Весами являются квадраты от достижимых баллов.

public class Historian implements Player {
    private static java.util.Random r = new java.util.Random();
    private static int[] sc=new int[36]; //reseted between games, use only one Historian bot
    public String getName() {return "Historian";}
    public int[] getMove(String [] a) {
        if (a[3].length()==0)  {sc=new int[36]; for(int i=0;i<6;i++) sc[i*6+(5-i)]=5-i;}
        else {int t=a[3].charAt(a[3].length()-1)-'0'; int g=a[4].charAt(a[3].length()-1)-'0';
            for(int i=0; i<6; i++) {sc[i*6+t]+=i+t; sc[g*6+i]-=t+g;}}
        int sum=0; for(int i=0; i<36; i++) {sum+=(sc[i]<1)?1:sc[i]*sc[i];}
        int seed=r.nextInt(sum);int mt=-1;
        while (seed>=0) {seed-=(sc[++mt]<1)?1:sc[mt]*sc[mt];}  
        return new int[] {(int)(mt/6),mt%6};} }

Бьет Quinn and Valor (больше не) и проигрывает Morra Cowbell. В турнире с большинством ботов Historianвторое место Quinn and Valor.

randomra
источник
Что ж, приятно видеть, что я выиграл на чьей-то машине. Я теряю текущий официальный список лидеров. Мне было интересно, что это из-за неудачи или какой-то непредвиденной ошибки.
johnchen902
@ johnchen902 У меня должно быть галлюцинация Morra Cowbell. Отредактировал пост. Вы можете удалить комментарии, если они устарели.
Рандомра
Я думаю, что теперь могу выиграть 75% нашего поединка после моего обновления!
johnchen902
5

Экстраполятор (v1.1)

Экстремальная экстраполяция из одного из равновесий Нэша в более простой игре.

Я поддерживаю краткий формат ответа! (В стиле питона.)

public class Extrapolator implements Player { 
    private static java.util.Random r = new java.util.Random();
    public String getName() { return "Extrapolator"; }
    public int[] getMove(String [] args) {
        int t=-1;
        for(int c=15,s=r.nextInt(60);s>=0;s-=c,c-=2,t++);
        return new int[] {t,5-t}; } }

Кажется, связывает с Волшебной Коровой (Морра Ковбелл) и бьет другие записи, которые я проверял.

randomra
источник
1
Пожалуйста, переместите Random r в статическое поле, чтобы не инициализировать его каждый раз, это повысит общую производительность!
Falco
Почему изменения в распределении?
Питер Тейлор
4

модный

Модный смотрит на прошлые шаги противника, взвешивая их по времени. Угадай самый весомый и выберет один, слегка сдвинутый вверх от этого. Вот оно во всей красе:

public class Trendy implements Player{public String getName(){return "Trendy";}public int[]getMove(String[]a){float h=0,c[]=new float[6];int i=0,l=a[3].length(),p=0;for(;i<l;)c[a[3].charAt(i++)-48]+=(float)i/l;for(i=0;i<6;i++)if(c[i]>h)h=c[p=i];return new int[]{(p+2)%6,p};}}    

Единственное, с чем я могу сравнить это сейчас, это Ковбелл. Он проигрывает с небольшим отрывом в большинстве случаев, но выходит на первое место достаточно часто, на мой вкус. Посмотрим, как это будет с другими конкурентами.

Geobits
источник
7
Не могли бы вы отформатировать код в несколько строк? Это не код гольф ...
mbomb007
7
@ mbomb007 Таким образом, он занимает меньше места. Одной из проблем KotH в целом является прокрутка для просмотра записей. Я описал, что он делает, и заинтересованным сторонам очень просто отформатировать его.
Geobits
4

Случайный догадчик

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

import java.util.Random;

public class RandomGuesser implements Player {
    private final Random rnd = new Random();
    public String getName() { return "RandomGuesser"; }

    public int[] getMove(String[] args) {
        return new int[] { rnd.nextInt(6), rnd.nextInt(6) };
    }
}
mbomb007
источник
4

Путать, Python 3

Излишне сложная запись. Даже я не знаю, что это делает.

import sys
from random import *

if len(sys.argv) == 7:
    mn,mg,ms,on,og,os = [list(map(int, v)) for v in sys.argv[1:]]
    s,t = sum(mn+on)%5, sum(mg+og)%5
    n = [0]*3+list(range(6))*5+[5,0,5]
    m = [1,0,5,4]+n[:-2:s//9+1]
    numoptions = [n.extend(n[i+s::5+t]+[i]*i*(6+t)) for i in n[:]] and n
    guessoptions = [m.extend(m[i+t//2::8]+[i]*i*(5+s)) for i in m[:]] and m
    num = choice(numoptions)
    guess = choice(guessoptions)
else:
    num, guess = randint(0, 5), randint(0, 5)

sys.stdout.write('%u %u\n' % (num, guess))

Хотя этот продвинутый алгоритм, кажется, работает хуже, чем случайный в этом турнире, и использует значительную память и время выполнения, он имеет потрясающие результаты для определенных значений 5 ;-)

Логика Найт
источник
4

Rainbolt

Принимает разницу между двумя последними числами, которые угадал наш оппонент, добавляет, что к последнему предположению оппонента, находит модуль и избегает выбора этого числа любой ценой. Например, если вы угадаете {5,4,3} (уменьшится на единицу), тогда мы будем избегать выбора 2 любой ценой.

Принимает разницу между двумя последними числами, которые выбрал наш оппонент, добавляет это к последнему выбору оппонента и угадывает это число. Например, если вы угадаете {1,4,5,2} (увеличивается на три), то мы догадаемся до 5.

Избегает бессмысленных или очень близких к бессмысленным броскам.

public class Rainbolt implements Player {

    public String getName() { 
        return "Rainbolt"; 
    }

    public int[] getMove(String[] args) {
        int[] yourChoices = toIntArray(args[3]);
        int[] yourGuesses = toIntArray(args[4]);

        int myChoice;
        if (yourGuesses.length > 1) {
            int latest = yourGuesses[yourGuesses.length - 1];
            int secondLatest = yourGuesses[yourGuesses.length - 2];
            int numberToAvoid = (2 * latest - secondLatest + 6) % 6;
            do {
                myChoice = rollRandom();
            } while (myChoice == numberToAvoid);
        } else { 
            myChoice = rollRandom();
        }

        int myGuess;
        if (yourChoices.length > 1) {
            int latest = yourChoices[yourChoices.length - 1];
            int secondLatest = yourChoices[yourChoices.length - 2];
            myGuess = (2 * latest - secondLatest + 6) % 6;
        } else { 
            myGuess = rollRandom();
        }

        if ((myChoice + myGuess) < 3) {
            do {
                myGuess = rollRandom();
            } while ((myChoice + myGuess) < 3);
        }

        return new int[] { myChoice, myGuess };
    }

    private static int[] toIntArray(String arg) {
        int[] result = new int[arg.length()];
        for (int i = 0; i < arg.length(); i++)
            result[i] = Character.getNumericValue(arg.charAt(i));
        return result;
    }

    private static int rollRandom() {
        return (int) (Math.random() * 6);
    }
}
Rainbolt
источник
Не делайте ваш getMove()метод статичным. Вы не можете реализовать нестатический метод, подобный этому (по крайней мере, в Java 8).
GiantTree
@GiantTree Спасибо, что поймали это.
Rainbolt
3

Развитый бот

Я превратил этого бота в лучшего случайного бота.

import java.util.Arrays;

public class EvolvedBot implements Player {

    private static final double MUTATION_RATE = .2;
    private static final double CROSS_OVER_RATE = .5;

    private final double[] pickProbabilities;
    private final double pickSum;
    private final double[] guessProbabilities;
    private final double guessSum;

    public EvolvedBot(){
        this(new double[]{1.0069058661897903, 0.8949716031797937, 0.5249198534098369, 0.437811964976626, 0.2630925750209125, 0.4862172884617061},
                new double[]{0.6336558074769376, 0.13700756148363913, 0.9586621925124863, 0.11223159366330251, 0.8931390659502754, 0.662974949440039});
    }

    public EvolvedBot(double[] pickProbabilities, double[] guessProbabilities) {
        this.pickProbabilities = pickProbabilities;
        this.guessProbabilities = guessProbabilities;
        pickSum = Arrays.stream(pickProbabilities).sum();
        guessSum = Arrays.stream(guessProbabilities).sum();
    }

    @Override
    public String getName() {
        return "EvolvedBot"/* + ": " + Arrays.toString(pickProbabilities) + Arrays.toString(guessProbabilities)*/;
    }

    @Override
    public int[] getMove(String[] args) {
        int[] move = new int[]{5, 5};
        double pick = Math.random() * pickSum;
        double guess = Math.random() * guessSum;
        for (int i = 0; i < 6; i++){
            if (pick >= 0) {
                pick -= pickProbabilities[i];
                if (pick < 0) {
                    move[0] = i;
                }
            }
            if (guess >= 0){
                guess -= guessProbabilities[i];
                if (guess < 0){
                    move[1] = i;
                }
            }
        }
        return move;
    }

    public EvolvedBot mutate(double mutationRate){
        double[] pickProbabilities = Arrays.copyOf(this.pickProbabilities, 6);
        double[] guessProbabilities = Arrays.copyOf(this.guessProbabilities, 6);

        for (int i = 0; i < 6; i++){
            pickProbabilities[i] = Math.max(pickProbabilities[i] + (Math.random() * 2 - 1) * mutationRate, 0);
        }

        for (int i = 0; i < 6; i++){
            guessProbabilities[i] = Math.max(guessProbabilities[i] + (Math.random() * 2 - 1) * mutationRate, 0);
        }

        return new EvolvedBot(pickProbabilities, guessProbabilities);
    }

}
Номер один
источник
3

Популярность, Python 3

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

import sys
from random import *

if len(sys.argv) == 7:
    mn,mg,ms,on,og,os = [list(map(int, v)) for v in sys.argv[1:]]
    n = list(range(6))
    guess = choice(n + on[-100:] + on[-20:]*8)
    num = choice(n + [guess]*6)
else:
    num, guess = randint(0, 5), randint(0, 5)

sys.stdout.write('%u %u\n' % (num, guess))
Логика Найт
источник
3

интерполятор

(Переключился на Java, так как Python вызывал проблемы)

Использует полиномиальную интерполяцию для последних 10 вариантов оппонента, чтобы определить следующий номер оппонента, затем делает то же самое с его собственным выбором и избегает выбора этого числа Кроме того, Интерполятор имеет небольшое смещение против выбора 0 или 5, и его выбор иногда зависит от его предположения:

  • Если он угадывает 0, он никогда не выберет 0
  • Если он угадает 5, он всегда будет выбирать 0 или 1
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class Interpolator implements Player
{
    private final int TAIL_LENGTH = 10;

    public String getName()
    {
        return "Interpolator";
    }

    public int[] toInts(String s) {
        char [] chars = s.toCharArray();
        int[] ints = new int[chars.length];

        for (int i = 0; i < chars.length; i++){
            ints[i] = Integer.parseInt(Character.toString(chars[i]));
        }

        return ints;
    }

    public int mod6(int n) {
        n = n % 6;
        if (n < 0) { n += 6; }
        return n;
    }

    public int interpolate(int[] nums){
        boolean allEqual = true;

        for (int i = 0; i < nums.length; i++){
            if (nums[i] != nums[0]){
                allEqual = false;
            }
        }

        if (allEqual) {
            return nums[0];

        } else {
            int [] newNums = new int[nums.length - 1];

            for (int i = 0; i < nums.length - 1; i++){
                newNums[i] = nums[i+1] - nums[i];
            }

            return nums[nums.length - 1] + interpolate(newNums);
        }
    }

    public int[] tail(int[] nums) {
        int minLength = Math.min(TAIL_LENGTH, nums.length);
        int[] tailArray = new int[minLength];

        for (int i = 0; i < minLength; i++){
            tailArray[i] = nums[nums.length - minLength + i];
        }

        return tailArray;
    }

    public int[] getMove(String [] args)
    {
        Random r = new Random();

        if (args[0].length() == 0){
            return new int[] {r.nextInt(5), r.nextInt(5)};
        }

        int[] myChoices = toInts(args[0]);
        int[] opponentChoices = toInts(args[3]);
        int[] opponentGuesses = toInts(args[4]);

        int guess = mod6(interpolate(tail(opponentChoices)));
        int avoid = mod6(interpolate(tail(myChoices)));

        if (guess == 5){ return new int[] {r.nextInt(2), 5}; }

        int[] choiceArray = {0, 1, 1, 2, 2, 3, 3, 4, 4, 5};
        ArrayList<Integer> choices = new ArrayList<Integer>();
        for (int i = 0; i < choiceArray.length; i++) { choices.add(choiceArray[i]); }

        choices.removeAll(Collections.singleton((Integer) avoid));
        if (guess <= 0) { choices.removeAll(Collections.singleton((Integer) 0)); }
        int choice = choices.get(r.nextInt(choices.size())); 

        return new int[] {choice, guess};
    }
}
Sp3000
источник
3

CounterBot

Не противостоит никому, а считает через 0-5 по кругу ( 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4 ...)

import java.util.Random;

public class Counter implements Player {

    int lastChoice = new Random().nextInt(6); //Chooses a random starting number

    public String getName() {
        return "CounterBot";
    }

    public int[] getMove(String[] args) {
        int[] oChoices = new int[6]; //Array to store the amount of individual choices of the opponent

        for (int i = 0; i < args[3].length(); i++) {
            int index = Integer.parseInt(String.valueOf(args[3].charAt(i))); //get that choice
            oChoices[index]++; //Increment the number corresponding the choice
        }
        int guess = 0, last = 0;
        for (int i = 0; i < oChoices.length; i++) { //Increment over the choices' array
            if (oChoices[i] > last) { //If the number has been chosen more often than the one before
                last = oChoices[i]; //Set the new maximum value (later the last maximum value)
                guess = i; //Set it as the next guess
            }
        }
        lastChoice++; //Increment our choice
        lastChoice %= 6; //Make sure it's within the bounds of 0-5 ie. modulo 6 (6 modulo 6 = 0)
        return new int[]{lastChoice, guess}; //return our choice and guess
    }
}
GiantTree
источник
2

Василиск, Питон

Согласно легенде, Василиск - король змей. ( источник ) Я подумал, что это подходящее имя для бота, который играет "Благородную игру королей" и написан на python. = D Этот бот вселяет страх в сердце других ботов и вызывает смерть одним взглядом.

import sys
import random

args = sys.argv
argc = len(args)
if argc < 6:
    sys.exit()

myChoices = args[1]
myGuesses = args[2]
myScore = args[3]
opponentChoices = args[4]
opponentGuesses = args[5]
opponentScore = args[6]

if len(myChoices) == 0:
    print (random.randint(0, 5))
    print (random.randint(0, 5))
    sys.exit()

guesses = [0, 0, 0, 0, 0, 0]
for char in opponentGuesses:
    i = int(char)
    guesses[i] += 1

#Will default towards smaller guesses to minimize opponent winnings
#For example, if the guess list is
#[5, 3, 7, 3, 4, 8]
#This will return 1. (index of the first 3)
myNextMove = guesses.index(min(guesses))

list = [
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]]
i = 0

while i < len(myGuesses) - 1:
    myGuess = int(myGuesses[i])
    opponentResponse = int(opponentChoices[i+1])
    list[myGuess][opponentResponse] += 1
    i += 1

myPreviousGuess = int(myGuesses[-1])
relevantList = list[myPreviousGuess]

#Defaults towards higher moves.
#For example, if the list is
#[3, 8, 6, 8, 0, 7]
#This will return 3 (index of the last 8)
highestValue = -1
highestIndex = -1
for i in range(len(relevantList)):
    if relevantList[i] >= highestValue:
        highestValue = relevantList[i]
        highestIndex = i


myNextGuess = highestIndex

print (myNextMove)
print (myNextGuess)

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

Как он выбирает свой следующий ход.

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

Как он выбирает свою следующую догадку.

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

С технической точки зрения, это будет работать правильно? Достаточно ли print () или я должен использовать что-то вроде sys.stdout.write (), как это сделали другие Pythonistas?

DJMcMayhem
источник
sys.stdout.write () работает в любом Python. print () работает только в Python 3. Все должно быть хорошо.
TheNumberOne
Нет, print () тоже работает, я в этом уверен. Скобки необязательны в 2.x
DJMcMayhem
В соответствии с этим они работают по-разному. Однако то, как вы его используете, не имеет значения.
TheNumberOne
Но имеет ли это какое-то значение?
DJMcMayhem
Очевидно нет.
TheNumberOne
2

то же самое

Это превращается в противника, но позади на одну догадку / выбор.

import java.util.Random;

public class Ditto implements Player {
    private final Random rnd = new Random();
    public String getName() { return "Ditto"; }

    // myChoices myGuesses myScore oppChoices oppGuesses oppScore
    public int[] getMove(String[] args) {
        if(args[0] == null || args[0].isEmpty()) {
            return new int[] { rnd.nextInt(6), rnd.nextInt(6) };
        }
        int[] myChoices = toIntArray(args[0]);
        int[] myGuesses = toIntArray(args[1]);
        //int myScore = Integer.parseInt(args[2]);
        int[] oppChoices = toIntArray(args[3]);
        int[] oppGuesses = toIntArray(args[4]);
        //int oppScore = Integer.parseInt(args[5]);

        return new int[] { oppChoices[oppChoices.length-1], oppGuesses[oppGuesses.length-1] };
    }

    private static int[] toIntArray(String arg) {
        int[] result = new int[arg.length()];
        for (int i = 0; i < arg.length(); i++)
            result[i] = Character.getNumericValue(arg.charAt(i));
        return result;
    }
}
mbomb007
источник
1

NullifierBot, Java

Всегда выбрасывает 0, чтобы минимизировать выигрыши противника. Если оппонент когда-нибудь угадает мой номер, он зарабатывает только то, что бросил.

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

public class NullifierBot implements Player
{
    public String getName()
    {
        return "NullifierBot";
    }

    public int[] getMove(String [] args)
    {
        // always throws 0 to minimize opponents score
        // always guesses 5 to maximize my score
        return new int[] {0, 5}; 
    }
}
Брайан Дж
источник
Я предполагаю, что этот бот будет делать ужасно. Любой бот, использующий шансы, может даже получить каждую догадку сразу после первой.
mbomb007
@ mbomb007 Хотя это не самое страшное! Хотя он работает хуже, чем ваш RandomBot.
Брайан Джей
1

Ошибка, Java

Не очень, но изначально он был спроектирован так, чтобы быть в основном случайным, пока ценность компромисса не показалась мне. Умудряется последовательно проигрывать против Counter Bot> _ <

import java.util.Random;
class Erratica implements Player
{
    private final Random rnd = new Random();

    public String getName() {
        return "Erratica";
    }

    public int[] getMove(String[] args) {
        if(args[0] == null || args[0].isEmpty())
        {
            return new int[]{rnd.nextInt(4)/3+4,rnd.nextInt(4)/3};
        }
        int[] myChoices = toIntArray(args[0]);
        int[] myGuesses = toIntArray(args[1]);
        int myScore = Integer.parseInt(args[2]);
        int[] opponentChoices = toIntArray(args[3]);
        int[] opponentGuesses = toIntArray(args[4]);
        int opponentScore = Integer.parseInt(args[5]);
        int round = opponentChoices.length + 1;
        int choice=0;
        int guess=0;
        if(round<7)
        {
            if(rnd.nextFloat()<(0.1f*(float)round-0.1f))
            {
                choice=(opponentChoices[round-2]+opponentGuesses[round-2])%6;
            }else
            {
                choice=rnd.nextInt(6);
            }
            if(rnd.nextFloat()<(0.1f*(float)round-0.1f))
            {
                guess=opponentChoices[round-2];
            }else
            {
                guess=rnd.nextInt(6);
            }
            return new int[]{choice, rnd.nextInt(6)/5*(5-choice-guess)+guess};
        }else
        {
            int lastError=Math.abs(opponentGuesses[round-2]-myChoices[round-2]);
            for(int i=round-2; i>round-8;i--)
            {
                if(lastError<rnd.nextInt(6))
                {
                    lastError++;
                }else
                {
                    lastError--;
                }
                if(lastError<0)
                    lastError+=6;

            }
            lastError = lastError%6; //shouldn't change
            switch(rnd.nextInt(4))
            {
                case 0:
                    choice=(myChoices[round-2-lastError-round/10])%6;
                    break;
                case 1:
                    choice=(myChoices[lastError+round/10])%6;
                    break;
                default:
                    choice = rnd.nextInt(6);
                    break;
            }

            lastError=Math.abs(myGuesses[round-2]-opponentChoices[round-2]);
            for(int i=round-2; i>round-8;i--)
            {
                if(lastError<rnd.nextInt(6))
                {
                    lastError++;
                }else
                {
                    lastError--;
                }
                if(lastError<0)
                    lastError+=6;
            }
            lastError = lastError%6; //shouldn't change
            switch(rnd.nextInt(4))
            {
                case 0:
                    guess=(opponentChoices[round-2-lastError-round/10])%6;
                    break;
                case 1:
                    guess=(opponentChoices[lastError+round/10])%6;
                    break;
                default:
                    guess = rnd.nextInt(4);
                    break;
            }
        }

        if(myScore>opponentScore)
            switch(rnd.nextInt(2)){
                case 0:
                    choice=5-guess;
                    break;
                case 1:
                    guess=5-choice;
                    break;
                default:
                    break;
            }
        return new int[]{choice, guess};
    }

    private static int[] toIntArray(String arg) {
        int[] result = new int[arg.length()];
        for (int i = 0; i < arg.length(); i++)
            result[i] = Character.getNumericValue(arg.charAt(i));
        return result;
    }
}
Fongoid
источник
1

Эхо, Рубин

mychoices, myguesses, myscore, opponentchoices, opponentguesses, opponentscore = $*

unless mychoices
 puts "0 5"
 exit
end

if mychoices.size > 990 && myscore == '0'
  nextchoice = rand(1..5)
else
  nextchoice = opponentchoices[-1].to_i
end

recentchoices = opponentchoices[/.{0,100}$/]

nextguess = (0..5).max_by do |choice|
  (recentchoices.count(choice.to_s)+1) * (nextchoice + choice)
end

puts "%s %s"%[nextchoice,nextguess]

Играет последнюю игру противника, основываясь на теории, что любой может создать бота, которого он не может предсказать. Предположения основаны на ожидаемом значении с использованием выборки из ста шагов.

histocrat
источник
Я получаю эту ошибку: echo.rb:3:in <main> ': неопределенный метод size' for nil:NilClass (NoMethodError). Кажется, это происходит только в первом раунде, когда нет истории ходов.
PhiNotPi
Странно, не случилось, когда я проверял. Я отредактирую
гистократ
Какова актуальность этой if (mychoices.size > 990 && myscore == '0') nextchoice = rand(1..5)части?
Рандомра
Если он собирается закончиться ничейным счетом (как, например, против себя), он начинает играть случайно, поскольку ~ 50% шансов на победу лучше, чем ничего.
гистократ
1

КОРОЛЬ ФИШЕР

    import java.util.Random;
public class KingFisher {

    private Random rnd = new Random();
    private int wins = 0;
    private int loses = 0;
    private int median = 0;
    private int medianMoved = 0;
    private int[] weightedLow = {40,65,80,90,95};
    private int[] weightedHigh = {5,15,30,55,95};
    private boolean highWeightMethod = true;

    public String getName() {
        return "KingFisher";
    }

    public int[] getMove(String [] args)
    {
        char[] mc  = args[0].toCharArray();
        char[] mg  = args[1].toCharArray();
        char[] oc  = args[3].toCharArray();
        char[] og  = args[4].toCharArray();
        int len = mc.length;
        int currentGuess = 0;
        int currentChoice = 0;
        if(len < 10)
            return new int[] {rnd.nextInt(6),rnd.nextInt(6)}; 
        int[] guessWeight = {0,0,0,0,0,0};
        int[] guessWeightTotal = {0,0,0,0,0,0};
        for(int a = 0; a< len;a++)
            guessWeight[oc[a]-48]++;
        if(!highWeightMethod){

            int[] whiteList = {1,1,1,1,1,1};
            for(int b = 0;b<3;b++){

                int min = 0;
                int max = 0;
                int minIndex = 0;
                int maxIndex = 0;
                for(int a = 0;a<6;a++){

                    if(whiteList[a] == 1){

                        min = guessWeight[a];
                        max = guessWeight[a];
                        minIndex = a;
                        maxIndex = a;
                        break;
                    }
                }

                for(int a = 0; a<6;a++){

                    if(whiteList[a] == 1){

                        if(guessWeight[a]<min){

                            min = guessWeight[a];
                            minIndex = a;
                        }
                        if(guessWeight[a]>max){

                            max = guessWeight[a];
                            maxIndex = a;
                        }
                    }
                }
                guessWeight[maxIndex] = min;
                guessWeight[minIndex] = max;
                whiteList[maxIndex] = 0;
                whiteList[minIndex] = 0;
            }
        }

        for(int a = 0; a< 6;a++)
            for(int b = 0; b<=a;b++)
                guessWeightTotal[a]+=guessWeight[b];
        int randInt = rnd.nextInt(guessWeightTotal[5]);
        for(int a = 0; a<6;a++){

            if(randInt < guessWeightTotal[a]){
                currentGuess = a;
                break;
            }
        }

        if(mg[len-1] == oc[len-1]){
            wins++;
            median++;
        }
        if(og[len-1] == mc[len-1]){
            loses++;
            median--;
        }
        if(median > 2){

            medianMoved++;
            median = 0;
        }
        if(median < -2){

            medianMoved--;
            median = 0;
        }

        randInt = rnd.nextInt(95);
        if((wins-medianMoved)>(loses+medianMoved)){

            for(int a = 0; a<6;a++){

                if(randInt < weightedLow[a]){
                    currentChoice = a;
                    break;
                }
            }
        }
        else{

            for(int a = 0; a<6;a++){

                if(randInt < weightedHigh[a]){
                    currentChoice = a;
                    break;
                }
            }
        }
        if(medianMoved < -5){

            highWeightMethod = !highWeightMethod;
            medianMoved = 0;
        }
        return new int[] {currentChoice,currentGuess}; 

    }
}

Этот парень состоит из алгоритмов плохого угадывания, которые в основном используют взвешенные массивы.

Vajura
источник
Будет в следующем обновлении.
PhiNotPi
1

Э-э-э Я знаю, о чем ты думаешь. "Он выберет пять или что-то еще?" Хорошо, чтобы сказать вам правду во всем этом волнении, я в чем-то не уверен, но так как это метод .44, самый мощный метод в мире, который сразу же перегружает ваш стек, вы должны задать себе один вопрос : "Чувствую ли я удачу?"

Что ж, панк?

public class DirtyHarry implements Player {

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

    @Override
    public int[] getMove(String[] args) {
        return new int[]{5, 5};
    }
}
Капитан человек
источник