Morra, trò chơi cao quý của các vị vua


28

Lý lịch

Trò chơi của Morra là một trò chơi đơn giản. Trong phiên bản "gốc", một số người chơi đồng thời ném số 0-5 bằng tay trong khi đoán tổng số bàn tay của mọi người. Phiên bản tôi sẽ sử dụng ở đây đã được sửa đổi để tăng tiềm năng cho chiến lược không tầm thường, và nó được mô tả dưới đây:

  • Có hai người chơi.
  • Giống như trong trò chơi kéo giấy bằng đá, người chơi di chuyển đồng thời.
  • Mỗi lượt, mỗi người chơi chọn một số 0-5 và cũng đoán đối thủ của họ chọn 0-5. Điều này có nghĩa là hai số được xuất ra mỗi lượt. Để làm rõ, cả hai đầu ra số phải nằm trong phạm vi 0-5, bao gồm.
  • Nếu bạn đoán đúng lựa chọn của đối thủ nhưng đối thủ của bạn không đoán đúng, bạn sẽ giành được một số điểm nhất định bằng tổng của hai số đã chơi. Ví dụ: nếu các số được chơi là 3 và 5, một dự đoán đúng sẽ có giá trị 8 điểm.
  • Nếu cả hai hoặc không người chơi đoán đúng, không có điểm nào được trao.
  • Người có nhiều điểm nhất sau 1000 vòng sẽ thắng trận đấu đó.

Giải đấu

Giải đấu sẽ được thực hiện theo kiểu vòng tròn và sẽ được điều hành bằng cách tạo ra từng cặp thí sinh có thể. Với mỗi chiến thắng, thí sinh đạt được 2 điểm chiến thắng. Mỗi trận đấu kết quả trong 1 điểm chiến thắng. Không có điểm chiến thắng có được cho một mất mát.

Theo trực giác, người chiến thắng của giải đấu sẽ là thí sinh có nhiều điểm chiến thắng nhất trước người khác.


Làm thế nào để nhập

Sẽ có hai phương pháp gửi bot để cạnh tranh. Phương thức đầu tiên và được ưa thích nhất là triển khai giao diện Java do bộ điều khiển cung cấp. Phương pháp thứ hai là viết một chương trình độc lập.

Trước tiên hãy bao quát phương thức Java. Giao diện bạn sẽ cần thực hiện là Playervà nó xác định hai phương thức: public String getName()xác định bot của bạn và public int[] getMove(String[] args)lấy argsnhư một mảng gồm sáu chuỗi , mychoices myguesses myscore opponentchoices opponentguesses opponentscore. Một ví dụ là như sau:

042 045 0 324 432 6

Điều này có nghĩa là tôi đã chọn 0 ở vòng đầu tiên và đoán rằng đối thủ của tôi sẽ ném 0. Đối thủ của tôi đã ném 3 và đoán tôi sẽ ném 4. Trong vòng thứ ba, đối thủ của tôi đã đoán đúng rằng tôi sẽ ném a 2, nghĩa là anh ta tăng 2 + 4 = 6 điểm.

Phương thức của bạn sẽ trả về một mảng gồm hai số nguyên, tương ứng là sự lựa chọn và đoán của bạn. Một ví dụ là {4,2}cho lựa chọn 4 và đoán 2.

Dưới đây là một ví dụ về bot Java hoàn chỉnh được viết dưới dạng phương thức. Nếu bạn muốn, bài nộp của bạn chỉ phải bao gồm những gì đang diễn ra trong getMovephương thức.

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

Là một chương trình độc lập

Tôi hiện đang bị hạn chế trong việc hỗ trợ các ngôn ngữ bổ sung. Ngoài Java, tôi có thể chấp nhận các chương trình được viết bằng Python 3.4, Perl 5 hoặc Ruby 2.1.5. Nếu có một ngôn ngữ mà nhiều người dường như muốn, tôi sẽ cố hết sức để thêm ngôn ngữ đó.

