Diagrama da porta lógica ASCII-art

12

Desafio você a escrever um código para criar um diagrama de portas lógicas (estendido) de arte ASCII para a forma da soma dos produtos de uma equação.

Use a seguinte notação para representar portões:

E
    INPUT───|&&
            |&&───OUTPUT
    INPUT───|&&
OU
    INPUT───|OR
            |OR───OUTPUT
    INPUT───|OR  
Portões com mais de 2 entradas
    INPUT───|OR
            |OR
    INPUT───|OR───OUTPUT
            |OR
    INPUT───|OR
NÃO
    INPUT───│>o───OUTPUT

Conjunto de caracteres

Observe que não é um sinal de canal ASCII, mas um caractere de desenho de caixa . Use caracteres de desenho de caixa, como ─ │ ┌ ┐ └ ┘para conexões.

Exemplo

Entrada
    A'*B'+B*C
Resultado
    A────│>o────│&&
                │&&─────┐
    B────│>o────│&&     └│OR
                         │OR─────A*B+B*C
    B───────────│&&     ┌│OR
                │&&─────┘
    C───────────│&&    

Vencedora

O vencedor é a resposta com mais votos positivos em 5 dias

Mukul Kumar
fonte
1
Existem apenas 95 caracteres ASCII imprimíveis, e eles não incluem qualquer um destes: ─ │ ┌ ┐ └ ┘. Eu acho que você está se referindo ao conjunto de caracteres do MS-DOS . Além disso, seu exemplo não deveria ter uma única Bentrada dividida entre os dois portões AND? E podemos supor que não haverá necessidade de cabos cruzarem qualquer lugar?
R3mainer #
2
Adoro como você diz "uma arte estritamente ASCII" e exige que usemos um conjunto de caracteres não ASCII.
Kendall Frey
@squeamishossifrage Eu acho que existem 128 caracteres ASCII e 256 após a extensão do ascii gráfico visita aqui juniper.net/techpubs/en_US/idp5.1/topics/reference/general/...
Mukul Kumar
@squeamishossifrage: Não, ele se refere a alguns caracteres ASCII estendidos . Eu editei a pergunta para esclarecer isso. O ASCII estendido inclui todos os caracteres ASCII de sete bits, além de alguns outros caracteres.
precisa
1
Dada a exigência de utilização de personagens de desenho de caixa, parece estranho que você está fazendo conexões como ─│em vez de ─┤.
Peter Taylor

Respostas:

16

C ++ 11

Feito finalmente. E isso me levou a maior parte do dia.

Antes de listar o código e a amostra de saída, algumas notas rápidas:

Coisas que este programa suporta

  • Qualquer número de termos, cada um com qualquer número de entradas
  • Reutilizando Entradas
  • Omitindo a representação de porta AND / OR quando apenas uma entrada estaria presente
  • Uso de caracteres de desenho de linha da página de código 437 e caracteres compatíveis com ASCII de 7 bits (use -DCP437 ou qualquer que seja o equivalente do seu compilador ao suporte da página de código 437)

Coisas que este programa não suporta

  • Agrupar com parênteses (porque, sério?)
  • Múltiplas NOTAS
  • Qualquer espaço em branco que não seja um espaço ASCII simples
  • Golfificação adequada (embora eu tenha removido todos os comentários em espírito)
  • Práticas de codificação sã
  • Fazendo contato visual com o código de análise de entrada
  • Caracteres de desenho de linha portáteis, Unicode. Não pude dar suporte ao Unicode porque a lógica de renderização depende de poder "baixar" um charbuffer bidimensional .

Código

#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <stdexcept>
#include <set>
#include <map>
#include <valarray>
#include <cmath>

using namespace std;

vector<string> split(const string str, const string delim)
{
    vector<string> v;

    set<char> d;
    for (char c : delim) d.insert(c);

    string current {};
    for (char c : str)
    {
        if (d.find(c) != d.end())
        {
            v.push_back(current);
            current = "";
        }
        else
        {
            current += c;
        }
    }
    v.push_back(current);

    return v;
}

