Morra, szlachetna gra królów


28

tło

Gra Morra jest prostą grą. W „oryginalnej” wersji kilku graczy jednocześnie wyrzuca z rąk liczbę 0-5, zgadując całkowitą sumę rąk wszystkich. Wersja, której użyję tutaj, została zmodyfikowana w celu zwiększenia potencjału nietrywialnej strategii i została opisana poniżej:

  • Jest dwóch graczy.
  • Podobnie jak w papierowych nożyczkach, gracze poruszają się jednocześnie.
  • W każdej turze każdy gracz wybiera liczbę 0-5, a także zgaduje wybór przeciwnika 0-5. Oznacza to, że w każdej turze wyprowadzane są dwie liczby. Aby wyjaśnić, dane wyjściowe obu liczb powinny zawierać się w przedziale 0–5 włącznie.
  • Jeśli poprawnie odgadniesz wybór przeciwnika, ale przeciwnik nie zgadł poprawnie, wygrywasz określoną liczbę punktów równą sumie dwóch rozegranych liczb. Na przykład, jeśli rozegrane liczby to 3 i 5, prawidłowe odgadnięcie byłoby warte 8 punktów.
  • Jeśli obaj lub żaden z graczy nie zgadnie poprawnie, nie przyznaje się punktów.
  • Osoba z największą liczbą punktów po 1000 rundach wygrywa tę grę.

Turniej

Turniej zostanie przeprowadzony w stylu robota okrągłego i będzie prowadzony przez utworzenie każdej możliwej pary zawodnika. Za każde zwycięstwo uczestnik otrzymuje 2 punkty zwycięstwa. Każdy remis daje 1 punkt zwycięstwa. Przegrana nie daje żadnych punktów zwycięstwa.

Intuicyjnie zwycięzcą turnieju będzie zawodnik z największą liczbą punktów zwycięstwa nad innymi.


Jak wejść

Będą dwie metody zgłaszania botów do rywalizacji. Pierwszą i bardzo preferowaną metodą jest implementacja interfejsu Java dostarczanego przez kontroler. Drugą metodą jest napisanie niezależnego programu.

Najpierw omówmy metodę Java. Interfejs trzeba będzie wdrożyć to Playeri to definiuje dwie metody: public String getName()identyfikuje bot, i public int[] getMove(String[] args)trwa argsjako tablica sześciu strun, mychoices myguesses myscore opponentchoices opponentguesses opponentscore. Przykład jest następujący:

042 045 0 324 432 6

Oznacza to, że wybrałem 0 w pierwszej rundzie i zgadywałem, że mój przeciwnik rzuci 0. Mój przeciwnik rzucił 3 i domyśliłem się, że rzuci 4. W trzeciej rundzie mój przeciwnik poprawnie zgadywał, że rzuciłem 2, co oznacza, że ​​zyskuje 2 + 4 = 6 punktów.

Twoja metoda zwróci tablicę dwóch liczb całkowitych, które są odpowiednio twoim wyborem i zgadnij. Przykładem jest {4,2}wybór 4 i zgadywanie 2.

Oto przykład kompletnego bota Java napisanego jako metoda. Jeśli chcesz, Twoje zgłoszenie musi zawierać tylko to, co dzieje się w getMovemetodzie.

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

Jako niezależny program

Obecnie mam ograniczone wsparcie dla dodatkowych języków. Poza Javą mogę akceptować programy napisane w Python 3.4, Perl 5 lub Ruby 2.1.5. Jeśli istnieje język, który wydaje się być potrzebny kilku osobom, dołożę wszelkich starań, aby go dodać.

Dane wejściowe do programu będą argumentami w wierszu poleceń. Może to wyglądać tak:

perl awesomebot.plx 042 045 0 324 432 6

Wyjście twojego programu powinno być twoim wyborem, a następnie zgadnięciem, a po każdym spacją.

Podaj w odpowiedzi dokładne polecenie potrzebne do jego uruchomienia. Pamiętaj, że korzystam z systemu Windows 8.1.


