Mạch domino


36

Bảng điểm

Dưới đây là điểm số thô (tức là số lượng domino) cho bài nộp của VisualMelon. Tôi sẽ biến những điểm này thành điểm số chuẩn hóa được mô tả dưới đây, khi có nhiều câu trả lời hơn. Giải pháp hiện tại có thể giải quyết tất cả các mạch trong điểm chuẩn:

 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

Các thách thức

Đó khả năng để xây dựng các cổng logic đơn giản từ domino. Do đó, bằng cách kết hợp những thứ này hoặc cách khác, các hàm nhị phân tùy ý có thể được tính toán với domino.

Nhưng tất nhiên, tất cả những người đã chơi với domino (trừ Robin Paul Weijers) đều trải qua sự thất vọng khi chạy ra khỏi chúng. Do đó, chúng tôi muốn sử dụng domino của mình một cách hiệu quả nhất có thể, vì vậy chúng tôi có thể thực hiện một số tính toán thực sự thú vị với tài liệu chúng tôi có.

Lưu ý rằng bạn không thể tạo đầu ra khác không từ đầu vào 0 mỗi lần, vì vậy chúng tôi sẽ cần thêm "đường dây điện", nằm trong thiết lập của bạn và bạn có thể kéo 1s từ bất cứ lúc nào.

Nhiệm vụ của bạn

Đưa ra một hàm boolean với Mđầu vào và Nđầu ra ( f: {0,1}^M --> {0,1}^Nđối với nghiêng về mặt toán học), tạo ra một mạch domino với càng ít domino càng tốt để tính toán hàm đó. Bạn sẽ được sử dụng những biểu tượng |, -, /, \để đại diện cho domino trong định hướng khác nhau.

Đầu vào

Bạn sẽ được cung cấp đầu vào thông qua các đối số dòng lệnh:

[command for your solver] M N f

trong đó MNlà các số nguyên dương và flà bảng chân lý được phân tách bằng dấu phẩy theo thứ tự chính tắc. Đó là, fsẽ chứa 2^Mcác giá trị của chiều dài N. Ví dụ: nếu M = N = 2và bit đầu tiên trong đầu ra là hàm AND trong khi bit thứ hai là hàm OR, fsẽ đọc

00,01,01,11

Đầu ra

Viết cho STDOUT một lưới ASCII đại diện cho thiết lập domino. Thiết lập của bạn phải phù hợp với khung sau

/////.../////
 ????...????
I????...????O
I????...????O
.............
.............
I????...????O
I????...????O
I????...????O
  • Hàng trên cùng bao gồm hoàn toàn /, và domino ngoài cùng bên trái được đảm bảo được lật đổ ngay từ đầu - đây là dòng sức mạnh của bạn.
  • Cột ngoài cùng bên trái bao gồm các đầu vào của bạn. Mỗi Icó thể là một khoảng trắng hoặc a |, sao cho có chính xác M |s.
  • Cột ngoài cùng bên phải bao gồm các đầu ra của bạn. Mỗi Ocó thể là một khoảng trắng hoặc a |, sao cho có chính xác N |s.
  • Lưu ý rằng có ít nhất một khoảng trống trước cái đầu tiên |trong đầu vào hoặc đầu ra.
  • Các .dấu hiệu cho thấy lưới có thể lớn tùy ý.
  • Bạn có thể điền ?vào bất kỳ cách nào bạn muốn.

Lưu ý rằng đầu vào dưới cùng là thay đổi nhanh nhất trong khi bạn đi dọc theo bảng chân lý, trong khi đầu vào trên cùng là 0nửa đầu của đầu ra và 1cho nửa sau.

Quy tắc

Dominoes tuyên truyền như được chỉ định trong Golfing cho Ngày Domino . Nói tóm lại, nếu chúng ta biểu thị các hướng rơi dưới dạng chữ cái

Q W E
A   D
Z X C

sau đó đây là tất cả các kết hợp độc đáo có thể truyền bá (cũng như các phép quay và phản xạ của chúng):

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

C|   ->    CD          C/   ->    CC

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

Tất cả các quy tắc trên được áp dụng đồng thời tại mỗi bước thời gian. Nếu hai trong số các quy tắc đó bị xung đột (nghĩa là một ô được đẩy vào hai hướng ngược nhau hợp lệ cùng một lúc), thì ô bị ảnh hưởng sẽ không rơi và sẽ bị khóa vào vị trí cho phần còn lại của mô phỏng.

