Domino Devreleri


36

sayı tahtası

VisualMelson'ın gönderiminde ham puanlar (yani domino sayılır). Bunları, daha fazla cevap geldiğinde, aşağıda açıklanan normalize edilmiş puanlara dönüştüreceğim. Mevcut çözüm, şimdi kıyaslamadaki tüm devreleri çözebilir:

 Author       Circuit:   1   2   3   4    5    6   7    8   9  10  11  12   13  14   15   16   17   18  19   20   21  22   23   24    25   26   27   28    29    30    31    32   33   34    35    36     37      38   39
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
VisualMelon             39  45  75  61  307  337  56  106  76  62  64  62  182  64  141  277  115  141  92  164  223  78  148  371  1482  232  107  782  4789  5035  1314  3213  200  172  1303  3732  97596  156889  857
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Legend:
  I - invalid circuit
  B - circuit too big
  W - circuit computes wrong function
  T - exceeded time limit

Meydan okuma

İse olası domino basit mantık kapıları oluşturmak için. Dolayısıyla, bunları veya başkalarını birleştirmek suretiyle, rastgele ikili fonksiyonlar dominolarla hesaplanabilir.

Fakat elbette, dominolarla oynayan (Robin Paul Weijers hariç) herkes tükendiğinde hayal kırıklığı yaşadı. Bu nedenle dominolarımızı mümkün olduğunca verimli kullanmak istiyoruz, böylece sahip olduğumuz malzemelerle gerçekten ilginç bazı hesaplamalar yapabiliriz.

Unutmayın, sıfır girişli sıfır çıkış üretemezsiniz, bu nedenle kurulumunuz boyunca düşen 1ve istediğiniz zaman s alabileceğiniz bir "güç hattı" eklememiz gerekir .

Senin görevin

MGiriş ve Nçıkışlara sahip bir boolean işlevi göz önüne alındığında ( f: {0,1}^M --> {0,1}^Nmatematiksel olarak eğimli için), bu işlevi hesaplayan mümkün olduğunca az domino içeren bir domino devresi oluşturur. Sen semboller kullanarak olacak |, -, /, \çeşitli yönlerde domino temsil etmek.

Giriş

Komut satırı argümanları ile size giriş verilecektir:

[command for your solver] M N f

pozitif tamsayılar nerede Mve virgülle ayrılmış doğruluk tablosu kanonik düzendedir. Bu, uzunluk değerlerini içerecektir . Örneğin eğer ikinci bit VEYA fonksiyonu iken çıktısında ilk bit VE fonksiyonu oldu okurdumNff2^MNM = N = 2f

00,01,01,11

Çıktı

Domino kurulumunu temsil eden bir ASCII ızgarasını STDOUT'a yazın. Kurulumunuz aşağıdaki çerçeveye uymalıdır

/////.../////
 ????...????
I????...????O
I????...????O
.............
.............
I????...????O
I????...????O
I????...????O
  • En üst sıra tamamen oluşur /ve en soldaki domino başlangıçta devrileceği garantilidir - bu sizin güç hattınızdır.
  • En soldaki sütun girdilerinizden oluşur. Her biri Ibir boşluk veya |tam olarak M |s olması için a olabilir .
  • En sağdaki sütun çıktılarınızdan oluşur. Her biri Obir boşluk veya |tam olarak N |s olması için a olabilir .
  • |Giriş veya çıkışta birinciden önce en az bir boşluk olduğuna dikkat edin .
  • .Izgara rasgele büyük olabilir göstermektedir.
  • İstediğiniz ?herhangi bir şekilde doldurabilirsiniz .

Doğruluk tablosu boyunca ilerlerken en alttaki girişin en değişken olduğunu ve en üst girişin 0çıkışların ilk yarısı ve 1ikinci yarısı için olduğunu unutmayın.

kurallar

Domino, Golf için Domino Günü'nde belirtildiği şekilde yayılır . Kısacası, düşen yönleri harf olarak gösterirsek

Q W E
A   D
Z X C

o zaman bunlar, yayılabilecek tüm benzersiz kombinasyonlardır (dönüşleri ve yansımaları ile birlikte):

D|   ->    DD          D\   ->    DE          D/   ->    DC

C|   ->    CD          C/   ->    CC

C    ->    C           C    ->    C           C    ->    C
 |          D           -          X           /          C

Yukarıdaki kuralların tümü, her bir zaman adımında aynı anda uygulanır. Bu kurallardan iki (yani bir kiremit iki itilir çakışıyorsa geçerli aynı anda zıt yönlerde), etkilenen kiremit olacak değil düşmek, ve etkili simülasyon geri kalanı için pozisyona kilitlenecektir.