Dodatkowe zasady

Saving State and Timeouts

Twój program będzie mógł utworzyć jeden plik tekstowy w katalogu lokalnym, w którym możesz przechowywać informacje. Informacje te będą przechowywane przez cały turniej, ale zostaną później usunięte. Nadaj plikowi nazwę, którą mogę zidentyfikować.

Kod ma limit czasowy 500 milisekund na odpowiedź. Brak odpowiedzi w wyznaczonym terminie (lub udzielenie nieprawidłowego ruchu) spowoduje przepadek tego konkretnego meczu. Zgłoszenia Java mają obecnie pasywny limit czasu (który mogę uaktualnić do aktywnego), podczas gdy zgłoszenia inne niż Java mają aktywny limit czasu, w którym ich proces kończy się po 500 milisekundach.

Więcej zasad składania

  • Dozwolone jest wielokrotne przesyłanie, o ile są one zgodne z zasadami i nie tagują zespołu.
  • Każdy wpis musi być unikalny. Nie można wykonać dokładnej kopii logiki innego bota w innym języku.
  • Boty nie mogą ze sobą wchodzić w interakcje (w celu utworzenia jakiegokolwiek zespołu).
  • Nie możesz użyć logiki innych botów wewnątrz bota, aby, powiedzmy, zidentyfikować konkurenta i przewidzieć jego działania. Możesz oczywiście spróbować ustalić strategię przeciwnika.
  • Nie próbuj zadzierać z kontrolerem, innymi uczestnikami lub moim komputerem. Nie łącz się z zewnętrznymi źródłami informacji.

Kontroler

Aktualna wersja kontrolera znajduje się tutaj . Jest napisany w Javie 8. Plik „Tournament” jest głównym kontrolerem, który zawiera również listę zawodników (jeśli chcesz organizować własne zawody).


Tabela liderów

Tak naprawdę nie byłem w stanie często aktualizować tabeli wyników. Jestem raczej zajęty w ten weekend. Przez „raczej zajęty” mam na myśli brak dostępu do komputera od 6:30 do 21:30. Oto wyniki po 5 biegach. Bot „Echo” z jakiegoś powodu wciąż przepadał (być może to moja wina, jeszcze nie zbadałem).

  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          

Kredyt

Ogromne podziękowania dla Rainbolt i Petera Taylora za pomoc w obsłudze kontrolera.


1
@ MartinBüttner Ruby 2.1.5 został dodany.
PhiNotPi

Jak działa okrągły robin? Gracz1 kontra Gracz2 1000 razy, Gracz1 vs Gracz3 1000 razy itp. LUB to jest Gracz1 vs Gracz2 raz, a następnie Gracz1 kontra gracz 3 raz itd.
Vajura

@Vajura Pojedynczy turniej składa się z 1 bitwy między każdą parą. Jedna bitwa ma 1000 rund, a najwyższy łączny wynik na końcu bitwy decyduje o tym, kto otrzyma dwa punkty zwycięstwa. Aktualna tabela wyników pokazuje całkowitą liczbę punktów zwycięstwa po 40 turniejach.
PhiNotPi

Przepraszamy za opóźnienia w aktualizacji forum. Jestem bardzo zajęty w ten weekend. Oczekuj i aktualizuj dziś wieczorem i jutro rano.
PhiNotPi

Wow, nie spodziewałem się, że mój bot tak dobrze sobie poradzi! Co też oznaczają liczby przez pierwszy zestaw wyników ... liczba wygranych?
mbomb007

Odpowiedzi:


17

Morra Cowbell

Dla każdego, kto szuka znaczenia w nazwie tego bota, nazwa Morra kojarzy mi się z kosmicznym włoskim , więc pomyślałem, że potrzebuję nazwy, która się na nim gra. Inni kandydaci to Morra oszukać ciebie i Morrę za mnie .

Jest to pełna klasa implementująca Playerinterfejs. Objaśnienie poniżej.

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

Wyjaśnienie

