Interpretuj schemat połączeń


12

Twoim zadaniem jest interpretacja schematu obwodu wraz z bramkami logicznymi.

Bramki logiczne (tak naprawdę nie musisz wiedzieć, co one robią / są, aby ukończyć to wyzwanie):

  • i brama: a
  • lub brama: o
  • Nand Gate: A
  • ani brama: O
  • brama xor: x
  • brama xnor: X
  • nie brama: ~

Każda bramka, ale ostatnia, przyjmuje dwa wejścia. Dane wejściowe pochodzą od a .w lewym górnym i lewym dolnym rogu kwadratu 3 na 3 wyśrodkowanego na bramie. W przeciwnym razie dane wejściowe znajdują się bezpośrednio po lewej stronie. Dane wyjściowe znajdują się .bezpośrednio po prawej stronie.

Przewody są reprezentowane przez -|\/.=

  • - styka się z dwoma przewodami, jeden po prawej i jeden po lewej: c-c
  • | styka się z dwoma przewodami, jednym powyżej i jednym poniżej:

    c
    |
    c
    
  • /i \pracuj w następujący sposób:

    c        c
     \      /
      c    c
    
  • . styka się z każdym otaczającym drutem:

    ccc
    c.c
    ccc
    
  • =jest wyjątkowy; łączy sąsiednie przewody:

    -=-
    

    łączy dwa przewody. W następującym

    \|/
    -=-
    /|\
    

    każdy przeciwny drut jest połączony ze sobą, ale nie z innymi (tutaj się różni .).

  • Aby prąd przepływał, oba przewody muszą być połączone z drugim, tak więc |-prąd nie płynie.

Przykład okablowania:

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

wejście jest podzielone na dwa przewody, a następnie na trzy. W tym podziale dolny drut przesuwa się na środek, a dolny podział górnego drutu pojawia się na dole. Następnie górna część trzech drutów zostaje przesunięta na środek.

Przykładowe okablowanie z bramkami:

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

Format wejściowy:

  • każdy przewód wejściowy będzie oznaczony cyfrą. Na końcu (tuż przed znakiem nowej linii) każde wyjście będzie oznaczone :(a drut zawsze będzie bezpośrednio w nim wchodził, tj. -:Lub .:lub =:)
  • dane wejściowe zawsze będą ważne; nie będzie pętli ani przewodów łączących się bez bramki. Pamiętaj, że mogą istnieć druty o luźnych końcach.
  • = będą używane tylko w razie potrzeby.

Format wyjściowy:

  • każde wejście jest oznaczone odpowiednim numerem.
  • wyprowadzane jest wyrażenie. Na przykład, jeśli przewody obliczają wejście 1 i wejście 2, wynikiem jest 1a2.
  • wszelkie wyjściowe funkcje muszą odpowiadać bramkom logicznym na początku.
  • aby nie pokazać, umieść ~przed właściwym miejscem.
  • w przypadku wielu funkcji użyj nawiasów, aby pokazać kolejność wykonywania. Nawiasów można także używać, gdy jest tylko jedna funkcja. Na przykład,

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

    ma jedno możliwe wyjście ~((2x3)A(~1))

  • wiele wyników musi być oddzielonych znakiem nowej linii (lub równoważnym)

Przykładowe dane wejściowe:

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

Jedno możliwe odpowiednie wyjście:

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

Ooooch, ciekawe! Spróbuję.
cjfaure

5
Przewiduję ciekawy exolang, który z tego wyjdzie, jeśli przedłużymy go w taki sposób, aby był on kompletny.
Victor Stafusa

W przypadku „błędu kompilatora” (tj. Zniekształconego okablowania wejściowego), co powinien zrobić tłumacz?
Victor Stafusa,

A jeśli podłączę bezpośrednio dwa wejścia? Lub podłączyć bezpośrednio dwa wyjścia? Lub wprowadzić otwarte linie do wyjścia?
Victor Stafusa,

1
@Victor To już jest podobne. Ale poszedłem naprzód i stworzyłem kolejny
Justin

Odpowiedzi:


4

Python 2488 1567 806 706 697 657 653

Tak dla gzip + exec!

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=='))

Ograniczenia i założenia

Obecnie obsługiwanych jest tylko do 9 wejść - wiele cyfr nie jest obsługiwanych poprawnie. Ponieważ specyfikacja wskazuje, że dane wejściowe są oznaczone cyfrą , a nie liczbą , jest to dozwolone.


Wejście i wyjście

Wejście jest pobierane poprzez standardowe wejście, a wyjście przez standardowe wyjście.


Testowanie

Przykładowe dane wejściowe i wyjściowe:

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)))))

Testowany tutaj: http://ideone.com/gP4CIq