using Input = string;
struct TermInput
{
    Input name;
    int ypos;
    bool neg;
};
using Term = vector<TermInput>;
using Expr = vector<Term>;

#ifdef CP437
constexpr char VERT    = '\xB3';
constexpr char HORIZ   = '\xC4';
constexpr char RBRANCH = '\xC3';
constexpr char LUP     = '\xD9';
constexpr char LDOWN   = '\xBF';
constexpr char RUP     = '\xC0';
constexpr char RDOWN   = '\xDA';
#else
constexpr char VERT    = '|';
constexpr char HORIZ   = '-';
constexpr char RBRANCH = '}';
constexpr char LUP     = '\'';
constexpr char LDOWN   = '.';
constexpr char RUP     = '`';
constexpr char RDOWN   = ',';
#endif

string repeat(string s, int n)
{
    stringstream ss;
    for (int i = 0; i < n; i++)
    {
        ss << s;
    }

    return ss.str();
}
string repeat(char c, int n)
{
    stringstream ss;
    for (int i = 0; i < n; i++)
    {
        ss << c;
    }

    return ss.str();
}

enum class Direction
{
    RIGHT,
    DOWN
};

void matrixPut(char *matrix, int h, int w, int x, int y, const string s, Direction dir)
{
    if (x >= w || y >= h)
    {
        stringstream ss;
        ss << "matrixPut: point (" << x << ", " << y << ") out of matrix bounds!";
        throw new out_of_range(ss.str());
    }

    char *ins = matrix + (y * w) + x;
    char *end = matrix + (h * w);
    for (char c : s)
    {
        if (ins >= end) break;
        *ins = c;

        if (dir==Direction::RIGHT)
        {
            ins++;
        }
        else
        {
            ins += w;
        }
    }
}

void matrixPrint(char *matrix, int h, int w)
{
    for (int i = 0; i < (h * w); i++)
    {
        cout << matrix[i];
        if ((i+1)%w == 0) cout << endl;
    }
}

