วงจรโดมิโน


36

ป้ายบอกคะแนน

นี่คือคะแนนดิบ (เช่นจำนวนโดมิโน) สำหรับการส่งของ VisualMelon ฉันจะเปลี่ยนเป็นคะแนนปกติตามที่อธิบายไว้ด้านล่างเมื่อมีคำตอบเพิ่มเติมเข้ามาโซลูชันที่มีอยู่ในขณะนี้สามารถแก้ไขวงจรทั้งหมดในมาตรฐาน:

 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

ความท้าทาย

มัน เป็น ไปได้ที่จะสร้างประตูตรรกะง่าย ๆ จากโดมิโน ดังนั้นโดยการรวมเหล่านี้หรือมิฉะนั้นฟังก์ชันไบนารีโดยพลการสามารถคำนวณได้ด้วยแต้ม

แต่แน่นอนทุกคนที่เล่นกับโดมิโน (ยกเว้น Robin Paul Weijers) ได้ประสบกับความผิดหวังเมื่อหมด ดังนั้นเราต้องการใช้แต้มของเราอย่างมีประสิทธิภาพมากที่สุดเพื่อให้เราสามารถทำการคำนวณที่น่าสนใจกับวัสดุที่เรามี

โปรดทราบว่าคุณไม่สามารถผลิตเอาต์พุตที่ไม่เป็นศูนย์จากศูนย์อินพุตต่อ se ดังนั้นเราจะต้องเพิ่ม "สายไฟ" ซึ่งอยู่ในการตั้งค่าของคุณและคุณสามารถดึง1s ได้ตลอดเวลา

งานของคุณ

รับฟังก์ชั่นบูลีนที่มีMอินพุตและNเอาต์พุต ( f: {0,1}^M --> {0,1}^Nสำหรับการเอียงทางคณิตศาสตร์) สร้างวงจรโดมิโนที่มีโดมิโนน้อยที่สุดเท่าที่จะทำได้ซึ่งคำนวณฟังก์ชันนั้น คุณจะใช้สัญลักษณ์|, -, /, \ที่จะเป็นตัวแทนแต้มในทิศทางต่างๆ

อินพุต

คุณจะได้รับข้อมูลผ่านอาร์กิวเมนต์บรรทัดคำสั่ง:

[command for your solver] M N f

โดยที่MและNเป็นจำนวนเต็มบวกและfเป็นตารางความจริงคั่นด้วยเครื่องหมายจุลภาคตามลำดับบัญญัติ นั่นคือfจะมีค่าของความยาว2^M Nเช่นถ้าM = N = 2บิตแรกในเอาต์พุตคือฟังก์ชัน AND ในขณะที่บิตที่สองคือฟังก์ชัน OR fจะอ่าน

00,01,01,11

เอาท์พุต

เขียนถึง STDOUT กริด ASCII ที่เป็นตัวแทนของการตั้งค่าโดมิโน การตั้งค่าของคุณจะต้องเหมาะสมในกรอบดังต่อไปนี้

/////.../////
 ????...????
I????...????O
I????...????O
.............
.............
I????...????O
I????...????O
I????...????O
  • แถวบนประกอบด้วยทั้งหมด/และโดมิโนซ้ายสุดรับประกันว่าจะล้มเมื่อเริ่มต้น - นี่คือสายไฟของคุณ
  • คอลัมน์ซ้ายสุดประกอบด้วยอินพุตของคุณ แต่ละคนIอาจจะเป็นพื้นที่หรือ|เช่นว่ามีตรงM |s
  • คอลัมน์ขวาสุดประกอบด้วยผลลัพธ์ของคุณ แต่ละคนOอาจจะเป็นพื้นที่หรือ|เช่นว่ามีตรงN |s
  • โปรดทราบว่ามีอย่างน้อยหนึ่งช่องว่างก่อนหน้าแรก|ในอินพุตหรือเอาต์พุต
  • .ระบุว่าตารางอาจมีขนาดใหญ่โดยพลการ
  • คุณสามารถกรอกข้อมูล?ใด ๆ ที่คุณต้องการ

โปรดทราบว่าการป้อนข้อมูลด้านล่างเป็นการเปลี่ยนแปลงที่เร็วที่สุดในขณะที่คุณไปตามตารางความจริงในขณะที่การป้อนข้อมูลด้านบนเป็น0ช่วงครึ่งแรกของเอาต์พุตและ1สำหรับครึ่งหลัง

กฎระเบียบ