Kısıtlamalar

  • Mve Nasla 6'yı geçmeyecek.
  • Çözücünüz N * 2 M saniye içerisinde bir devre üretmelidir .
  • Çözücünüz 1 GB'tan fazla bellek kullanmamalıdır . Bu yumuşak bir limit, çünkü bunu manuel olarak izleyeceğim ve bu sınırı önemli ölçüde / sürekli olarak aşarsa işleminizi sonlandıracağım.
  • Hiçbir devrenin 8.000.000'den fazla hücre veya 1.000.000 domino içermesine izin verilmez .
  • Gönderiminiz deterministik olmalı . Sözde rasgele sayı üreteçleri kullanmanıza izin verilir, ancak bir kodlanmış tohum kullanmaları gerekir (ki bu istediğiniz kadar optimize etmek için özgürsünüz).

puanlama

Her devre için, devrenizdeki Dtoplam domino Bsayısı ve bu devrenin çözdüğü en düşük domino sayısı (siz veya başka bir katılımcı tarafından) olsun. O zaman bu devre için puanınız 10,000 * B / Dyuvarlatılarak verilir . Devreyi çözemediyseniz, puanınız 0'dır. Toplam puanınız, bir test test kümesinin karşılaştırmalı toplamı olacaktır. Henüz hiç kimse tarafından çözülmemiş olan devreler toplam puana dahil edilmeyecektir.

Her katılımcı kriterlere bir test durumu ekleyebilir (ve bu yeni test durumu da dahil olmak üzere diğer tüm başvurular yeniden değerlendirilecektir).

Benchmark dosyasını GitHub'da bulabilirsiniz .

Örnekler

İşte bazı optimal olmayan çözülmüş örnekler.

Sabit 1

1 1
1,1

///////
   /
|   |||

Domino sayısı: 12

VEYA kapısı

2 1
0,1,1,1

///////////

|||||/
      |||||
|||||\

Domino sayısı: 28

VE geçit

2 1
0,0,0,1

///////////////////

       \-/
       - -
|||||/|\ /|||/
      /      -
       -    \-
      \-   \ -
|||||\ /  \  /
        |\    |||||

Domino sayısı: 62

Şerit değiştirme

2 2
00,10,01,11

////////////

||||/  \||||
     /\
     \/
||||\  /||||

Domino sayısı: 36

ek Notlar

Yayılma kuralları çapraz şerit ki şekildedir olabilir , bir (gerçek domino ile farklı olarak) diğerinden önce düşse bile (son örneğe bakın) bir elmas şekli ile çapraz.

Bir başlangıç ​​noktası olarak, bu boşlukta (simge durumuna küçültülmüş olmayan) mantıksal kapıları kullanabilir ve mümkün olduğunca az sayıda birleştirmeyi deneyebilirsiniz. AND, VEYA ve DEĞİL kapılarından rasgele boolean işlevler oluşturmanın basit (optimal olmayan) bir yolu için, Konjunktif ve Disjunktif Normal Formlara bakın.

Bu GitHub deposunu kodunuzu sınamak için bir doğrulama var, bu da tüm gönderileri puanlamak için de kullanılacak. Bu ham puanları (domino sayar) verir ve final puanlarını almak için ayrı bir puanlayıcı (aynı zamanda bu depoda) tarafından işlenecek bir dosyaya kaydeder.

Genel dokümantasyon iki Ruby dosyasında bulunabilir, ancak controller.rbkıyaslama dosyasından önce iki komut satırı anahtarını alır:

  • -v Çözücünüz tarafından üretilen gerçek devreler dahil, size daha fazla çıktı verir.
  • -cTest etmek istediğiniz kriterin altkümesini seçmenize izin verir. İstenen devreleri virgülle ayrılmış 1 tabanlı dizinlerin bir listesi olarak sağlayın. Ruby çeşitlerini de kullanabilirsiniz, böylece böyle bir şey yapabilirsiniz -c 1..5,10,15..20.

Lütfen cevabınıza ekleyin:

  • Senin kodun
  • Kodunuzu çalıştırmak (derlemek ve) komutu. Sizde yoksa, gerekli derleyicileri / tercümanları nereden edinebileceğinizi soracağım.
  • Kriterlere bir test davası olarak eklenecek, ismiyle birlikte ek bir doğruluk tablosu. (Bu isteğe bağlıdır, ancak şiddetle teşvik edilmektedir.)

Windows 8'deki tüm başvuruları test edeceğim.


Hepsi aynı anda itti?
14m2'de

@ l4m2 Evet, en soldaki sütundaki girişler aynı anda devrilir.
Martin Ender

Yanıtlar:


33

Büyük, Yavaş ve verimsiz çözüm

İtiraf: bu çözümü bir süre önce, soru hala sanal alandayken yazdı, ancak bu pek iyi değil: daha iyisini yapabilirsiniz!

Düzenleme: sondaj çözme yerine daha az sıkıcı, daha esnek ve genellikle daha iyi bir yöntem kullanıldı