Đầu vào cho chương trình của bạn sẽ là đối số trên dòng lệnh. Nó có thể trông như thế này:

perl awesomebot.plx 042 045 0 324 432 6

Đầu ra của chương trình nên là lựa chọn của bạn theo sau là dự đoán của bạn, mỗi lần theo sau là khoảng trắng.

Vui lòng bao gồm trong câu trả lời của bạn lệnh chính xác cần thiết để chạy nó. Hãy nhớ rằng tôi đang chạy Windows 8.1.


Quy tắc bổ sung

Tiết kiệm trạng thái và thời gian chờ

Chương trình của bạn sẽ được phép tạo một tệp văn bản trong thư mục cục bộ, nơi bạn có thể lưu trữ thông tin. Thông tin này sẽ được giữ trong suốt giải đấu nhưng sau đó sẽ bị xóa. Đặt tên cho tập tin tôi có thể xác định.

Có giới hạn thời gian là 500 mili giây để mã của bạn phản hồi. Việc không đáp ứng trong thời hạn (hoặc đưa ra một động thái không hợp lệ) sẽ dẫn đến việc bị mất quyền đối với trận đấu cụ thể đó. Các bài nộp Java hiện có thời gian chờ thụ động (mà tôi có thể nâng cấp lên hoạt động), trong khi các bài nộp không phải Java có thời gian chờ hoạt động trong đó quá trình của chúng bị chấm dứt sau 500 mili giây.

Thêm quy tắc trình

  • Bạn được phép gửi nhiều lần, miễn là họ tuân thủ các quy tắc và không gắn thẻ nhóm.
  • Mỗi mục phải là duy nhất. Bạn không thể tạo một bản sao chính xác logic của bot khác bằng một ngôn ngữ khác.
  • Các bot không thể tương tác với nhau (để tạo thành một nhóm bất kỳ).
  • Bạn không thể sử dụng logic của các bot khác trong bot của mình để xác định đối thủ cạnh tranh và dự đoán hành động của nó. Tất nhiên, bạn có thể cố gắng xác định chiến lược của đối thủ.
  • Đừng cố gây rối với bộ điều khiển, các thí sinh khác hoặc máy tính của tôi. Đừng kết nối với các nguồn thông tin bên ngoài.

Bộ điều khiển

Phiên bản hiện tại của bộ điều khiển được tìm thấy ở đây . Nó được viết bằng Java 8. Tệp "Giải đấu" là bộ điều khiển chính, cũng chứa danh sách các đối thủ cạnh tranh (nếu bạn muốn tổ chức các cuộc thi của riêng bạn).


Bảng xếp hạng

Tôi thực sự không thể cập nhật bảng xếp hạng rất thường xuyên. Cuối tuần này tôi khá bận. Bởi "khá bận" Tôi có nghĩa là không có quyền truy cập vào máy tính từ 6:30 sáng đến 9:30 tối. Dưới đây là điểm số sau 5 lần chạy. Bot "Echo" bị tịch thu vì một số lý do (có thể là lỗi của tôi, tôi chưa điều tra).

  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          

tín dụng

Rất cám ơn Rainbolt và Peter Taylor đã giúp đỡ họ với bộ điều khiển.


1
@ MartinBüttner Ruby 2.1.5 đã được thêm vào.
PhiNotPi

Làm thế nào để vòng tròn hoạt động? Player1 vs Player2 1000 lần, Player1 vs Player3 1000 lần, v.v ... HOẶC là Player1 vs Player2 một lần rồi player1 vs player 3 một lần v.v ...
Vajura 12/2/2015

@Vajura Một giải đấu duy nhất bao gồm 1 trận chiến giữa mỗi cặp. Một trận chiến có 1000 vòng, với tổng số điểm cao nhất vào cuối trận chiến quyết định ai sẽ giành được hai điểm chiến thắng. Bảng điểm hiện tại cho thấy tổng số điểm chiến thắng sau 40 giải đấu.
PhiNotPi