int main (int argc, char *argv[])
{
    string expression;

    if (argc == 1)
    {
        cout << "Enter expression:" << endl;
        getline(cin, expression);
    }
    else
    {
        expression = argv[1];
    }

    expression.erase(remove(expression.begin(), expression.end(), ' '), expression.end());

    Expr expr {};
    auto inputs = set<Input>();
    auto termInputs = multimap<Input, TermInput>();

    int inputYPos = 0;

    auto e = split(expression, "+");
    for (string term : e)
    {
        Term currTerm {};

        auto t = split(term, "*");
        for (string in : t)
        {
            bool neg = false;
            if (in.back() == '\'')
            {
                in.pop_back();
                neg = true;
            }

            Input currInput {in};
            inputs.insert(currInput);

            TermInput ti {currInput, inputYPos, neg};
            currTerm.push_back(ti);

            termInputs.insert(pair<Input, TermInput>{in, ti});
            inputYPos++;
        }

        expr.push_back(currTerm);
        inputYPos++;
    }


    int height = inputs.size() + termInputs.size() + expr.size() - 1;

    int width = 0;

    width += max_element(inputs.begin(), inputs.end(), [](Input a, Input b){ return a.length() < b.length(); })->length() + 2;
    int inputWidth = width;
    width += inputs.size()*2;

    int notAndStart = width;

    width += 7;
    width += expr.size()+1;

    int orStart = width;

    width += 4;

    width += 4;

    width += expression.length();

    char matrix[height * width];
    for (int i = 0; i < height*width; i++) matrix[i] = ' ';

    int  baseY = inputs.size();

    {
        int x = width - 4 - expression.length();
        int y = baseY + ((height-baseY) / 2);
        matrixPut(matrix, height, width, x, y, repeat(HORIZ, 4) + expression, Direction::RIGHT);
    }

    {
        int x = orStart;
        int y = baseY + (height-baseY)/2 - expr.size()/2;

        if (expr.size() == 1)
        {
            matrixPut(matrix, height, width, x, y, repeat(HORIZ, 4), Direction::RIGHT);
        }
        else {
            matrixPut(matrix, height, width, x  , y, repeat(HORIZ, expr.size()), Direction::DOWN);
            matrixPut(matrix, height, width, x+1, y, repeat(VERT , expr.size()), Direction::DOWN);
            matrixPut(matrix, height, width, x+2, y, repeat('O'  , expr.size()), Direction::DOWN);
            matrixPut(matrix, height, width, x+3, y, repeat('R'  , expr.size()), Direction::DOWN);
        }
    }

    {
        int x = notAndStart;
        int y = baseY;
        for (Term t : expr)
        {
            string layer[7];
            for (TermInput ti : t)
            {
                layer[0] += HORIZ;
                layer[1] += (ti.neg ? '>' : HORIZ);
                layer[2] += (ti.neg ? 'o' : HORIZ);
                layer[3] += HORIZ;
                layer[4] += (t.size() > 1 ? VERT : HORIZ);
                layer[5] += (t.size() > 1 ? '&' : HORIZ);
                layer[6] += (t.size() > 1 ? '&' : HORIZ);
            }

            for (int i = 0; i < 7; i++)
            {
                matrixPut(matrix, height, width, x+i, y, layer[i], Direction::DOWN);
            }

            y += t.size() + 1;
        }
    }

    {
        int x = 0;
        int y = 0;

        for (Input i : inputs)
        {
            string str = i + ": ";
            str += repeat(HORIZ, inputWidth - str.length());

            matrixPut(matrix, height, width, x, y, str, Direction::RIGHT);

            y++;
        }
    }

    {
        int x = inputWidth;
        int num = 0;
        int offset = inputs.size() * 2 - 1;

        for (Input in : inputs)
        {
            int y = 0;
            int len = inputs.size() * 2 - 1;
            auto it = inputs.find(in);
            while (it != inputs.begin())
            {
                it--;
                y++;
                len -= 2;
            }
            matrixPut(matrix, height, width, x, y, repeat(HORIZ, len) + LDOWN, Direction::RIGHT);
        }

        for (Input in : inputs)
        {
            auto yBreakRange = termInputs.equal_range(in);
            valarray<int> yBreaks(termInputs.count(in));
            int idx = 0;
            for (auto ti = yBreakRange.first; ti != yBreakRange.second; ti++)
            {
                yBreaks[idx++] = baseY + ti->second.ypos;
            }

            for (int y : yBreaks)
            {
                matrixPut(matrix, height, width, x+offset, y, repeat(HORIZ, inputs.size()*2 - offset), Direction::RIGHT);
            }

            int y = num + 1;
            int maxBreak = yBreaks.max();
            string branch = repeat(VERT, maxBreak - y + 1);

            for (int i : yBreaks)
            {
                branch[i-y] = RBRANCH;
            }
            branch.back() = RUP;

            matrixPut(matrix, height, width, x+offset, y, branch, Direction::DOWN);

            offset -= 2;
            num++;
        }
    }

    {
        int x = notAndStart + 7;
        int outY = baseY + (height-baseY)/2 - expr.size()/2;
        int breakx = expr.size()/2;

        for (Term t : expr)
        {
            int inY = baseY + (t.front().ypos + t.back().ypos) / 2;

            matrixPut(matrix, height, width, x, inY, repeat(HORIZ, abs(breakx)+1), Direction::RIGHT);

            matrixPut(matrix, height, width, x+abs(breakx)+1, outY, repeat(HORIZ, expr.size()-abs(breakx)), Direction::RIGHT);

            if (inY < outY)
            {
                string branch = LDOWN + repeat(VERT, outY-inY-1) + RUP;
                matrixPut(matrix, height, width, x+abs(breakx)+1, inY, branch, Direction::DOWN);
            }
            else if (inY > outY)
            {
                string branch = RDOWN + repeat(VERT, inY-outY-1) + LUP;
                matrixPut(matrix, height, width, x+abs(breakx)+1, outY, branch, Direction::DOWN);
            }

            outY++;
            breakx--;
        }
    }

    cout << endl;
    matrixPrint(matrix, height, width);
    cout << endl;
}