Hạn chế

  • MNsẽ không bao giờ vượt quá 6.
  • Bộ giải của bạn phải tạo ra một mạch trong vòng N * 2 M giây .
  • Bộ giải của bạn không được sử dụng nhiều hơn 1 GB bộ nhớ . Đây là một giới hạn mềm, vì tôi sẽ theo dõi thủ công này và giết quá trình của bạn nếu nó vượt quá / liên tục vượt quá giới hạn này.
  • Không có mạch nào được phép chứa hơn 8.000.000 ô hoặc 1.000.000 domino .
  • Nộp hồ sơ của bạn phải được xác định . Bạn được phép sử dụng các trình tạo số giả ngẫu nhiên, nhưng họ phải sử dụng một hạt giống được mã hóa cứng (mà bạn có thể tự do tối ưu hóa nhiều như bạn quan tâm).

Chấm điểm

Đối với mỗi mạch, hãy Dtính tổng số domino trong mạch của bạn và Bsố lượng domino thấp nhất mà mạch này đã được giải quyết (bởi bạn hoặc bất kỳ người tham gia nào khác). Sau đó, điểm số của bạn cho mạch này được đưa ra bằng cách 10,000 * B / Dlàm tròn xuống. Nếu bạn không giải được mạch, điểm của bạn là 0. Điểm tổng thể của bạn sẽ là tổng của một tập hợp các trường hợp kiểm tra. Mạch chưa được giải quyết bởi bất cứ ai sẽ không được bao gồm trong tổng số điểm.

Mỗi người tham gia có thể thêm một trường hợp thử nghiệm vào điểm chuẩn (và tất cả các lần gửi khác sẽ được đánh giá lại bao gồm cả trường hợp thử nghiệm mới đó).

Tệp điểm chuẩn có thể được tìm thấy trên GitHub .

Ví dụ

Dưới đây là một số ví dụ không được giải quyết tối ưu.

Hằng số 1

1 1
1,1

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

Số lượng domino: 12

Cổng OR

2 1
0,1,1,1

///////////

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

Số lượng domino: 28

Và cổng

2 1
0,0,0,1

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

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

Số lượng domino: 62

Hoán đổi làn đường

2 2
00,10,01,11

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

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

Số lượng domino: 36

Ghi chú bổ sung

Các quy tắc lan truyền là như vậy, rằng các đường chéo có thể giao nhau bằng cách sử dụng hình dạng kim cương (xem ví dụ cuối cùng) ngay cả khi một ngã trước mặt kia (không giống như các domino thực sự).

Là một điểm khởi đầu, bạn có thể sử dụng các cổng logic (không được thu nhỏ) trong ý chính này và thử kết hợp càng ít trong số này càng tốt. Đối với một cách đơn giản (không tối ưu) để xây dựng các hàm boolean tùy ý từ các cổng AND, OR và NOT, hãy xem các dạng thông thường kết hợpphân biệt .

Có một trình xác minh kho lưu trữ GitHub này để kiểm tra mã của bạn, mã này cũng sẽ được sử dụng để chấm điểm tất cả các bài nộp. Điều này xuất ra điểm số thô (số lượng domino) và lưu chúng vào một tệp được xử lý bởi một trình ghi điểm riêng biệt (cũng trong kho lưu trữ đó) để có được điểm số cuối cùng.

Tài liệu chung có thể được tìm thấy trong hai tệp Ruby, nhưng controller.rbphải có hai chuyển đổi dòng lệnh trước tệp chuẩn:

  • -v cung cấp cho bạn một số đầu ra nhiều hơn, bao gồm các mạch thực tế được tạo bởi bộ giải của bạn.
  • -ccho phép bạn chọn một tập hợp con của điểm chuẩn bạn muốn kiểm tra. Cung cấp các mạch mong muốn dưới dạng danh sách các chỉ số dựa trên 1 được phân tách bằng dấu phẩy. Bạn cũng có thể sử dụng phạm vi Ruby, vì vậy bạn có thể làm một cái gì đó như -c 1..5,10,15..20.

Vui lòng bao gồm trong câu trả lời của bạn:

  • Ma cua ban
  • Một lệnh để (biên dịch và) chạy mã của bạn. Tôi sẽ hỏi bạn nơi để có được trình biên dịch / phiên dịch cần thiết nếu tôi không có chúng.
  • Một bảng chân lý bổ sung có tên, được thêm vào như một trường hợp thử nghiệm cho điểm chuẩn. (Đây là tùy chọn, nhưng được khuyến khích mạnh mẽ.)

Tôi sẽ kiểm tra tất cả các bài nộp trên Windows 8.


Tất cả đẩy cùng một lúc?
l4m2

@ l4m2 Có, các đầu vào trong cột ngoài cùng bên trái được lật đổ đồng thời.
Martin Ender

