Morra, Game Raja Mulia

28

Latar Belakang

Game Morra adalah game sederhana. Dalam versi "asli", beberapa pemain secara bersamaan membuang angka 0-5 dengan tangan mereka sambil menebak jumlah total tangan semua orang. Versi yang akan saya gunakan di sini telah dimodifikasi untuk meningkatkan potensi strategi non-sepele, dan dijelaskan di bawah ini:

  • Ada dua pemain.
  • Seperti di gunting batu-kertas, para pemain bergerak secara bersamaan.
  • Setiap belokan, setiap pemain memilih angka 0-5 dan juga menebak pilihan lawan mereka 0-5. Ini berarti bahwa dua angka adalah output setiap belokan. Untuk memperjelas, kedua angka keluaran harus dalam kisaran 0-5, inklusif.
  • Jika Anda menebak pilihan lawan dengan benar tetapi lawan Anda tidak menebak dengan benar, Anda memenangkan sejumlah poin yang sama dengan jumlah dari dua angka yang dimainkan. Misalnya, jika angka yang dimainkan adalah 3 dan 5, tebakan yang benar akan bernilai 8 poin.
  • Jika kedua atau kedua pemain menebak dengan benar, tidak ada poin yang diberikan.
  • Orang dengan poin terbanyak setelah 1000 putaran memenangkan permainan itu.

Turnamen

Turnamen akan dilakukan dengan gaya round-robin dan akan dijalankan dengan menciptakan setiap pasangan yang memungkinkan dari kontestan. Untuk setiap kemenangan, kontestan memperoleh 2 poin kemenangan. Setiap pertandingan menghasilkan 1 poin kemenangan. Tidak ada poin kemenangan yang diperoleh karena kekalahan.

Secara intuitif, pemenang turnamen adalah kontestan dengan poin kemenangan terbanyak melawan yang lain.


Cara Masuk

Akan ada dua metode pengiriman bot untuk bersaing. Metode pertama, dan banyak disukai, adalah untuk mengimplementasikan antarmuka Java yang disediakan oleh pengontrol. Metode kedua adalah menulis program independen.

Mari kita bahas metode Java terlebih dahulu. Antarmuka Anda akan perlu untuk mengimplementasikan adalah Playerdan mendefinisikan dua metode: public String getName()mengidentifikasi bot Anda, dan public int[] getMove(String[] args)mengambil argssebagai array dari enam senar, mychoices myguesses myscore opponentchoices opponentguesses opponentscore. Contohnya adalah sebagai berikut:

042 045 0 324 432 6

Ini berarti bahwa saya memilih 0 pada ronde pertama dan menebak bahwa lawan saya akan melempar 0. Lawan saya melempar 3 dan menebak saya akan melempar 4. Pada ronde ketiga, lawan saya membuat tebakan yang benar bahwa saya akan melempar a 2, artinya dia mendapatkan 2 + 4 = 6 poin.

Metode Anda akan mengembalikan array dua bilangan bulat, yang merupakan pilihan dan tebakan Anda masing-masing. Contohnya adalah {4,2}untuk pilihan 4 dan menebak 2.

Berikut adalah contoh bot Java lengkap yang ditulis sebagai metode. Jika Anda mau, kiriman Anda hanya perlu memasukkan apa yang ada di dalam getMovemetode.

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

Sebagai Program Independen

Saat ini saya terbatas dalam mendukung bahasa tambahan. Selain Java, saya dapat menerima program yang ditulis dalam Python 3.4, Perl 5, atau Ruby 2.1.5. Jika ada bahasa yang tampaknya diinginkan beberapa orang, saya akan berusaha sebaik mungkin untuk menambahkannya.

Input ke program Anda akan menjadi argumen di baris perintah. Itu bisa terlihat seperti ini:

perl awesomebot.plx 042 045 0 324 432 6

Output dari program Anda harus menjadi pilihan Anda diikuti oleh tebakan Anda, masing-masing diikuti oleh spasi.

Harap sertakan dalam jawaban Anda perintah tepat yang diperlukan untuk menjalankannya. Ingatlah bahwa saya menjalankan Windows 8.1.


Aturan Ekstra

Menyimpan Status dan Timeout

Program Anda akan diizinkan untuk membuat satu file teks di direktori lokal, tempat Anda dapat menyimpan informasi. Informasi ini akan disimpan sepanjang turnamen tetapi dihapus setelahnya. Beri nama file yang bisa saya identifikasi.

