Phân tích cờ vua với thông tin hạn chế


19

Trong thử thách này, bạn được cung cấp một lượng thông tin hạn chế về một ván cờ cụ thể và bạn cần dự đoán ai là người chiến thắng trò chơi .

Bạn được cung cấp hai bộ dữ liệu:

  1. Đếm từng mảnh (Những mảnh vẫn còn sống)
  2. Màu bảng (Màu của miếng trên bảng)

Quan trọng hơn, bạn không biết các mảnh được đặt ở đâu . Bạn cần xác định người mà bạn nghĩ sẽ giành chiến thắng.

Các trò chơi được chọn từ tất cả các sự kiện được liệt kê trên PGNMentor từ năm 2010 đến nay. Tôi đã chọn 10% tất cả các vị trí trên bảng từ mỗi trò chơi kết thúc bằng một trận thắng hoặc thua. Vị trí ban sẽ luôn có ít nhất 30 bước vào trò chơi. Các trường hợp thử nghiệm có thể được tìm thấy ở đây . (Chiến thắng trắng được liệt kê đầu tiên, tiếp theo là chiến thắng đen)

Đầu vào

Số lượng mảnh sẽ là một chuỗi bao gồm một ký tự cho mỗi mảnh: king, queen, rook, k night, bishop hoặc pawn. Chữ thường có nghĩa là màu đen, chữ hoa màu trắng. Bảng sẽ là một chuỗi gồm 64 ký tự (8 hàng 8 cột). Bđại diện cho một mảnh màu đen, Wđại diện cho một mảnh màu trắng và .đại diện cho một điểm trống. Mẫu vật:

W..WB......W.BB....W..B..W.WWBBB..W...B....W..BBWWW...BB.W....B.,BBKPPPPPPPQRRbbkpppppppqrr

sẽ đại diện cho hội đồng sau

...B.BB.
.BBBBBBB
.B.B....
B..W....
WWWW.W..
....W.W.
...W..WW
W.....W.

và nơi cả hai màu sắc có 2 Giám mục, 1 Vua, 7 Chân, 1 Nữ hoàng, 2 Rooks

Đầu ra

Bạn cần trả về số có dấu phẩy động trong khoảng từ 0 đến 1 (đã bao gồm) để xác định khả năng chiến thắng trắng đó có khả năng như thế nào. Mẫu vật:

0.3     (30% chance that white wins)

Thêm chi tiết:

  • Mỗi trường hợp kiểm tra có giá trị 1 điểm. Điểm của bạn sẽ là 1 - (1-Output)^2nếu trắng thắng, hoặc 1 - (Output)^2nếu đen thắng.
  • Điểm cuối cùng của bạn sẽ là tổng của tất cả các trường hợp kiểm tra.
  • Nếu tôi cảm thấy rằng các bài nộp đang mã hóa đầu vào, tôi có quyền thay đổi các trường hợp kiểm tra. (Nếu tôi thay đổi chúng, chúng sẽ có hàm băm SHA-256 893be4425529f40bb9a0a7632f7a268a087ea00b0eb68293d6c599c6c671cdee)
  • Chương trình của bạn phải chạy các trường hợp thử nghiệm một cách độc lập. Không lưu thông tin từ một trường hợp thử nghiệm tiếp theo.
  • Nếu bạn đang sử dụng học máy, tôi khuyên bạn nên đào tạo 80% dữ liệu đầu tiên và kiểm tra bằng 20% ​​còn lại . (Hoặc bất cứ tỷ lệ phần trăm bạn sử dụng). Tôi sử dụng các trò chơi nhiều lần trong dữ liệu, nhưng tôi đặt các trò chơi giống nhau theo tuần tự.
  • CẬP NHẬT: Tôi đã thêm hơn một triệu trường hợp thử nghiệm cho mục đích thử nghiệm và học tập. Chúng được chia thành các phần màu đen và trắng vì giới hạn kích thước repo github.

Chúc may mắn và vui vẻ!


Cuộc trò chuyện này đã được chuyển sang trò chuyện .
Dennis

Các trường hợp thử nghiệm mới có chứa các trường hợp cũ, hoặc hai bộ tách rời nhau không?
Gây tử vong vào

Tôi không có ý kiến. Tôi đã nhận được chúng từ các trang web khác nhau, vì vậy có thể cả hai đều bao gồm cùng một bộ trò chơi.
Nathan Merrill

Câu trả lời:


8

Java 8 + Weka, 6413 điểm, 94,5%

