ASCII-арт логическая схема


12

Я призываю вас написать код для создания (расширенной) логической схемы логического элемента ASCII-искусства для формы уравнения суммы продуктов.

Используйте следующие обозначения для представления ворот:

И
    INPUT───|&&
            |&&───OUTPUT
    INPUT───|&&
ИЛИ
    INPUT───|OR
            |OR───OUTPUT
    INPUT───|OR  
Ворота с более чем 2 входами
    INPUT───|OR
            |OR
    INPUT───|OR───OUTPUT
            |OR
    INPUT───|OR
НЕ
    INPUT───│>o───OUTPUT

Набор символов

Обратите внимание, что это не знак канала ASCII, а символ рисования прямоугольника . Используйте символы рисования коробок, например, ─ │ ┌ ┐ └ ┘для соединений.

пример

вход
    A'*B'+B*C
Выход
    A────│>o────│&&
                │&&─────┐
    B────│>o────│&&     └│OR
                         │OR─────A*B+B*C
    B───────────│&&     ┌│OR
                │&&─────┘
    C───────────│&&    

победитель

Победителем является ответ с наибольшим количеством голосов за 5 дней


1
Есть только 95 символов ASCII для печати, и они не включают в себя какие - либо из них: ─ │ ┌ ┐ └ ┘. Я думаю, что вы имеете в виду набор символов MS-DOS . Кроме того, разве в вашем примере не должно быть одного Bвходного разбиения между двумя элементами И? И можем ли мы предположить, что не будет необходимости где-либо пересекать провода?
r3mainer

2
Мне нравится, как вы говорите «СТРОГО ASCII-арт» и требуете, чтобы мы использовали набор символов не-ASCII.
Кендалл Фрей

@squeamishossifrage Я думаю, что есть 128 символов ASCII и 256 после расширения диаграммы ascii, посетите здесь juniper.net/techpubs/en_US/idp5.1/topics/reference/general/…
Мукул Кумар

@squeamishossifrage: Нет, он ссылается на некоторые расширенные символы ASCII . Я отредактировал вопрос, чтобы уточнить это. Расширенный ASCII включает в себя все семибитные символы ASCII, а также некоторые другие символы.
ProgramFOX

1
Принимая во внимание требование использовать символы рисования прямоугольников, кажется странным, что вы создаете соединения, ─│а не ─┤.
Питер Тейлор,

Ответы:


16

C ++ 11

Готово наконец. И это заняло у меня большую часть дня.

Прежде чем я перечислю код и пример вывода, несколько быстрых заметок:

Вещи, которые поддерживает эта программа

  • Любое количество терминов, каждое с любым количеством входов
  • Повторное использование входов
  • Пропуск представления логического элемента И / ИЛИ при наличии только одного входа
  • Используйте как кодовую страницу 437 символов рисования линий, так и 7-битные ASCII-дружественные символы (используйте -DCP437 или любой другой эквивалентный код вашего компилятора для поддержки кодовой страницы 437)

Вещи, которые не поддерживает эта программа

  • Группировка с круглыми скобками (потому что, серьезно?)
  • Несколько НОТ
  • Любой пробел, который не является простым пространством ASCII
  • Правильная игра в гольф (хотя я удалил все комментарии по духу)
  • Вменяемые практики кодирования
  • Зрительный контакт с кодом ввода
  • Переносимые символы Unicode для рисования линий. Я не мог поддерживать Unicode, потому что логика рендеринга основана на возможности рисовать «вниз» двухмерный charбуфер.

Код

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

Образец вывода

$ ./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-|&&   |
      |                    |
      `--------------------'

Пример вывода (с включенным CP437)

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─│&&   │
      │                    │
      └────────────────────┘

4
+10 за упорную решимость :-)
r3mainer

Это не тот результат, который я хотел, но +1 за вашу усердную работу (лично я ценю это). Также упомяните ваш язык!
Мукул Кумар

Престижность. Это очень приятно, CP437 или нет.
Джонатан Ван Матре

Я сделал несколько правок к сообщению (не код) на основе обратной связи выше. Я также заставил MinGW работать на моей системе, чтобы я мог собрать ее с собственной поддержкой CP437, поэтому я добавил пример выходной формы.
curtmack

В строке 202 я получаю ошибку компиляции в VisualExpress: int height и int width: выражение должно иметь постоянное значение. Также вы пропали без вести#include <vector>
Джек Коул

5

C ++

Вот так! Сделано за 1 день 12 часов !!!
Этот код обрабатывает только массив

ВХОД (ВИДЫ)

  • Форма только СОП (сумма продуктов).
  • Только сложение слагаемых с умножением двух переменных

    EXAMPLES :-
    
        A*B'+B*A+C*D  
    
        X*Y+Z'*A'*V*D+B*G+C'*A'  
    
  • Может обрабатывать любое количество терминов, переменных.

    КОД: -

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

ВЫХОД

введите описание изображения здесь

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.