Інтерпретувати схему


12

Ваше завдання полягає в тому, щоб інтерпретувати схему, доповнену логічними воротами.

Логічні ворота (вам фактично не потрібно знати, що вони роблять / є для виконання цього завдання):

  • і ворота: a
  • або ворота: o
  • нанд ворота: A
  • ні ворота: O
  • xor gate: x
  • xnor ворота: 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))))

Oooohhhhh, цікаво! Я пострілю.
cjfaure

5
Мені передбачено, що цікавий екзоланг виходить із цього, якщо ми розширимо його таким чином, щоб зробити його Тюрінг-завершеним.
Віктор Стафуса

У разі "помилки компілятора" (тобто неправильного введення проводки), що повинен робити перекладач?
Віктор Стафуса

І якщо я підключую безпосередньо два входи? Або підключити безпосередньо два виходи? Або ввести відкриті лінії на вихід?
Віктор Стафуса

1
@Victor Це вже схоже. Але я пішов вперед і створив ще одну
Джастін

Відповіді:


4

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

Так, для 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;
    }
}

Крихітні трохи дешевше у використанні try{}catch(Exception e){}, ніж два throws Exception. Мабуть, є й інші речі, але я не маю уявлення, як грати в Java.
Боб

@Bob Спасибі, ваша пропозиція змусила мене зменшити його на 7 символів. Крім того, я міг би зменшити ще 4.
Віктор Стафуса
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.