Wythoff matrix modulo 2'de belirli bir değeri yazdırın


11

Wythoff matrisi, Wythoff'un oyunundaki bir satranç tahtasındaki her karenin Grundy sayılarından oluşan sonsuz bir matristir .

Bu matristeki her giriş, girişin konumunun üstünde, solunda veya çapraz olarak kuzeybatısında görünmeyen en küçük negatif olmayan sayıya eşittir.

Sol üst 20 x 20 kare şöyle görünür:

  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 matrisinde rasgele bir girişi hesaplamak için bilinen etkin bir algoritma mevcut değildir. Ancak, bu sorundaki göreviniz, belirli bir koordinattaki sayının wythoff(x, y)çift ​​mi yoksa tek mi olduğunu söyleyecek sezgisel bir işlev tasarlamaya çalışmaktır .

Programınız 64 KB'den (65,536 bayt) fazla kaynak kodu içeremez veya 2 MB'den (2,097,152 bayt) fazla çalışma belleği kullanamaz.

Özellikle bellek kullanımı için bu, programınızın maksimum yerleşik ayar boyutunun, o dilde boş bir programın maksimum yerleşik ayar boyutundan 2 MB'ı aşmayacağı anlamına gelir. Yorumlanan bir dil söz konusu olduğunda, tercüman / sanal makinenin kendisinin bellek kullanımı ve derlenmiş bir dil söz konusu olduğunda, ana yöntemi uygulayan ve hiçbir şey yapmayan bir programın bellek kullanımı olacaktır.

Programınız, 10000 x 10000satır değerleri 20000 <= x <= 29999ve sütun değerleri için matriste test edilecektir 20000 <= y <= 29999.

Programınızın puanı, programınızın başardığı doğruluk oranıdır (doğru tahmin sayısı) ve daha kısa kod bir tiebreaker işlevi görür.


3
01.R, doğru veya yanlış rasgele çıktı veren bir 05AB1E'dir. Bırakın 0 doğru ve 1 yanlış olsun, programım teorik olarak doğru ~% 50 olacak. Bu geçerli bir giriş mi?
Sihirli Ahtapot Urn

@carusocomputing Aslında, randomize çözümlere izin verilmediğini söylemeyi unuttum - word fonksiyonunun bunu ima ettiğinden şüphelenmeme rağmen, programınız her seferinde aynı girdi için aynı çıktıyı üretmelidir .
Joe Z.

Her çağrımda prng'imin tohumunu sabitlersem, aynı giriş için aynı çıkışı üretecek ve ne demek istediğinizi biliyorum, ancak muhtemelen bir şekilde daha spesifik bir şekilde kelime söylemek zorunda kalacaksınız.
mil


@Linus "Wythoff'un Oyun Matrisi" daha iyi olur mu? Ben de o sayfayı gördüm.
Joe Z.

Yanıtlar:


6

Python; doğruluk = 54,074,818; boyut = 65,526 bayt

Önceki puanlar: 50,227,165; 50.803.687; 50953001

#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

Bu yaklaşım, matrisin tüm benzersiz girişlerini 523,200 gruba ayırır ve grup için (x, y) en iyi tahminleri ikili bir dizeden okur . Kaynak kodun tamamını Google Drive'dan indirebilirsiniz .

Ben kullandım PeterTaylor en pariteler @ dize oluşturmak için ve doğruluğunu hesaplamak için.


Birçok farklı, daha ilginç yaklaşım denedim, ama sonunda, basit bir sabit kod hepsinden daha iyi sonuç verdi ...
Dennis

Hardcoding aynı zamanda geçerli bir yaklaşımdır - diyelim ki hangi hardcoding şeması en iyi sonucu verir.
Joe Z.

Aksine söylememekle birlikte, paritelerin dağılımı çok açık bir şekilde rastgele olmadığı için, bu yaklaşımı alt etmek istiyordum. Şimdiye kadar tüm girişimlerim başarısız oldu.
Dennis

Hayır, sorun değil. Sadece bu sorunun düzgün bir şekilde yapılması çok zor olduğu anlamına gelir. Bir boyutlu dışında bu tarzda bir sürü sorun yapıyorum. Eğer kontrol etmek istiyorsanız hepsi kum havuzunda.
Joe Z.

4

CJam (doğruluk 50016828/100000000, 6 bayt)

{+1&!}

(CJammers olmayanlar için ALGOL tarzı sözde kodunda:) return ((x + y) & 1) == 0.

Bu, denediğim diğer iki düzine sezgisel taramadan daha iyi performans gösteriyor. Sonraki iki en iyi olanla herhangi bir kombinasyondan daha iyi.


Skor, matrisin hesaplanmış bölümümün doğru olduğunu varsayar. Bağımsız doğrulama memnuniyetle karşılandı. Hesaplanan parite bitlerini http://cheddarmonk.org/codegolf/PPCG95604-parity.bz2 adresinde barındırıyorum (8MB indirme, 50MB metin dosyasına ayıklar: matris ana diyagonal hakkında simetrik olduğundan, sadece her birini dahil ettim ana diyagonalden başlayarak, tam kareyi elde etmek için ofset, transpoze ve bit yönlü VEYA gerekir).

Hesaplamak için kullandığım kod Java. Tanımı oldukça basit bir şekilde kullanır, ancak çalışma uzunluğu aralıkları kodlayan ve böylece bir sonraki izin verilen değere atlamak için hızlı bir şekilde ayarlanan bir veri yapısına sahiptir. Daha fazla optimizasyon mümkün olabilir, ancak orta derecede eski masaüstümde yaklaşık iki saat ve 1,5 GB yığın alanı içinde çalışır.

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, doğruluk = 50022668/10 8 =% 50.0227, 4 bayt

2|*.

Koordinatları iki argüman olarak alır, aralarındaki LCM'yi hesaplar ve modulo 2'yi alır. A 0eşittir ve bir 1tuhaftır.

Performans, @ Peter Taylor tarafından sağlanan parite bitlerine dayanmaktadır .

7 bayt için daha önce PRNG sürümü 2|?.@#., 50010491/10 8 doğruluk vardı .

açıklama

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

1
LCM'nin paritesi, bitsel AND'in paritesidir. Bu size bir bayt kazandırır mı? Büyüleyici olan şey, çok açık bir şekilde kötü bir sezgisel taramadır ( 1doğru oranın neredeyse% 50 olduğu zamanın sadece% 25'ini verir ) ve yine de çok açık olmayan kötü olan birçok kişiden daha iyidir.
Peter Taylor

Teşekkürler, ama ne yazık ki bitwise VE J tam anlamıyla AND.
mil

@PeterTaylor Bu tür şaşırtıcı sezgisel keşif, bunun gibi zorlukların hepsiyle ilgili olması gerekiyordu.
Joe Z.10
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.