Морра, благородна гра королів


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. У третьому раунді мій опонент зробив правильну здогадку, що я кину a 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. Файл "Турнір" є основним контролером, який також містить список учасників (якщо ви хочете влаштувати власні змагання).


Таблиця лідерів

Мені не вдалося дуже часто оновлювати таблицю лідерів. Я досить зайнятий цими вихідними. Під "досить зайнятим" я маю на увазі відсутність доступу до комп'ютера з 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          

Кредит

Велике спасибі Рейнболту та Пітеру Тейлору за допомогу з контролером.


1
@ MartinBüttner Ruby додано 2.1.5.
PhiNotPi

Як працює кругла робіна? Player1 - Player2 1000 разів, Player1 - Player3 - 1000 разів і т.д. ... А чи це Player1 - проти Player2 - один раз, потім player1 - проти гравця - 3 рази тощо
Vajura

@Vajura Один турнір складається з 1 битви між кожною парою. Один бій має 1000 раундів, причому найбільший загальний бал в кінці бою визначає, хто отримує дві очки перемоги. Поточне табло показує загальну кількість очок перемоги після 40 турнірів.
PhiNotPi

Вибачте за затримки з оновленням плати. Я надзвичайно зайнятий у ці вихідні. Очікуйте та оновіть сьогодні та завтра вранці.
PhiNotPi

Нічого собі, я не очікував, що мій бот зробить це так добре! Також, що означають цифри під першим набором результатів ... кількість виграшів?
mbomb007

Відповіді:


17

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

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

Це повний клас, що реалізує 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грантодавцями, зберігаючи свою перевагу.

Оновлення:

Ну ... все просто ускладнилося.


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

6

DeltaMax

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

Складається з декількох стратегій, які починаються простими, а потім стають складнішими - якщо ви очистите її, вона перейде до наступного розділу.

  • Розділ 1: Вгадайте {0, 5}послідовно
  • Розділ 2: Перевірте, чи останні ваші здогадки утворюють постійний, лінійний або квадратичний візерунок і продовжуйте вгадувати шаблон, поки він не зламається
  • Розділ 3: Перевірте, чи не здогадуєтесь ви про аномально низьку кількість якоїсь кількості (менше 1/13) та виберіть це число
  • Розділ 4: Проаналізуйте біграми у виборі та подивіться, що більше шансів вийти далі
  • Розділ 5: Подивіться на останні 100 раундів і виберіть (choice, guess)пару, яка б найкраще очікувала, зваживши так, що останні раунди є важливішими
  • Підсумковий розділ: Вгадайте випадковим чином, з більшою ймовірністю мати низький вибір і високі здогади. Якщо ви потрапили сюди, тоді DeltaMax відмовився і хотів би сказати "хороша гра".

Щоб дізнатися, який прошарок був використаний, врешті-решт, відмініть коментар

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

рядок.

Вибачте за жахливу Яву, я провів у другій половині дня, забираючи шматочки разом і вивчаючи мову :)

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

При поточній реалізації контролера немає необхідності зберігати речі у файлі, якщо дані використовуються лише для однієї гри. тобто private int strat;досить хороший
johnchen902

@ johnchen902 Спасибі, я не розумів, що можу це зробити. Це значно спрощує справи.
Sp3000

6

Історик

(Оновлено: така ж логіка, коротший код і в 100 разів швидше, але ви можете використовувати лише одного бота-історика на турнірі.)

Використовує зважений випадковий вибір для вибору пари відгадок на основі ефективності використання лише цієї пари проти опонентів попередньої історії. Ваги - це квадрати від досяжних балів.

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.


Що ж, добре бачити, що я переміг на чиїйсь машині. Я програю нинішню офіційну лідерську раду. Мені було цікаво, що це через нещастя чи якусь непередбачувану тонку помилку.
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}; } }

Здається, зв’язується з Чарівною коровою (Морра Каубл) і б’є інші записи, які я перевірив.


1
Перемістіть випадковий r у статичне поле, щоб ви не ініціалізували його кожен раз, це допоможе загальній продуктивності!
Фалько

Чому зміна розподілу?
Пітер Тейлор

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

Єдине, з чим я можу порівняти це зараз, - Каубл. Більшу частину часу вона втрачає невеликий запас, але виходить на вершині досить часто, як мені подобається. Ми побачимо, як це робиться з більшою кількістю конкурентів.


7
Чи можете ви відформатувати код на кілька рядків? Це не код гольфу ...
mbomb007

7
@ mbomb007 Цей спосіб займає менше місця. Один з болів KotHs взагалі - це все прокручування, щоб переглянути записи. Я описав, що це робить, і зацікавленим сторонам це дуже просто відформатувати.
Геобіт

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

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

Не робіть свій 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};
    }
}

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

2

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

За легендою, Василіск - цар змій. ( джерело ) Я зрозумів, що це відповідне ім’я для бота, який грає "The Noble Game Of Kings" і написаний пітоном. = 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. У разі вирівнювання , він вибере більшу кількість (щоб збільшити кількість балів, які він міг би зробити).

На технічну примітку, чи буде це працювати правильно? Чи достатньо друку (), чи я повинен використовувати щось на зразок sys.stdout.write (), як це робили інші Pythonistas?


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

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

Ерратіка, Ява

Не чудово, але спочатку він був розроблений, щоб бути здебільшого випадковим, поки цінність компромісу не вискочила у мене. Вдається втрачати послідовно проти 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;
    }
}

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]

Відтворює останню гру, яку робив противник, на теорії про те, що кожен може скласти бота, якого він не може передбачити. Відгадування, засновані на вартості очікування, використовуючи зразок сто-ходу.


Я отримую цю помилку: echo.rb:3:in <main> ': undefined method size' for nil:NilClass (NoMethodError). Здається, це відбувається лише на першому раунді, коли історії пересування немає.
PhiNotPi

Як це не сталося, коли я тестував. Я відредагую.
гістократ

Яка актуальність if (mychoices.size > 990 && myscore == '0') nextchoice = rand(1..5)частини?
randomra

Якщо він ось-ось закінчиться безрезультатним рахунком (як це станеться, наприклад, проти себе), він починає грати випадковим чином, оскільки ~ 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}; 

    }
}

Цей хлопець складається з алгоритмів поганого відгадування, які використовують переважно зважені масиви.


Буде в наступному оновлення.
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};
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.