Câu trả lời này sử dụng phương pháp học máy. Bạn cần lấy thư viện Weka , đáng chú ý weka.jarPackageManager.jar.

Ở đây, tôi sử dụng một perceptionron đa lớp làm phân loại; bạn có thể thay thế mlpbằng bất kỳ Classifierlớp Weka nào để so sánh kết quả.

Tôi đã không nghiên cứu nhiều về các thông số của MLP, và chỉ đơn giản là nhìn chúng (một lớp ẩn gồm 50 nơ-ron, 100 epoch, tốc độ học 0,2, động lượng 0,1).

Tôi ngưỡng giá trị đầu ra của MLP, vì vậy đầu ra thực sự là 1 hoặc 0 như được xác định trong thử thách. Bằng cách đó, số lượng các trường hợp được phân loại chính xác như được in bởi Weka trực tiếp là điểm số của chúng tôi.

Xây dựng tính năng vector

Tôi biến mỗi thể hiện từ một chuỗi thành một vectơ gồm 76 phần tử, trong đó:

  • 64 phần tử đầu tiên đại diện cho các ô của bảng, theo thứ tự như trong chuỗi, trong đó 1là một mảnh màu trắng, -1là một mảnh màu đen và 0là một ô trống.
  • 12 yếu tố cuối cùng đại diện cho từng loại quân cờ (6 mỗi người chơi); giá trị của các phần tử đó là số phần của loại đó trên bảng ( 0là "không có phần nào của loại đó"). Người ta có thể áp dụng chuẩn hóa để chỉnh lại các giá trị đó giữa -1 và 1 nhưng điều này có lẽ không hữu ích lắm ở đây.

Số lượng các trường hợp đào tạo

Nếu tôi sử dụng tất cả các trường hợp kiểm tra được đưa ra để huấn luyện trình phân loại của mình, tôi đã quản lý để có được 6694 (tức là 98,6588%) các trường hợp được phân loại chính xác . Điều này rõ ràng không có gì đáng ngạc nhiên vì việc thử nghiệm một mô hình trên cùng một dữ liệu bạn đã sử dụng để huấn luyện nó là quá dễ dàng (vì trong trường hợp đó thực sự tốt khi mô hình đó mặc trang phục).

Sử dụng một tập hợp con ngẫu nhiên 80% các trường hợp làm dữ liệu huấn luyện, chúng tôi thu được 6413 (tức là 94,5173%) con số được phân loại chính xác được báo cáo trong tiêu đề (tất nhiên vì tập hợp con là ngẫu nhiên, bạn có thể nhận được kết quả hơi khác nhau). Tôi tin tưởng rằng mô hình sẽ hoạt động tốt trên dữ liệu mới, bởi vì thử nghiệm trên 20% trường hợp còn lại (không được sử dụng cho đào tạo) cho phân loại đúng 77.0818% , cho thấy các mô hình tổng quát hóa tốt (giả sử trường hợp chúng tôi được đưa ra ở đây là đại diện cho các trường hợp thử nghiệm mới, chúng tôi sẽ được cung cấp).

Sử dụng một nửa số trường hợp để đào tạo và nửa còn lại để kiểm tra, chúng tôi nhận được 86,7502% cho cả dữ liệu đào tạo và kiểm tra và 74,4988% chỉ cho dữ liệu kiểm tra.

Thực hiện

Như tôi đã nói, mã này yêu cầu weka.jarPackageManager.jartừ Weka.

Người ta có thể kiểm soát phần trăm dữ liệu được sử dụng trong tập huấn luyện với TRAIN_PERCENTAGE.

Các thông số của MLP có thể được thay đổi ngay bên dưới TRAIN_PERCENTAGE. Người ta có thể thử các trình phân loại khác của Weka (ví dụ SMOcho các SVM) bằng cách thay thế mlpbằng một trình phân loại khác.

Chương trình này in ra các tập kết quả, lần đầu tiên trên toàn bộ tập hợp (bao gồm cả dữ liệu được sử dụng cho đào tạo) là điểm số được xác định trong thử thách này và lần thứ hai chỉ dựa trên dữ liệu không được sử dụng cho đào tạo.

Người ta nhập dữ liệu bằng cách chuyển đường dẫn của tệp chứa dữ liệu đó làm đối số cho chương trình.

import weka.classifiers.Classifier;
import weka.classifiers.Evaluation;
import weka.classifiers.functions.MultilayerPerceptron;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.Instance;
import weka.core.Instances;

