Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
zmx0142857
GitHub Repository: zmx0142857/mini-games
Path: blob/master/c/cube-font/cube-font.cpp
363 views
1
/*
2
* Name: CubeFont-2.0
3
* Author: zmx0142857
4
* Description:Input 2D graphics, output 3D.
5
* Examples:
6
* _____
7
* /\ \
8
* /::\____\
9
* /:::/ /
10
* /:::/ /
11
* /:::/ /
12
* 00 00 /:::/____/
13
* 00 00 /::::\ \
14
* 00 00 /::::::\ \ _____
15
* 00 00 /:::/\:::\ \ /\ \
16
* 0000000000 -> /:::/ \:::\ /::\____\
17
* 0000000000 \::/ \:::\ /:::/ /
18
* 00 00 \/____/ \:::\/:::/ /
19
* 00 00 \::::::/ /
20
* 00 00 \::::/ /
21
* 00 00 /:::/ /
22
* /:::/ /
23
* /:::/ /
24
* /:::/ /
25
* \::/ /
26
* \/____/
27
* _____________
28
* /000\ /::::::::\ \
29
* /00000\ /::::::::::\ \
30
* /0000000\ /:::/~~\:::::\____\
31
* /0/ \000 /::::\~~ \:::::| |
32
* 00 000 /::::::\ \::::| |
33
* 0000000000 -> /:::/\:::\ |:::| |
34
* 0000000000 \::/ \:::\ |:::| |
35
* 00 000 \/____\:::\/::::| |
36
* 00 000 \::::::::|____|
37
* 00 000 \::::::/ /
38
* /:::::/ /
39
* /:::::/ /
40
* /:::::/ /
41
* \::::/ /
42
* \::/ /
43
* \/____/
44
* _____
45
* /\ \
46
* /::\ \
47
* /::::\ \
48
* /::::::\ \
49
* 00000000\ /:::/\:::\ \
50
* 000000000 /:::/__\:::\ \
51
* 00 \00 /::::\ \:::\ \
52
* 00 /0/ /::::::\ \:::\ ___\
53
* 00000000\ -> /:::/\:::\ |:::| |
54
* 000000000\ /:::/__\:::\__|:::|____|
55
* 00 \00 \:::\ \:::::::::/ /
56
* 00 /00 \:::\ \:::::::/___/
57
* 000000000/ \:::\ \:::|~~ |
58
* 00000000/ \:::\ |::| |
59
* \:::\__|::|_____|
60
* \::::::::/ /
61
* \::::::/ /
62
* \::::/ /
63
* ~~~~~~~~~
64
*/
65
66
#include <iostream>
67
#include <vector>
68
#include <cctype> // isspace()
69
using std::istream;
70
using std::ostream;
71
using std::cin;
72
using std::cout;
73
using std::endl;
74
using std::vector;
75
using std::string;
76
77
typedef vector<string> Map;
78
struct Pixel
79
{
80
char type; // the char from the inbuffer
81
int thickness;
82
bool hastop; // true if exist a pixel on the top
83
bool hasbottom;
84
bool hasleft;
85
bool hasright;
86
bool hasrightbottom;
87
bool has_slope_on_right;
88
bool has_slope_on_right_bottom;
89
90
static Map img_data[5];
91
enum PixelType {
92
BLOCK, RIGHT_BOTTOM, LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP
93
};
94
95
Pixel(const Map &, int r, int c);
96
bool empty() const; // true iff this is empty
97
const Map img() const; // return proper image for this
98
};
99
100
class CubeFont
101
{
102
friend istream &operator>>(istream &, CubeFont &);
103
friend ostream &operator<<(ostream &, const CubeFont &);
104
105
protected:
106
void build(); // build outbuffer by calling build_pixel()
107
void build_pixel(const Map &, int r, int c);
108
// print pixel, resize outbuffer if necessary
109
110
Map inbuffer;
111
Map outbuffer;
112
};
113
114
istream &operator>>(istream &is, CubeFont &rhs)
115
{
116
rhs.inbuffer.clear();
117
string line;
118
while (getline(is, line))
119
rhs.inbuffer.push_back(line);
120
rhs.build();
121
return is;
122
}
123
124
ostream &operator<<(ostream &os, const CubeFont &rhs)
125
{
126
for (const auto &line: rhs.outbuffer)
127
os << line << '\n';
128
return os;
129
}
130
131
void CubeFont::build()
132
{
133
outbuffer.clear();
134
135
// build from bottom/base, so this is in reversed order
136
const int height = inbuffer.size();
137
for (int r = height - 1; r >= 0; --r)
138
{
139
const int width = inbuffer[r].size();
140
for (int c = 0; c < width; ++c)
141
{
142
Pixel p(inbuffer, r, c);
143
if (p.empty()) continue;
144
// use coordinate transformation
145
build_pixel(p.img(), c+r, c-r+height-2);
146
}
147
}
148
}
149
150
void CubeFont::build_pixel(const Map &img, int row, int col)
151
{
152
int sz = outbuffer.size();
153
int newsz = row + img.size();
154
if (newsz > sz)
155
outbuffer.resize(newsz);
156
for (int i = 0; i < img.size(); ++i)
157
{
158
sz = outbuffer[row+i].size();
159
newsz = col + img[i].size();
160
if (newsz > sz)
161
outbuffer[row+i].resize(newsz, ' ');
162
for (int j = 0; j < img[i].size(); ++j)
163
outbuffer[row+i][col+j] = img[i][j];
164
}
165
}
166
167
/* Visualize:
168
*
169
* BLOCK RIGHT_BOTTOM LEFT_TOP LEFT_BOTTOM RIGHT_TOP
170
*
171
* :\ \ :: _______ |: :| |
172
* :/ / ~~~~~~~ ::\ \ |: :| |
173
*
174
*/
175
Map Pixel::img_data[5] = {
176
{
177
":\\",
178
":/"
179
},
180
{
181
"::",
182
"~~"
183
},
184
{
185
"__",
186
"::\\"
187
},
188
{
189
"|:",
190
"|:"
191
},
192
{
193
":|",
194
":|"
195
}
196
};
197
198
Pixel::Pixel(const Map &map, int r, int c)
199
{
200
type = map[r][c];
201
thickness = 4;
202
hastop = r != 0 && c < int(map[r-1].size())
203
&& !isspace(map[r-1][c]);
204
hasbottom = r != int(map.size())-1 && c < int(map[r+1].size())
205
&& !isspace(map[r+1][c]);
206
hasleft = c != 0 && !isspace(map[r][c-1]);
207
hasright = c != int(map[r].size())-1 && !isspace(map[r][c+1]);
208
hasrightbottom = r != int(map.size())-1 && c < int(map[r+1].size())-1
209
&& !isspace(map[r+1][c+1]);
210
has_slope_on_right = c != int(map[r].size())-1 && map[r][c+1] == '\\';
211
has_slope_on_right_bottom =
212
r != int(map.size())-1 && c < int(map[r+1].size())-1
213
&& map[r+1][c+1] == '\\';
214
}
215
216
bool Pixel::empty() const
217
{
218
return type != '0' && type != '/' && type != '\\';
219
}
220
221
const Map Pixel::img() const
222
{
223
int choice = 0;
224
switch (type)
225
{
226
case '0': choice = BLOCK; break;
227
case '/': choice = RIGHT_BOTTOM + !(hastop && hasleft); break;
228
case '\\': choice = LEFT_BOTTOM + !(hastop && hasright); break;
229
default: cout << "\nerror: img() called by void Pixel\n";break;
230
}
231
Map &img = img_data[choice];
232
233
char fill[2] = {' ', ' '};
234
if (choice == BLOCK || choice == RIGHT_TOP)
235
{
236
if (!hasleft)
237
img[0][0] = '/'; // left edge
238
else
239
img[0][0] = ':';
240
241
if (!hasleft && !hastop)
242
fill[0] = '~'; // upper line
243
else if (
244
choice == BLOCK
245
&&
246
((!hasright && !hastop) || has_slope_on_right)
247
)
248
{
249
fill[0] = '_'; // mid line
250
}
251
}
252
else if (choice == LEFT_TOP)
253
{
254
fill[0] = '_';
255
}
256
else if (choice == RIGHT_BOTTOM)
257
{
258
fill[0] = '~';
259
}
260
261
if (choice == BLOCK || choice == LEFT_TOP || choice == RIGHT_TOP)
262
{
263
if (!hasbottom)
264
img[1][0] = '\\'; // bottom edge
265
else
266
img[1][0]=':';
267
268
if (
269
(
270
hasrightbottom
271
&&
272
(choice != RIGHT_TOP || !has_slope_on_right_bottom)
273
)
274
||
275
(choice == BLOCK && !hasbottom)
276
||
277
(choice == RIGHT_TOP && !has_slope_on_right_bottom)
278
)
279
{
280
fill[1] = '_'; // lower line
281
}
282
283
}
284
if (choice != LEFT_BOTTOM)
285
return Map{
286
img[0] + string(thickness, fill[0])
287
+ (choice == RIGHT_BOTTOM ? ' ': img[0][1]),
288
img[1] + string(thickness, fill[1]) + img[1][1]
289
};
290
return img;
291
}
292
293
int main(int argc, char **argv)
294
{
295
cout << "Input a 2D map, using '/', '\\', '0' and ' ':" << endl;
296
CubeFont cubefont;
297
cin >> cubefont;
298
cout << cubefont;
299
return 0;
300
}
301
302