Xin lỗi vì sự chậm trễ trong việc cập nhật bảng. Cuối tuần này tôi rất bận. Mong đợi và cập nhật tối nay và sáng mai.
PhiNotPi

Wow, tôi không mong đợi bot của tôi sẽ làm tốt như vậy! Ngoài ra, các con số có ý nghĩa gì với tập kết quả đầu tiên ... số lần thắng?
mbomb007

Câu trả lời:


17

Chuông Morra

Đối với bất cứ ai tìm kiếm ý nghĩa trong tên của bot này, tên Morra khiến tôi nghĩ về Space Italian , vì vậy tôi cho rằng tôi cần một cái tên chơi trên đó. Các ứng cử viên khác bao gồm Morra đánh lừa bạnMorra cho tôi .

Đây là một lớp đầy đủ thực hiện Playergiao diện. Giải thích bên dưới.

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

Giải trình

Tôi bắt đầu bằng cách phân tích các trò chơi với ít ngón tay hơn. Đơn giản không tầm thường đơn giản nhất cho phép các cuộc gọi của 0hoặc 1có bảng thanh toán sau (giá trị là mức chi trả cho trình phát hàng):

       (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

Các (0,0) chiến lược bị chi phối bởi (0,1), vì vậy chúng ta có thể giảm bớt bảng để

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

Bây giờ (1,0) chiến lược bị chi phối bởi (0,1), vì vậy chúng tôi có thể giảm thêm bảng xuống

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

Và bây giờ (1,1) bị chi phối bởi (0,1), vì vậy chúng tôi kết thúc với

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

Do đó luôn luôn chơi (0,1) là một điểm cân bằng Nash. Nhưng điều gây tò mò là nó không phải là người duy nhất. Đây là một trò chơi có tổng bằng không đối xứng, do đó, tỷ lệ hoàn trả dự kiến ​​là 0 và bất kỳ chiến lược hỗn hợp nào kết hợp (0,1)(1,0)nơi (0,1)được chọn ít nhất 50% thời gian đạt được số tiền đó. Vì vậy, chúng ta có một không gian cân bằng một chiều của Nash.

Có vẻ như là trường hợp, mặc dù tôi chưa chứng minh được điều đó, nhưng nMorra có mộtn đa giác hai chiều của cân bằng Nash là chiến lược hỗn hợp giữa các n+1 (pick, guess)cặp pick + guess = n.

Các số ma thuật trong đoạn mã trên mã hóa 32 đỉnh của đa giác 5 chiều của cân bằng Nash. Tôi đã tìm thấy chúng bằng cách thiết lập một thể hiện lập trình tuyến tính đại diện cho đa giác và sau đó sử dụng các hàm mục tiêu ngẫu nhiên. Lý do để mã hóa tất cả 32 thay vì chọn một đơn giản là: tỷ lệ hoàn trả dự kiến ​​là 0, vì vậy tôi cần phải làm tốt hơn mong đợi để có được một chiến thắng. Về cơ bản, tôi cho rằng người chơi khác đang sử dụng chiến lược hỗn hợp và ước tính phân phối dựa trên lịch sử chọn của họ. Sau đó, tôi chọn đỉnh đa giác để tối đa hóa mức tăng dự kiến ​​của tôi so với phân phối ước tính đó.

QuinnAndValor chứng minh lỗ hổng của giả định rằng người chơi khác đang sử dụng chiến lược hỗn hợp. Bằng cách phát hiện một người chơi sử dụng các chiến lược từ trạng thái cân bằng Nash, nó có thể chuyển sang chế độ đi bộ ngẫu nhiên trong đó, chơi chiến lược không cân bằng, trung bình có thể bị mất, nhưng chỉ cần giành được vị trí dẫn đầu một lần và sau đó nó có thể trở lại để chơi các cặp mà pick + guess = n. Vì vậy, cân bằng Nash cho một trò chơi duy nhất không khái quát hóa tầm thường với cân bằng Nash cho trò chơi lặp lại, cho phép các chiến lược phức tạp hơn.


4
Có thể là phép thuật của bạn chứa một phần của Hamming Numbers ? Nó chắc chắn không chứa tất cả chúng, nhưng nhiều ( hoặc tất cả? ) Trong số chúng có trong danh sách trên trang web đó.
GiantTree

@GiantTree, chúng đều là số Hamming. Quan sát thú vị.
Peter Taylor

Không có thắc mắc bot của bạn sẽ ham. : D
mbomb007

11

Quinn và Valor (Cập nhật)

Quinn và Valor là một đội kiểm lâm ưu tú. Với nỏ và móng vuốt, chúng xé toạc mọi đối thủ dám thách thức chúng.

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

Họ hầu như luôn giành chiến thắng trước tất cả các giải pháp Java trên máy của tôi.

Chỉnh sửa:

Tôi thừa nhận Quinn và Valor đã thất bại trong trận đấu với Nhà sử học, nhưng tôi vẫn có niềm tin tốt vào họ để giành chiến thắng trong giải đấu.

Nguyên tắc của tôi là, đối với bất kỳ giải pháp nào choice + guess == 5, cũng chơi với những choice + guess == 5người được cấp quyền giữ lợi thế của bạn.

Cập nhật:

Chà ... mọi thứ trở nên phức tạp.


1
Tôi thích tài liệu tham khảo Liên Minh Huyền Thoại. Tôi thực sự muốn làm một bot Teemo bây giờ. :)
mbomb007