import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;

public class Test {

    public static void main(String[] arg) {

        final double TRAIN_PERCENTAGE = 0.5;

        final String HIDDEN_LAYERS = "50";
        final int NB_EPOCHS = 100;
        final double LEARNING_RATE = 0.2;
        final double MOMENTUM = 0.1;

        Instances instances = parseInstances(arg[0]);
        instances.randomize(new java.util.Random(0));
        Instances trainingSet = new Instances(instances, 0, (int) Math.floor(instances.size() * TRAIN_PERCENTAGE));
        Instances testingSet = new Instances(instances, (int) Math.ceil(instances.size() * TRAIN_PERCENTAGE), (instances.size() - (int) Math.ceil(instances.size() * TRAIN_PERCENTAGE)));

        Classifier mlp = new MultilayerPerceptron();
        ((MultilayerPerceptron) mlp).setHiddenLayers(HIDDEN_LAYERS);
        ((MultilayerPerceptron) mlp).setTrainingTime(NB_EPOCHS);
        ((MultilayerPerceptron) mlp).setLearningRate(LEARNING_RATE);
        ((MultilayerPerceptron) mlp).setMomentum(MOMENTUM);


        try {
            // Training phase
            mlp.buildClassifier(trainingSet);
            // Test phase
            System.out.println("### CHALLENGE SCORE ###");
            Evaluation test = new Evaluation(trainingSet);
            test.evaluateModel(mlp, instances);
            System.out.println(test.toSummaryString());
            System.out.println();
            System.out.println("### TEST SET SCORE ###");
            Evaluation test2 = new Evaluation(trainingSet);
            test2.evaluateModel(mlp, testingSet);
            System.out.println(test2.toSummaryString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Instances parseInstances(String filePath) {
        ArrayList<Attribute> attrs = new ArrayList<>(); // Instances constructor only accepts ArrayList
        for(int i = 0 ; i < 76 ; i++) {
            attrs.add(new Attribute("a" + String.valueOf(i)));
        }
        attrs.add(new Attribute("winner", new ArrayList<String>(){{this.add("white");this.add("black");}}));
        Instances instances = new Instances("Rel", attrs, 10);
        instances.setClassIndex(76);

        try {
            BufferedReader r = new BufferedReader(new FileReader(filePath));
            String line;
            String winner = "white";
            while((line = r.readLine()) != null) {
                if(line.equals("White:")) {
                    winner = "white";
                } else if(line.equals("Black:")) {
                    winner = "black";
                } else {
                    Instance instance = new DenseInstance(77);
                    instance.setValue(attrs.get(76), winner);
                    String[] values = line.split(",");
                    for(int i = 0 ; i < values[0].length() ; i++) {
                        if(values[0].charAt(i) == 'B') {
                            instance.setValue(attrs.get(i), -1);
                        } else if(values[0].charAt(i) == 'W') {
                            instance.setValue(attrs.get(i), 1);
                        } else {
                            instance.setValue(attrs.get(i), 0);
                        }
                    }
                    // Ugly as hell
                    instance.setValue(attrs.get(64), values[1].length() - values[1].replace("k", "").length());
                    instance.setValue(attrs.get(65), values[1].length() - values[1].replace("q", "").length());
                    instance.setValue(attrs.get(66), values[1].length() - values[1].replace("r", "").length());
                    instance.setValue(attrs.get(67), values[1].length() - values[1].replace("n", "").length());
                    instance.setValue(attrs.get(68), values[1].length() - values[1].replace("b", "").length());
                    instance.setValue(attrs.get(69), values[1].length() - values[1].replace("p", "").length());
                    instance.setValue(attrs.get(70), values[1].length() - values[1].replace("K", "").length());
                    instance.setValue(attrs.get(71), values[1].length() - values[1].replace("Q", "").length());
                    instance.setValue(attrs.get(72), values[1].length() - values[1].replace("R", "").length());
                    instance.setValue(attrs.get(73), values[1].length() - values[1].replace("N", "").length());
                    instance.setValue(attrs.get(74), values[1].length() - values[1].replace("B", "").length());
                    instance.setValue(attrs.get(75), values[1].length() - values[1].replace("P", "").length());

                    instances.add(instance);
                }
            }
        } catch (Exception e) { // who cares
            e.printStackTrace();
        }
        return instances;
    }
}

Làm thế nào để bạn mã hóa đầu vào?
Nathan Merrill

@NathanMerrill Tôi không chắc là tôi hiểu câu hỏi của bạn
Fatalize 22/03/2017

Làm thế nào bạn vượt qua trường hợp thử nghiệm như là đầu vào cho mạng thần kinh? Bạn chỉ đi qua trong chuỗi thô?
Nathan Merrill

@NathanMerrill Đã chỉnh sửa với một đoạn về cấu trúc vector tính năng.
Gây tử vong

Làm thế nào để weka biết bạn đang cố gắng dự đoán người chiến thắng?
user1502040

8

GNU sed + bc, 4336 5074,5 điểm, 64 75%

Cập nhật: OP đã đưa ra một cách mới để tính điểm dự đoán cho một trường hợp thử nghiệm riêng lẻ. Sử dụng Wolfram Alpha , tôi đã vẽ cả hai bộ công thức để thấy sự khác biệt.

Cách hiện tại mang lại một động lực mạnh mẽ để đưa ra xác suất thực tế, và không chỉ các cực trị, 0 và 1, mà các công thức mới cho điểm tối đa như trước. Đây là lý do tại sao thuật toán không thay đổi dưới đây, giờ đây có tỷ lệ dự đoán tốt hơn, trên thực tế là một tỷ lệ tuyệt vời do tính đơn giản của nó.

Tuy nhiên, cũng có một nhược điểm liên quan đến các công thức mới, như được giải thích trong 'Chỉnh sửa 1'.


Đây là một ước tính đơn giản chỉ dựa trên lợi thế / bất lợi vật chất, bỏ qua vị trí thực tế của các mảnh. Tôi tò mò làm thế nào điều này sẽ thực hiện. Lý do tôi sử dụng sed, và không phải một số ngôn ngữ có thể làm điều này trong một dòng, là vì đó là ngôn ngữ bí truyền yêu thích của tôi.

/:/d                                             # delete the two headers
s:.*,::                                          # delete board positions
s:$:;Q9,R5,B3,N3,P1,K0,q-9,r-5,b-3,n-3,p-1,k-0:  # add relative piece value table
:r                                               # begin replacement loop
s:([a-Z])((.*)\1([^,]+)):\4+\2:                  # table lookup: letter-value repl.
tr                                               # repeat till last piece
s:;.*::                                          # delete value table
s:.*:echo '&0'|bc:e                              # get material difference: bc call
/^0$/c0.5                                        # print potential draw score
/-/c0                                            # print potential black win score
c1                                               # print potential white win score

Giá trị mảnh tiêu chuẩn được sử dụng:

  • 9 - Nữ hoàng
  • 5 - Rook
  • 3 - Hiệp sĩ
  • 3 - Giám mục
  • 1 - Cầm đồ
  • 0 - Vua

Tôi tính toán vật liệu cho cả hai mặt và trừ vật liệu đen ra khỏi vật liệu trắng. Đầu ra cho mỗi trường hợp thử nghiệm dựa trên sự khác biệt đó như sau:

  • nếu chênh lệch> 0, thì sản lượng = 1 (thắng trắng tiềm năng)
  • nếu chênh lệch = 0, thì đầu ra = 0,5 (rút thăm tiềm năng).

Đây là đầu ra phân đoạn duy nhất của tôi, do đó lý do của sự cải thiện như được giải thích ở trên.

  • nếu chênh lệch <0, thì đầu ra = 0 (thắng đen tiềm năng)

Tỷ lệ dự đoán cho phương pháp này là 64%. Bây giờ là 75% với các công thức mới.

Ban đầu tôi dự đoán nó sẽ cao hơn, nói 70%, nhưng với tư cách là một người chơi cờ, tôi có thể hiểu được kết quả, vì tôi đã thua rất nhiều trò chơi khi tôi là +1 / +2 và đã thắng rất nhiều khi tôi thất bại vật chất. Đó là tất cả về vị trí thực tế. (Chà, bây giờ tôi đã có được điều ước của mình!)

Chỉnh sửa 1: nhược điểm

Giải pháp tầm thường là xuất 0,5 cho mỗi trường hợp thử nghiệm, bởi vì cách này bạn đã ghi được nửa điểm bất kể ai thắng. Đối với các trường hợp thử nghiệm của chúng tôi, điều này có nghĩa là tổng điểm 3392,5 điểm (50%).

Nhưng với các công thức mới, 0,5 (là đầu ra bạn đưa ra nếu bạn không quyết định ai thắng) được chuyển đổi thành 0,75 điểm. Hãy nhớ rằng số điểm tối đa bạn có thể nhận được cho một trường hợp thử nghiệm là 1, để tin tưởng 100% vào người chiến thắng. Như vậy, tổng số điểm mới cho sản lượng 0,5 không đổi là 5088,75 điểm, tương đương 75%! Theo tôi, động cơ quá mạnh cho trường hợp này.

Tuy nhiên, điểm số đó tốt hơn so với thuật toán dựa trên lợi thế vật chất của tôi. Lý do cho điều đó là bởi vì thuật toán đưa ra xác suất 1 hoặc 0 (không khuyến khích), giả định thắng hoặc thua, nhiều lần hơn (3831) so với tỷ lệ 0,5 (khuyến khích), hòa giả định (2954). Phương pháp cuối cùng rất đơn giản và vì thế nó không có tỷ lệ câu trả lời đúng cao. Sự gia tăng từ công thức mới lên hằng số 0,5, quản lý để đạt được tỷ lệ phần trăm đó, một cách giả tạo.

Chỉnh sửa 2:

Đó là một thực tế được biết đến, được đề cập trong sách cờ vua, rằng thường có một cặp giám mục tốt hơn là một cặp hiệp sĩ. Điều này đặc biệt đúng trong giai đoạn từ giữa đến cuối của trò chơi, trong đó các trường hợp thử nghiệm, vì nhiều khả năng nó sẽ có một vị trí mở trong đó phạm vi của một giám mục được tăng lên.

Do đó, tôi đã làm một bài kiểm tra thứ hai, nhưng lần này tôi đã thay thế giá trị của các giám mục từ 3 thành 3,5. Giá trị của hiệp sĩ vẫn là 3. Đây là một sở thích cá nhân, vì vậy tôi đã không biến nó thành đệ trình mặc định của mình. Tổng số điểm trong trường hợp này là 4411 điểm (65%). Chỉ tăng 1 điểm phần trăm đã được quan sát.

Với các công thức mới, tổng số điểm là 4835 điểm (71%). Bây giờ các giám mục có trọng số kém. Nhưng, hiệu quả được giải thích bởi vì phương pháp có trọng số hiện cung cấp nhiều lần hơn so với giả định thắng hoặc thua (5089), so với rút thăm giả định (1696).


1
+1 để cung cấp giải pháp cơ bản hợp lý. Tôi cũng đã tự hỏi làm thế nào điều này sẽ thực hiện tốt.
Martin Ender

@MartinEnder Cảm ơn bạn. Ý tưởng của tôi về việc tăng giá trị của giám mục, được đề cập lần trước, chỉ tạo ra mức tăng tỷ lệ thành công 1% (xem Cập nhật 2). Tôi nghĩ rằng các giá trị tiêu chuẩn đã bao gồm hiệu ứng đó sau khi tất cả.
seshoumara

Này, theo nhận xét của xnor, bạn có phiền nếu tôi thay đổi cách tính điểm thành sự khác biệt tuyệt đối bình phương không?
Nathan Merrill

1
Tuyệt vời. Ngoài ra, cảm ơn vì đã trả lời! Tôi luôn lo lắng rằng những câu hỏi khó hơn của tôi sẽ không bao giờ có câu trả lời.
Nathan Merrill

@NathanMerrill Tôi đã cập nhật câu trả lời của mình để sử dụng cách tính điểm mới khi được hỏi. Xin lỗi vì đã phân tích dài, nhưng tôi thực sự rất tò mò.
seshoumara

4

Python 3 - 84,6%, 5275 điểm trên bộ xác thực

Nếu chúng tôi gian lận và sử dụng tất cả dữ liệu, chúng tôi có thể đạt được độ chính xác 99,3% và điểm số 6408

Chỉ là một MLP lớn đơn giản với việc bỏ học bằng Keras

import collections
import numpy as np
import random

import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.layers.noise import GaussianDropout
from keras.optimizers import Adam

np.random.seed(0)
random.seed(0)

def load_data():
    with open('test_cases.txt', 'r') as f:
        for line in f:
            yield line.split(',')

def parse_data(rows):
    black_pieces = "kpbkrq"
    white_pieces = black_pieces.upper()
    for i, row in enumerate(rows):
        if len(row) >= 2:
            board = row[0]
            board = np.array([1 if c == 'W' else -1 if c == 'B' else 0 for c in board], dtype=np.float32)
            pieces = row[1]
            counts = collections.Counter(pieces)
            white_counts = np.array([counts[c] for c in white_pieces], dtype=np.float32)
            black_counts = np.array([counts[c] for c in black_pieces], dtype=np.float32)
            yield (outcome, white_counts, black_counts, board)
        else:
            if 'White' in row[0]:
                outcome = 1
            else:
                outcome = 0

data = list(parse_data(load_data()))
random.shuffle(data)
data = list(zip(*data))
y = np.array(data[0])
x = list(zip(*data[1:]))
x = np.array([np.concatenate(xi) for xi in x])

i = len(y) // 10

x_test, x_train = x[:i], x[i:]
y_test, y_train = y[:i], y[i:]

model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(76,)))
model.add(GaussianDropout(0.5))
model.add(Dense(512, activation='relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(512, activation='relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1, activation='sigmoid'))

model.compile(loss='mean_squared_error', optimizer=Adam())

use_all_data = False

x_valid, y_valid = x_test, y_test

if use_all_data:
    x_train, y_train = x_test, y_test = x, y
    validation_data=None
else:
    validation_data=(x_test, y_test)

batch_size = 128

history = model.fit(x_train, y_train, batch_size=batch_size, epochs=50, verbose=1, validation_data=validation_data)

y_pred = model.predict_on_batch(x_test).flatten()
y_class = np.round(y_pred)
print("accuracy: ", np.sum(y_class == y_test) / len(y_test))

score = np.sum((y_pred - (1 - y_test)) ** 2) * (len(y) / len(y_test))
print("score: ", score)

Bạn sử dụng bao nhiêu dữ liệu cho đào tạo để có được con số 84,6%?
Gây tử vong

Tôi đã sử dụng phân tách 90-10 như được hiển thị trong mã
user1502040

Hey, tôi đã thêm một tấn trường hợp thử nghiệm nếu bạn quan tâm.
Nathan Merrill

2

Python 3 - Độ chính xác 94,3%, 6447 điểm trên bộ xác thực 20% dữ liệu

Sử dụng 3 mạng thần kinh, một hồi quy lân cận gần nhất, một khu rừng ngẫu nhiên và tăng cường độ dốc. Những dự đoán này được kết hợp với một khu rừng ngẫu nhiên cũng có quyền truy cập vào dữ liệu.

import collections
import numpy as np
import numpy.ma as ma
import random

import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, BatchNormalization, Activation, Conv2D, Flatten
from keras.layers.noise import GaussianDropout
from keras.callbacks import EarlyStopping
from keras.optimizers import Adam
from sklearn.neighbors import KNeighborsRegressor
from sklearn.ensemble import RandomForestRegressor
from sklearn.ensemble import GradientBoostingRegressor
import tensorflow

tensorflow.set_random_seed(1)
np.random.seed(1)
random.seed(1)

def load_data():
    with open('test_cases.txt', 'r') as f:
        for line in f:
            yield line.split(',')

def parse_data(rows):
    black_pieces = "kqrnbp"
    white_pieces = black_pieces.upper()
    for i, row in enumerate(rows):
        if len(row) >= 2:
            board = row[0]
            board = np.array([1 if c == 'W' else -1 if c == 'B' else 0 for c in board], dtype=np.float32)
            pieces = row[1]
            counts = collections.Counter(pieces)
            white_counts = np.array([counts[c] for c in white_pieces], dtype=np.float32)
            black_counts = np.array([counts[c] for c in black_pieces], dtype=np.float32)
            yield (outcome, white_counts, black_counts, board)
        else:
            if 'White' in row[0]:
                outcome = 1
            else:
                outcome = 0

data = list(parse_data(load_data()))
random.shuffle(data)
data = list(zip(*data))
y = np.array(data[0])
x = list(zip(*data[1:]))
conv_x = []
for white_counts, black_counts, board in x:
    board = board.reshape((1, 8, 8))
    white_board = board > 0
    black_board = board < 0
    counts = [white_counts, black_counts]
    for i, c in enumerate(counts):
        n = c.shape[0]
        counts[i] = np.tile(c, 64).reshape(n, 8, 8)
    features = np.concatenate([white_board, black_board] + counts, axis=0)
    conv_x.append(features)
conv_x = np.array(conv_x)
x = np.array([np.concatenate(xi) for xi in x])
s = x.std(axis=0)
u = x.mean(axis=0)
nz = s != 0
x = x[:,nz]
u = u[nz]
s = s[nz]
x = (x - u) / s

i = 2 * len(y) // 10

x_test, x_train = x[:i], x[i:]
conv_x_test, conv_x_train = conv_x[:i], conv_x[i:]
y_test, y_train = y[:i], y[i:]

model = Sequential()

def conv(n, w=3, shape=None):
    if shape is None:
        model.add(Conv2D(n, w, padding="same"))
    else:
        model.add(Conv2D(n, w, padding="same", input_shape=shape))
    model.add(BatchNormalization())
    model.add(Activation('relu'))

conv(128, shape=conv_x[0].shape) 
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(128)
conv(2, w=1)
model.add(Flatten())
model.add(GaussianDropout(0.5))
model.add(Dense(256))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1))
model.add(BatchNormalization())
model.add(Activation('sigmoid'))