csc dominoPrinter.csÖrneğin, (4 bit üssü denetleyicisi) derleyerek ve sonra da çalıştırılabilir değişkenleri ileterek programı çalıştırın.

dominoPrinter.exe 4 1 0,0,1,1,0,1,0,1,0,0,0,1,0,1,1,1

Açıklama:

"Domino Yazıcı" 3 aşamalı bir programdır:

Aşama 1 : "Çözücü", verilen girişlerle "ifnot" ve "veya" ikili işlemlerin "ve" 1 "ifadesinin bir ağacını oluşturur ve elektrik hattından" 1 "in, giriş sayısına bağlı olarak bu işlemin 2 yolu vardır:

  • 4'ten az giriş varsa, program en az sayıda işlem için bir çözüm sunar

  • 4 veya daha fazla giriş varsa, program her 8 bitlik yığın çıktısını kaldırır ve ardından istenen çıkışı vermek için sonuçları birleştirir. Esnekse şeritli uçlar: daha fazla şeritli uçlar, çözüm ne kadar küçükse, çalışma süresi o kadar uzun olur.

"Çözücü", her zaman (veya en azından eskisi gibi) alan şeydir ve ayrıca kodun çoğu. Ben inanıyorum bu soruna bir iyi belgelenmiş, hızlı, bellek değil bu yüzden aç ve muhtemelen en uygun çözüm yoktur, ama nerede eğlenceli yukarı bakarak olurdu?

4 bitlik prime denetleyicisinin (bruted) ifade ağacı

((2 or 1) ifnot (((0 ifnot 1) or ((1 ifnot 0) or (0 ifnot 2))) ifnot 3))

sayılar girişlerin indeksleridir.

Aşama 2 : "Düzenleyici", ifade ağacını girdi olarak alır ve bazı 4x5 örtüşen hücrelerden oluşan bir domino düzenini tam olarak tanımlayan bir "iskelet" düzenini birleştirir. Aşağıda, 4-bit prime denetleyicisinin iskeleti verilmiştir bruteBase(bu sonucu almak için 473 satırındaki 4 tam sayı değişkenini (veya daha büyük) değiştirmeniz gerekir).

18 9
I ___ _ _______  O
 v _ X X ____  uu 
I X X X u    UU/  
 v X X v ___///   
I X X \ u   //    
 v X \ v __//     
I_X \ \_u  /      
   \ \ ___/       
    \_U 

Bu çıktı iki aşamadan oluşur, sağdaki “değerlendirici”, 1. aşamadaki ifade ağacından yaratılır ve soldaki “geçiş panosu”, girişleri yerlerine girecek şekilde değiştirir ve böler. Değerlendiricinin kullanması gereken doğru yerler.

Düzenin bu noktada sıkıştırılması için önemli bir alan var, ancak program şu anda çok az iş yapıyor. Bu aşama için kod korkunç, ama altında oldukça basit ("orifnot" yöntemine bakın). Çıkış, aşama 3'e geçirilir.

Aşama 3 : "Yazıcı" çıktıyı "düzenleyiciden" alır ve karşılık gelen 4x5 örtüşen "hücreleri" güç hattıyla birlikte yazdırır. Aşağıda, 5'in asal olup olmadığını kontrol eden yivli 4 bitlik ana denetleyicinin bir animasyonu gösterilmektedir.

Görünüşe göre 5 asal

Kod girintili eksikliği SE 30k karakter sınırı üzerinden gidiyor önlemek için hangi aksi olurdu :

using System;
using System.Collections.Generic;

namespace dominoPrinter
{
 class Program
 {
  static string bstring(bool[] barr)
  {
   string str = "";
   foreach (bool b in barr)
    str += b?1:0;
   return str;
  }

  public static void Main(string[] args)
  {

   int inputCount;
   val[] vals = resolveVals(args[0], args[1], args[2], out inputCount);

   System.IO.StringWriter sw = new System.IO.StringWriter();
   orifnot(inputCount, vals, sw);
   System.IO.StringReader sr = new System.IO.StringReader(sw.ToString());

   printDominoes(sr, Console.Out, args.Length > 3 && args[3] == "quite");
  }

  public abstract class val
  {
   public int size;
   public bool[] rs;
   public abstract string strness();
  }

  public class baseVal : val
  {
   public bool b;
   public int id;

   public baseVal(int idN)
   {
    id = idN;
    size = 1;
   }

   public override string strness()
   {
    return id.ToString();
   }
  }

  public abstract class biopVal : val
  {
   public val a, b;

   public biopVal(val aN, val bN)
   {
    a = aN;
    b = bN;
    size = a.size + b.size;
   }