Ada batas waktu 500 milidetik untuk kode Anda merespons. Kegagalan untuk merespons dalam batas waktu (atau memberikan langkah yang tidak valid) akan mengakibatkan kehilangan pertandingan tersebut. Pengiriman Java saat ini memiliki batas waktu pasif (yang saya dapat tingkatkan ke aktif), sedangkan pengiriman non-Jawa memiliki batas waktu aktif di mana proses mereka dihentikan setelah 500 milidetik.

Lebih banyak aturan pengiriman

  • Anda diizinkan beberapa kali kiriman, asalkan mematuhi aturan dan tidak memberi tag tim.
  • Setiap entri harus unik. Anda tidak dapat membuat salinan persis dari logika bot lain dalam bahasa yang berbeda.
  • Bot tidak dapat berinteraksi satu sama lain (untuk membentuk tim apa pun).
  • Anda tidak dapat menggunakan logika bot lain di dalam bot Anda untuk, katakanlah, mengidentifikasi pesaing Anda dan memprediksi tindakannya. Anda bisa, tentu saja, mencoba menentukan strategi lawan Anda.
  • Jangan berusaha mengacaukan controller, kontestan lain, atau komputer saya. Jangan terhubung ke sumber informasi eksternal.

Pengendali

Versi pengontrol saat ini ditemukan di sini . Ini ditulis dalam Java 8. File "Tournament" adalah pengontrol utama, yang juga berisi daftar pesaing (jika Anda ingin meng-host kompetisi Anda sendiri).


Papan peringkat

Saya belum benar-benar dapat memperbarui papan peringkat sangat sering. Saya agak sibuk akhir pekan ini. Dengan "agak sibuk" Maksudku tidak ada akses ke komputer dari 6:30 pagi hingga 9:30 malam. Berikut adalah skor setelah 5 kali berjalan. Bot "Echo" terus hangus karena suatu alasan (mungkin salah saya, saya belum menyelidiki).

  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          

Kredit

Banyak terima kasih kepada Rainbolt dan Peter Taylor untuk bantuan mereka dengan controller.

PhiNotPi
sumber
1
@ MartinBüttner Ruby 2.1.5 telah ditambahkan.
PhiNotPi
Bagaimana cara kerja round robin? Player1 vs Player2 1000 kali, Player1 vs Player3 1000 kali dll ... ATAU apakah itu Player1 vs Player2 sekali maka player1 vs pemain 3 sekali dll ...
Vajura
@ Vajura Sebuah turnamen tunggal terdiri dari 1 pertarungan antara masing-masing pasangan. Satu pertempuran memiliki 1000 putaran, dengan skor total tertinggi di akhir pertempuran menentukan siapa yang mendapatkan dua poin kemenangan. Papan skor saat ini menunjukkan total poin kemenangan setelah 40 turnamen.
PhiNotPi
Maaf atas keterlambatan memperbarui papan. Saya sangat sibuk akhir pekan ini. Harapkan dan perbarui malam ini dan besok pagi.
PhiNotPi
Wow, saya tidak berharap bot saya bekerja dengan baik! Juga, apa arti angka-angka dengan set hasil pertama ... jumlah kemenangan?
mbomb007

Jawaban:

17

Morra Cowbell

Bagi siapa pun yang mencari arti penting dalam nama bot ini, nama Morra membuat saya berpikir tentang Space Italian , jadi saya rasa saya membutuhkan nama yang dimainkan pada itu. Kandidat lain termasuk Morra menipu Anda dan Morra untuk saya .

Ini adalah kelas penuh yang mengimplementasikan Playerantarmuka. Penjelasan di bawah ini.

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

Penjelasan

