C ++ 11
Thực hiện cuối cùng. Và nó chỉ đưa tôi hầu hết các ngày.
Trước khi tôi liệt kê mã và đầu ra mẫu, một số lưu ý nhanh:
Những điều mà chương trình này hỗ trợ
- Bất kỳ số lượng điều khoản, mỗi điều khoản với bất kỳ số lượng đầu vào
- Tái sử dụng đầu vào
- Bỏ qua đại diện cổng AND / OR khi chỉ có một đầu vào
- Sử dụng cả hai ký tự vẽ dòng mã 437 và các ký tự thân thiện với ASCII 7 bit (sử dụng -DCP437 hoặc bất cứ thứ gì tương đương với trình biên dịch của bạn để hỗ trợ mã hóa 437)
Những điều chương trình này không hỗ trợ
- Phân nhóm với dấu ngoặc đơn (vì, nghiêm túc?)
- Nhiều ghi chú
- Bất kỳ khoảng trắng nào không phải là không gian ASCII đơn giản
- Chơi golf đúng cách (mặc dù tôi đã loại bỏ tất cả các ý kiến trong tinh thần)
- Thực hành mã hóa Sane
- Giao tiếp bằng mắt với mã phân tích cú pháp đầu vào
- Di động, ký tự vẽ Unicode. Tôi không thể hỗ trợ Unicode vì logic kết xuất phụ thuộc vào khả năng vẽ "xuống"
char
bộ đệm hai chiều .
Mã
#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;
}
Sản lượng mẫu
$ ./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-|&& |
| |
`--------------------'
Đầu ra mẫu (đã bật 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─│&& │
│ │
└────────────────────┘
─ │ ┌ ┐ └ ┘
. Tôi nghĩ rằng bạn đang đề cập đến bộ ký tự MS-DOS . Ngoài ra, ví dụ của bạn cóB
phân chia đầu vào duy nhất giữa hai cổng AND không? Và chúng ta có thể cho rằng sẽ không cần dây để đi qua bất cứ nơi nào không?