   public bool buildCheckApply(nodev ntree)
   {
    nodev cur = ntree;
    rs = new bool[a.rs.Length];
    bool notOK = true;
    for (int i = 0; i < rs.Length; i++)
    {
     bool r = rs[i] = go(a.rs[i], b.rs[i]);
     if (notOK)
     {
      if (r)
      {
       if (cur.a == null)
        notOK = false;
       else
       {
        cur = cur.a;
        if (cur == nodev.full)
         return false;
       }
      }
      else
      {
       if (cur.b == null)
        notOK = false;
       else
       {
        cur = cur.b;
        if (cur == nodev.full)
         return false;
       }
      }
     }
    }

    ntree.apply(this, 0);
    return true;
   }

   public abstract bool go(bool a, bool b);
  }

  public class ifnotVal : biopVal
  {
   public override bool go(bool a, bool b)
   {
     return a ? false : b; // b IF NOT a, else FALSE
   }

   public ifnotVal(val aN, val bN) : base(aN, bN)
   {
   }

   public override string strness()
   {
    return "(" + b.strness() + " ifnot " + a.strness() + ")";
   }
  }

  public class orval : biopVal
  {
   public override bool go(bool a, bool b)
   {
    return a || b; // a OR b
   }

   public orval(val aN, val bN) : base(aN, bN)
   {
   }

   public override string strness()
   {
    return "(" + b.strness() + " or " + a.strness() + ")";
   }
  }

  static bool boolCompare(bool[] a, bool b)
  {
   for (int i = 0; i < a.Length; i++)
   {
    if (a[i] != b)
    {
     return false;
    }
   }
   return true;
  }

  static bool boolFlat(bool[] a)
  {
   bool p = a[0];
   for (int i = 1; i < a.Length; i++)
   {
    if (a[i] != p)
     return false;
   }
   return true;
  }

  static bool boolCompare(bool[] a, bool[] b)
  {
   if (a.Length != b.Length)
    return false; // let's do this proeprly
   for (int i = 0; i < a.Length; i++)
   {
    if (a[i] != b[i])
    {
     return false;
    }
   }
   return true;
  }

  // solver

  // these is something VERY WRONG with the naming in this code
  public class nodev
  {
   public static nodev full = new nodev();

   public nodev a, b;

   public nodev()
   {
    a = null;
    b = null;
   }

   public bool contains(bool[] rs)
   {
    nodev cur = this;
    if (cur == full)
     return true;

    for (int i = 0; i < rs.Length; i++)
    {
     if (rs[i])
     {
      if (cur.a == null)
       return false;
      cur = cur.a;
     }
     else
     {
      if (cur.b == null)
       return false;
      cur = cur.b;
     }

     if (cur == full)
      return true;
    }
    return true;
   }

   public bool contains(val v)
   {
    nodev cur = this;
    if (cur == full)
     return true;

    for (int i = 0; i < v.rs.Length; i++)
    {
     if (v.rs[i])
     {
      if (cur.a == null)
       return false;
      cur = cur.a;
     }
     else
     {
      if (cur.b == null)
       return false;
      cur = cur.b;
     }

     if (cur == full)
      return true;
    }
    return true;
   }

   // returns whether it's full or not
   public bool apply(val v, int idx)
   {
    if (v.rs[idx])
    {
     if (a == null)
     {
      if (idx == v.rs.Length - 1)
      { // end of the line, fellas
       a = full;
       if (b == full)
        return true;
       return false;
      }
      else
      {
       a = new nodev();
      }
     }
     if (a.apply(v, idx + 1))
      a = full;
     if (a == full && b == full)
      return true;
    }
    else
    {
     if (b == null)
     {
      if (idx == v.rs.Length - 1)
      { // end of the line, fellas
       b = full;
       if (a == full)
        return true;
       return false;
      }
      else
      {
       b = new nodev();
      }
     }
     if (b.apply(v, idx + 1))
      b = full;
     if (a == full && b == full)
      return true;
    }
    return false;
   }
  }

  public static void sortOutIVals(baseVal[] ivals, int rc)
  {
   for (int i = 0; i < ivals.Length; i++)
   {
    ivals[i].rs = new bool[rc];
    ivals[i].b = false;
   }

   int eri = 0;

   goto next;
  again:
   for (int i = ivals.Length - 1; i >= 0; i--)
   {
    if (ivals[i].b == false)
    {
     ivals[i].b = true;
     goto next;
    }
    ivals[i].b = false;
   }

   return;
  next:
   for (int i = ivals.Length - 1; i >= 0; i--)
   {
    ivals[i].rs[eri] = ivals[i].b;
   }

   eri++;
   goto again;
  }