Saya mulai dengan menganalisis game dengan lebih sedikit jari. Yang non-sepele yang paling sederhana memungkinkan panggilan 0atau 1dan memiliki tabel hadiah berikut (nilai adalah hadiah untuk pemain baris):

       (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

The (0,0)Strategi didominasi oleh (0,1), sehingga kita dapat mengurangi meja untuk

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

Sekarang (1,0)strategi didominasi oleh (0,1), sehingga kita dapat mengurangi tabel

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

Dan sekarang (1,1)didominasi oleh (0,1), jadi kita berakhir dengan

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

Karena itu selalu bermain (0,1)adalah keseimbangan Nash. Tetapi yang aneh adalah bahwa itu bukan satu-satunya. Ini adalah permainan zero-sum simetris, jadi hadiah yang diharapkan adalah 0, dan setiap strategi campuran digabungkan (0,1)dan di (1,0)mana (0,1)diambil setidaknya 50% dari waktu mencapai hasil itu. Jadi kita memiliki ruang satu dimensi dari kesetimbangan Nash.

Tampaknya memang demikian, meskipun saya belum membuktikannya, bahwa njari kaki Morra memiliki npolytope -dimensional Nash equilibria yang merupakan strategi campuran antara n+1 (pick, guess)pasangan - pasangan yang dengannya pick + guess = n.

Angka-angka ajaib dalam kode di atas mengkodekan 32 simpul dari 5-dimensi polytope dari Nash equilibria. Saya menemukan mereka dengan membuat contoh pemrograman linier yang mewakili polytope dan kemudian menggunakan fungsi objektif acak. Alasan untuk meng-encode semua 32 daripada memilih satu adalah sederhana: hasil yang diharapkan adalah 0, jadi saya harus melakukan lebih baik dari yang diharapkan untuk mendapatkan kemenangan. Saya pada dasarnya berasumsi bahwa pemain lain menggunakan strategi campuran dan memperkirakan distribusi berdasarkan riwayat pilihan mereka. Kemudian saya memilih vertex polytope yang memaksimalkan keuntungan yang saya harapkan terhadap perkiraan distribusi.

QuinnAndValor menunjukkan kerentanan asumsi bahwa pemain lain menggunakan strategi campuran. Dengan mendeteksi seorang pemain yang menggunakan strategi dari Nash equilibria, ia dapat beralih ke mode jalan acak di mana, dengan memainkan strategi non-ekuilibrium, rata-rata kemungkinan ia akan kalah, tetapi ia hanya perlu mendapatkan petunjuk sekali dan kemudian itu dapat kembali ke pasangan bermain yang pick + guess = n. Jadi ekuilibria Nash untuk satu game tidak bisa digeneralisasi secara sepele ke ekuilibria Nash untuk game berulang, yang memungkinkan strategi yang lebih kompleks.

Peter Taylor
sumber
4
Mungkinkah sihirmu mengandung bagian dari Nomor Hamming ? Tentu saja tidak mengandung semuanya, tetapi banyak ( atau semua? ) Dari mereka ada dalam daftar di situs web itu.
GiantTree
@GiantTree, mereka semua nomor Hamming. Pengamatan menarik.
Peter Taylor
Tidak heran bot Anda akan ham. : D
mbomb007
11

Quinn dan Valor (Diperbarui)

Quinn dan Valor adalah tim ranger elit. Dengan panah dan cakar, mereka merobek setiap lawan yang berani menantang mereka.

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

Mereka hampir selalu menang melawan semua solusi Java di mesin saya.

Edit:

Saya akui Quinn dan Valor gagal duel Sejarawan, tetapi saya masih memiliki itikad baik untuk memenangkan turnamen.

Prinsip saya adalah, untuk solusi apa pun choice + guess == 5, juga bermain dengan choice + guess == 5penerima untuk menjaga keuntungan Anda.

Memperbarui:

Yah ... semuanya jadi rumit.

johnchen902
sumber
1
Saya suka referensi League of Legends. Saya benar-benar ingin membuat bot Teemo sekarang. :)
mbomb007
6

Sarjana

Cendekia mencoba belajar dari gerakan lawannya, memilih yang lawannya tidak bisa ditebak dan menebak yang lawannya paling banyak digunakan. Tapi teori bukanlah segalanya, jadi Cendekiawan tidak melakukan dengan sangat baik ...

import java.util.HashMap;

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

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

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

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

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

DeltaMax

(Diperbarui untuk tidak menggunakan file dan menambahkan bagian baru. Juga dimodifikasi untuk tidak lagi macet mengikat di bagian pertama.)

Terdiri dari beberapa strategi yang mulai sederhana kemudian menjadi lebih kompleks - jika Anda menghapus satu, itu memindahkan Anda ke bagian berikutnya.

  • Bagian 1: Tebak {0, 5}secara konsisten
  • Bagian 2: Periksa apakah 4 tebakan terakhir Anda membentuk pola konstan, linier, atau kuadratik dan terus tebak pola itu sampai rusak
  • Bagian 3: Periksa apakah Anda menebak sejumlah angka yang rendah dan abnormal (kurang dari 1/13) dan pilih nomor itu
  • Bagian 4: Analisis bigrams dalam pilihan Anda dan lihat apa yang lebih mungkin terjadi selanjutnya
  • Bagian 5: Lihatlah 100 putaran terakhir dan pilih (choice, guess)pasangan yang akan memiliki harapan terbaik, tertimbang sehingga putaran terakhir lebih penting
  • Bagian akhir: Tebak secara acak, dengan kemungkinan lebih tinggi untuk memiliki pilihan rendah dan tebakan tinggi. Jika Anda sampai di sini, maka DeltaMax telah menyerah dan ingin mengatakan, "permainan bagus".