model.compile(loss='mse', optimizer=Adam())

model5 = model

model = Sequential()
model.add(Dense(50, input_shape=(x.shape[1],)))
model.add(Activation('sigmoid'))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='mse', optimizer=Adam())

model0 = model

model = Sequential()
model.add(Dense(1024, input_shape=(x.shape[1],)))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1024))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1024))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(GaussianDropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))

model.compile(loss='mse', optimizer=Adam())

model4 = model

use_all_data = False

x_valid, y_valid = x_test, y_test

if use_all_data:
    x_train, y_train = x_test, y_test = x, y
    validation_data=None
else:
    validation_data=(x_test, y_test)

def subsample(x, y, p=0.9, keep_rest=False):
    m = np.random.binomial(1, p, size=len(y)).astype(np.bool)
    r = (x[m,:], y[m])
    if not keep_rest:
        return r
    m = ~m
    return r + (x[m,:], y[m])

epochs=100

x0, y0, x_valid, y_valid = subsample(conv_x_train, y_train, keep_rest=True)
model5.fit(x0, y0, epochs=epochs, verbose=1, validation_data=(x_valid, y_valid), callbacks=[EarlyStopping(patience=1)])

x0, y0, x_valid, y_valid = subsample(x_train, y_train, keep_rest=True)
model0.fit(x0, y0, epochs=epochs, verbose=1, validation_data=(x_valid, y_valid), callbacks=[EarlyStopping(patience=1)])