Algorytm

Zasadniczo jest to dość naiwny DFS z wyjść. Dla każdego wyjścia zaczyna się od znaku jeden po lewej stronie i śledzi drut, rozgałęziając się (i dodając do wyrażenia) przy każdej bramie. Kiedy osiągnie wejście, dodaje je do wyrażenia i cofa do ostatniego punktu, w którym rozgałęził się, ponieważ możemy być pewni, że rozgałęzienie nie jest możliwe bez bramki. I oczywiście wszelkie nieważne przypadki są odrzucane. Nie ma w tym nic specjalnego - dlatego prawdopodobnie jest on dłuższy niż mógł być.


Notatki

Rozmiar można prawdopodobnie nieco zmniejszyć przy pewnej restrukturyzacji, ale poświęciłem na to wystarczająco dużo czasu na dziś. Wersja ręcznie golfowa była skompresowana.

Kompresja gzip sprawia, że ​​gra w golfa jest interesująca, ponieważ pewne buforowanie (np. d=(-1,0,1)) Faktycznie zajmuje więcej miejsca niż pozwalanie na to algorytmowi kompresji. Jednak zdecydowałem się na grę w golfa w wersji ręcznej, o ile to możliwe, zamiast optymalizować kompresję.


Gra w golfa ręcznie ( 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])

Pełna nie golfa (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)

Co to jest DFS? Również praca wstecz od wyjścia jest dokładnie tym, o czym myślałem.
Justin

@Quincunx Głębokie pierwsze wyszukiwanie. Zasadniczo rekurencja (lub w inny sposób przy użyciu konstruktu LIFO, stosu) i podróżowanie tak daleko, jak to możliwe, wzdłuż ścieżki, aż trafi w ślepy zaułek lub cel, w którym to momencie wraca do ostatniego punktu rozbieżności i wypróbowuje inne ścieżki.
Bob

Dobre założenie na wejściach. Właśnie to miałem na myśli (i próbowałem to sformułować, aby to zasugerować). Jednak czy Twój program działa 0jako cyfra? Co powiesz na zamieniające się zamówienia, które 2pojawią się wcześniej 1itp.
Justin

@Quincunx Używam Pythona .isdigit(), co jest efektywnie równoważne z wyrażeniem regularnym, [0-9]o ile wiem. Czy to zgodne z twoją specyfikacją? Co rozumiesz przez zamienianie zamówień? Sposób, w jaki jest zaimplementowany, będzie najpierw kierował się ku odgałęzieniu dowolnej bramki logicznej, ale nie ma gwarancji kolejności wprowadzania danych.
Bob

isdigit()jest spójny. Zamieniane porządkowanie oznacza coś takiego 2jak pierwsze wejście i 1drugie wejście (posortowane pionowo).
Justin

6

Java: 1523 1512 znaków

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

Daje to wynik dla przykładowego wejścia:

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

Aby wycisnąć jego rozmiar:

  • Nie wykonuje żadnego sprawdzania błędów, obsługi błędów ani sprawdzania poprawności danych wejściowych, przy założeniu, że dane wejściowe są zawsze prawidłowe.
  • Jest ograniczony do 99 linii wejściowych.
  • Jego plik wejściowy musi być nazwany po prostu rbez rozszerzenia nazwy.
  • Nie stara się wykryć, czy nawiasy są lub nie są konieczne. Zakłada się, że zawsze są one konieczne, a ponieważ to założenie jest fałszywe, istnieje o wiele więcej nawiasów niż potrzeba, ale ponieważ nie oznacza to, że i tak nie spełnia specyfikacji, nie stanowi problemu.
  • Kolejność parametrów dla każdego operatora binarnego jest na ogół nieprzewidywalna, ponieważ zależy od prędkości propagacji wartości i od kolejności skanowania komórek. Ale ponieważ wszystkie operatory binarne są przemienne, nie powinno to stanowić problemu.

Jestem pewien, że powinno być możliwe jej ograniczenie, ale tylko odrobinę.

Tłumacz jest zaimplementowany w postaci pewnego rodzaju automatów komórkowych. Skanuje całe wartości ustawień pola, powtarzając je tyle razy, ile potrzeba, dopóki nie zostaną wykryte żadne zmiany.

Oto wersja bez golfa:

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

Troszkę tańszy w użyciu try{}catch(Exception e){}niż dwa throws Exception. Prawdopodobnie są inne rzeczy, ale nie mam pojęcia, jak grać w golfa Java.
Bob

@ Bob Dzięki, twoja sugestia zmusiła mnie do zmniejszenia jej o 7 znaków. Mógłbym również zmniejszyć kolejne 4.
Victor Stafusa
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.