6

Học giả

Học giả cố gắng học hỏi từ các bước di chuyển của đối thủ, chọn một người mà anh ta ít đoán và đoán người mà đối thủ của anh ta sử dụng nhiều nhất. Nhưng lý thuyết không phải là tất cả, vì vậy Học giả không làm tốt lắm ...

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

(Đã cập nhật để không sử dụng tệp và thêm phần mới. Cũng được sửa đổi để không còn bị kẹt trong phần đầu tiên.)

Bao gồm một vài chiến lược bắt đầu đơn giản và phức tạp hơn - nếu bạn xóa một chiến lược, nó sẽ chuyển bạn sang phần tiếp theo.

  • Mục 1: Đoán {0, 5}nhất quán
  • Mục 2: Kiểm tra xem 4 lần đoán cuối cùng của bạn có tạo thành một mẫu không đổi, tuyến tính hoặc bậc hai hay không và tiếp tục đoán mẫu cho đến khi nó bị hỏng
  • Mục 3: Kiểm tra xem bạn có đoán được số lượng thấp bất thường của một số nào đó (dưới 1/13) không và chọn số đó
  • Phần 4: Phân tích bigrams trong lựa chọn của bạn và xem xét những gì nhiều khả năng sẽ xuất hiện tiếp theo
  • Mục 5: Nhìn vào 100 vòng vừa qua và chọn(choice, guess) cặp có kỳ vọng tốt nhất, có trọng số để các vòng gần đây quan trọng hơn
  • Phần cuối cùng: Đoán ngẫu nhiên, khả năng có lựa chọn thấp và đoán cao hơn. Nếu bạn đến đây, thì DeltaMax đã từ bỏ và muốn nói, "trò chơi hay".

Để tìm ra chiến thuật nào đã được sử dụng cuối cùng, hãy bỏ qua

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

hàng.

Xin lỗi về Java khủng khiếp, tôi đã dành buổi chiều của mình để ghép các bit lại với nhau và học lại ngôn ngữ :)

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

Với việc triển khai bộ điều khiển hiện tại, không cần phải lưu mọi thứ trong một tệp nếu dữ liệu chỉ được sử dụng cho một trò chơi. tức private int strat;là đủ tốt
johnchen902

@ johnchen902 Cảm ơn, tôi đã không nhận ra mình có thể làm điều đó. Điều đó làm cho mọi thứ dễ dàng hơn nhiều.
Sp3000

6

Nhà sử học