  public static val[] resolve(int inputCount, int c, bool[][] erss, out baseVal[] inputs)
  {
   val[] res = new val[erss.Length];

   List<List<val>> bvals = new List<List<val>>();
   nodev ntree = new nodev();

   List<val> nvals = new List<val>();

   baseVal tval = new baseVal(-1);
   baseVal fval = new baseVal(-2);
   baseVal[] ivals = new baseVal[inputCount];
   inputs = new baseVal[inputCount + 2];

   for (int i = 0; i < inputCount; i++)
   {
    ivals[i] = new baseVal(i); // value will change anyway
    inputs[i] = ivals[i];
   }
   inputs[inputCount] = fval;
   inputs[inputCount + 1] = tval;

   sortOutIVals(ivals, c);

   for (int i = 0; i < inputCount; i++)
   {
    nvals.Add(ivals[i]);
   }

   tval.rs = new bool[c];
   fval.rs = new bool[c];
   for (int i = 0; i < c; i++)
   {
    tval.rs[i] = true;
    fval.rs[i] = false;
   }

   nvals.Add(tval);
   nvals.Add(fval); // ifnot and or do nothing with falses

   bvals.Add(new List<val>());

   foreach (val v in nvals)
   {
    ntree.apply(v, 0);
    if (!boolFlat(v.rs))
     bvals[0].Add(v); // I trust these are distinct..
   }

   Func<biopVal, bool> checkValb = (v) =>
   {
    if (!v.buildCheckApply(ntree))
    {
     return false;
    }
    bvals[v.size-1].Add(v);
    return true;
   };

   Action<biopVal, List<val>> checkVal = (v, li) =>
   {
    if (checkValb(v))
     li.Add(v);
   };

   int maxSize = 1;

  again:
   for (int i = 0; i < erss.Length; i++)
   {
    bool[] ers = erss[i];
    if (res[i] == null && ntree.contains(ers))
    {
     // there is a reason this is separate... I'm sure there is....
     foreach (val rv in nvals)
     {
      if (boolCompare(rv.rs, ers))
      {
       res[i] = rv;
       break;
      }
     }
    }
   }

   for (int i = 0; i < erss.Length; i++)
   {
    if (res[i] == null)
     goto notoveryet;
   }
   return res;

  notoveryet:

   maxSize++;
   bvals.Add(new List<val>()); // bvals[maxSize-1] always exists

   nvals.Clear();
   long cc = 0;

   List<val> sbvals = bvals[maxSize - 2];
   // NOTs have a habit of working out, get it checked first
   for (int i = sbvals.Count - 1; i >= 0; i--)
   { // also known as nvals, but let's ignore that
    val arv = sbvals[i];
    checkVal(new ifnotVal(arv, tval), nvals);
    cc += 1;
   }

   for (int s = 1; s < maxSize; s++)
   {
    List<val> abvals = bvals[s - 1];
    int t = maxSize - s;
    if (t < s)
     break;
    List<val> bbvals = bvals[t - 1];

    for (int i = abvals.Count - 1; i >= 0; i--)
    {
     val arv = abvals[i];

     int jt = t == s ? i : bbvals.Count - 1;
     for (int j = jt; j >= 0; j--)
     {
      val brv = bbvals[j];

      checkVal(new ifnotVal(brv, arv), nvals);
      checkVal(new ifnotVal(arv, brv), nvals);
      checkVal(new orval(brv, arv), nvals); // don't technically need ors, but they are good fun
      cc += 3;
     }
    }
   }

   int bc = 0;
   foreach (List<val> bv in bvals)
    bc += bv.Count;
   goto again;
  }

  public static val[] resolveVals(string mStr, string nStr, string erStr, out int inputCount)
  {
   int ic = int.Parse(mStr);
   int oc = int.Parse(nStr);
   inputCount = ic;
   int bruteBase = 3;
   if (inputCount <= bruteBase)
    return resolveVals(ic, oc, erStr);
   else
    return resolveValFours(bruteBase, ic, oc, erStr);
  }

  public static val joinVals(val low, val high, baseVal inp, baseVal tval, baseVal fval)
  {
   val lowCut = low == fval ? (val)fval : low == tval ? (val)new ifnotVal(inp, tval) : (val)new ifnotVal(inp, low);

   val highCut = high == fval ? (val)fval : high == tval ? (val)inp : (val)new ifnotVal(new ifnotVal(inp, tval), high);

   if (highCut == fval)
    return lowCut;
   if (lowCut == fval)
    return highCut;
   return new orval(highCut, lowCut);
  }