Untuk mengetahui strategi yang digunakan pada akhirnya, batalkan komentar pada

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

baris.

Permintaan maaf untuk Jawa yang mengerikan, saya menghabiskan sore saya mengumpulkan bit bersama dan belajar kembali bahasa :)

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

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

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

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

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

        return ints;
    }

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

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

       int rounds = myChoices.length;

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

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

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

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

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

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

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

           strat = 300;
       }

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

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

           int minCount = rounds;

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

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

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

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

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

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

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

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

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

               int maxIndex = -1;
               int maxScore = 0;

               int minIndex = -1;
               int minScore = rounds;

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

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

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

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

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

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

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

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

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

       // Section final - hope for the best
       int num = (int) Math.floor(Math.sqrt(r.nextInt(35)));
       return new int[] {5 - num, num};
    }
}
Sp3000
sumber
Dengan implementasi controller saat ini, tidak perlu menyimpan hal-hal dalam file jika data hanya digunakan untuk satu game. yaitu private int strat;cukup baik.
johnchen902
@ johnchen902 Terima kasih, saya tidak sadar saya bisa melakukan itu. Itu membuat banyak hal lebih mudah.
Sp3000
6

Sejarawan

(Diperbarui: logika yang sama, kode lebih pendek dan 100 kali lebih cepat tetapi Anda hanya dapat menggunakan satu bot Sejarawan di sebuah turnamen.)

Menggunakan pembobotan acak untuk memilih pasangan lemparan-tebak berdasarkan efektivitas hanya menggunakan pasangan itu terhadap sejarah lawan sebelumnya. Bobot adalah kuadrat dari skor yang dapat dicapai.

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

Ketukan Quinn and Valor (tidak lagi) dan kalah Morra Cowbell. Dalam turnamen dengan sebagian besar bot Historiandatang kedua Quinn and Valor.

randomra
sumber
Yah, senang melihat saya menang di mesin seseorang. Saya kehilangan papan pemimpin resmi saat ini . Saya bertanya-tanya itu karena nasib buruk atau beberapa bug halus yang tak terduga.
johnchen902
@ johnchen902 Saya pasti pemukulan halusinasi Morra Cowbell. Mengedit pos. Anda dapat menghapus komentar jika itu menjadi usang.
randomra
Saya pikir saya bisa memenangkan 75% dari duel kami sekarang setelah pembaruan saya!
johnchen902
5

Extrapolator (v1.1)

Ekstrapolasi ekstrem dari salah satu kesetimbangan Nash dari permainan yang lebih sederhana.

Saya mendukung format jawaban singkat! (Dalam gaya 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}; } }

Tampaknya terikat dengan Sapi Sihir (Morra Cowbell) dan mengalahkan entri lain yang saya periksa.

randomra
sumber
1
Harap pindahkan Random r ke bidang statis, jadi Anda tidak menginisialisasi setiap kali, ini akan membantu kinerja secara keseluruhan!
Falco
Mengapa terjadi perubahan distribusi?
Peter Taylor
4

Trendi

Trendy melihat gerakan masa lalu lawan, menimbangnya dengan kebaruan. Menebak yang paling berat, dan mengambil satu bergeser sedikit dari itu. Ini dia, dengan segala kemuliaan:

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

Satu-satunya hal yang dapat saya bandingkan dengan sekarang adalah Cowbell. Sebagian besar waktu hilang dengan margin kecil, tetapi muncul di atas cukup sering sesuai dengan keinginan saya. Kita akan lihat bagaimana hasilnya dengan lebih banyak pesaing.

Geobit
sumber
7
Bisakah Anda memformat kode ke beberapa baris? Ini bukan kode golf ...
mbomb007
7
@ mbomb007 Butuh lebih sedikit ruang dengan cara ini. Salah satu rasa sakit KotH secara umum adalah semua bergulir untuk melihat entri. Saya telah menjelaskan apa yang dilakukannya, dan sangat mudah bagi pihak yang berminat untuk memformatnya.
Geobits
4

Tebak Acak

Ini sangat mudah. Ini secara efektif menggulung d6, dan menambahkan gulungan lain ke gulungan sebelumnya untuk tebakannya. Itu tidak akan menang, tetapi itu akan memberikan tolok ukur yang bagus.