Câu trả lời:


33

C # - Giải pháp lớn, chậm và không hiệu quả

Thú nhận: đã viết giải pháp này một thời gian trước khi câu hỏi vẫn còn trong hộp cát, nhưng nó không tốt lắm: bạn có thể làm tốt hơn!

Chỉnh sửa: thay thế cách giải nhàm chán bằng phương pháp ít nhàm chán hơn, linh hoạt hơn và thường tốt hơn

Bạn chạy chương trình bằng cách biên dịch với csc dominoPrinter.csvà sau đó chuyển các đối số cho tệp thực thi, ví dụ (trình kiểm tra chính 4 bit):

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

Giải trình:

"Máy in Domino" là một chương trình gồm 3 giai đoạn:

Giai đoạn 1 : "Bộ giải" tạo ra một cây biểu thức gồm "ifnot" và "hoặc" các phép toán nhị phân với các đầu vào đã cho và "1" từ đường dây điện, có 2 cách được thực hiện, tùy thuộc vào số lượng đầu vào:

  • Nếu có ít hơn 4 đầu vào, chương trình sẽ đưa ra giải pháp cho số lượng hoạt động ít nhất

  • Nếu có 4 đầu vào trở lên, chương trình sẽ xử lý mỗi khối đầu ra 8 bit và sau đó kết hợp các kết quả để đưa ra đầu ra mong muốn. Các bit bị vỡ nếu linh hoạt: các bit càng bị hỏng, giải pháp càng nhỏ, nhưng thời gian chạy càng dài.

"Bộ giải" là những gì mất toàn bộ thời gian (hoặc ít nhất là trước đây) và cũng là phần lớn mã. Tôi tin rằng có một tài liệu tốt, nhanh, không quá đói bộ nhớ và có lẽ là giải pháp tối ưu cho vấn đề này, nhưng niềm vui sẽ ở đâu khi tìm kiếm nó?

Cây biểu thức (bị bẻ khóa) cho trình kiểm tra nguyên tố 4 bit là

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

trong đó các số là chỉ số của đầu vào.

Giai đoạn 2 : "Trình tổ chức" lấy cây biểu thức làm đầu vào và lắp ráp bố cục "khung xương", mô tả chính xác bố cục domino được tạo từ một số tập hợp các ô chồng chéo 4x5. Dưới đây là bộ xương cho trình kiểm tra nguyên tố 4 bit bị bẻ khóa (bạn sẽ cần thay đổi bruteBasebiến số nguyên trên dòng 473 thành 4 (hoặc lớn hơn) để có kết quả này).

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 

Đầu ra này được tạo một cách hiệu quả với hai phần, "bộ đánh giá" ở bên phải, được tạo từ cây biểu thức từ giai đoạn 1 và "tổng đài" ở bên trái, hoán đổi và tách các đầu vào để chúng đến đúng nơi để "người đánh giá" xử lý.

Có phạm vi đáng kể để thu gọn bố cục tại thời điểm này, nhưng chương trình hiện đang thực hiện rất ít công việc như vậy. Mã cho giai đoạn này là khủng khiếp, nhưng khá đơn giản bên dưới (xem phương pháp "orifnot"). Đầu ra được chuyển sang giai đoạn 3.

Giai đoạn 3 : "Máy in" lấy đầu ra từ "người tổ chức" và in các "ô" chồng chéo 4x5 tương ứng cùng với đường dây nguồn. Dưới đây là hình ảnh động của trình kiểm tra số nguyên tố 4 bit được kiểm tra xem 5 có phải là số nguyên tố hay không.

Rõ ràng 5 là số nguyên tố

thiếu sự thụt lề là để tránh vượt quá giới hạn ký tự SE 30k mà nếu không :

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

Một trường hợp thử nghiệm bổ sung:

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

Điều này kiểm tra xem hai bit liền kề (không gói) có phải là 1s hay không (ví dụ true cho 0110, nhưng sai cho 0101 và 1001)


2
Thật là đẹp Bây giờ chúng ta cần một người giải meta domino đưa bảng chân lý vào Ivà kết quả đầu ra xác định bố cục domino mới
sai

Tôi bối rối không biết làm thế nào mà bảng chân lý đại diện cho trình kiểm tra chính bốn bit. Nó không nói rằng 14 và 15 là số nguyên tố?
quintopia

@quintopia đã nhìn lại ... bạn có vẻ đúng, và đó là lỗi của tôi, cái mà Martin sử dụng là chính xác, nhưng tôi KHÔNG xây dựng lại công cụ sơ khai đó ngay bây giờ!
VisualMelon
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.