Интерпретировать принципиальную схему

12

Ваша задача - интерпретировать принципиальную схему, дополненную логическими элементами.

Логические элементы (вам на самом деле не нужно знать, что они делают / являются для выполнения этой задачи):

  • и ворота: a
  • или ворота: o
  • Нанд Гейт: A
  • ни ворота: O
  • xor gate: x
  • xnor gate: X
  • не ворота: ~

Каждый вход, кроме последнего, занимает два входа. Входные данные находятся .в верхнем левом и нижнем левом углах квадрата 3 на 3 с центром на воротах. В противном случае вход находится слева от него. Выход находится .прямо направо.

Провода представлены -|\/.=

  • - соединяет два провода, один справа и один слева: c-c
  • | контакты двух проводов, один сверху и один снизу:

    c
    |
    c
    
  • /и \работать следующим образом:

    c        c
     \      /
      c    c
    
  • . контакты каждого окружающего провода:

    ccc
    c.c
    ccc
    
  • =особенный; это соединяет смежные провода через это:

    -=-
    

    соединяет два провода. В следующих

    \|/
    -=-
    /|\
    

    каждый противоположный провод связан друг с другом, но не с другими (это то, чем он отличается .).

  • Чтобы ток протекал, два провода должны быть подключены к другому, поэтому |-ток не протекает.

Пример проводки:

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

вход разделен на два провода и затем разделен на три. В этом разделении нижний провод перемещается к середине, а внизу появляется разделение верхнего провода. Далее верхняя часть трех проводов перемещается в середину.

Пример проводки с воротами:

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

Формат ввода:

  • каждый входной провод будет помечен цифрой. В конце (прямо перед новой строкой) каждый выход будет помечен :(и провод всегда будет идти прямо в него, т. Е. -:Или .:или =:)
  • ввод всегда будет действительным; не будет петель или проводов, соединяющих друг с другом без ворот. Обратите внимание, что могут быть провода со свободными концами.
  • = будет использоваться только при необходимости.

Выходной формат:

  • на каждый вход ссылается соответствующий номер.
  • выражение выводится. Например, если провода вычисляют вход 1 и вход 2, выход будет 1a2.
  • все функции, которые выводятся, должны соответствовать логическим элементам в начале.
  • чтобы не показывать, поставьте ~перед правильным местом.
  • для нескольких функций используйте скобки, чтобы показать порядок выполнения. Скобки также можно использовать, когда есть только одна функция. Например,

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

    имеет один возможный выход ~((2x3)A(~1))

  • несколько выходов должны быть разделены новой строкой (или эквивалентной)

Пример ввода:

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

Один возможный соответствующий вывод:

(~1)a(~(3O(4X5))
((1x2)x3)X((~1)a(~(3O(4X5))))
Джастин
источник
Ооооооо, интересно! Я сделаю это.
cjfaure
5
Я предвижу интересный экзоланг, выходящий из этого, если мы расширим его таким образом, чтобы сделать его полным по Тьюрингу.
Виктор Стафуса
Что делать интерпретатору в случае «ошибки компилятора» (т. Е. Неправильно сформированной входной проводки)?
Виктор Стафуса
А если я подключу напрямую два входа? Или подключить напрямую два выхода? Или вводить открытые строки на выходе?
Виктор Стафуса
1
@Victor Это уже похоже. Но я пошел дальше и создал еще один
Джастин

Ответы:

4

Питон 2488 1567 806 706 697 657 653

Yay для 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=='))

Ограничения и предположения

На самом деле поддерживается только до 9 входов - несколько цифр обрабатываются некорректно. Поскольку в спецификации указано, что входы помечены цифрой , а не цифрой , это разрешено.


Вход и выход

Вход берется через стандартный вход, а выход через стандартный выход.


тестирование

Пример ввода и вывода:

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

Протестировано здесь: http://ideone.com/gP4CIq


Алгоритм

Это в основном довольно наивный DFS с выходов. Для каждого вывода он начинается с символа один слева от него и отслеживает провод, разветвляясь (и добавляя к выражению) на каждом элементе. Когда он достигает вход, он добавляет его к выражению и откатывается до последнего момента она разветвленная, так как мы можем быть уверены , что ветвление не возможно без ворота. И, конечно же, любые недействительные дела отбрасываются. Ничего особенного в этом нет - и поэтому он, вероятно, дольше, чем мог бы быть.


Примечания

Вероятно, размер можно немного уменьшить с помощью некоторой реструктуризации, но я потратил достаточно времени на это сегодня. Версия для гольфа с ручным управлением была сжатой.

Сжатие gzip делает гольф интересным, потому что определенное кэширование (например d=(-1,0,1)) фактически занимает больше места, чем позволяет алгоритму сжатия позаботиться об этом. Тем не менее, я выбрал гольф-версию с ручным управлением как можно дальше, а не оптимизировал сжатие.


Вручную ( 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])

Полное разгул (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? Кроме того, работать в обратном направлении от вывода - это именно то, о чем я думал.
Джастин
@Quincunx Поиск в глубину. По сути, рекурсия (или иное использование конструкции LIFO, стека) и продвижение как можно дальше по пути, пока он не достигнет тупика или цели, после чего он возвращается к последней точке расхождения и пробует другие пути.
Боб
Хорошее предположение на входах. Это именно то, что я имел в виду (и я попытался сказать это, чтобы предложить это). Однако работает ли ваша программа с 0цифрой? Как насчет обмена местами так, чтобы он был 2раньше 1и т. Д.
Джастин,
@Quincunx Я использую Python .isdigit(), который, [0-9]насколько я могу судить, фактически эквивалентен регулярному выражению . Это правильно в соответствии с вашими требованиями? Что вы подразумеваете под обменом заказа? Как это реализовано, он сначала направится вверх по ветке любого логического элемента, но нет никакой гарантии упорядочения входов.
Боб
isdigit()согласуется. Сменный порядок означает что-то вроде 2первого входа и 1второго входа (отсортировано по вертикали).
Джастин
6

Ява: 1523 1512 символов

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

Это дает этот вывод для образца ввода:

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

Чтобы сжать его размер:

  • Он не выполняет никакой проверки ошибок, обработки ошибок или проверки ввода, предполагая, что ввод всегда действителен.
  • Ограничено до 99 строк ввода.
  • Его входной файл должен называться просто r, без расширения файла в имени.
  • Он не прилагает никаких усилий, чтобы определить, являются ли скобки необходимыми или нет. Предполагается, что они всегда необходимы, и поскольку это предположение неверно, скобок гораздо больше, чем необходимо, но, поскольку это не делает его ошибочным, в любом случае это не проблема.
  • Порядок параметров для каждого бинарного оператора в общем случае непредсказуем, поскольку он зависит от скорости распространения значений и порядка сканирования ячеек. Но так как все бинарные операторы коммутативны, это не должно быть проблемой.

Я уверен, что должно быть возможно уменьшить это больше, но только немного.

Интерпретатор реализован в виде своего рода клеточных автоматов. Он сканирует все значения настроек поля, повторяя их столько раз, сколько необходимо, пока не обнаружены изменения.

Вот негольфированная версия:

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;
    }
}
Виктор Стафуса
источник
Tiny немного дешевле в использовании try{}catch(Exception e){}, чем два throws Exception. Возможно, есть и другие вещи, но я понятия не имею, как играть в гольф на Яве.
Боб
@Bob Спасибо, ваше предложение заставило меня уменьшить его на 7 символов. Кроме того, я мог бы уменьшить еще 4.
Виктор Стафуса