Sirkuit Domino

36

Papan angka

Berikut adalah skor mentah (yaitu jumlah domino) untuk pengiriman VisualMelon. Saya akan mengubahnya menjadi skor yang dinormalisasi yang dijelaskan di bawah ini, ketika lebih banyak jawaban masuk. Solusi yang ada sekarang dapat menyelesaikan semua sirkuit di benchmark:

 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

Tantangan

Hal ini dimungkinkan untuk membangun gerbang logika sederhana dari domino. Oleh karena itu, dengan menggabungkan ini atau sebaliknya, fungsi biner sewenang-wenang dapat dihitung dengan kartu domino.

Tapi tentu saja, semua orang yang telah bermain dengan kartu domino (kecuali Robin Paul Weijers) telah mengalami kekecewaan ketika kehabisan mereka. Oleh karena itu, kami ingin menggunakan kartu domino kami seefisien mungkin, sehingga kami dapat melakukan beberapa perhitungan yang sangat menarik dengan bahan yang kami miliki.

Perhatikan, bahwa Anda tidak dapat menghasilkan output non-nol dari input nol per se, jadi kami perlu menambahkan "saluran listrik", yang jatuh di sepanjang pengaturan Anda, dan yang dapat Anda tarik 1kapan saja.

Tugas Anda

Diberikan fungsi boolean dengan Minput dan Noutput ( f: {0,1}^M --> {0,1}^Nuntuk kemiringan matematis), menghasilkan sirkuit domino dengan sesedikit mungkin domino yang menghitung fungsi itu. Anda akan menggunakan simbol-simbol |, -, /, \untuk mewakili domino di berbagai orientasi.

Memasukkan

Anda akan diberikan masukan melalui argumen baris perintah:

[command for your solver] M N f

di mana Mdan Nbilangan bulat positif dan fmerupakan tabel kebenaran yang dipisahkan koma dalam urutan kanonik. Artinya, fakan mengandung 2^Mnilai panjang N. Misal jika M = N = 2dan bit pertama dalam output adalah fungsi AND sedangkan bit kedua adalah fungsi OR, fakan dibaca

00,01,01,11

Keluaran

Menulis ke STDOUT kisi ASCII yang mewakili pengaturan domino. Pengaturan Anda harus sesuai dengan kerangka kerja berikut

/////.../////
 ????...????
I????...????O
I????...????O
.............
.............
I????...????O
I????...????O
I????...????O
  • Baris teratas seluruhnya terdiri dari /, dan domino paling kiri dijamin akan terguling di awal - ini adalah saluran listrik Anda.
  • Kolom paling kiri terdiri dari input Anda. Masing I- masing bisa berupa spasi atau |, sedemikian rupa sehingga ada persis M |s.
  • Kolom paling kanan terdiri dari output Anda. Masing O- masing bisa berupa spasi atau |, sedemikian rupa sehingga ada persis N |s.
  • Perhatikan bahwa setidaknya ada satu yang kosong sebelum yang pertama |di input atau output.
  • The .menunjukkan bahwa grid dapat sewenang-wenang besar.
  • Anda dapat mengisi ?dengan cara apa pun yang Anda inginkan.

Perhatikan bahwa input bawah adalah yang paling beragam saat Anda menelusuri tabel kebenaran, sedangkan input atas adalah 0untuk bagian pertama dari output dan 1untuk bagian kedua.

Aturan

Domino menyebar seperti yang ditentukan dalam Golfing untuk Domino Day . Singkatnya, jika kita mewakili arah jatuh sebagai huruf

Q W E
A   D
Z X C

maka ini semua kombinasi unik yang dapat diperbanyak (serta rotasi dan pantulannya):

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

C|   ->    CD          C/   ->    CC

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

Semua aturan di atas diterapkan secara bersamaan pada setiap langkah waktu. Jika dua orang dari aturan-aturan yang bertentangan (ubin yaitu didorong ke dua valid arah berlawanan pada waktu yang sama), ubin yang terkena akan tidak jatuh, dan akan efektif dikunci ke posisi untuk sisa simulasi.