x0, y0, x_valid, y_valid = subsample(x_train, y_train, keep_rest=True)
model4.fit(x0, y0, epochs=epochs, verbose=1, validation_data=(x_valid, y_valid), callbacks=[EarlyStopping(patience=1)])

model1 = RandomForestRegressor(n_estimators=400, n_jobs=-1, verbose=1)
model1.fit(*subsample(x_train, y_train))

model2 = GradientBoostingRegressor(learning_rate=0.2, n_estimators=5000, verbose=1)
model2.fit(*subsample(x_train, y_train))

model3 = KNeighborsRegressor(n_neighbors=2, weights='distance', p=1)
model3.fit(*subsample(x_train, y_train))

models = (model0, model1, model2, model3, model4, model5)

model_names = [
    "shallow neural net",
    "random forest",
    "gradient boosting",
    "k-nearest neighbors",
    "deep neural net",
    "conv-net",
    "ensemble"
]

def combine(predictions):
    clip = lambda x: np.clip(x, 0, 1)
    return clip(np.array([y.flatten() for y in predictions]).T)

def augment(x, conv_x):
    p = combine([m.predict(x) for m in models[:-1]] + [models[-1].predict(conv_x)])
    return np.concatenate((x, p), axis=1)

model = RandomForestRegressor(n_estimators=200, n_jobs=-1, verbose=1)
model.fit(augment(x_train, conv_x_train), y_train)