(Đã cập nhật: cùng logic, mã ngắn hơn và nhanh hơn 100 lần nhưng bạn chỉ có thể sử dụng một bot Lịch sử tại một giải đấu.)

Sử dụng ngẫu nhiên có trọng số để chọn một cặp ném dựa trên hiệu quả của việc chỉ sử dụng cặp đó so với lịch sử trước đó của đối thủ. Các trọng số là bình phương có điểm số có thể đạt được.

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

Nhịp đập Quinn and Valor (không còn nữa) và thua Morra Cowbell. Trong giải đấu với hầu hết các bot Historianđến thứ hai Quinn and Valor.


Chà, thật tốt khi thấy tôi đã thắng trên máy của ai đó. Tôi đang mất ban lãnh đạo chính thức hiện tại . Tôi đã tự hỏi nó là do xui xẻo hoặc một số lỗi tinh vi không lường trước được.
johnchen902

@ johnchen902 Tôi phải bị ảo giác đập Morra Cowbell. Chỉnh sửa bài. Bạn có thể xóa bình luận mặc dù nếu chúng trở nên lỗi thời.
Randomra

Tôi nghĩ rằng tôi có thể giành được 75% cuộc đấu tay đôi của chúng tôi ngay sau khi cập nhật!
johnchen902

5

Phép ngoại suy (v1.1)

Phép ngoại suy cực đoan từ một trong những điểm cân bằng Nash của một trò chơi đơn giản hơn.

Tôi ủng hộ định dạng câu trả lời ngắn gọn! (Theo kiểu trăn.)

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

Có vẻ như buộc với Magic Cow (Morra Cowbell) và đánh bại các mục khác mà tôi đã kiểm tra.


1
Vui lòng di chuyển Random r sang trường tĩnh, do đó bạn không khởi tạo nó mỗi lần, điều này sẽ giúp hiệu suất tổng thể!
Falco

Tại sao sự thay đổi trong phân phối?
Peter Taylor

4

Hợp thời trang

Xu hướng nhìn vào những bước đi trong quá khứ của đối thủ, cân nhắc họ bằng cách ẩn dật. Đoán trọng lượng nặng nhất, và chọn một trong những thay đổi nhẹ từ đó. Nó ở đây trong tất cả ánh hào quang của nó:

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

Điều duy nhất tôi có thể so sánh với bây giờ là Cowbell. Nó bị mất bởi một phần nhỏ trong phần lớn thời gian, nhưng xuất hiện trên đầu thường đủ cho sở thích của tôi. Chúng ta sẽ thấy nó làm như thế nào với nhiều đối thủ cạnh tranh hơn.


7
Bạn có thể vui lòng định dạng mã lên nhiều dòng? Đây không phải là mã golf ...
mbomb007

7
@ mbomb007 Nó chiếm ít không gian theo cách này. Một trong những khó khăn của KotH nói chung là tất cả các cuộn để xem các mục. Tôi đã mô tả những gì nó làm, và nó rất đơn giản cho các bên quan tâm định dạng nó.
Geobits

4

Đoán ngẫu nhiên

Điều này thực sự đơn giản. Nó có hiệu quả cuộn d6 và thêm một cuộn nữa vào cuộn trước để đoán. Nó sẽ không thắng, nhưng nó sẽ cung cấp một điểm chuẩn tốt.

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

Bối rối, Python 3

Một mục phức tạp không cần thiết. Ngay cả tôi cũng không biết nó làm gì.

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

Mặc dù thuật toán tiên tiến này dường như hoạt động kém hơn ngẫu nhiên trong giải đấu này và sử dụng bộ nhớ và thời gian chạy đáng kể, nhưng nó có kết quả tuyệt vời cho các giá trị nhất định là 5 ;-)


4

Mưa rào

