2を法とするWythoff行列の特定の値を出力します


11

Wythoff行列は、Wythoffのゲームのチェス盤上の各正方形のグランディ数で構成される無限行列です。

このマトリックスの各エントリは、エントリの位置の上、左、または斜め北西に表示されない最小の非負数に等しくなります。

左上の20行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)が偶数か奇数かを判断するヒューリスティック関数を設計することです。

プログラムには、64 KB(65,536バイト)を超えるソースコードを含めたり、2 MB(2,097,152バイト)を超える作業メモリを使用したりすることはできません。

特にメモリ使用量の場合、これは、プログラムの最大常駐セットサイズが、その言語の空のプログラムの最大常駐セットサイズよりも2 MBを超えないことを意味します。インタープリター言語の場合は、インタープリター/仮想マシン自体のメモリ使用量であり、コンパイル済み言語の場合は、メインメソッドを実行して何もしないプログラムのメモリ使用量です。

プログラムは、10000 x 10000で行の値20000 <= x <= 29999と列の値のマトリックスでテストされます20000 <= y <= 29999

プログラムのスコアは、プログラムが達成する正確度(正しい推測の数)であり、短いコードがタイブレーカーとして機能します。


3
01.Rランダムにtrueまたはfalseを出力する05AB1Eです。0をtrue、1をfalseとすると、私のプログラムは理論的には50%の確率で正しいでしょう。これは有効なエントリですか?
魔法のタコUr

実は@carusocomputing、私はランダム化されたソリューションが許可されていないことを言及するのを忘れてしまった-私はワードと思われるものの、同じ入力するたびに同じ出力を生成する必要がありますあなたのプログラム機能はそのことを意味しています。
ジョーZ.

各呼び出しでprngのシードを修正すると、同一の入力に対して同じ出力が生成され、その意味はわかりますが、おそらく何らかの形でより具体的に説明する必要があります。
マイル


@Linus「Wythoffのゲームマトリックス」の方が良いでしょうか?私もそのページを見ました。
ジョーZ.

回答:


6

Python; 精度= 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 Driveから完全なソースコードをダウンロードできます。

私が使用してきましたPeterTaylorのパリティ@文字列を生成し、精度を計算します。


私はさまざまな、より興味深いアプローチを試みましたが、最終的には、単純なハードコードがそれらすべてを上回っていました...-
デニス

ハードコーディングも有効なアプローチです。たとえば、どのハードコーディング方式が最良の結果を返すかなどになります。
ジョーZ.

別の言い方をしませんが、パリティの分布は非常に明らかにランダムではないため、このアプローチを上回ることを望んでいました。これまでのところ、私の試みはすべて失敗しています。
デニス

いや、大丈夫です。これは、この問題が適切に実行するには難しすぎることを意味します。私は一次元を除いてこのスタイルのより多くの問題を作っています。それらをチェックアウトする場合は、すべてサンドボックスにあります。
ジョーZ.

4

CJam(精度50016828 / 100000000、6バイト)

{+1&!}

(CJammer以外のALGOLスタイルの擬似コード:)return ((x + y) & 1) == 0

これは、私が試した他の20個の単純なヒューリスティックのいずれよりも優れたパフォーマンスを発揮します。次の2つの最高の組み合わせとの組み合わせよりも優れています。


スコアは、マトリックスの計算されたセクションが正しいと想定しています。独立した検証を歓迎します。計算されたパリティビットをhttp://cheddarmonk.org/codegolf/PPCG95604-parity.bz2でホストしています(8MBのダウンロード、50MBのテキストファイルへの抽出:マトリックスは主対角線に関して対称であるため、それぞれを含めました)メインの対角線から始まる線なので、完全な正方形を得るにはオフセット、転置、ビット単位のORを行う必要があります)。

計算に使用したコードはJavaです。定義はかなり簡単に使用されますが、ランレングスが範囲をエンコードするデータ構造を設定しているため、次の許可された値にすばやくスキップできます。さらに最適化することも可能ですが、適度に古いデスクトップで約2時間、1.5 GBのヒープ領域で実行されます。

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|*.

座標を2つの引数として受け取り、それらの間のLCMを計算し、2を法としてそれを受け取ります。A 0は偶数であり、1奇数であることを意味します。

パフォーマンスは、@ Peter Taylorが提供するパリティビットに基づいています。

以前の7バイトのPRNGバージョン2|?.@#.の精度は50010491/10 8でした。

説明

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

1
LCMのパリティは、ビット単位のANDのパリティです。それでバイトが節約できますか?魅力的なことは、明らかにそれは悪いヒューリスティックであり(1正しい割合がほぼ正確に50%である場合、時間のわずか25%を与える)、それでもそれほど明らかにない多くのものよりも優れています。
ピーターテイラー

ありがとう、しかし残念ながらJのビット単位のANDは文字通りANDです。
マイル

@PeterTaylor驚くべき発見的発見のようなものは、このような挑戦がすべてであると想定されるものです。
ジョーZ.
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.