Zacząłem od analizy gier z mniejszą liczbą palców. Najprostszy nietrywialny pozwala na wywołania 0lub 1ma następującą tabelę wypłat (wartości są wypłatą dla gracza rzędowego):

       (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)Strategia dominuje (0,1), więc możemy zmniejszyć tabelę

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

Teraz (1,0)strategia jest zdominowana przez (0,1), więc możemy jeszcze bardziej zredukować stół do

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

A teraz (1,1)jest zdominowany przez (0,1), więc kończymy

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

Dlatego zawsze granie (0,1)jest równowagą Nasha. Ale ciekawe jest to, że nie jest to jedyny. To symetryczne gry sumie zerowej, tak więc oczekiwano wypłata jest 0, a każda mieszana strategii łączenia (0,1)i (1,0)w której (0,1)jest zbierany w co najmniej 50% czasu, to osiąga wypłat. Mamy więc jednowymiarową przestrzeń równowagi Nasha.

Wydaje się, że tak jest, chociaż nie udowodniłem tego, że n-wysyłka Morra ma wielowymiarowy politop nrównowag Nasha, które są mieszanymi strategiami między n+1 (pick, guess)parami, dla których pick + guess = n.

Liczby magiczne w powyższym kodzie kodują 32 wierzchołki 5-wymiarowego politopu równowag Nasha. Znalazłem je, ustawiając instancję programowania liniowego, która reprezentowała polytop, a następnie używając losowych funkcji celu. Powód kodowania wszystkich 32 zamiast wybierania jednego jest prosty: oczekiwana wypłata wynosi 0, więc muszę zrobić lepiej niż się spodziewałem, aby wygrać. Zasadniczo zakładam, że drugi gracz stosuje mieszaną strategię i szacuję dystrybucję na podstawie historii wyboru. Następnie wybieram wierzchołek polytopa, który maksymalizuje moje oczekiwane wzmocnienie w stosunku do tego szacowanego rozkładu.

QuinnAndValor pokazuje podatność założenia, że ​​drugi gracz stosuje strategię mieszaną. Po wykryciu gracza, który korzysta ze strategii z równowag Nasha, jest w stanie przejść do trybu losowego chodzenia, w którym grając w strategię nierównowagi, może przegrać, ale musi zdobyć przewagę tylko raz może powrócić do par gry, dla których pick + guess = n. Tak więc równowaga Nasha dla pojedynczej gry nie uogólnia na równowagę Nasha dla powtarzanej gry, co pozwala na bardziej złożone strategie.


4
Czy to możliwe, że twoja magia zawiera część liczb Hamminga ? Z pewnością nie zawiera ich wszystkich, ale wiele z nich ( lub wszystkie? ) Znajduje się na liście na tej stronie.
GiantTree

@GiantTree, wszystkie są liczbami Hamminga. Ciekawa obserwacja.
Peter Taylor

Nic dziwnego, że twój bot idzie na szynkę. : D
mbomb007

11

Quinn and Valor (zaktualizowany)

Quinn i Valor to elitarna drużyna zwiadowcza. Kuszą i pazurami rozdzierają każdego przeciwnika, który ma odwagę rzucić mu wyzwanie.

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

Prawie zawsze wygrywają ze wszystkimi rozwiązaniami Java na moim komputerze.

Edytować:

Przyznaję, że Quinn i Valor nie zdążyli pojedynkować się z Historianem, ale nadal wierzę w nie, aby wygrać turniej.

Moją zasadą jest, aby w przypadku każdego rozwiązania choice + guess == 5również bawić się z choice + guess == 5beneficjentami zachowującymi przewagę.

Aktualizacja:

Cóż ... wszystko się skomplikowało.


1
Lubię referencje do League of Legends. Naprawdę chcę teraz stworzyć bota Teemo. :)
mbomb007

6

Uczony

Uczony próbuje uczyć się na podstawie ruchów swojego przeciwnika, wybierając ten, którego jego przeciwnik mniej zgadł, i domyślając się tego, którego jego przeciwnik najczęściej używał. Ale teoria to nie wszystko, więc Scholar nie radzi sobie zbyt dobrze ...

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

