Devre şemasını yorumlama


12

Zorluğunuz, mantık kapıları ile birlikte bir devre şemasını yorumlamaktır.

Mantık kapıları (bu zorluğu tamamlamak için bunların ne yaptığını / neler olduğunu bilmeniz gerekmez):

  • ve kapı: a
  • veya kapı: o
  • nand kapısı: A
  • ne kapı: O
  • xor kapısı: x
  • xnor geçidi: X
  • kapı değil: ~

Sonuncusu hariç her kapı iki girdi alır. Girişler ., kapı üzerinde ortalanmış 3 x 3 karenin sol üst ve sol alt köşelerinde yer alır. Değilse, giriş doğrudan solundadır. Çıktı .doğrudan sağa doğrudur.

Teller ile temsil edilir -|\/.=

  • - biri sağda, diğeri solda olmak üzere iki kabloyla bağlantı kurar: c-c
  • | biri yukarıda diğeri aşağıda olmak üzere iki kabloyla bağlantı kurar:

    c
    |
    c
    
  • /ve \aşağıdaki gibi çalışın:

    c        c
     \      /
      c    c
    
  • . çevresindeki her tel ile temas eder:

    ccc
    c.c
    ccc
    
  • =özeldir; bitişik kabloları birbirine bağlar:

    -=-
    

    iki kabloyu birbirine bağlar. Aşağıdaki

    \|/
    -=-
    /|\
    

    her bir zıt tel birbirine bağlanır, ancak diğerleri ile bağlanmaz (burası farklıdır .).

  • Akım geçmesi için amacıyla, iki tel de çok içinde, diğer bir bağlanmalıdır |-, akım yok değildir akar.

Kablolama örneği:

      .-.
     =   \
 .--. .---=---
-.   =     .--
 .--. .-------

giriş iki kabloya ve sonra üçe ayrılır. Bu bölmede, alt tel ortaya doğru hareket eder ve üst telin aşağı doğru bölünmesi altta görünür. Daha sonra, üç kablonun üstü ortaya taşınır.

Kapılı örnek kablolama:

--.
   o..~..
--.      o.---
   a.---.
--.

Giriş biçimi:

  • her giriş teli bir rakamla etiketlenecektir. Sonunda (satırsonundan hemen önce), her çıkış etiketlenir :(ve tel her zaman doğrudan içine girer, yani -:veya .:veya =:)
  • giriş her zaman geçerli olacaktır; kapı olmadan birbirine bağlanan halkalar veya teller olmayacaktır. Gevşek uçlu teller olabileceğini unutmayın.
  • = sadece gerektiğinde kullanılacaktır.

Çıkış formatı:

  • her girişe karşılık gelen numara ile başvurulur.
  • bir ifade çıkar. Örneğin, teller giriş 1 ve giriş 2'yi hesaplarsa, çıkış olur 1a2.
  • Hangi işlev çıktılanırsa alınsın, başlangıçtaki mantık kapılarına karşılık gelmelidir.
  • değil göstermek için, ~önce doğru yere koyun .
  • birden çok işlev için, yürütme sırasını göstermek üzere parantez kullanın. Parantezler, yalnızca tek bir işlev olduğunda da kullanılabilir. Örneğin,

    1-.~.-.
           A.~.-:
          .
    2-.  /
       x.
    3-.
    

    olası bir çıktısı var ~((2x3)A(~1))

  • birden çok çıktı bir satırsonu (veya eşdeğeri) ile ayrılmalıdır

Örnek giriş:

1--.---.
    x.  \
2--.  x.-=---------.
     .    .~.       X.--.
3---. .      a.----.   /
       O.~.-.       \ /
      .              =
4-.  /              / .-:
   X.              .----:
5-.

Karşılık gelen olası bir çıktı:

