In một giá trị cụ thể trong ma trận Wythoff modulo 2


11

Ma trận Wythoff là một ma trận vô hạn bao gồm các số Grundy của mỗi ô vuông trên bàn cờ trong trò chơi của Wythoff .

Mỗi mục trong ma trận này bằng với số không âm nhỏ nhất không xuất hiện ở bất cứ đâu phía trên, bên trái hoặc theo hướng tây bắc của vị trí của mục nhập.

Hình vuông 20 x 20 trên cùng bên trái trông như thế này:

  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19
  1  2  0  4  5  3  7  8  6 10 11  9 13 14 12 16 17 15 19 20
  2  0  1  5  3  4  8  6  7 11  9 10 14 12 13 17 15 16 20 18
  3  4  5  6  2  0  1  9 10 12  8  7 15 11 16 18 14 13 21 17
  4  5  3  2  7  6  9  0  1  8 13 12 11 16 15 10 19 18 17 14
  5  3  4  0  6  8 10  1  2  7 12 14  9 15 17 13 18 11 16 21
  6  7  8  1  9 10  3  4  5 13  0  2 16 17 18 12 20 14 15 11
  7  8  6  9  0  1  4  5  3 14 15 13 17  2 10 19 21 12 22 16
  8  6  7 10  1  2  5  3  4 15 16 17 18  0  9 14 12 19 23 24
  9 10 11 12  8  7 13 14 15 16 17  6 19  5  1  0  2  3  4 22
 10 11  9  8 13 12  0 15 16 17 14 18  7  6  2  3  1  4  5 23
 11  9 10  7 12 14  2 13 17  6 18 15  8 19 20 21  4  5  0  1
 12 13 14 15 11  9 16 17 18 19  7  8 10 20 21 22  6 23  3  5
 13 14 12 11 16 15 17  2  0  5  6 19 20  9  7  8 10 22 24  4
 14 12 13 16 15 17 18 10  9  1  2 20 21  7 11 23 22  8 25 26
 15 16 17 18 10 13 12 19 14  0  3 21 22  8 23 20  9 24  7 27
 16 17 15 14 19 18 20 21 12  2  1  4  6 10 22  9 13 25 11 28
 17 15 16 13 18 11 14 12 19  3  4  5 23 22  8 24 25 21 26 10
 18 19 20 21 17 16 15 22 23  4  5  0  3 24 25  7 11 26 12 13
 19 20 18 17 14 21 11 16 24 22 23  1  5  4 26 27 28 10 13 25

Hiện tại không có thuật toán hiệu quả được biết đến để tính toán một mục tùy ý trong ma trận Wythoff. Tuy nhiên, nhiệm vụ của bạn trong vấn đề này là cố gắng thiết kế một hàm heuristic sẽ cho biết số tại một tọa độ cụ thể wythoff(x, y)là chẵn hay lẻ.

Chương trình của bạn không được chứa nhiều hơn 64 KB (65.536 byte) mã nguồn hoặc sử dụng hơn 2 MB (2.097.152 byte) bộ nhớ làm việc.

Đặc biệt đối với việc sử dụng bộ nhớ, điều này có nghĩa là kích thước cài đặt thường trú tối đa của chương trình của bạn không được vượt quá 2 MB so với kích thước cài đặt thường trú tối đa của một chương trình trống trong ngôn ngữ đó. Trong trường hợp ngôn ngữ được dịch, nó sẽ là cách sử dụng bộ nhớ của chính trình thông dịch / máy ảo và trong trường hợp ngôn ngữ được biên dịch, nó sẽ là cách sử dụng bộ nhớ của chương trình thực thi phương thức chính và không làm gì cả.

Chương trình của bạn sẽ được kiểm tra trên 10000 x 10000ma trận cho các giá trị hàng trong 20000 <= x <= 29999và giá trị cột trong 20000 <= y <= 29999.

Điểm số của chương trình của bạn là tỷ lệ chính xác (số lần đoán đúng) chương trình của bạn đạt được, với mã ngắn hơn đóng vai trò là người bẻ khóa.


3
01.Rlà 05AB1E xuất ra đúng hoặc sai ngẫu nhiên. Đặt 0 là đúng và 1 là sai, về mặt lý thuyết, chương trình của tôi sẽ đúng ~ 50%. Đây có phải là một mục hợp lệ?
Bạch tuộc ma thuật Urn

@carusocomputing Trên thực tế, tôi quên đề cập rằng các giải pháp ngẫu nhiên không được phép - chương trình của bạn sẽ tạo ra cùng một đầu ra cho cùng một đầu vào mỗi lần, mặc dù tôi nghi ngờ rằng hàm từ ngụ ý điều đó.
Joe Z.

Nếu tôi sửa hạt giống prng của tôi trên mỗi cuộc gọi, nó sẽ tạo ra cùng một đầu ra cho đầu vào giống hệt nhau và tôi biết ý của bạn là gì nhưng có lẽ bạn sẽ phải nói từ đó cụ thể hơn.
dặm

