#include <bits/stdc++.h>
using namespace std;
// 立体图:把 m x n 个格子上摞的积木画成字符画
//
// 投影规则(x 向右为列,y 向上为行,画布左下角为原点):
// · 一块积木的正面宽 4 列、高 3 行(上下两条边 + 两行 '|')
// · 顶面与右侧面都朝「右上」偏 (2 列, 2 行)
// · 同一行相邻的格子横向差 4 列;往后再退一排纵向差 (2 列, 2 行)
//
// 画法(画家算法):先画后排再画前排,同一排从左往右,每格从下往上;
// 近的覆盖远的,正好把被挡住的棱盖掉。
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int m, n;
cin >> m >> n;
vector<vector<int>> a(m + 1, vector<int>(n + 1));
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
}
}
// 画布大小:最高的那块积木的顶面后沿、最右那格的右侧面后沿
int H = 0, W = 0;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
int by = 2 * (m - i);
int bx = 4 * (j - 1) + 2 * (m - i);
H = max(H, by + 3 * a[i][j] + 3);
W = max(W, bx + 7);
}
}
vector<string> pic(H, string(W, '.'));
// y 从画布底部往上数
auto put = [&](int x, int y, char c) {
if (x < 0 || x >= W || y < 0 || y >= H) return;
pic[H - 1 - y][x] = c;
};
for (int i = 1; i <= m; i++) { // 从后排画到前排
for (int j = 1; j <= n; j++) { // 同一排从左往右
int bx = 4 * (j - 1) + 2 * (m - i);
int by = 2 * (m - i);
for (int k = 0; k < a[i][j]; k++) { // 每格从下往上
int y0 = by + 3 * k;
// 正面:上下两条横边 + 中间两行竖边
for (int t = 0; t <= 4; t++) {
char c = (t == 0 || t == 4) ? '+' : '-';
put(bx + t, y0, c);
put(bx + t, y0 + 3, c);
}
put(bx, y0 + 1, '|');
put(bx, y0 + 2, '|');
put(bx + 4, y0 + 1, '|');
put(bx + 4, y0 + 2, '|');
// 正面中间要留空(把被挡住的部分盖掉)
for (int t = 1; t <= 3; t++) {
put(bx + t, y0 + 1, ' ');
put(bx + t, y0 + 2, ' ');
}
// 顶面:两条斜边 + 后沿
put(bx + 1, y0 + 4, '/');
put(bx + 5, y0 + 4, '/');
put(bx + 2, y0 + 4, ' ');
put(bx + 3, y0 + 4, ' ');
put(bx + 4, y0 + 4, ' ');
for (int t = 0; t <= 4; t++) {
char c = (t == 0 || t == 4) ? '+' : '-';
put(bx + 2 + t, y0 + 5, c);
}
// 右侧面:底沿斜线 + 后沿竖边
put(bx + 5, y0 + 1, '/');
put(bx + 5, y0 + 2, ' ');
put(bx + 5, y0 + 3, ' ');
put(bx + 6, y0 + 2, '+');
put(bx + 6, y0 + 3, '|');
put(bx + 6, y0 + 4, '|');
put(bx + 6, y0 + 5, '+');
}
}
}
for (const string &row : pic) {
cout << row << '\n';
}
return 0;
}