def accuracy(prediction):
    class_prediction = np.where(prediction > 0.5, 1, 0)
    return np.sum(class_prediction == y_test) / len(y_test)

predictions = [m.predict(x_test).flatten() for m in models[:-1]] + [models[-1].predict(conv_x_test).flatten()]+ [model.predict(augment(x_test, conv_x_test))]

for s, p in zip(model_names, predictions):
    print(s + " accuracy: ", accuracy(p))

def evaluate(prediction):
    return np.sum(1 - (prediction - y_test) ** 2) * (len(y) / len(y_test))

for s, p in zip(model_names, predictions):
    print(s + " score: ", evaluate(p))

Hey, tôi đã thêm một tấn trường hợp thử nghiệm nếu bạn quan tâm.
Nathan Merrill

Woah bạn đã đi ra ngoài này.
Robert Fraser

Lưu ý câu trả lời java ở đây rằng "nhịp đập" của bạn dường như báo cáo% trên toàn bộ tập dữ liệu và chỉ nhận được 77% trên dữ liệu mà nó không được đào tạo.
Robert Fraser

0

Python 3 - 4353,25 / 6785 điểm - 64%

Vì vậy, tôi đã làm việc về điều này chủ yếu là ngày hôm qua. Bài đánh gôn đầu tiên của tôi và tôi chỉ mới sử dụng python một tuần hoặc lâu hơn, vì vậy hãy tha thứ cho tôi nếu không phải mọi thứ đều được tối ưu hóa.