Batasan

  • Mdan Ntidak akan pernah melebihi 6.
  • Pemecah Anda harus menghasilkan sirkuit dalam N * 2 M detik .
  • Solver Anda tidak boleh menggunakan memori lebih dari 1 GB . Ini adalah batas lunak, karena saya akan memonitor ini secara manual dan membunuh proses Anda jika secara signifikan / terus menerus melebihi batas ini.
  • Tidak ada sirkuit yang diizinkan mengandung lebih dari 8.000.000 sel atau 1.000.000 kartu domino .
  • Kiriman Anda harus bersifat deterministik . Anda diizinkan untuk menggunakan generator angka pseudo-acak, tetapi mereka harus menggunakan seed hardcoded (yang Anda bebas untuk mengoptimalkan sebanyak yang Anda mau).

Mencetak gol

Untuk setiap sirkuit, biarlah Djumlah total kartu domino di sirkuit Anda dan Bjumlah kartu domino terendah yang pernah diselesaikan oleh sirkuit ini (oleh Anda atau peserta lain). Kemudian skor Anda untuk sirkuit ini diberikan dengan 10,000 * B / Ddibulatkan ke bawah. Jika Anda gagal menyelesaikan sirkuit, skor Anda adalah 0. Skor keseluruhan Anda akan menjadi jumlah atas serangkaian kasus uji patokan. Sirkuit yang belum diselesaikan oleh siapa pun tidak akan dimasukkan dalam skor total.

Setiap peserta dapat menambahkan satu test case ke benchmark (dan semua pengiriman lainnya akan dievaluasi ulang termasuk case test yang baru).

File benchmark dapat ditemukan di GitHub .

Contohnya

Berikut adalah beberapa contoh yang tidak diselesaikan secara optimal.

Konstan 1

1 1
1,1

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

Hitungan domino: 12

ATAU gerbang

2 1
0,1,1,1

///////////

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

Hitungan domino: 28

DAN gerbang

2 1
0,0,0,1

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

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

Jumlah domino: 62

Ganti jalur

2 2
00,10,01,11

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

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

Hitungan domino: 36

catatan tambahan

Aturan propagasi sedemikian rupa, sehingga jalur diagonal dapat menyeberang menggunakan bentuk berlian (lihat contoh terakhir) meskipun satu jatuh sebelum yang lain (tidak seperti dengan domino nyata).

Sebagai titik awal, Anda dapat menggunakan gerbang logis (tidak diminimalkan) dalam inti ini dan mencoba menggabungkan sesedikit mungkin dari ini. Untuk cara sederhana (tidak optimal) untuk membangun fungsi boolean yang sewenang-wenang dari gerbang AND, ATAU dan BUKAN, lihatlah Bentuk Normal Konjungtif dan Disjungtif .

Ada verifikasi tempat penyimpanan GitHub ini untuk menguji kode Anda, yang juga akan digunakan untuk menilai semua pengiriman. Ini menghasilkan skor mentah (jumlah domino) dan menyimpannya ke file untuk diproses oleh pencetak skor terpisah (juga dalam repositori itu) untuk mendapatkan skor akhir.

Dokumentasi umum dapat ditemukan dalam dua file Ruby, tetapi controller.rbdibutuhkan dua switch baris perintah sebelum file benchmark:

  • -v memberi Anda lebih banyak output, termasuk sirkuit aktual yang dihasilkan oleh pemecah Anda.
  • -cmemungkinkan Anda memilih subset benchmark yang ingin Anda uji. Berikan sirkuit yang diinginkan sebagai daftar indeks berbasis 1 yang dipisahkan koma. Anda juga dapat menggunakan rentang Ruby, sehingga Anda dapat melakukan sesuatu seperti -c 1..5,10,15..20.

Harap sertakan dalam jawaban Anda:

  • Kode Anda
  • Perintah untuk (kompilasi dan) menjalankan kode Anda. Saya akan bertanya kepada Anda di mana mendapatkan kompiler / juru bahasa yang diperlukan jika saya tidak memilikinya.
  • Tabel kebenaran tambahan dengan nama, akan ditambahkan sebagai kasus uji untuk benchmark. (Ini opsional, tetapi sangat dianjurkan.)

Saya akan menguji semua pengiriman pada Windows 8.

Martin Ender
sumber
Semua didorong pada saat bersamaan?
l4m2
@ l4m2 Ya, input di kolom paling kiri digulingkan secara bersamaan.
Martin Ender