  public static val resolveValFour(int n, int m, int inputCount, bool[] ers)
  {
   // solves fours
   int fc = ers.Length / m;
   bool[][] fours = new bool[fc][];

   for (int i = 0; i < fc; i++)
   {
    fours[i] = new bool[m];
    for (int j = 0; j < m; j++)
    {
     fours[i][j] = ers[i*m+j];
    }
   }

   baseVal[] inputs;
   val[] fres = resolve(n, m, fours, out inputs);
   baseVal tval = inputs[inputs.Length - 1];
   baseVal fval = inputs[inputs.Length - 2];

   for (int i = 0; i < n; i++)
   {
    inputs[i].id += inputCount - n;
   }

   // assemble
   for (int i = 0, c = 1; c < fc; c *= 2, i++)
   {
    for (int j = 0; j + c < fc; j += c * 2)
    {
     fres[j] = joinVals(fres[j], fres[j+c], new baseVal((inputCount - n - 1) - i), tval, fval);
    }
   }

   return fres[0];
  }

  public static val[] resolveValFours(int n, int inputCount, int outputCount, string erStr)
  {
   int m = 1;
   for (int i = 0; i < n; i++)
    m *= 2;

   val[] res = new val[outputCount];

   string[] data = erStr.Split(',');
   for (int i = 0; i < outputCount; i++)
   {
    bool[] ers = new bool[data.Length];
    for (int j = 0; j < data.Length; j++)
     ers[j] = data[j][i] == '1';
    res[i] = resolveValFour(n, m, inputCount, ers);
   }

   return res;
  }

  public static val[] resolveVals(int inputCount, int outputCount, string erStr)
  {
   val[] res;

   string[] data = erStr.Split(',');
   bool[][] erss = new bool[outputCount][];
   for (int i = 0; i < outputCount; i++)
   {
    bool[] ers = new bool[data.Length];
    for (int j = 0; j < data.Length; j++)
     ers[j] = data[j][i] == '1';
    erss[i] = ers;
   }

   baseVal[] inputs; // no need
   res = resolve(inputCount, data.Length, erss, out inputs);

   return res;
  }

  // organiser
  public class vnode
  {
   private static vnode[] emptyVC = new vnode[0];
   public static vnode oneVN = new vnode('1');
   public static vnode noVN = new vnode(' ');
   public static vnode flatVN = new vnode('_');
   public static vnode moveUpVN = new vnode('/');
   public static vnode moveDownVN = new vnode('\\');
   public static vnode inputVN = new vnode('I');
   public static vnode outputVN = new vnode('O');
   public static vnode swapVN = new vnode('X');
   public static vnode splitDownVN = new vnode('v');

   public int size;
   public vnode[] children;
   public char c;
   public int id = -3;

   public vnode(char cN)
   {
    c = cN;
    children = emptyVC;
    size = 1;
   }

   public vnode(val v)
   {
    biopVal bv = v as biopVal;

    if (bv != null)
    {
     children = new vnode[2];
     children[0] = new vnode(bv.a);
     children[1] = new vnode(bv.b);
     size = children[0].size + children[1].size;

     if (bv is orval)
      c = 'U';
     if (bv is ifnotVal)
      c = 'u';
    }
    else
    {
     children = emptyVC;
     size = 1;
     c = 'I';
     id = ((baseVal)v).id;
    }
   }
  }

  public class nonArray<T>
  {
   public int w = 0, h = 0;
   Dictionary<int, Dictionary<int, T>> map;

   public nonArray()
   {
    map = new Dictionary<int, Dictionary<int, T>>();
   }

   public T this[int x, int y]
   {
    get
    {
     Dictionary<int, T> yd;
     if (map.TryGetValue(x, out yd))
     {
      T v;
      if (yd.TryGetValue(y, out v))
      {
       return v;
      }
     }
     return default(T);
    }
    set
    {
     if (x >= w)
      w = x + 1;
     if (y >= h)
      h = y + 1;
     Dictionary<int, T> yd;
     if (map.TryGetValue(x, out yd))
     {
      yd[y] = value;
     }
     else
     {
      map[x] = new Dictionary<int, T>();
      map[x][y] = value;
     }
    }
   }
  }

  public static int fillOutMap(nonArray<vnode> map, vnode rn, int y, int x)
  {
   if (rn.children.Length == 0)
   {
    map[y,x] = rn;
    return 1;
   }
   else
   {
    map[y+1,x] = rn;
    for (int i = 0; i < rn.children.Length; i++)
    {

     if (i == 0)
     {
      fillOutMap(map, rn.children[i], y, x + 1);
     }

     if (i == 1)
     {
      int ex = x + rn.children[0].size;
      for (int j = 1; j < ex - x; j++)
       map[y - j + 1,ex - j] = vnode.moveUpVN;
      fillOutMap(map, rn.children[i], y, ex);
     }

     y += rn.children[i].size;
    }
   }

   return rn.size;
  }