โดมิโนเผยแพร่ตามที่ระบุไว้ในกอล์ฟสำหรับวัน Domino ในระยะสั้นหากเราเป็นตัวแทนของทิศทางตกเป็นตัวอักษร

Q W E
A   D
Z X C

จากนั้นเป็นชุดค่าผสมที่ไม่ซ้ำกันซึ่งสามารถเผยแพร่ (รวมถึงการหมุนและการสะท้อน):

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

C|   ->    CD          C/   ->    CC

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

กฎข้างต้นทั้งหมดจะถูกนำไปใช้พร้อมกันในแต่ละขั้นตอน หากกฎสองข้อนั้นขัดแย้งกัน (เช่นไทล์ถูกผลักเข้าไปในทิศทางตรงกันข้ามสองอันที่ถูกต้องในเวลาเดียวกัน) ไทล์ที่ได้รับผลกระทบจะไม่ตกและจะถูกล็อคอย่างมีประสิทธิภาพในตำแหน่งที่เหลือของการจำลอง

ข้อ จำกัด

  • MและNจะไม่เกิน 6
  • แก้ของคุณจะต้องผลิตวงจรภายในN * 2 Mวินาที
  • แก้ของคุณต้องไม่ใช้มากกว่า1 GB หน่วยความจำ นี่เป็นขีด จำกัด ที่อ่อนนุ่มเนื่องจากฉันจะตรวจสอบสิ่งนี้ด้วยตนเองและฆ่ากระบวนการของคุณหากเกินขีด จำกัด นี้อย่างมีนัยสำคัญ / ต่อเนื่อง
  • ไม่มีวงจรได้รับอนุญาตให้มีมากกว่า8,000,000 เซลล์หรือ1,000,000 แต้ม
  • การส่งของคุณจะต้องกำหนดไว้ล่วงหน้า คุณได้รับอนุญาตให้ใช้ตัวสร้างตัวเลขสุ่มหลอก แต่พวกเขาต้องใช้เมล็ดพันธุ์แบบ hardcoded (ซึ่งคุณมีอิสระที่จะเพิ่มประสิทธิภาพได้มากเท่าที่คุณต้องการ)

เกณฑ์การให้คะแนน

สำหรับแต่ละวงจรให้Dเป็นจำนวนโดมิโนทั้งหมดในวงจรของคุณและBจำนวนโดมิโนที่น้อยที่สุดในวงจรนี้ได้รับการแก้ไขด้วย (โดยคุณหรือผู้เข้าร่วมคนอื่น ๆ ) จากนั้นคะแนนของคุณสำหรับวงจรนี้จะถูก10,000 * B / Dปัดเศษลง หากคุณไม่สามารถแก้ไขวงจรได้คะแนนของคุณคือ 0 คะแนนโดยรวมของคุณจะเป็นผลรวมของชุดทดสอบมาตรฐาน วงจรที่ยังไม่ได้รับการแก้ไขโดยทุกคนจะไม่รวมอยู่ในคะแนนรวม

ผู้เข้าร่วมแต่ละคนอาจเพิ่มกรณีทดสอบหนึ่งกรณีไปยังเกณฑ์มาตรฐาน (และการส่งอื่น ๆ ทั้งหมดจะได้รับการประเมินอีกครั้งรวมถึงกรณีทดสอบใหม่นั้น)

ไฟล์เบนช์มาร์กสามารถพบได้ใน GitHub

ตัวอย่าง

นี่คือตัวอย่างที่ไม่สามารถแก้ไขได้อย่างเหมาะสม

คงที่ 1

1 1
1,1

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

นับ Domino: 12

หรือเกท

2 1
0,1,1,1

///////////

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

จำนวน Domino: 28

และประตู

2 1
0,0,0,1

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

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

นับ Domino: 62

สลับเลน

2 2
00,10,01,11

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

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

จำนวน Domino: 36

หมายเหตุเพิ่มเติม

กฎการขยายพันธุ์เป็นเช่นนั้นเลนในแนวทแยงสามารถข้ามโดยใช้รูปทรงเพชร (ดูตัวอย่างสุดท้าย) แม้ว่าจะมีใครตกลงมาก่อน (ไม่เหมือนกับโดมิโนจริง)

ในฐานะที่เป็นจุดเริ่มต้นคุณสามารถใช้ประตูลอจิคัล (ไม่ย่อเล็กสุด) ในส่วนสำคัญนี้และลองรวมกันให้น้อยที่สุดเท่าที่จะทำได้ หาง่าย (ที่ไม่เหมาะสม) วิธีการสร้างฟังก์ชั่นบูลโดยพลการจาก AND, OR และ NOT ประตูมีลักษณะที่เยื่อตาและลักษณะที่แยกปกติแบบฟอร์ม