import java.util.Random;

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

    public int[] getMove(String[] args) {
        return new int[] { rnd.nextInt(6), rnd.nextInt(6) };
    }
}
mbomb007
sumber
4

Bingung, Python 3

Entri rumit yang tidak perlu. Bahkan saya tidak tahu apa fungsinya.

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

Meskipun algoritme canggih ini tampaknya berkinerja lebih buruk daripada acak di turnamen ini, dan menggunakan memori dan run-time yang signifikan, namun hasilnya menakjubkan untuk nilai 5 ;-)

Ksatria Logika
sumber
4

Rainbolt

Membawa perbedaan antara dua angka terakhir yang ditebak lawan kami, menambahkannya ke tebakan terbaru lawan kami, menemukan modulus, dan menghindari memilih nomor itu dengan cara apa pun. Misalnya, jika Anda menebak {5,4,3} (berkurang satu) maka kami akan menghindari memilih 2 di semua biaya.

Membawa perbedaan antara dua angka terakhir yang dipilih lawan kita, menambahkannya ke pilihan terakhir lawan kita, dan menebak angka itu. Misalnya, jika Anda menebak {1,4,5,2} (bertambah tiga kali lipat) maka kami akan menebak 5.

Menghindari roll yang tidak berguna atau sangat dekat.

public class Rainbolt implements Player {

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

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

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

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

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

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

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

    private static int rollRandom() {
        return (int) (Math.random() * 6);
    }
}
Rainbolt
sumber
Jangan buat getMove()metode Anda statis. Anda tidak dapat menerapkan metode non-statis seperti itu (setidaknya tidak di Java 8).
GiantTree
@GTiTree Terima kasih sudah menangkapnya.
Rainbolt
3

Bot Berkembang

Saya mengembangkan bot ini menjadi bot berbasis acak terbaik.

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

}
TheNumberOne
sumber
3

Popularitas, Python 3

Hitung tebakan berdasarkan angka populer yang digunakan di masa lalu oleh lawan. Angka yang digunakan baru-baru ini memiliki bobot lebih. Pilihan angka seringkali sama dengan tebakan.

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))
Ksatria Logika
sumber
3

Interpolator

(Beralih ke Java sejak Python menyebabkan masalah)

Gunakan interpolasi polinomial pada 10 pilihan lawan terakhir untuk mencari tahu nomor lawan berikutnya, kemudian lakukan hal yang sama dengan pilihannya sendiri dan hindari memilih nomor itu. Selain itu, Interpolator memiliki sedikit bias terhadap pemilihan 0 atau 5, dan pilihannya terkadang dipengaruhi oleh tebakannya:

  • Jika menebak 0 maka tidak akan pernah memilih 0
  • Jika menebak 5 maka akan selalu memilih 0 atau 1
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

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

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

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

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

        return ints;
    }

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

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

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

        if (allEqual) {
            return nums[0];

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

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

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

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

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

        return tailArray;
    }

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

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

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

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

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

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

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

        return new int[] {choice, guess};
    }
}
Sp3000
sumber
3

CounterBot

Tidak melawan siapa pun melainkan menghitung melalui 0-5 dalam lingkaran ( 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4 ...)

import java.util.Random;

public class Counter implements Player {

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

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

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

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

Basilisk, Python

Menurut legenda, The Basilisk adalah raja ular. ( sumber ) Saya pikir itu nama yang tepat untuk bot yang memainkan "The Noble Game Of Kings" dan ditulis dengan python. = D Bot ini menyerang ketakutan ke jantung bot lain, dan menyebabkan kematian dengan sekali pandang.

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)

Ini berjalan pada strategi yang cukup sederhana. Saya tidak berharap untuk menang, tapi itu menyenangkan untuk ditulis. Ini juga tantangan KoTH pertama saya, jadi saya senang melihat seberapa baik kinerjanya.

Bagaimana ia mengambil langkah selanjutnya.

Basilisk selalu melakukan langkah yang paling tidak bisa ditebak lawannya. Dalam kasus dasi, ia akan memilih nomor yang lebih kecil. (untuk meminimalkan jumlah poin lawan.)

Bagaimana ia mengambil tebakan berikutnya.