def GetWhiteWinPercent(a):
finalWhiteWinPercent=0
i=a.index(',')

#position
board=a[:i]
blackBoardScore=0
whiteBoardScore=0
for r in range(i):
    if board[r] == 'B': blackBoardScore += abs(7 - (r % 8))
    if board[r] == 'W': whiteBoardScore += r % 8
if   whiteBoardScore > blackBoardScore: finalWhiteWinPercent += .5
elif whiteBoardScore < blackBoardScore: finalWhiteWinPercent += .0
else: finalWhiteWinPercent+=.25

#pieces
pieces=a[i:]
s = {'q':-9,'r':-5,'n':-3,'b':-3,'p':-1,'Q':9,'R':5,'N':3,'B':3,'P':1}
pieceScore = sum([s.get(z) for z in pieces if s.get(z) != None])
if   pieceScore < 0: finalWhiteWinPercent += 0
elif pieceScore > 0: finalWhiteWinPercent += .5
else: finalWhiteWinPercent += .25

return finalWhiteWinPercent

Tôi đã kết thúc dọc theo con đường giống như câu trả lời của seshoumara để bắt đầu. Nhưng số lượng lớn các trường hợp thử nghiệm thậm chí có số lượng mảnh còn lại khiến tôi không hài lòng.

Vì vậy, tôi đã tìm ra những đặc điểm cho thấy ai là người chiến thắng trong cờ vua (tôi không chơi trò chơi này) và nhận thấy vị trí bảng, đặc biệt là kiểm soát trung tâm, là lớn. Đó là nơi mà bit này đến.