Có sự khác biệt giữa hai số cuối mà đối thủ của chúng tôi đoán, thêm vào đó là lần đoán mới nhất của đối thủ, tìm ra mô-đun và tránh chọn số đó bằng mọi giá. Ví dụ: nếu bạn đoán {5,4,3} (giảm một) thì chúng tôi sẽ tránh chọn 2 bằng mọi giá.

Lấy sự khác biệt giữa hai số cuối mà đối thủ của chúng tôi đã chọn, thêm số đó vào lựa chọn mới nhất của đối thủ và đoán số đó. Ví dụ: nếu bạn đoán {1,4,5,2} (tăng gấp ba lần) thì chúng tôi sẽ đoán 5.

Tránh vô nghĩa hoặc rất gần với cuộn vô nghĩa.

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

Đừng làm cho getMove()phương thức của bạn tĩnh. Bạn không thể thực hiện một phương thức không tĩnh như thế (ít nhất là không có trong Java 8).
GiantTree

@GiantTree Cảm ơn bạn đã nắm bắt điều đó.
Rainbolt

3

Bot tiến hóa

Tôi đã phát triển bot này để trở thành bot dựa trên ngẫu nhiên tốt nhất.

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

Mức độ phổ biến, Python 3

Tính toán dựa trên những con số phổ biến được sử dụng trong quá khứ của đối thủ. Những con số được sử dụng gần đây có trọng lượng hơn. Sự lựa chọn số thường giống như dự đoán.

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

Bộ nội suy

(Chuyển sang Java vì Python gây ra sự cố)

Sử dụng phép nội suy đa thức trên 10 lựa chọn đối thủ gần nhất để tìm ra số tiếp theo của đối thủ, sau đó thực hiện tương tự với các lựa chọn của chính nó và tránh chọn số đó. Ngoài ra, Bộ nội suy có một chút sai lệch so với việc chọn 0 hoặc 5 và sự lựa chọn của nó đôi khi bị ảnh hưởng bởi dự đoán của nó:

  • Nếu nó đoán 0 nó sẽ không bao giờ chọn 0
  • Nếu nó đoán 5, nó sẽ luôn chọn 0 hoặc 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

Không truy cập bất cứ ai mà thay vào đó đếm từ 0-5 trong một vòng tròn ( 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

Basilisk, Python

Theo truyền thuyết, The Basilisk là vua của các con rắn. ( nguồn ) Tôi đoán rằng đó là một tên thích hợp cho một bot chơi "Trò chơi cao quý của các vị vua" và được viết bằng trăn. = D Bot này tấn công nỗi sợ vào trái tim của các bot khác và gây ra cái chết chỉ bằng một cái liếc mắt.

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)

Điều này chạy trên một chiến lược khá đơn giản. Tôi không hy vọng nó sẽ thắng, nhưng thật vui khi viết. Đây cũng là thử thách KoTH đầu tiên của tôi, vì vậy tôi rất phấn khích khi thấy nó hoạt động tốt như thế nào.

Làm thế nào nó chọn di chuyển tiếp theo của nó.

Basilisk luôn thực hiện động tác mà đối thủ của mình đã đoán được số lần ít nhất. Trong trường hợp hòa, anh ta sẽ chọn số nhỏ hơn. (để giảm thiểu số điểm của đối thủ.)

Làm thế nào nó chọn dự đoán tiếp theo của nó.

Basilisk sẽ chọn phản hồi có khả năng nhất cho dự đoán trước đó của nó. Ví dụ: Nếu lần trước, nó đoán được 3, nó sẽ quay lại tất cả các lần trước đó mà nó đã đoán được 3, và sau đó trả lại động tác đối thủ phổ biến nhất xuất hiện sau khi đoán 3. Trong trường hợp hòa , nó sẽ chọn số lớn hơn (để tối đa hóa số điểm có thể đạt được.)

Trên một lưu ý kỹ thuật, điều này sẽ chạy chính xác? In () có đủ không, hay tôi nên sử dụng cái gì đó như sys.stdout.write () như các Pythonistas khác đã làm?


