Wythoff 매트릭스 모듈로 2에서 특정 값 인쇄


11

Wythoff 행렬은 Wythoff의 게임 에서 체스 판에있는 각 사각형 의 Grundy 숫자 로 구성된 무한 행렬입니다 입니다.

이 행렬의 각 항목은 항목 위치의 위, 왼쪽 또는 대각선 북서쪽에 나타나지 않는 가장 작은 음수가 아닙니다.

왼쪽 위 20 x 20 사각형은 다음과 같습니다.

  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

Wythoff 매트릭스에서 임의의 엔트리를 계산하기위한 효율적인 알고리즘은 현재 알려져 있지 않다. 그러나이 문제의 임무는 특정 좌표의 숫자인지 여부를 알려주는 휴리스틱 함수를 디자인하는 것입니다.wythoff(x, y) 가 짝수인지 홀수 입니다.

프로그램에 64KB (65,536 바이트) 이상의 소스 코드가 포함되어 있지 않거나 2MB (2,097,152 바이트) 이상의 작업 메모리가 사용될 수 있습니다.

특히 메모리 사용의 경우 이는 프로그램의 최대 상주 세트 크기가 해당 언어의 빈 프로그램의 최대 상주 세트 크기보다 2MB를 초과 할 수 없음을 의미합니다. 해석 된 언어의 경우 인터프리터 / 가상 시스템 자체의 메모리 사용량이되고 컴파일 된 언어의 경우 기본 메소드를 실행하고 아무 것도 수행하지 않는 프로그램의 메모리 사용량이됩니다.

프로그램은의 10000 x 10000행 값 20000 <= x <= 29999과 열 값 에 대해 매트릭스에서 테스트됩니다 20000 <= y <= 29999.

프로그램의 점수는 프로그램이 달성하는 정확도 (정확한 추측 횟수)이며 짧은 코드는 순위 결정 역할을합니다.


3
01.R무작위로 true 또는 false를 출력하는 05AB1E입니다. 0은 true이고 1은 false입니다. 내 프로그램은 이론적으로 ~ 50 %의 시간이 정확합니다. 유효한 항목입니까?
매직 문어 Urn

@carusocomputing 실제로, 무작위 솔루션은 허용되지 않는다는 것을 언급하지 않았습니다 . 워드 함수가 의미하는 것으로 생각되지만 프로그램은 매번 동일한 입력에 대해 동일한 출력을 생성해야 합니다.
Joe Z.

각 호출에서 내 prng의 시드를 수정하면 동일한 입력에 대해 동일한 출력이 생성되며 의미가 무엇인지 알지만 어떻게 든 더 구체적으로 말해야 할 것입니다.
마일


@Linus "Wythoff의 게임 매트릭스"가 더 좋을까요? 나는 그 페이지도 보았다.
Joe Z.

답변:


6

파이썬; 정확도 = 54,074,818; 크기 = 65,526 바이트

이전 점수 : 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

이 방법은 행렬의 모든 고유 항목을 523,200 개의 그룹으로 나누고 이진 문자열에서 그룹 (x, y)에 대한 최상의 추측을 읽습니다 . Google 드라이브 에서 전체 소스 코드를 다운로드 할 수 있습니다 .

내가 사용했습니다 PeterTaylor의 패리티 @ 문자열을 생성하고 정확도를 계산하기.


나는 여러 가지 더 흥미로운 접근 방식을 시도했지만 결국에는 간단한 하드 코드가 모든 것을 능가했습니다.
Dennis

하드 코딩도 유효한 접근 방식입니다. 예를 들어 어떤 하드 코딩 체계가 최상의 결과를 반환 할 수 있습니다.
Joe Z.

달리 말하지는 않지만, 패리티의 분포는 분명히 무작위가 아니기 때문에 나는이 접근법을 과시하기를 바랐다. 지금까지 나의 모든 시도는 실패했습니다.
Dennis

아냐 괜찮아 그것은 단지이 문제가 너무 어렵다는 것을 의미합니다. 나는 1 차원을 제외하고이 스타일에 대해 더 많은 문제를 만들어 왔습니다. 체크 아웃하려면 모두 샌드 박스에 있습니다.
Joe Z.

4

CJam (정확도 50016828/100000000, 6 바이트)

{+1&!}

(CJammer 이외의 경우 ALGOL 스타일 의사 코드 :) return ((x + y) & 1) == 0.

이것은 내가 시도한 다른 24 가지 간단한 휴리스틱 중 하나보다 우수합니다. 다음 두 가지 최고의 조합과 비교하면 훨씬 좋습니다.


점수는 계산 된 행렬 섹션이 정확하다고 가정합니다. 독립적 인 확인을 환영합니다. http://cheddarmonk.org/codegolf/PPCG95604-parity.bz2 에서 계산 된 패리티 비트를 호스팅하고 있습니다 . (8MB 다운로드, 50MB 텍스트 파일로 추출 : 매트릭스는 기본 대각선에 대해 대칭이므로 각 블록 만 포함했습니다 주 대각선에서 시작하므로 전체 정사각형을 얻으려면 오프셋, 조옮김 및 비트 OR을 사용해야합니다.

내가 계산하는 데 사용한 코드는 Java입니다. 정의를 매우 간단하게 사용하지만 실행 길이를 인코딩하는 세트 데이터 구조를 사용하여 다음 허용 값으로 빠르게 건너 뛸 수 있습니다. 추가 최적화가 가능하지만 약 2 시간 및 1.5GB의 힙 공간에서 적당히 오래된 데스크탑에서 실행됩니다.

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, 정확도 = 50022668/10 8 = 50.0227 %, 4 바이트

2|*.

좌표를 두 개의 인수로 취하고 그 사이의 LCM을 계산하여 모듈로 2를 취합니다. A 0 .1 수단은 홀수이다.

성능은 @에서 제공하는 패리티 비트를 기반으로합니다. Peter Taylor가 .

7 바이트 이전의 PRNG 버전 2|?.@#. 10분의 50,010,491의 정확도했다 (8) 입니다.

설명

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

1
LCM의 패리티는 비트 AND의 패리티입니다. 바이트를 절약합니까? 매혹적인 것은 휴리스틱이 너무 나쁘다는 것입니다 ( 1정확한 비율이 거의 정확히 50 % 일 때 시간의 25 % 만 제공 함 ). 그러나 그렇게 나쁘지 않은 많은 것보다 낫습니다.
Peter Taylor

고맙지 만 불행히도 J의 AND는 문자 그대로 AND입니다.
마일

@PeterTaylor 놀랄만 한 휴리스틱 발견은 이런 도전에 관한 것입니다.
Joe Z.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.