  public static void orifnot(int inputCount, val[] vals, System.IO.TextWriter writer)
  {
   // step one - build weird tree like thing of death
   nonArray<vnode> map = new nonArray<vnode>();

   int curY = 0;
   foreach (val v in vals)
   {
    vnode vnt = new vnode(v);
    map[curY, 0] = vnode.outputVN;
    curY += fillOutMap(map, vnt, curY, 1);
   }

   // step two - build the thing to get the values to where they need to be
   // find Is
   List<int> tis = new List<int>();
   for (int y = 0; y < map.w; y++)
   {
    for (int x = map.h - 1; x >= 0; x--)
    {
     vnode vn = map[y,x];
     if (vn != null && vn.c == 'I')
     {
      tis.Add(vn.id);
      if (vn.id > -2)
      {
       for (;x < map.h; x++)
       {
        map[y,x] = vnode.flatVN;
       }
      }
      goto next;
     }
    }
    tis.Add(-2);
   next:
    continue;
   }

   // I do not like this piece of code, it can be replaced further down for the better if you get round to thinking about it
   // add unused Is
   for (int z = 0; z < inputCount; z++)
   {
    if (!tis.Contains(z))
    {
     int midx = tis.IndexOf(-2);
     if (midx != -1)
     {
      tis[midx] = z;
      map[midx,map.h-1] = vnode.noVN;
     }
     else
     {
      tis.Add(z);
      map[map.w,map.h-1] = vnode.noVN;
     }
    }
   }

   int curX = map.h;

  MORE:
   for (int y = 0; y < map.w; y++)
   {
    if (y == map.w - 1)
    {
     if (tis[y] == -2)
      map[y,curX] = vnode.noVN;
     else
      map[y,curX] = vnode.flatVN;
    }
    else
    {
     int prev = tis[y];
     int cur = tis[y + 1];

     if (cur != -2 && (prev == -2 || cur < prev))
     { // swap 'em
      map[y,curX] = vnode.noVN;
      if (prev == -2)
       map[y+1,curX] = vnode.moveDownVN;
      else
       map[y+1,curX] = vnode.swapVN;
      int temp = tis[y];
      tis[y] = tis[y + 1];
      tis[y + 1] = temp;
      y++; // skip
     }
     else
     {
      if (/*thatThingThat'sAThing*/ prev == cur && cur != -2)
      {
       map[y,curX] = vnode.noVN;
       map[y+1,curX] = vnode.splitDownVN;
       int temp = tis[y];
       tis[y+1] = -2;
       y++; // skip
      }
      else
      {
       if (prev == -2)
        map[y,curX] = vnode.noVN;
       else
        map[y,curX] = vnode.flatVN;
      }
     }
    }
   }

   // check if sorted
   for (int y = 0; y < map.w - 1; y++)
   {
    int prev = tis[y];
    int cur = tis[y + 1];

    if (cur != -2 && (prev == -2 || cur < prev))
     goto NOTSORTED;
   }

   goto WHATNOW;

  NOTSORTED:
   curX++;
   goto MORE;

  WHATNOW:

   tis.Add(-2); // this is to avoid boud checking y+2
   // so... it's sorted now, so add the splits
  morePlease:
   curX++;
   for (int y = 0; y < map.w; y++)
   {
    if (y == map.w - 1)
    {
     if (tis[y] == -2)
      map[y,curX] = vnode.noVN;
     else
      map[y,curX] = vnode.flatVN;
    }
    else
    {
     int prev = tis[y];
     int cur = tis[y + 1];
     int next = tis[y + 2];

     if (cur != -2 && prev == cur && cur != next)
     { // split
      map[y,curX] = vnode.noVN;
      map[y+1,curX] = vnode.splitDownVN;
      tis[y + 1] = -2;
      y++; // skip
     }
     else
     {
      if (prev == -2)
       map[y,curX] = vnode.noVN;
      else
       map[y,curX] = vnode.flatVN;
     }
    }
   }

   // check if collapsed
   for (int y = 0; y < map.w - 1; y++)
   {
    int prev = tis[y];
    int cur = tis[y + 1];

    if (cur != -2 && prev == cur)
     goto morePlease;
   }

   // ok... now we put in the Is and 1
   curX++;
   map[0, curX] = vnode.oneVN;
   int eyeCount = 0;
   int ly = 0;
   for (int y = 0; y < map.w; y++)
   {
    if (tis[y] > -1)
    {
     map[y, curX] = vnode.inputVN;
     eyeCount++;
     ly = y;
    }
   }

   // step three - clean up if we can
   // push back _  esq things to  _
   //           _/               /
   // this /shouldn't/ be necessary if I compact the vals properlu
   for (int y = 0; y < map.w - 1; y++)
   {
    for (int x = 1; x < map.h; x++)
    {
     if (map[y, x] != null && map[y+1, x] != null && map[y+1, x-1] != null)
     {
      char uc = map[y+1, x-1].c;
      if (map[y, x].c == '_' && map[y+1, x].c == '_'
          && (uc == 'U' || uc == 'u'))
      {
       map[y, x] = vnode.noVN;
       map[y, x-1] = vnode.flatVN;
       map[y+1, x] = map[y+1, x-1];
       map[y+1, x-1] = vnode.noVN;
      }
     }
    }
   }

   // step four - write out map
   writer.WriteLine(map.h + " " + map.w);

   for (int y = 0; y < map.w; y++)
   {
    for (int x = map.h - 1; x >= 0; x--)
    {
     vnode vn = map[y,x];
     if (vn != null)
      writer.Write(vn.c);
     else
      writer.Write(' ');
    }
    writer.WriteLine();
   }
  }