sys.stdout.write () hoạt động trong cả Python. print () chỉ hoạt động trong Python 3. Mặc dù vậy cũng không sao.
TheNumberOne

Không, print () hoạt động ở một trong hai, tôi chắc chắn về điều đó. Dấu ngoặc đơn là tùy chọn trong 2.x
DJMcMayhem

Theo đó , họ làm việc khác nhau. Tuy nhiên, cách bạn sử dụng nó, nó không thành vấn đề.
TheNumberOne

Nhưng điều đó có làm nên sự khác biệt nào không?
DJMcMayhem

Rõ ràng là không.
TheNumberOne

2

Như trên

Điều này biến thành đối thủ, nhưng đằng sau bởi một phỏng đoán / lựa chọn.

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

Luôn ném 0 để giảm thiểu bất kỳ chiến thắng của đối thủ. Nếu đối thủ từng đoán số của tôi, họ chỉ kiếm được những gì họ đã ném.

Luôn luôn đoán 5 để tối đa hóa tiền thắng cược của tôi. Vì tôi không thể nhận được bất kỳ điểm nào từ cú ném của mình, tôi muốn nhận được càng nhiều từ đối thủ. Tôi có thể đoán ngẫu nhiên, nhưng đâu là niềm vui trong đó?

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

Tôi đoán bot này sẽ làm rất khủng khiếp. Bất kỳ bot nào sử dụng tỷ lệ cược thậm chí có thể nhận được mọi dự đoán ngay sau lần đầu tiên.
mbomb007

@ mbomb007 Tuy nhiên, đó không phải là điều tồi tệ nhất! Mặc dù nó hoạt động kém hơn RandomBot của bạn.
Brian J

1

Erratica, Java

Không tuyệt vời, nhưng ban đầu nó được thiết kế chủ yếu là ngẫu nhiên, cho đến khi giá trị của sự đánh đổi xuất hiện ở tôi. Quản lý để mất liên tục so với 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

Tiếng vọng, 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]

Chơi lần cuối cùng mà đối thủ thực hiện, trên lý thuyết rằng bất kỳ ai cũng có thể tạo ra một bot mà họ không thể dự đoán được. Đoán dựa trên giá trị kỳ vọng bằng cách sử dụng một mẫu di chuyển hàng trăm.


Tôi đang gặp lỗi này: echo.rb:3:in <main> ': phương thức không xác định size' for nil:NilClass (NoMethodError). Nó dường như chỉ xảy ra ở vòng đầu tiên, khi không có lịch sử di chuyển.
PhiNotPi

Kì lạ, đã không xảy ra khi tôi thử nghiệm. Tôi sẽ chỉnh sửa.
lịch sử

Sự liên quan của if (mychoices.size > 990 && myscore == '0') nextchoice = rand(1..5)một phần là gì?
ngẫu nhiên 16/2/2015

Nếu nó sắp kết thúc bằng một trận đấu không cân sức (ví dụ như sẽ xảy ra với chính nó), thì nó bắt đầu chơi ngẫu nhiên, vì ~ 50% cơ hội chiến thắng là tốt hơn không có gì.
lịch sử

1

CÂU CÁ

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

    }
}

Anh chàng này bao gồm các thuật toán đoán xấu sử dụng mảng trọng số là chủ yếu.


Sẽ có trong bản cập nhật tiếp theo.
PhiNotPi

1

Ừm Tôi biết bạn đang nghĩ gì. "Anh ta sẽ chọn năm hay cái gì khác?" Vâng để nói với bạn sự thật trong tất cả sự phấn khích này Tôi không chắc mình, nhưng đây là Phương pháp .44, phương pháp mạnh nhất trên thế giới và sẽ làm quá tải ngăn xếp của bạn ngay lập tức, bạn phải tự hỏi mình một câu hỏi : "Tôi có cảm thấy may mắn không?"

Vâng, làm ya, punk?

public class DirtyHarry implements Player {

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

    @Override
    public int[] getMove(String[] args) {
        return new int[]{5, 5};
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.