for r in range(i):
    if board[r] == 'B': blackBoardScore += abs(7 - (r % 8))
    if board[r] == 'W': whiteBoardScore += r % 8
if   whiteBoardScore > blackBoardScore: finalWhiteWinPercent += .5
elif whiteBoardScore < blackBoardScore: finalWhiteWinPercent += .0
else: finalWhiteWinPercent+=.25

Cả hai nửa kết hợp được sử dụng để tìm điểm (0,0, 0,25, 0,50, 0,75, 1,0)

Rất thú vị khi vị trí bảng này thêm dường như không làm tăng cơ hội đoán tất cả người chiến thắng.

Nếu bạn thả các trường hợp thử nghiệm vào một số tệp, thì đây là thử nghiệm.

whiteWins=0
blackWins=0
totalWins=0
for line in open('testcases2.txt','r'):
    totalWins += 1
    blackWins += 1 - GetWhiteWinPercent(line)
for line in open('testcases.txt','r'):
    totalWins += 1
    whiteWins += GetWhiteWinPercent(line)

print(str(whiteWins+blackWins) +'/'+str(totalWins))

Tôi biết đây không phải là một thử thách golf, nhưng bất kỳ lời khuyên hoặc lời khuyên nào về vấn đề đó đều được đánh giá cao!


Câu trả lời của tôi? Bạn có nghĩa là câu trả lời của seshoumara? Ngoài ra, bạn không cần phải đánh gôn này (trừ khi bạn muốn). Đây không phải là một thử thách golf-code .
Nathan Merrill

Bạn có thể lưu nhiều byte chỉ bằng cách sử dụng tên biến một ký tự. (Mặc dù nó không thực sự quan trọng bởi vì đây không phải là môn đánh gôn)
HyperNeutrino 22/03/2017

Ái chà! Chỉnh sửa mà bây giờ. Trong công việc, đây là những gì tôi nhận được để lướt qua!
Datastream

2
Xin đừng chơi golf. Tốt hơn là giữ mã có thể đọc được khi không phải là mã golf.
mbomb007

Kiểm soát giữa bảng không có nghĩa là chiếm giữa bảng, mà tấn công vào giữa bảng. Nếu bạn muốn thêm một số phức tạp xung quanh đó, nó có thể cải thiện điểm số của bạn.
Không phải Charles
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.