มีตัวตรวจสอบพื้นที่เก็บข้อมูล GitHub นี้เพื่อทดสอบรหัสของคุณซึ่งจะใช้เพื่อให้คะแนนการส่งทั้งหมด สิ่งนี้จะส่งผลคะแนนดิบ (โดมิโนนับ) และบันทึกลงในไฟล์ที่จะดำเนินการโดยผู้บันทึกคะแนนแยกต่างหาก (รวมถึงในที่เก็บข้อมูลนั้น) เพื่อรับคะแนนสุดท้าย

เอกสารทั่วไปสามารถพบได้ในไฟล์ทับทิมสองไฟล์ แต่controller.rbสวิตช์รับบรรทัดคำสั่งสองคำสั่งก่อนไฟล์เบนช์มาร์ก:

  • -v ให้เอาต์พุตเพิ่มขึ้นรวมถึงวงจรจริงที่ผลิตโดยตัวแก้ของคุณ
  • -cให้คุณเลือกชุดย่อยของเกณฑ์มาตรฐานที่คุณต้องการทดสอบ จัดทำวงจรที่ต้องการเป็นรายการที่คั่นด้วยเครื่องหมายจุลภาคของดัชนี 1 รายการ -c 1..5,10,15..20นอกจากนี้คุณยังสามารถใช้ช่วงทับทิมเพื่อให้คุณสามารถทำสิ่งที่ชอบ

โปรดระบุในคำตอบของคุณ:

  • รหัสของคุณ
  • คำสั่งเพื่อ (คอมไพล์และ) เรียกใช้โค้ดของคุณ ฉันจะถามคุณว่าจะหาคอมไพเลอร์ / ล่ามที่จำเป็นได้ที่ไหนถ้าฉันไม่มีพวกเขา
  • ตารางความจริงเพิ่มเติมพร้อมชื่อที่จะเพิ่มเป็นกรณีทดสอบในเกณฑ์มาตรฐาน (นี่เป็นตัวเลือก แต่ได้รับการสนับสนุนอย่างยิ่ง)

ฉันจะทดสอบการส่งทั้งหมดใน Windows 8


ผลักทั้งหมดในเวลาเดียวกัน?
l4m2

@ l4m2 ใช่อินพุตในคอลัมน์ซ้ายสุดจะถูกโค่นล้มพร้อมกัน
Martin Ender

คำตอบ:


33

C # - โซลูชันขนาดใหญ่ช้าและไม่มีประสิทธิภาพ

คำสารภาพ: เขียนวิธีนี้เมื่อไม่นานมานี้เมื่อคำถามยังอยู่ในกล่องทราย แต่มันก็ไม่ดีมาก: คุณทำได้ดีกว่า!

แก้ไข: แทนที่การแก้ปัญหาที่น่าเบื่อด้วยวิธีที่น่าเบื่อน้อยกว่ายืดหยุ่นกว่าและดีกว่าโดยทั่วไป

คุณรันโปรแกรมโดยการคอมไพล์ด้วยcsc dominoPrinter.csแล้วส่งอาร์กิวเมนต์ไปยังไฟล์ที่เรียกทำงานได้ตัวอย่าง (ตัวตรวจสอบนายก 4 บิต):

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

คำอธิบาย:

"เครื่องพิมพ์ Domino" เป็นโปรแกรม 3 ขั้นตอน:

ขั้นที่ 1 : "ตัวแก้ปัญหา" สร้างแผนภูมินิพจน์ของ "ifnot" และ "หรือ" การดำเนินการแบบไบนารีที่มีอินพุตที่กำหนดและ "1" จาก powerline มี 2 วิธีนี้ขึ้นอยู่กับจำนวนอินพุต:

  • หากมีอินพุตน้อยกว่า 4 อินพุตโปรแกรมจะแก้ปัญหาการดำเนินการที่น้อยที่สุด

  • หากมีอินพุตมากกว่า 4 โปรแกรมโปรแกรมจะทำการเอาต์พุต 8 บิตแต่ละอันแล้วรวมผลลัพธ์เพื่อให้ได้ผลลัพธ์ที่ต้องการ บิต bruted ถ้ายืดหยุ่น: ยิ่ง bruted บิตโซลูชันที่มีขนาดเล็กลง แต่ยิ่งใช้เวลาทำงานนานขึ้น