Saída de amostra

$ ./gates "A'*B'+B*C"

A: -----.
B: ---. |
C: -. | |
    | | `->o-|&&--.
    | }--->o-|&&  `-|OR
    | |          ,--|OR----A'*B'+B*C
    | `------|&&-'
    `--------|&&

$ ./gates "A*B'*C+B*D'+F*C'*D+G*E*A'+F"

A: -------------.
B: -----------. |
C: ---------. | |
D: -------. | | |
E: -----. | | | |
F: ---. | | | | |
G: -. | | | | | |
    | | | | | | }----|&&
    | | | | | }--->o-|&&---.
    | | | | }--------|&&   |
    | | | | | | |          |
    | | | | | `------|&&--.|
    | | | }------->o-|&&  ||
    | | | | |   |         |`---|OR
    | }--------------|&&  `----|OR
    | | | | `----->o-|&&-------|OR----A*B'*C+B*D'+F*C'*D+G*E*A'+F
    | | | `----------|&&  ,----|OR
    | | |       |         |,---|OR
    `----------------|&&  ||
      | `------------|&&--'|
      |         `->o-|&&   |
      |                    |
      `--------------------'

Saída de amostra (com CP437 ativado)

A: ─────────────┐
B: ───────────┐ │
C: ─────────┐ │ │
D: ───────┐ │ │ │
E: ─────┐ │ │ │ │
F: ───┐ │ │ │ │ │
G: ─┐ │ │ │ │ │ │
    │ │ │ │ │ │ ├────│&&
    │ │ │ │ │ ├───>o─│&&───┐
    │ │ │ │ ├────────│&&   │
    │ │ │ │ │ │ │          │
    │ │ │ │ │ └──────│&&──┐│
    │ │ │ ├───────>o─│&&  ││
    │ │ │ │ │   │         │└───│OR
    │ ├──────────────│&&  └────│OR
    │ │ │ │ └─────>o─│&&───────│OR────A*B'*C+B*D'+F*C'*D+G*E*A'+F
    │ │ │ └──────────│&&  ┌────│OR
    │ │ │       │         │┌───│OR
    └────────────────│&&  ││
      │ └────────────│&&──┘│
      │         └─>o─│&&   │
      │                    │
      └────────────────────┘
curtmack
fonte
4
+10 para determinação pura e obstinada :-)
r3mainer
Essa não é a saída que eu queria, mas +1 pelo seu trabalho duro (pessoalmente, eu aprecio isso). Também mencione seu idioma!
Mukul Kumar
Parabéns. Isso é muito bom, CP437 ou não.
Jonathan Van Matre
Fiz algumas edições na postagem (não no código) com base nos comentários acima. Também instalei o MinGW para trabalhar no meu sistema para que eu pudesse construí-lo com suporte nativo ao CP437, então adicionei alguns exemplos de formulário de saída.
curtmack #
Na linha 202, recebo um erro de compilação no VisualExpress: int height e int width: A expressão deve ter um valor constante. Também estava faltando#include <vector>
Jack Cole
5

C ++

Ufa! Feito em 1 dia 12 horas !!!
Esse código lida apenas com matriz

ENTRADA (TIPOS)

  • Somente o formulário SOP (soma de produtos)
  • Somente adição de termos com duas variáveis ​​multiplicando

    EXAMPLES :-
    
        A*B'+B*A+C*D  
    
        X*Y+Z'*A'*V*D+B*G+C'*A'  
    
  • Pode lidar com qualquer número de termos, variáveis.

    CÓDIGO: -

    #include<iostream>
    using namespace std;
    int main()
    {
    int i,j,k,l,m=0;
    char arr[80][80],expr[45];
    cout<<"enter the SOP(Sum Of products) expression : ";
    cin>>expr;
    cout<<"\n\n";
    for(i=0;expr[i]!='\0';i++)
    if(expr[i]=='*')m++;
    for(i=0;i<80;i++)
        for(j=0;j<80;j++)
            arr[i][j]=' ';
    for(i=0,j=0;i<80,expr[j]!='\0';j++)
    {
        if(expr[j]<=90&&expr[j]>=65||expr[j]<=122&&expr[j]>=97)
        {
            arr[i][0]=expr[j];
            i+=2;
        }
    }
    for(i=0,j=1;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i][j-1]<=90&&arr[i][j-1]>=65||arr[i][j-1]<=122&&arr[i][j-1]>=97)
        {
            for(k=0;k<7;k++)
                arr[i][j+k]=196;
            arr[i][j+k]=180;
        }
    }
    for(i=0,j=0;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i][j]==(char)180&&arr[i][j+1]==' ')
        {
            arr[i][j+1]=38;
        }
    }
    for(i=0,j=0,k=1;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i-1][j]==(char)180&&arr[i+1][j]==(char)180)
        {
            if(arr[i-1][j+1]==(char)38&&arr[i+1][j+1]==(char)38&&k)
            {
                arr[i][j]=179;arr[i][j+1]=38;
                for(l=2;l<4;l++)
                {
                    arr[i][j+l]=196;
                }
                k--;
            }
            else if(k==0)
            {
                k=1;
            }
        }
    }
    l=m;
    for(i=0,j=0;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i][j-1]==(char)196&&arr[i][j+1]==' '&&arr[i][j-2]==(char)38)
            {
            if(arr[i+3][j-2]==(char)38)
            {
                for(k=0;k<l;k++)
                    arr[i][j+k]=(char)196;
                arr[i][j+k-1]=(char)191;
    
                l--;
            }
            else
            {
                for(k=0;k<m;k++)
                arr[i][j+k]=(char)196;
            }
        }
    }
    for(i=0,j=0,k=1;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i][j]==(char)191&&arr[i][j-1]==(char)196)
        {
            for(;arr[i+k][j]==' ';k++)
            {
                arr[i+k][j]=(char)179;
            }
        k=1;
        }
    }
    for(i=0,j=0;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i][j]==(char)179&&arr[i][j-3]==(char)38&&arr[i+1][j]==(char)196)
        {
            arr[i][j]=(char)192;
            for(k=1;arr[i-k][j+k]==(char)179;k++)
            {
                arr[i-k][j+k]=(char)192;
            }
        }
    }
    for(i=0,j=0;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i][j-1]==(char)192)
        {
            for(k=0;arr[i][j+k]!=' ';k++)
                arr[i][j+k]=(char)196;
        }
    }
    for(i=0,j=0;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i][j-1]==(char)192&&arr[i][j]==' '||arr[i][j-1]==(char)196&&arr[i][j]==' ')
        {
            arr[i][j]=(char)180;
            arr[i][j+1]='O';
            arr[i][j+2]='R';
        }
    }
    for(i=0,j=0;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i][j-1]=='R'&&arr[i+1][j-1]==' ')
        {
            for(k=0;k<3;k++)
                arr[i][j+k]=(char)196;
            j+=k;
            for(k=0;expr[k]!='\0';k++)
            {
                arr[i][j+k]=expr[k];
            }
        }
    }
    for(i=0,k=0;i<80,expr[k]!='\0';k++)
    {
        if((expr[k]<='z'&&expr[k]>='a'||expr[k]<='Z'&&expr[k]>='A'))
        {
            if(expr[k+1]=='\'')
                arr[i][1]='\'';
            i+=2;
        }
    }
    for(i=0,j=0;i<80;j++)
    {
        if(j==80){i++;j=0;}
        if(arr[i][j]=='\''&&arr[i][j+1]==(char)196)
        {
            arr[i][j+3]=(char)180;
            arr[i][j+4]=(char)62;
            arr[i][j+5]='o';
        }
    }
    for(i=0;i<35;i++)
    {
        for(j=0;j<80;j++)
            cout<<arr[i][j];
        cout<<'\n';
    }
    return 0;
    }  
    

RESULTADO

insira a descrição da imagem aqui

Mukul Kumar
fonte