(~1)a(~(3O(4X5))
((1x2)x3)X((~1)a(~(3O(4X5))))

Oooohhhh, ilginç! Bir şans vereceğim.
cjfaure

5
Turing-tamamlaması için bir şekilde uzatırsak, bundan ilginç bir exolang çıkacağını tahmin ediyorum.
Victor Stafusa

"Derleyici hatası" durumunda (yani hatalı biçimlendirilmiş giriş kablolaması) tercüman ne yapmalıdır?
Victor Stafusa

Ve doğrudan iki giriş bağlarsam? Veya doğrudan iki çıkış mı bağlamak istiyorsunuz? Veya çıkışa açık satırlar mı gireceksiniz?
Victor Stafusa

1
@Victor Bu zaten benzer. Ama devam ettim ve bir tane daha
Justin

Yanıtlar:


4

Python 2488 1567 806 706 697 657 653

Gzip + exec için Yay!

import zlib,base64;exec zlib.decompress(base64.b64decode('eNp1U8FuqzAQvPMV7sm2gBSuuFupX9BLD5UoBxNMMAkEgQmJVPXb364Daiu9ntaznt2dWYzthvPo2HSbgsrU7E3so0FmAWtgnyeFshjSImC2Zs1Tws4js/fQPMPJ9KKTlFrPeVPIbDRuHnvOA3YByuS2UCNwrloYqOMRQ1ooDY0qwaoKRJxGSZRKP+QCwBn/0YRyzPYcYq77irUATVbGcIytGkN4E7mOyiLayx/MT888AthMx9DGDTLj/zIfPz44emUGqC/Zoio1UdFzohzFp0TNNA7xQhFxDWJiNGNG98L54yLVYUsv3+kZx9G8/uyEoQFk8NELrDeIIggf5Cb3b3/I3nnFNdZe0QOrCHl4+4ZsgVyH16gMb4XHq4IrwA0gkV7kAwyZH7Fs7f0S/O7IbnZX7jelzy+v13f8LsAFD0kVfrQyTklZyCUPL+F2Ef66WHug7i9f/bWyfnOIsrNTZQ/WCXxCcAnY/QmwMeggLwIyeCKD+FB3k6tsj/K6nR4G01fiZCcnTlIGBkw/d2bUzvgSG2kqMvhOkU+ZNirvGS1XgyWKy/xS2TDa3uE/kNuoJX0UC/kP8j/kmA=='))

Sınırlamalar ve varsayımlar

Olduğu gibi, yalnızca 9 giriş desteklenir - birden fazla basamak doğru şekilde işlenmez. Spesifikasyon, girişlerin bir sayı değil bir rakamla etiketlendiğini belirttiği için buna izin verilir.


Giriş ve çıkış

Giriş standart giriş üzerinden ve çıkış standart çıkış üzerinden alınır.


Test yapmak

Örnek giriş ve çıkış:

1--.---.
    x.  \
2--.  x.-=---------.
     .    .~.       X.--.
3---. .      a.----.   /
       O.~.-.       \ /
      .              =
4-.  /              / .-:
   X.              .----:
5-.


(~(1))a(~((3)O((4)X(5))))
(((1)x(2))x(3))X((~(1))a(~((3)O((4)X(5)))))

Burada test edilmiştir: http://ideone.com/gP4CIq


Algoritma

Temelde çıktılardan oldukça naif bir DFS. Her çıktı için, bir karakterden sola başlar ve her kapıda dallanır (ve ifadeye eklenir) teli izler. Bir giriş ulaştığında emin dallanma olduğunu olabilir, çünkü bu, bu kollara ayrılmış son noktaya ekspresyonu ve geriye doğru ilerleyen ekler olmayan bir kapı olmaksızın mümkün. Ve elbette geçersiz durumlar atılır. Gerçekten özel bir şey yok - ve bu yüzden olması gerekenden daha uzun.


notlar

Boyut, bazı yeniden yapılandırmalarla muhtemelen biraz azaltılabilir, ancak bugün için bunun için yeterince zaman geçirdim. Manuel golfçü versiyonu sıkıştırılmıştı.

Gzip sıkıştırması golfü ilginç hale getirir, çünkü bazı önbellekleme (örn. d=(-1,0,1)) Aslında sıkıştırma algoritmasının ilgilenmesini sağlamaktan daha fazla yer kaplar. Ancak, manuel sürümü sıkıştırma için optimize etmek yerine mümkün olduğunca golf seçtim.


El ile (golfed 909 895 840 803):

import sys
def T(c,p):
 h=c[0];i=c[1]
 if h<0 or i<0 or h>=len(m)or i>=len(m[h]):return''
 v=m[h][i];r='';j=p[0];k=p[1];a=h;b=i;d=(-1,0,1)
 if v==' ':return''
 if v in'=-'and j==h:b-=k-i;r+=T([a,b],c)
 if v in'=|'and k==i:a-=j-h;r+-T([a,b],c)
 if v in'=/\\':
  e=j==h or k==i;s=j-h>0;t=j-h<0;u=k-i>0;w=k-i<0;f=(s and u)or(t and w);g=(s and w)or(t and u)
  if not(e or v=='/'and f or v=='\\'and g):a-=j-h;b-=k-i;r+=T([a,b],c)
 if v=='.':
  for x in d:
   for y in d:
    w=[a+x,b+y]
    if not(x==y==0)and w!=p:r+=T(w,c)
 if j==h and k-i>0:
  if v in'aoAOxX':r='('+T([a-1,b-1],c)+')'+v+'('+T([a+1,b-1],c)+')'
  if v=='~':r='~('+T([a,b-1],c)+')'
 if v.isdigit():r=v
 return r
m=[]
for l in sys.stdin:
 m.append(list(l))
e=enumerate
for i,a in e(m):
 for j,b in e(a):
  if b==':':
   print T([i,j-1],[i,j])

Tam dinsiz (2488):

import sys

def findOuts(c):
    for i, iVal in enumerate(c):
        for j, jVal in enumerate(iVal):
            if jVal == ':':
                yield [i, j]

def trace(pos, prev):
    if pos[0] < 0 or pos[1] < 0 or pos[0] >= len(circuit) or pos[1] >= len(circuit[pos[0]]):
        return ''
    val = circuit[pos[0]][pos[1]]
    if val == ' ':
        return ''
    next = pos[:]
    ret = ''
    if val in '=-':
        if prev[0] == pos[0]:
            next[1] -= prev[1] - pos[1]
            ret += trace(next, pos)
    if val in '=|':
        if prev[1] == pos[1]:
            next[0] -= prev[0] - pos[0]
            ret += trace(next, pos)
    if val in '=/\\':
        # top-bottom, left-right
        tblr = prev[0] == pos[0] or prev[1] == pos[1]
        # top-left, bottom-right
        tlbr = (prev[0] - pos[0] == 1 and prev[1] - pos[1] == 1) or (prev[0] - pos[0] == -1 and prev[1] - pos[1] == -1)
        # top-right, bottom-left
        trbl = (prev[0] - pos[0] == 1 and prev[1] - pos[1] == -1) or (prev[0] - pos[0] == -1 and prev[1] - pos[1] == 1)
        if not ((val == '/' and (tlbr or tblr)) or (val == '\\' and (trbl or tblr)) or (val == '=' and tblr)):
            next[0] -= prev[0] - pos[0]
            next[1] -= prev[1] - pos[1]
            ret += trace(next, pos)

    if val == '.':
        for x in (-1,0,1):
            for y in (-1,0,1):
                if x == y == 0:
                    continue

                w = [next[0] + x, next[1] + y]
                if w == prev:
                    continue

                # only one of them should return anything
                ret += trace(w, pos)

    # assumption that a logic gate always has a . on its connections, as according to spec
    if val in 'aoAOxX':
        # only from the right/output
        if not (prev[0] == pos[0] and prev[1] == pos[1] + 1):
            return ret
        ret = '(' + trace([next[0] - 1, next[1] - 1], pos) + ')' + val + '(' + trace([next[0] + 1, next[1] - 1], pos) + ')'

    if val == '~':
        # only from the right/output
        if not (prev[0] == pos[0] and prev[1] == pos[1] + 1):
            return ret
        ret = '~(' + trace([next[0], next[1] - 1], pos) + ')'

    if val in '123456789':
        ret = val

    return ret

circuit = []
for line in sys.stdin.readlines():
    # padding added to prevent index out of bounds later
    circuit.append(list(line))

for out in findOuts(circuit):
    next = out[:]
    next[1] -= 1
    print trace(next, out)

DFS nedir? Ayrıca, çıktıdan geriye doğru çalışmak tam olarak düşündüğüm şeydi.
Justin

@Quincunx Derinlik-ilk arama. Temel olarak, özyineleme (veya bir LIFO yapısı, bir yığın kullanarak) ve bir çıkmaza veya hedefe ulaşana kadar bir yol boyunca mümkün olduğunca seyahat ederek, o noktada son ıraksama noktasına geri dönüp diğer yolları dener.
Bob

Girdiler üzerinde iyi varsayım. Bu tam olarak kastettiğim şeydi (ve bunu önermek için söz vermeye çalıştım). Ancak programınız 0rakam olarak çalışıyor mu? Takas siparişe ne dersiniz? Bu 2daha önce gelir 1, vs.
Justin

@Quincunx Ben söyleyebildiğim kadarıyla .isdigit()düzenli regex eşdeğer Python's kullanıyorum [0-9]. Spesifikasyonunuza göre doğru mu? Değiştirilmiş siparişle ne demek istiyorsun? Uygulandığı şekilde, önce herhangi bir mantık kapısının yukarı koluna gidecek, ancak girişlerin sipariş edilme garantisi yoktur.
Bob

isdigit()tutarlıdır. Değiştirilmiş sıralama 2, ilk giriş ve 1ikinci giriş (dikey olarak sıralanmış) gibi bir şey anlamına gelir .
Justin

6

Java: 1523 1512 karakter

import java.util.*;class W{int v=99;Map<Integer,String>t;boolean k;public static void main(String[]y){new W().d();}W(){try{java.io.InputStream i=new java.io.File("r").toURL().openStream();t=new HashMap<>();int a=0,x=0,y=0;while((a=i.read())>-1){if(a==10){y++;x=0;continue;}q(x,y,(a>47&a<58?"!":"")+(char)a);x++;}}catch(Exception e){}}void d(){while(!k){k=!k;for(Map.Entry<Integer,String>g:t.entrySet())e(g.getKey(),g.getValue());}for(String b:t.values())if(b.startsWith("$"))System.out.println(b.substring(1));}void e(int a,String s){if(s==null||!s.startsWith("!"))return;int x=a/v,y=a%v;s=s.substring(1);b(s,x,y,x-1,y+1);b(s,x,y,x,y+1);b(s,x,y,x+1,y+1);b(s,x,y,x-1,y);b(s,x,y,x+1,y);b(s,x,y,x-1,y-1);b(s,x,y,x,y-1);b(s,x,y,x+1,y-1);}void b(String p,int m,int n,int x,int y){String s=t.get(x*v+y);if(s==null)return;boolean g=y==n+1;boolean h=y==n-1;boolean i=x==m+1;boolean j=x==m-1;if(z(s,"-=")&n==y){if(i)b(p,x,y,x+1,y);if(j)b(p,x,y,x-1,y);}if(z(s,"|=")&m==x){if(g)b(p,x,y,x,y+1);if(h)b(p,x,y,x,y-1);}if(z(s,"/=")){if(j&g)b(p,x,y,x-1,y+1);if(i&h)b(p,x,y,x+1,y-1);}if(z(s,"\\=")){if(i&g)b(p,x,y,x+1,y+1);if(j&h)b(p,x,y,x-1,y-1);}if(z(s,".")){q(x,y,"!"+p);u();}if(z(s,"~")){q(x,y,"!~("+p+")");u();}if((s.charAt(0)=='%'&n==y-1)|(s.charAt(0)=='&'&n==y+1)){q(x,y,"!("+p+")"+s.charAt(1)+"("+s.substring(2)+")");u();}if(z(s,"OoAaXx")){q(x,y,(n==y+1?"%":"&")+s+p);u();}if(z(s,":")){q(x,y,"$"+p);u();}}void q(int x,int y,String z){t.put(x*v+y,z);}void u(){k=false;}boolean z(String s,String c){return c.indexOf(s)>-1;}}

Bu çıktıyı örnek girişi için verir:

(~(((5)X(4))O(3)))a(~(1))
((~(((5)X(4))O(3)))a(~(1)))X(((2)x(1))x(3))

Boyutunu sıkmak için:

  • Girişin her zaman geçerli olduğu varsayılarak hata kontrolü, hata işleme veya giriş doğrulaması yapmaz.
  • 99 satır giriş ile sınırlıdır.
  • Girdi dosyası, adında rherhangi bir dosya uzantısı olmadan sadece çağrılmalıdır .
  • Parantezin gerekli olup olmadığını tespit etmek için hiçbir çaba sarf etmez. Her zaman gerekli olduklarını varsayar ve bu varsayım yanlış olduğundan, gerekenden çok daha fazla parantez vardır, ancak bu yine de spesifikasyonu başarısız kılmadığı için sorun değildir.
  • Her bir ikili operatöre parametrelerin sırası, değerlerin yayılma hızına ve hücre tarama sırasına bağlı olduğundan genel olarak öngörülemez. Ancak tüm ikili operatörler değişmeli olduğu için bu sorun olmamalı.

Eminim daha fazla, ancak biraz azaltmak mümkün olmalıdır.

Yorumlayıcı bir çeşit hücresel otomata şeklinde uygulanır. Tüm alan ayarı değerlerini tarar ve hiçbir değişiklik algılanana kadar gerektiği kadar tekrarlar.

İşte ungolfed versiyonu:

import java.util.*;

class Wiring {

    int maxLines = 99;
    Map<Integer, String> circuitState;
    boolean finished;

    public static void main(String[] args) {
        new Wiring().interpret();
    }

    Wiring() {

        try {
            // Always read the input from the "r" file, and do not check if it even
            // exists. BTW, the toURL() method is deprecated, but we don't care about
            // this in code-golfing.
            java.io.InputStream stream = new java.io.File("r").toURL().openStream();

            circuitState = new HashMap<>();
            int byteRead = 0, cellX = 0, cellY = 0;

            while ((byteRead = stream.read()) > -1) {

                // Check for line break;
                if (byteRead == 10) {
                    cellY++;
                    cellX = 0;
                    continue;
                }

                // Populate the circuit cell. Precede numbers with an exclamation mark.
                setCircuitCell(cellX, cellY, (byteRead >= '0' & byteRead <= '9' ? "!" : "") + (char) byteRead);
                cellX++;
        } catch (Exception e) {
        }
    }

    void interpret() {
        while (!finished) {
            finished = !finished; // i.e. finished = false;
            for (Map.Entry<Integer, String> entry : circuitState.entrySet()) {
                analyzeCell(entry.getKey(), entry.getValue());
            }
        }

        // Now print the output. To do that scan for cells marked with "$".
        for (String cell : circuitState.values()) {
            if (cell.startsWith("$")) System.out.println(cell.substring(1));
        }
    }

    void analyzeCell(int cellIndex, String cellValue) {
        // Only the cells with a value marked with "!" are worth to analyze.
        if (cellValue == null || !cellValue.startsWith("!")) return;

        // Convert the cellIndex to a bidimensional coordinate.
        int x = cellIndex / maxLines, y = cellIndex % maxLines;

        // Remove the "!".
        cellValue = cellValue.substring(1);

        // Propagate the cell value to neighbouring cells.
        propagateCellData(cellValue, x, y, x - 1, y + 1);
        propagateCellData(cellValue, x, y, x, y + 1);
        propagateCellData(cellValue, x, y, x + 1, y + 1);
        propagateCellData(cellValue, x, y, x - 1, y);
        propagateCellData(cellValue, x, y, x + 1, y);
        propagateCellData(cellValue, x, y, x - 1, y - 1);
        propagateCellData(cellValue, x, y, x, y - 1);
        propagateCellData(cellValue, x, y, x + 1, y - 1);
    }

    void propagateCellData(String cellValue, int sourceX, int sourceY, int targetX, int targetY) {
        String targetContent = circuitState.get(targetX * maxLines + targetY);

        // If the target cell does not exist, just ignore.
        if (targetContent == null) return;

        boolean targetBelowSource = targetY == sourceY + 1;
        boolean targetAboveSource = targetY == sourceY - 1;
        boolean targetRightToSource = targetX == sourceX + 1;
        boolean targetLeftToSource = targetX == sourceX - 1;

        // Propagate horizontally through wires.
        if (isStringContained(targetContent, "-=") & sourceY == targetY) {
            if (targetRightToSource) propagateCellData(cellValue, targetX, targetY, targetX + 1, targetY);
            if (targetLeftToSource) propagateCellData(cellValue, targetX, targetY, targetX - 1, targetY);
        }

        // Propagate vertically.
        if (isStringContained(targetContent, "|=") & sourceX == targetX) {
            if (targetBelowSource) propagateCellData(cellValue, targetX, targetY, targetX, targetY + 1);
            if (targetAboveSource) propagateCellData(cellValue, targetX, targetY, targetX, targetY - 1);
        }

        // Propagate in the diagonal x=-y.
        if (isStringContained(targetContent, "/=")) {
            if (targetLeftToSource & targetBelowSource) {
                propagateCellData(cellValue, targetX, targetY, targetX - 1, targetY + 1);
            }
            if (targetRightToSource & targetAboveSource) {
                propagateCellData(cellValue, targetX, targetY, targetX + 1, targetY - 1);
            }
        }

        // Propagate in the diagonal x=y.
        if (isStringContained(targetContent, "\\=")) {
            if (targetRightToSource & targetBelowSource) {
                propagateCellData(cellValue, targetX, targetY, targetX + 1, targetY + 1);
            }
            if (targetLeftToSource & targetAboveSource) {
                propagateCellData(cellValue, targetX, targetY, targetX - 1, targetY - 1);
            }
        }

        // If we got a dot, store the value there.
        // Do not forget to mark it with "!", so we can rescan it later.
        if (isStringContained(targetContent, ".")) {
            setCircuitCell(targetX, targetY, "!" + cellValue);
            markThatStateChanged();
        }

        // If we got a "~", store the inverted value there.
        // Do not forget to mark it with "!", so we can rescan it later.
        if (isStringContained(targetContent, "~")) {
            setCircuitCell(targetX, targetY, "!~(" + cellValue + ")");
            markThatStateChanged();
        }

        // If we found a binary logical port with one of the values set and
        // we can set the another value, do it. Use "%" and "&" to know which
        // one was already defined.
        // BTW, do not forget to mark it with "!", so we can rescan it later.
        if ((targetContent.charAt(0) == '%' & sourceY == targetY - 1)
                | (targetContent.charAt(0) == '&' & sourceY == targetY + 1))
        {
            setCircuitCell(targetX, targetY,
                    "!(" + cellValue + ")"
                    + targetContent.charAt(1)
                    + "(" + targetContent.substring(2) + ")");
            markThatStateChanged();
        }

        // Found a binary logical port without any value setted, so set it.
        // Use "%" and "&" to mark which one was setted.
        if (isStringContained(targetContent, "OoAaXx")) {
            setCircuitCell(targetX, targetY, (sourceY == targetY + 1 ? "%" : "&") + targetContent + cellValue);
            markThatStateChanged();
        }

        // If we found an output, store the value there.
        // Mark it with "$", so we will print it in the future.
        if (isStringContained(targetContent, ":")) {
            setCircuitCell(targetX, targetY, "$" + cellValue);
            markThatStateChanged();
        }
    }

    void setCircuitCell(int cellX, int cellY, String cellContents) {
        circuitState.put(cellX * maxLines + cellY, cellContents);
    }

    void markThatStateChanged() {
        finished = false;
    }

    boolean isStringContained(String searchingString, String searchTarget) {
        return searchTarget.indexOf(searchingString) > -1;
    }
}

try{}catch(Exception e){}İki yerine kullanmak için biraz daha ucuz throws Exception. Muhtemelen başka şeyler var, ama Java'yı nasıl golf oynayacağımı bilmiyorum.
Bob

@Bob Teşekkürler, öneriniz 7 karakteri azaltmamı sağladı. Ayrıca, 4 tane daha azaltabilirim.
Victor Stafusa
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.