回路図を解釈する


12

あなたの課題は、論理ゲートを備えた回路図を解釈することです。

論理ゲート(実際にこれらが何をするかを知る必要はありません/このチャレンジを完了するには):

  • およびゲート: a
  • またはゲート: o
  • ナンドゲート: A
  • また、ゲート: O
  • XORゲート: x
  • xnorゲート: X
  • ゲートではない: ~

最後のゲートを除く各ゲートには2つの入力があります。入力は.、ゲートを中心とした3 x 3の正方形の左上隅と左下隅のaからです。ないため、入力はその左側に直接あります。出力は.、右側に直接あります。

ワイヤは -|\/.=

  • - 右に1本、左に1本の2本のワイヤに接触します。 c-c
  • | 2本のワイヤに接続します。1本は上、もう1本は下です。

    c
    |
    c
    
  • /そして\次のように動作します:

    c        c
     \      /
      c    c
    
  • . 周囲のすべてのワイヤに接触します:

    ccc
    c.c
    ccc
    
  • =特別です; 隣接するワイヤを接続します:

    -=-
    

    2本のワイヤを接続します。以下では

    \|/
    -=-
    /|\
    

    反対側の各ワイヤは相互に接続されていますが、他のワイヤは接続されていません(これは、それとは異なるところです.)。

  • 電流が流れるためには、2本のワイヤが両方とも他方に接続されている必要があるため|-、電流は流れませ

配線の例:

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

入力は2本のワイヤに分割され、その後3本に分割されます。この分割では、下部のワイヤが中央に移動し、上部のワイヤの下向きの分割が下部に表示されます。次に、3本のワイヤの上部を中央に移動します。

ゲート付きのサンプル配線:

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

入力形式:

  • 各入力ワイヤには数字のラベルが付けられます。最後(改行の直前)に、各出力にラベルが付けられます:(そして、ワイヤは常にその中に直接入ります、つまり-:または.:または=:
  • 入力は常に有効です。ゲートなしで結合するループやワイヤはありません。端が緩んでいるワイヤが存在する可能性があることに注意してください。
  • = 必要な場合にのみ使用されます。

出力フォーマット:

  • 各入力は、対応する番号で参照されます。
  • 式が出力されます。たとえば、ワイヤが入力1と入力2を計算する場合、出力は1a2です。
  • 出力される関数はすべて、最初の論理ゲートに対応する必要があります。
  • 表示しないようにする~には、正しい場所の前に置きます。
  • 複数の関数の場合、括弧を使用して実行の順序を示します。括弧は、関数が1つしかない場合にも使用できます。例えば、

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

    の1つの可能な出力があります ~((2x3)A(~1))

  • 複数の出力は改行(または同等のもの)で区切る必要があります

サンプル入力:

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

1つの可能な対応する出力:

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

ああ、面白い!試してみます。
cjfaure 14

5
これをチューリング完全にする方法で拡張すると、私はこれから面白いエキソランが出てくると予測しています。
ビクターStafusa 14

「コンパイラエラー」(つまり、不正な入力配線)の場合、インタプリタは何をすべきですか?
ビクターStafusa 14

また、2つの入力を直接接続するとどうなりますか?または、2つの出力を直接接続しますか?または、オープンラインを出力に入力しますか?
ビクターStafusa 14

1
@Victor これはすでに似ています。しかし、私は先に進み、別のもの
ジャスティン14

回答:


4

Pythonの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です。出力ごとに、左から1文字目から始まり、ワイヤをトレースし、すべてのゲートで分岐(および式に追加)します。入力に到達すると、それを式に追加し、分岐していない最後のポイントに戻ります。これは、ゲートなしでは分岐できないことを確認できるためです。そしてもちろん、無効なケースは破棄されます。それにとって特別なものは何もありません。したがって、それはおそらく、以前よりも長くなります。


ノート

おそらく再構築によってサイズをかなり小さくすることができますが、今日はこれに十分な時間を費やしました。手動でゴルフしたバージョンは圧縮されたものでした。

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とは何ですか?また、出力から逆方向に作業することは、まさに私が考えていたものです。
ジャスティン14

@Quincunx深さ優先検索。基本的に、再帰(またはLIFOコンストラクト、スタックを使用)および行き止まりまたはゴールに到達するまでパスに沿って可能な限り移動し、その時点で分岐の最後のポイントに戻り、他のパスを試行します。
ボブ14

入力に関する適切な仮定。それがまさに私が意図したことです(そしてそれを示唆するためにそれを言い表そうとしました)。ただし、プログラム0は数字として機能しますか?21に来るように順序を入れ替えてみてはどうでしょうか?
ジャスティン14

@Quincunx私はPythonを使用しています。これは、私が知る限り.isdigit()、正規表現と事実上同等[0-9]です。それはあなたの仕様に従って正しいですか?交換注文とはどういう意味ですか?実装方法は、まず論理ゲートの上位ブランチに進みますが、入力の順序付けの保証はありません。
ボブ14

isdigit()一貫しています。交換順序は次のようなものを意味します2、最初の入力と12番目の入力(垂直に並べ替えられた)の。
ジャスティン14

6

Java: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){}するのに2つよりも少し安いthrows Exception。おそらく他にもありますが、Javaをゴルフする方法はわかりません。
ボブ14

@Bobありがとう、あなたの提案で7文字削減しました。また、さらに4つ削減できます。
ビクターStafusa 14
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.