(Zaktualizowano, aby nie używać plików i dodano nową sekcję. Zmodyfikowano również, aby nie blokować wiązania w pierwszej sekcji).

Składa się z kilku strategii, które zaczynają się od prostych, a następnie stają się bardziej złożone - jeśli wyczyścisz jedną, spowoduje to przejście do następnej sekcji.

  • Część 1: Zgadnij {0, 5}konsekwentnie
  • Część 2: Sprawdź, czy twoje ostatnie 4 domysły tworzą stały, liniowy lub kwadratowy wzór i zgaduj wzór, aż się zepsuje
  • Część 3: Sprawdź, czy zgadujesz nienormalnie małą liczbę (mniej niż 1/13) i wybierz tę liczbę
  • Część 4: Przeanalizuj wybrane opcje i sprawdź, co będzie bardziej prawdopodobne
  • Część 5: Spójrz na ostatnie 100 rund i wybierz (choice, guess)parę, która miałaby najlepsze oczekiwania, ważona tak, aby ostatnie rundy były ważniejsze
  • Część końcowa: Zgadnij losowo, z większym prawdopodobieństwem niskich wyborów i wysokich przypuszczeń. Jeśli się tu dostaniesz, DeltaMax się poddał i chciałby powiedzieć „dobra gra”.

Aby dowiedzieć się, która warstwa została użyta na końcu, odkomentuj

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

linia.

Przepraszam za okropną Javę, spędziłem popołudnie składając kawałki i ucząc się języka :)

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

Przy obecnej implementacji kontrolera nie ma potrzeby zapisywania rzeczy w pliku, jeśli dane są używane tylko dla jednej gry. tj. private int strat;jest wystarczająco dobry.
johnchen902

@ johnchen902 Dzięki, nie zdawałem sobie sprawy, że mogę to zrobić. To sprawia, że ​​jest o wiele łatwiej.
Sp3000,

6

Historyk

(Zaktualizowano: ta sama logika, krótszy kod i 100 razy szybszy, ale w turnieju można użyć tylko jednego bota Historian.)

Używa ważonej losowo, aby wybrać parę zgadywania rzutów na podstawie skuteczności użycia tylko tej pary przeciwko poprzedniej historii przeciwników. Wagi są kwadratami osiągalnych wyników.

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

Bije Quinn and Valor (już nie) i przegrywa Morra Cowbell. W turnieju z większością botów Historianjest na drugim miejscu Quinn and Valor.


Dobrze jest widzieć, że wygrałem na czyjejś maszynie. Tracę obecną oficjalną tablicę liderów. Zastanawiałem się, czy to z powodu pecha lub nieprzewidzianych subtelnych błędów.
johnchen902

@ johnchen902 Musiałem mieć halucynacje Morra Cowbell. Edytowałem post. Możesz usunąć komentarze, jeśli staną się nieaktualne.
randomra

Myślę, że po aktualizacji mogę wygrać 75% naszego pojedynku!
johnchen902

5

Ekstrapolator (v1.1)

Ekstremalna ekstrapolacja z jednej z równowag Nasha w prostszej grze.

Obsługuję zwięzły format odpowiedzi! (W stylu python.)

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

Wydaje się wiązać z Magic Cow (Morra Cowbell) i bije inne wpisy, które sprawdziłem.


1
Proszę przenieść Random r do pola statycznego, aby nie inicjować go za każdym razem, to poprawi ogólną wydajność!
Falco

Dlaczego zmiana w dystrybucji?
Peter Taylor,

4

Modny

Trendy przygląda się wcześniejszym ruchom przeciwnika, ważąc je według aktualności. Zgaduje najcięższy i wybiera jeden, który nieznacznie się podniósł. Oto w pełnej krasie:

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

Jedyne, co mogę teraz z tym porównać, to Cowbell. Traci przez większość czasu niewielkim marginesem, ale dość często wychodzi mi na wierzch. Zobaczymy, jak to działa z większą liczbą konkurentów.