"ตัวแก้ปัญหา" คือสิ่งที่ต้องใช้เวลาตลอดเวลา (หรืออย่างน้อยก็เคยเป็น) และยังเป็นรหัสส่วนใหญ่ ฉันเชื่อว่ามีเอกสารที่ดีรวดเร็วไม่จำหน่วยความจำหิวมากและอาจเป็นทางออกที่ดีที่สุดสำหรับปัญหานี้ แต่ความสนุกจะอยู่ที่ไหนในการค้นหามัน

ทรีนิพจน์ (bruted) สำหรับตัวตรวจสอบเฉพาะแบบ 4 บิตคือ

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

โดยที่ตัวเลขคือดัชนีของอินพุต

ขั้นตอนที่ 2 : "ผู้จัดงาน" ใช้แผนผังต้นไม้เป็นอินพุตและประกอบโครงร่าง "โครงกระดูก" ซึ่งอธิบายโครงร่างโดมิโนอย่างแม่นยำซึ่งทำจากเซลล์ 4x5 บางส่วนที่ซ้อนทับกันอย่างแม่นยำ ด้านล่างนี้เป็นโครงกระดูกสำหรับตัวตรวจสอบนายกรัฐมนตรี 4 บิตแบบ bruted (คุณจะต้องเปลี่ยนbruteBaseตัวแปรจำนวนเต็มในบรรทัด 473 ถึง 4 (หรือใหญ่กว่า) เพื่อให้ได้ผลลัพธ์นี้)

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 

เอาต์พุตนี้ประกอบด้วยสองส่วนอย่างมีประสิทธิภาพ "ผู้ประเมิน" ทางด้านขวาซึ่งสร้างจากทรีนิพจน์จากระยะที่ 1 และ "สวิตช์บอร์ด" ทางด้านซ้ายซึ่งสลับและแยกอินพุตเพื่อให้เข้ามาใน สถานที่ที่เหมาะสมสำหรับ "ผู้ประเมิน" เพื่อจัดการ

มีขอบเขตมากสำหรับการกระชับเค้าโครงในจุดนี้ แต่โปรแกรมปัจจุบันทำงานดังกล่าวน้อยมาก รหัสสำหรับสเตจนี้น่ากลัว แต่ค่อนข้างง่ายภายใต้ (ดูวิธี "orifnot") เอาต์พุตจะถูกส่งผ่านไปยังสเตจ 3

ขั้นตอนที่ 3 : "เครื่องพิมพ์" รับเอาต์พุตจาก "ผู้จัดการ" และพิมพ์ "เซลล์" ที่ซ้อนกัน 4x5 ที่สอดคล้องกันพร้อมกับสายไฟ ด้านล่างนี้เป็นภาพเคลื่อนไหวของตัวตรวจสอบนายกรัฐมนตรีแบบ 4 บิตที่มีการตรวจสอบว่า 5 เป็นแบบเฉพาะหรือไม่

เห็นได้ชัดว่า 5 เป็นเรื่องสำคัญ

โค้ดการขาดการเยื้องคือการหลีกเลี่ยงการเกินขีด จำกัด อักขระ SE 30k ซึ่งจะเป็นอย่างอื่น :

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

กรณีทดสอบเพิ่มเติม:

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

สิ่งนี้ตรวจสอบว่าบิตที่อยู่ติดกัน (ไม่ใช่การห่อข้อมูล) เป็นทั้ง 1s (เช่นเป็นจริงสำหรับ 0110 แต่เป็นเท็จสำหรับ 0101 และ 1001)


2
นี่คือสิ่งที่สวยงาม ตอนนี้เราต้องเมตาดาต้าโดมิโนแก้ซึ่งจะมีตารางความจริงในIและเอาท์พุทที่มีระบุรูปแบบโดมิโนใหม่
wrongu

ฉันสับสนว่าตารางความจริงนั้นหมายถึงตัวตรวจสอบนายกสี่บิตได้อย่างไร มันไม่ได้บอกว่า 14 และ 15 นั้นดีหรือไม่?
quintopia

@quintopia เมื่อมองอีกครั้ง ... คุณดูเหมือนจะถูกและมันเป็นความผิดของฉันคนหนึ่งที่ใช้มาร์ตินถูกต้อง แต่ฉันไม่ได้สร้างใหม่ที่นายกรัฐมนตรีตอนนี้!
VisualMelon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.