Tôi nhận được một cái gì đó rất khác khi tôi tìm kiếm Ma trận Wythoff
Linus

@Linus "Ma trận trò chơi của Wythoff" sẽ tốt hơn chứ? Tôi thấy trang đó quá.
Joe Z.

Câu trả lời:


6

Con trăn; độ chính xác = 54.074.818; kích thước = 65,526 byte

Điểm trước: 50.227.165; 50.803.687; 50.953.001

#coding=utf-8
d=r'''<65,400 byte string>'''
def f(x,y):
 a=max(x,y)-20000;b=min(x,y)-20000;c=(a*(a+1)//2+b)%523200
 return(ord(d[c//8])>>(c%8))&1

Cách tiếp cận này chia tất cả các mục duy nhất của ma trận thành 523.200 nhóm và đọc dự đoán tốt nhất cho nhóm (x, y) từ một chuỗi nhị phân. Bạn có thể tải xuống mã nguồn đầy đủ từ Google Drive .

Tôi đã sử dụng các tính chẵn lẻ của @ PeterTaylor để tạo chuỗi và tính toán độ chính xác.


Tôi đã thử nhiều cách tiếp cận khác nhau, thú vị hơn, nhưng cuối cùng, một mã cứng đơn giản đã vượt qua tất cả chúng ...
Dennis

Hardcoding cũng là một cách tiếp cận hợp lệ - nó có thể biến thành sơ đồ mã hóa cứng nào trả về kết quả tốt nhất.
Joe Z.

Không nói khác, nhưng vì sự phân phối của các cộng đồng rất rõ ràng là không ngẫu nhiên, tôi đã hy vọng vượt qua cách tiếp cận này. Cho đến nay, tất cả các nỗ lực của tôi đã thất bại.
Dennis

Không, không sao đâu. Nó chỉ có nghĩa là vấn đề này là quá khó để làm đúng. Tôi đã tạo ra một loạt các vấn đề của phong cách này ngoại trừ một chiều. Tất cả đều nằm trong hộp cát nếu bạn muốn xem chúng.
Joe Z.

4

CJam (độ chính xác 50016828/100000000, 6 byte)

{+1&!}

(Trong mã giả kiểu ALGOL dành cho những người không phải là CJammers :) return ((x + y) & 1) == 0.

Điều này thực hiện tốt hơn bất kỳ hai tá heuristic đơn giản khác mà tôi đã thử. Nó thậm chí còn tốt hơn bất kỳ sự kết hợp nào với hai cái tốt nhất tiếp theo.


Điểm số giả định rằng phần tính toán của tôi trong ma trận là chính xác. Xác nhận độc lập hoan nghênh. Tôi đang lưu trữ các bit chẵn lẻ được tính toán tại http://cheddarmonk.org/codegolf/PPCG95604-parity.bz2 (tải xuống 8 MB, trích xuất tệp văn bản 50 MB: vì ma trận đối xứng với đường chéo chính, tôi chỉ bao gồm mỗi ma trận đường bắt đầu từ đường chéo chính, do đó bạn phải bù, hoán vị và bitwise HOẶC để có được hình vuông đầy đủ).

Mã mà tôi đã sử dụng để tính toán nó là Java. Nó sử dụng định nghĩa khá đơn giản, nhưng với cấu trúc dữ liệu được thiết lập, độ dài chạy sẽ mã hóa các phạm vi để nhanh chóng chuyển sang giá trị được phép tiếp theo. Tối ưu hóa hơn nữa sẽ có thể, nhưng nó chạy trên máy tính để bàn cũ vừa phải của tôi trong khoảng hai giờ và 1,5 GB không gian heap.

import java.util.*;

public class PPCG95604Analysis
{
    static final int N = 30000;

    public static void main(String[] args) {
        Indicator[] cols = new Indicator[N];
        Indicator[] diag = new Indicator[N];
        for (int i = 0; i < N; i++) {
            cols[i] = new Indicator();
            diag[i] = new Indicator();
        }

        int maxVal = 0;

        for (int y = 0; y < N; y++) {
            Indicator row = new Indicator(cols[y]);

            for (int x = y; x < N; x++) {
                Indicator col = cols[x];
                Indicator dia = diag[x - y];

                Indicator.Result rr = row.firstCandidate();
                Indicator.Result rc = col.firstCandidate();
                Indicator.Result rd = dia.firstCandidate();

                while (true) {
                    int max = Math.max(Math.max(rr.candidateValue(), rc.candidateValue()), rd.candidateValue());
                    if (rr.candidateValue() == max && rc.candidateValue() == max && rd.candidateValue() == max) break;

                    if (rr.candidateValue() != max) rr = rr.firstCandidateGreaterThan(max - 1);
                    if (rc.candidateValue() != max) rc = rc.firstCandidateGreaterThan(max - 1);
                    if (rd.candidateValue() != max) rd = rd.firstCandidateGreaterThan(max - 1);
                }

                if (y >= 20000 && x >= 20000) System.out.format("%d", rr.candidateValue() & 1);
                maxVal = Math.max(maxVal, rr.candidateValue());
                rr.markUsed();
                rc.markUsed();
                rd.markUsed();
            }
            if (y >= 20000) System.out.println();
        }
    }

    static class Indicator
    {
        private final int INFINITY = (short)0xffff;
        private final int MEMBOUND = 10000;

        private short[] runLengths = new short[MEMBOUND];

        public Indicator() { runLengths[1] = INFINITY; }

        public Indicator(Indicator clone) { System.arraycopy(clone.runLengths, 0, runLengths, 0, MEMBOUND); }

        public Result firstCandidate() {
            // We have a run of used values, followed by a run of unused ones.
            return new Result(1, 0xffff & runLengths[0], 0xffff & runLengths[0]);
        }

        class Result
        {
            private final int runIdx;
            private final int runStart;
            private final int candidateValue;

            Result(int runIdx, int runStart, int candidateValue) {
                this.runIdx = runIdx;
                this.runStart = runStart;
                this.candidateValue = candidateValue;
            }

            public int candidateValue() {
                return candidateValue;
            }

            public Result firstCandidateGreaterThan(int x) {
                if (x < candidateValue) throw new IndexOutOfBoundsException();

                int idx = runIdx;
                int start = runStart;
                while (true) {
                    int end = start + (0xffff & runLengths[idx]) - 1;
                    if (end > x) return new Result(idx, start, x + 1);

                    // Run of excluded
                    start += 0xffff & runLengths[idx];
                    idx++;
                    // Run of included
                    start += 0xffff & runLengths[idx];
                    idx++;

                    if (start > x) return new Result(idx, start, start);
                }
            }

            public void markUsed() {
                if (candidateValue == runStart) {
                    // Transfer one from the start of the run to the previous run
                    runLengths[runIdx - 1]++;
                    if (runLengths[runIdx] != INFINITY) runLengths[runIdx]--;
                    // May need to merge runs
                    if (runLengths[runIdx] == 0) {
                        runLengths[runIdx - 1] += runLengths[runIdx + 1];
                        for (int idx = runIdx; idx < MEMBOUND - 2; idx++) {
                            runLengths[idx] = runLengths[idx + 2];
                            if (runLengths[idx] == INFINITY) break;
                        }
                    }

                    return;
                }

                if (candidateValue == runStart + (0xffff & runLengths[runIdx]) - 1) {
                    // Transfer one from the end of the run to the following run.
                    if (runLengths[runIdx + 1] != INFINITY) runLengths[runIdx + 1]++;
                    if (runLengths[runIdx] != INFINITY) runLengths[runIdx]--;
                    // We never need to merge runs, because if we did we'd have hit the previous case instead
                    return;
                }

                // Need to split the run. From
                //   runIdx: a+1+b
                // to
                //   runIdx: a
                //   runIdx+1: 1
                //   runIdx+2: b
                //   runIdx+3: previous val at runIdx+1
                for (int idx = MEMBOUND - 1; idx > runIdx + 2; idx--) {
                    runLengths[idx] = runLengths[idx - 2];
                }
                runLengths[runIdx + 2] = runLengths[runIdx] == INFINITY ? INFINITY : (short)((0xffff & runLengths[runIdx]) + runStart - 1 - candidateValue);
                runLengths[runIdx + 1] = 1;
                runLengths[runIdx] = (short)(candidateValue - runStart);
            }
        }
    }
}

3

J, độ chính xác = 50022668/10 8 = 50.0227%, 4 byte

2|*.

Lấy tọa độ là hai đối số, tính LCM giữa chúng và lấy modulo 2. A 0có nghĩa là chẵn và a 1có nghĩa là lẻ.

Hiệu suất được dựa trên các bit chẵn lẻ được cung cấp bởi @ Peter Taylor .

Phiên bản PRNG trước đây cho 7 byte, 2|?.@#.có độ chính xác 50010491/10 8 .

Giải trình

2|*.  Input: x on LHS, y on RHS
  *.  LCM(x, y)
2|    Modulo 2

1
Tính chẵn lẻ của LCM là tính chẵn lẻ của bitwise AND. Điều đó có giúp bạn tiết kiệm một byte không? Điều thú vị là nó rõ ràng là một heuristic tồi tệ (nó 1chỉ chiếm 25% thời gian, khi tỷ lệ chính xác gần như chính xác là 50%), nhưng nó tốt hơn nhiều so với những thứ rõ ràng không tệ.
Peter Taylor

Cảm ơn, nhưng không may bitwise VÀ trong J là nghĩa đen AND.
dặm

@PeterTaylor Loại khám phá heuristic đáng ngạc nhiên đó là những thách thức như thế này được cho là tất cả về.
Joe Z.
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.