7
Czy możesz sformatować kod w wielu wierszach? To nie jest kod golfowy ...
mbomb007 11.02.15

7
@ mbomb007 W ten sposób zajmuje mniej miejsca. Jedną z bolączek KotHs jest przewijanie, aby przejrzeć wpisy. Opisałem, co robi, i bardzo łatwo jest go sformatować dla zainteresowanych stron.
Geobity

4

Random Guesser

To jest naprawdę proste. Skutecznie rzuca k6 i zgaduje, że dodaje kolejny rzut do poprzedniego rzutu. Nie wygra, ale zapewni dobry poziom odniesienia.

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

Zmieszany, Python 3

Niepotrzebnie skomplikowany wpis. Nawet ja nie wiem co to robi.

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

Chociaż ten zaawansowany algorytm wydaje się działać gorzej niż losowo w tym turnieju i zużywa znaczną pamięć i czas wykonywania, ma oszałamiające wyniki dla niektórych wartości 5 ;-)


4

Rainbolt

Uwzględnia różnicę między dwiema ostatnimi liczbami, które odgadł nasz przeciwnik, dodaje, że do najnowszej odpowiedzi naszego przeciwnika, znajduje moduł i unika wyboru tej liczby za wszelką cenę. Na przykład, jeśli zgadniesz {5,4,3} (zmniejszając się o jeden), unikalibyśmy wyboru 2 za wszelką cenę.

Uwzględnia różnicę między dwoma ostatnimi liczbami, które wybrał nasz przeciwnik, dodaje to do ostatniego wyboru naszego przeciwnika i zgaduje tę liczbę. Na przykład, jeśli zgadniesz {1,4,5,2} (wzrost o trzy), zgadniemy 5.

Unika bezcelowych lub bardzo blisko bezcelowych rzutów.

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

Nie zmieniaj getMove()metody na statyczną. Nie można zaimplementować takiej metody niestatycznej (przynajmniej nie w Javie 8).
GiantTree

@GiantTree Dzięki za złapanie tego.
Rainbolt

3

Evolved Bot

Ewoluowałem tego bota, aby był najlepszym botem opartym na losowości.

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

Popularność, Python 3

Oblicz zgadywanie na podstawie popularnych liczb używanych w przeszłości przez przeciwnika. Ostatnio używane liczby mają większą wagę. Wybór liczb jest często taki sam jak przypuszczenie.

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

Interpolator

(Przełączono na Javę, ponieważ Python powodował problemy)

Używa interpolacji wielomianowej dla ostatnich 10 wyborów przeciwnika, aby obliczyć kolejny numer przeciwnika, a następnie robi to samo z własnymi wyborami i unika wybierania tej liczby. Interpolator ma również niewielkie uprzedzenie do wyboru 0 lub 5, a jego wybór czasami zależy od zgadywania:

  • Jeśli zgadnie 0, nigdy nie wybierze 0
  • Jeśli zgadnie 5, zawsze wybierze 0 lub 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

Nie przeciwdziała nikomu, ale liczy od 0 do 5 w okręgu ( 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

Bazyliszek, Python

Według legendy Bazyliszek jest królem węży. ( źródło ) Uznałem, że to odpowiednia nazwa dla bota, który gra w „Noble Game Of Kings” i jest napisany w pythonie. = D Ten bot wywołuje strach w sercu innych botów i powoduje śmierć jednym spojrzeniem.

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)

Działa to na dość prostej strategii. Nie oczekuję, że wygra, ale pisanie było fajne. To także moje pierwsze wyzwanie KoTH, więc jestem podekscytowany tym, jak dobrze sobie radzi.

Jak wybiera następny ruch.

Bazyliszek zawsze wykonuje ruch, który jego przeciwnik odgadł najmniej razy. W przypadku remisu wybierze mniejszą liczbę. (aby zminimalizować liczbę punktów przeciwnika).

Jak wybiera następną zgadywankę.