  // printer
  static string up1 = @"      /     /     /     /";
  static string input = @"                    |||||";
  static string output = @"                    |    ";
  static string flat = @"            |/  \  /|\   ";
  static string splitDown = @"|//   / /\  |\/    /     ";
  static string splitUp = @"         \  |/\ \ \/|\\  ";
  static string moveDown = @"|//     /     /    /     ";
  static string moveUp = @"         \    \   \ |\\  ";
  static string swap = @"|/  |  /\   /\   \/ |\  |";
  static string orDown = @"|/    /     |/  \  /|\   ";
  static string orUp = @"|/    /  \  |\  \   |\   ";
  static string ifnotDown = @"|/     /     -   \/ |\  |";
  static string ifnotUp = @"|/  |  /\    -   \  |\   ";

  public static void printDominoes(System.IO.TextReader reader, System.IO.TextWriter writer, bool moreverbosemaybe)
  {
   string line;
   string[] data;

   line = reader.ReadLine();
   data = line.Split(' ');
   int w = int.Parse(data[0]);
   int h = int.Parse(data[1]);

   int ox = 0;
   int oy = 0;
   int cx = 5;
   int cy = 5;

   char[,] T = new char[ox + w * cx, oy + h * (cy - 1) + 1];

   Action<int, int, string> setBlock = (int x, int y, string str) =>
   {
    for (int i = 0; i < cx; i++)
    {
     for (int j = 0; j < cy; j++)
     {
      char c = str[i + j * cx];
      if (c != ' ')
       T[ox + x * cx + i, oy + y * (cy - 1) + j] = c;
     }
    }
   };

   // read and write
   for (int j = 0; j < h; j++)
   {
    line = reader.ReadLine();
    for (int i = 0; i < w; i++)
    {
     if (line[i] != ' ')
     {
      switch (line[i])
      {
       case '1':
        setBlock(i, j, up1);
        break;
       case '_':
        setBlock(i, j, flat);
        break;
       case '^':
        setBlock(i, j, splitUp);
        break;
       case 'v':
        setBlock(i, j, splitDown);
        break;
       case '/':
        setBlock(i, j, moveUp);
        break;
       case '\\':
        setBlock(i, j, moveDown);
        break;
       case 'X':
        setBlock(i, j, swap);
        break;
       case 'U':
        setBlock(i, j, orUp);
        break;
       case 'D':
        setBlock(i, j, orDown);
        break;
       case 'u':
        setBlock(i, j, ifnotUp);
        break;
       case 'd':
        setBlock(i, j, ifnotDown);
        break;
       case 'I':
        setBlock(i, j, input);
        break;
       case 'O':
        setBlock(i, j, output);
        break;
      }
     }
    }
   }

   // end
   for (int i = 0; i < T.GetLength(0); i++)
   {
    T[i, 0] = '/';
   }

   // writeout
   w = T.GetLength(0) - cx + 1;
   h = T.GetLength(1);
   if (moreverbosemaybe)
    writer.Write(w + " " + h + " ");
   for (int j = 0; j < T.GetLength(1); j++)
   {
    for (int i = 0; i < T.GetLength(0) - cx + 1; i++)
    {
     char c = T[i, j];
     writer.Write(c == 0 ? ' ' : c);
    }
    if (!moreverbosemaybe)
     writer.WriteLine();
   }
  }
 }
}

Ek bir test durumu:

4 1 0,0,0,1,0,0,1,1,0,0,0,1,1,1,1,1

Bu, iki bitişik (sargısız) bitin her ikisinin de 1 olup olmadığını kontrol eder (örneğin 0110 için doğru, ancak 0101 ve 1001 için yanlış)


2
Bu güzel. Şimdi doğruluk tablosunu alan Ive çıktıları yeni bir domino düzeni belirten bir meta domino çözücüsüne ihtiyacımız var
wrongu

Bu doğruluk tablosunun dört bitlik bir ana denetleyiciyi nasıl temsil ettiği konusunda kafam karıştı. 14 ve 15'in birinci sınıf olduğu söylenmiyor mu?
quintopia

@quintopia tekrar aradı ... doğru gibi görünüyorsun ve BT benim hatam, Martin'in kullandığı doğru, ama ben şimdi bu primechecker'ı yeniden inşa etmiyorum!
VisualMelon
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.