Jawaban:

33

C # - Solusi masif, Lambat, dan tidak efisien

Pengakuan: menulis solusi ini beberapa waktu lalu ketika pertanyaannya masih di kotak pasir, tapi itu tidak terlalu baik: Anda bisa melakukan yang lebih baik!

Sunting: mengganti penyelesaian yang membosankan dengan metode yang kurang membosankan, lebih fleksibel, dan umumnya lebih baik

Anda menjalankan program dengan kompilasi dengan csc dominoPrinter.csdan kemudian meneruskan argumen ke executable, misalnya (pemeriksa utama 4-bit):

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

Penjelasan:

"Domino Printer" adalah program 3 tahap:

Tahap 1 : "pemecah" menghasilkan pohon ekspresi "ifnot" dan "atau" operasi biner dengan input yang diberikan, dan "1" dari kabel listrik, ada 2 cara ini dilakukan, tergantung pada jumlah input:

  • Jika terdapat kurang dari 4 input, program akan menghasilkan solusi dari jumlah operasi yang paling sedikit

  • Jika ada 4 atau lebih input, program akan melakukan brute setiap 8 bit output dan kemudian menggabungkan hasilnya untuk memberikan output yang diinginkan. Bit yang dirusak jika fleksibel: bit yang lebih kasar, semakin kecil solusinya, tetapi semakin lama waktu proses.

"Pemecah masalah" adalah yang membutuhkan waktu lama (atau paling tidak seperti dulu), dan juga sebagian besar kode. Saya percaya ada solusi yang terdokumentasi dengan baik, cepat, tidak begitu memori, dan mungkin solusi optimal untuk masalah ini, tetapi di mana kesenangan berada dalam mencari itu?

Pohon ekspresi (brute) untuk pemeriksa utama 4-bit adalah

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

di mana angka-angka adalah indeks input.

Tahap 2 : "Penyelenggara" mengambil pohon ekspresi sebagai input dan merakit tata letak "kerangka", yang secara tepat menggambarkan tata letak domino yang dibuat dari beberapa set sel 4x5 yang tumpang tindih. Di bawah ini adalah kerangka untuk pemeriksa prima 4-bit yang dibasahi (Anda harus mengubah bruteBasevariabel integer pada baris 473 ke 4 (atau lebih besar) untuk mendapatkan hasil ini).

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 

Output ini secara efektif dibuat hingga dua bagian, "evaluator" di sebelah kanan, yang dibuat dari pohon ekspresi dari tahap 1, dan "switchboard" di sebelah kiri, yang menukar dan membagi input sehingga mereka tiba di tempat yang tepat untuk ditangani oleh "evaluator".

Ada ruang yang cukup besar untuk memadatkan tata letak pada titik ini, tetapi program saat ini tidak begitu berfungsi. Kode untuk tahap ini mengerikan, tetapi cukup sederhana di bawahnya (lihat metode "orifnot"). Output dilewatkan ke tahap 3.

Tahap 3 : "Printer" mengambil output dari "organizer" dan mencetak "sel" 4x5 yang sesuai bersama dengan saluran listrik. Di bawah ini adalah animasi dari pemeriksa prime 4-bit yang diperiksa memeriksa apakah 5 adalah prima.

Rupanya 5 adalah prima

Kode kurangnya indentasi adalah untuk menghindari melampaui batas karakter SE 30k yang seharusnya :

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();
   }
  }
 }
}

Kasing uji tambahan:

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

Ini memeriksa apakah dua bit yang berdekatan (non-pembungkus) keduanya 1s (mis. True untuk 0110, tetapi false untuk 0101 dan 1001)

VisualMelon
sumber
2
Ini indah. Sekarang kita membutuhkan pemecah meta domino yang mengambil tabel kebenaran Idan yang hasilnya menentukan tata letak domino baru
salah
Saya bingung bagaimana tabel kebenaran itu mewakili pemeriksa empat bit utama. Tidakkah dikatakan bahwa 14 dan 15 adalah prima?
kuintopia
@quintopia telah melihat lagi ... Anda tampaknya benar, dan ITU salah saya, yang digunakan Martin benar, tetapi saya TIDAK membangun kembali primechecker itu sekarang!
VisualMelon