Bazyliszek wybierze najbardziej prawdopodobną odpowiedź na swoje poprzednie przypuszczenia. Na przykład, jeśli ostatnim razem odgadł 3, wróci do wszystkich poprzednich czasów, w których odgadł 3, a następnie zwróci najczęstszy ruch przeciwnika, który pojawia się po odgadnięciu 3. W przypadku remisu , wybierze większą liczbę (aby zmaksymalizować liczbę punktów, które mógłby zdobyć).

Czy w informacji technicznej będzie to działało poprawnie? Czy print () jest wystarczające, czy powinienem użyć czegoś takiego jak sys.stdout.write (), tak jak zrobiły to inne Pythonisty?


sys.stdout.write () działa w dowolnym języku Python. print () działa tylko w Pythonie 3. Powinno być w porządku.
TheNumberOne

Nie, print () działa w obu, jestem tego pewien. Nawiasy są opcjonalne w wersji 2.x
DJMcMayhem

Zgodnie z tym działają one inaczej. Jednak sposób korzystania z niego nie ma znaczenia.
TheNumberOne

Ale czy to robi różnicę?
DJMcMayhem

Najwyraźniej nie.
TheNumberOne

2

Tak samo

To zamienia się w przeciwnika, ale z tyłu jednym zgadywaniem / wyborem.

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

Zawsze rzuca 0, aby zminimalizować wygrane przeciwnika. Jeśli przeciwnik kiedykolwiek zgadnie mój numer, zarabia tylko tyle, ile rzucił.

Zawsze zgaduję 5, aby zmaksymalizować moje wygrane. Ponieważ nie mogę zdobyć żadnych punktów z rzutu, chcę zdobyć jak najwięcej od przeciwnika. Mogłem losowo zgadywać, ale gdzie jest w tym zabawa?

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

Zgaduję, że ten bot zrobi strasznie. Każdy bot korzystający z kursów może nawet zgadnie za każdym razem.
mbomb007

@ mbomb007 Nie jest to jednak najgorsze! Chociaż działa gorzej niż Twój RandomBot.
Brian J

1

Erratica, Java

Nie wspaniale, ale pierwotnie został zaprojektowany tak, aby był w większości losowy, dopóki nie spadła na mnie wartość kompromisu. Konsekwentnie przegrywa z 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

Echo, Ruby

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]

Odtwarza ostatnią grę przeciwnika, na podstawie teorii, że każdy może stworzyć bota, którego nie jest w stanie przewidzieć. Domysły oparte na wartości oczekiwanej przy użyciu próbki o stu ruchach.


Otrzymuję ten błąd: echo.rb:3:in <główna> ': niezdefiniowana metoda size' for nil:NilClass (NoMethodError). Wydaje się, że występuje tylko w pierwszej rundzie, gdy nie ma historii ruchów.
PhiNotPi

Dziwne, nie zdarzyło się, kiedy testowałem. Będę edytować.
histocrat

Jakie jest znaczenie tej if (mychoices.size > 990 && myscore == '0') nextchoice = rand(1..5)części?
randomra

Jeśli niedługo skończy się remisem bez gola (jak by się to zdarzyło na przykład przeciwko sobie), zaczyna grać losowo, ponieważ ~ 50% szans na wygraną jest lepsze niż nic.
histocrat

1

KING FISHER

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

    }
}

Ten facet składa się ze złych algorytmów zgadywania, które używają głównie tablic ważonych.


Będzie w następnej aktualizacji.
PhiNotPi

1

Uh Wiem, o czym myślisz. „Czy wybierze pięć czy coś innego?” Cóż, prawdę mówiąc, w całym tym podekscytowaniu sam nie jestem pewien, ale ponieważ jest to metoda .44, najsilniejsza metoda na świecie i od razu przeciążałaby twój stos, musisz zadać sobie jedno pytanie : „Czy mam szczęście?”

Cóż, punk?

public class DirtyHarry implements Player {

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

    @Override
    public int[] getMove(String[] args) {
        return new int[]{5, 5};
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.