Basilisk akan memilih respons yang paling mungkin untuk perkiraan sebelumnya. Misalnya, Jika terakhir kali, ia menebak 3, ia akan kembali melalui semua waktu sebelumnya bahwa ia telah menebak 3, dan kemudian mengembalikan gerakan lawan paling umum yang muncul setelah tebakan 3. Dalam kasus seri , ia akan memilih jumlah yang lebih besar (untuk memaksimalkan jumlah poin yang bisa dihasilkannya.)

Pada catatan teknis, apakah ini akan berjalan dengan benar? Apakah print () cukup, atau haruskah saya menggunakan sesuatu seperti sys.stdout.write () seperti yang dilakukan oleh Pythonista lainnya?

DJMcMayhem
sumber
sys.stdout.write () bekerja dengan Python. print () hanya berfungsi di Python 3. Seharusnya tidak apa-apa.
TheNumberOne
Tidak, print () berfungsi baik, saya yakin itu. Tanda kurung adalah opsional dalam 2.x
DJMcMayhem
Menurut ini , mereka bekerja secara berbeda. Namun, cara Anda menggunakannya, tidak masalah.
TheNumberOne
Tetapi apakah itu membuat perbedaan?
DJMcMayhem
Sepertinya tidak.
TheNumberOne
2

Dito

Ini berubah menjadi lawan, tetapi dibelakang dengan satu tebakan / pilihan.

import java.util.Random;

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

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

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

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

NullifierBot, Java

Selalu melempar 0 untuk meminimalkan kemenangan lawan. Jika lawan pernah menebak nomor saya, mereka hanya mendapatkan apa yang mereka lemparkan.

Selalu tebak 5 untuk memaksimalkan kemenangan saya. Karena saya tidak bisa mendapatkan poin dari lemparan saya, saya ingin mendapatkan banyak dari lawan. Saya bisa menebak secara acak, tapi di mana kesenangannya?

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}; 
    }
}
Brian J
sumber
Saya menduga bot ini akan sangat buruk. Bot apa pun yang menggunakan peluang bahkan mungkin akan mendapatkan setiap tebakan tunggal setelah yang pertama.
mbomb007
@ mbomb007 Tapi ini bukan yang terburuk! Meskipun kinerjanya lebih buruk daripada RandomBot Anda.
Brian J
1

Erratica, Jawa

Tidak hebat, tetapi pada awalnya dirancang untuk sebagian besar acak, sampai nilai tukar muncul pada saya. Berhasil kehilangan secara konsisten vs. Counter Bot> _ <

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

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

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

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

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

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

    private static int[] toIntArray(String arg) {
        int[] result = new int[arg.length()];
        for (int i = 0; i < arg.length(); i++)
            result[i] = Character.getNumericValue(arg.charAt(i));
        return result;
    }
}
Fongoid
sumber
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]

Mainkan drama terakhir yang dibuat lawan, berdasarkan teori bahwa siapa pun dapat membuat bot yang tidak dapat mereka prediksi. Tebakan berdasarkan nilai ekspektasi menggunakan sampel seratus langkah.

histokrat
sumber
Saya mendapatkan kesalahan ini: echo.rb:3:in <main> ': metode yang tidak ditentukan size' for nil:NilClass (NoMethodError). Tampaknya hanya terjadi di babak pertama, ketika tidak ada riwayat bergerak.
PhiNotPi
Aneh, tidak terjadi ketika saya menguji. Saya akan mengedit.
histokrat
Apa relevansi if (mychoices.size > 990 && myscore == '0') nextchoice = rand(1..5)bagian itu?
randomra
Jika itu akan berakhir dengan seri tanpa gol (seperti yang akan terjadi, misalnya, melawan dirinya sendiri), itu mulai bermain secara acak, karena ~ 50% kemungkinan menang lebih baik daripada tidak sama sekali.
histokrat
1

RAJA NELAYAN

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

    }
}

Orang ini terdiri dari alghoritma tebakan buruk yang kebanyakan menggunakan array berbobot.

Vajura
sumber
Akan di pembaruan berikutnya.
PhiNotPi
1

Uh uh. Saya tahu apa yang Anda pikirkan. "Apakah dia akan memilih lima atau yang lain?" Ya, sejujurnya dalam semua kegembiraan ini, saya agak tidak yakin, tetapi karena ini adalah metode .44, metode yang paling kuat di dunia dan akan membebani tumpukan Anda dengan segera, Anda harus bertanya pada diri sendiri satu pertanyaan : "Apakah saya merasa beruntung?"

Nah, lakukan ya, punk?

public class DirtyHarry implements Player {

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

    @Override
    public int[] getMove(String[] args) {
        return new int[]{5, 5};
    }
}
Kapten Man
sumber