Mini ASCII Art Studio
Napraviti mini editor za ASCII art na malom platnu. Platno je pravougaona mreža znakova (boja). Treba omogućiti osnovne operacije crtanja i transformacija.
Zadatak rešiti u više fajlova: platno.hpp, platno.cpp, main.cpp.
Boja se predstavlja jednim ASCII karakterom char, koji je moguće ispisati (npr. A, B, #, .).
Reprezentacija: Platno ima sirina, visina i piksel — matricu fiksnog kapaciteta char piksel[MAX_VISINA][MAX_SIRINA], gde je karakter na koloni x, redu y dat sa piksel[y][x]; koriste se samo pozicije u opsegu 0 <= y < visina, 0 <= x < sirina.
Operacije:
-
Platno napravi_platno(int sirina, int visina, char boja)— pravi novo platno i popunjava ga bojomboja. Preduslov:sirina <= MAX_SIRINA,visina <= MAX_VISINA. -
void postavi_piksel(Platno& p, int x, int y, char boja)— postavlja piksel(x,y)naboja; -
void nacrtaj_horizontalnu_liniju(Platno& p, int y, int x1, int x2, char boja)— horizontalna linija u reduy, odx1dox2(uključivo); -
void nacrtaj_vertikalnu_liniju(Platno& p, int x, int y1, int y2, char boja)— vertikalna linija u kolonix, ody1doy2(uključivo); -
void popuni_pravougaonik(Platno& p, int x, int y, int w, int h, char boja)— puni pravougaonik dimenzijew x h, sa gornjim levim uglom u(x,y); -
void preslikaj(Platno& p, char osa)—osa='H'za horizontalno preslikavanje (levo-desno),osa='V'za vertikalno (gore-dole); -
void rotiraj90(Platno& p)— rotira platno za$90°$ udesno (sirinaivisinase razmenjuju); i -
int broj_razlicitih_boja(const Platno& p)— vraća broj različitih (ispisivih) boja na platnu.
Ulaz
Sa standardnog ulaza se učitava broj upita
-
c <w> <h> <c>— kreira novo platno dimenzije<w>x<h>ispunjeno bojom<c>; -
s <x> <y> <c>— postavlja piksel(<x>,<y>)na<c>; -
h <y> <x1> <x2> <c>— iscrtava horizontalnu liniju boje<c>u redu<y>od<x1>do<x2>; -
v <x> <y1> <y2> <c>— iscrtava vertikalnu liniju boje<c>u koloni<x>od<y1>do<y2>; -
r <x> <y> <w> <h> <c>— iscrtava pravougaonik boje<c>sa početkom u(<x>,<y>)dimenzije<w>x<h>; -
m <axis>— preslikava, horizontalno za<axis>=Hili vertikalno za<axis>=V; -
t— rotira platno za$90°$ udesno; -
p— ispisuje platno; i -
n— ispisuje broj različitih boja na platnu.
Svi indeksi su nula-bazirani. Dimenzije i koordinate su garantovano u granicama platna i neće biti nevalidnih upita. Platno neće biti veće od
Izlaz
Na standardni izlaz ispisati platno pri obradi upita p (jedan red platna po liniji), ili broj različitih boja pri obradi upita n.
Primer
Ulaz
10
c 5 4 .
h 1 0 4 A
v 0 0 3 B
s 4 3 C
p
n
m H
p
t
p
Izlaz
B....
BAAAA
B....
B...C
4
....B
AAAAB
....B
C...B
C.A.
..A.
..A.
..A.
BBBB
Rešenje
platno.hpp
#ifndef PLATNO_HPP
#define PLATNO_HPP
namespace matf
{
const int MAX_SIRINA = 32;
const int MAX_VISINA = 32;
struct Platno {
int sirina;
int visina;
char piksel[MAX_VISINA][MAX_SIRINA]; // piksel[y][x], y u [0, visina), x u [0, sirina)
};
// preduslov: sirina <= MAX_SIRINA, visina <= MAX_VISINA
Platno napravi_platno(int sirina, int visina, char boja);
void postavi_piksel(Platno& p, int x, int y, char boja);
void nacrtaj_horizontalnu_liniju(Platno& p, int y, int x1, int x2, char boja);
void nacrtaj_vertikalnu_liniju(Platno& p, int x, int y1, int y2, char boja);
void popuni_pravougaonik(Platno& p, int x, int y, int w, int h, char boja);
// osa == 'H' za horizontalno, osa == 'V' za vertikalno preslikavanje
void preslikaj(Platno& p, char osa);
// rotira platno za 90 stepeni udesno; sirina i visina se razmenjuju
void rotiraj90(Platno& p);
int broj_razlicitih_boja(const Platno& p);
void ispisi_platno(const Platno& p);
} // namespace matf
#endif // PLATNO_HPP
platno.cpp
#include "platno.hpp"
#include <algorithm>
#include <cassert>
#include <cctype>
#include <iostream>
namespace matf
{
Platno napravi_platno(int sirina, int visina, char boja)
{
assert(sirina <= MAX_SIRINA && visina <= MAX_VISINA);
Platno p;
p.sirina = sirina;
p.visina = visina;
for (int y = 0; y < visina; ++y)
for (int x = 0; x < sirina; ++x)
p.piksel[y][x] = boja;
return p;
}
void postavi_piksel(Platno& p, int x, int y, char boja)
{
p.piksel[y][x] = boja;
}
void nacrtaj_horizontalnu_liniju(Platno& p, int y, int x1, int x2, char boja)
{
for (int x = x1; x <= x2; ++x)
p.piksel[y][x] = boja;
}
void nacrtaj_vertikalnu_liniju(Platno& p, int x, int y1, int y2, char boja)
{
for (int y = y1; y <= y2; ++y)
p.piksel[y][x] = boja;
}
void popuni_pravougaonik(Platno& p, int x, int y, int w, int h, char boja)
{
for (int yy = y; yy < y + h; ++yy)
for (int xx = x; xx < x + w; ++xx)
p.piksel[yy][xx] = boja;
}
void preslikaj(Platno& p, char osa)
{
if (osa == 'H') {
for (int y = 0; y < p.visina; ++y)
std::reverse(p.piksel[y], p.piksel[y] + p.sirina);
} else if (osa == 'V') {
for (int y = 0; y < p.visina / 2; ++y)
std::swap_ranges(p.piksel[y], p.piksel[y] + p.sirina, p.piksel[p.visina - 1 - y]);
}
}
void rotiraj90(Platno& p)
{
Platno novo;
novo.sirina = p.visina;
novo.visina = p.sirina;
for (int y = 0; y < novo.visina; ++y)
for (int x = 0; x < novo.sirina; ++x)
novo.piksel[y][x] = p.piksel[p.visina - 1 - x][y];
p = novo;
}
int broj_razlicitih_boja(const Platno& p)
{
bool vidjeno[256] = {};
for (int y = 0; y < p.visina; ++y)
for (int x = 0; x < p.sirina; ++x)
if (std::isprint(static_cast<unsigned char>(p.piksel[y][x])))
vidjeno[static_cast<unsigned char>(p.piksel[y][x])] = true;
int broj = 0;
for (bool b : vidjeno)
if (b)
++broj;
return broj;
}
void ispisi_platno(const Platno& p)
{
for (int y = 0; y < p.visina; ++y) {
for (int x = 0; x < p.sirina; ++x)
std::cout << p.piksel[y][x];
std::cout << std::endl;
}
}
} // namespace matf
main.cpp
#include "platno.hpp"
#include <iostream>
int main()
{
int q;
std::cin >> q;
matf::Platno p;
while (q--) {
char op;
std::cin >> op;
if (op == 'c') {
int w, h;
char boja;
std::cin >> w >> h >> boja;
p = matf::napravi_platno(w, h, boja);
} else if (op == 's') {
int x, y;
char boja;
std::cin >> x >> y >> boja;
matf::postavi_piksel(p, x, y, boja);
} else if (op == 'h') {
int y, x1, x2;
char boja;
std::cin >> y >> x1 >> x2 >> boja;
matf::nacrtaj_horizontalnu_liniju(p, y, x1, x2, boja);
} else if (op == 'v') {
int x, y1, y2;
char boja;
std::cin >> x >> y1 >> y2 >> boja;
matf::nacrtaj_vertikalnu_liniju(p, x, y1, y2, boja);
} else if (op == 'r') {
int x, y, w, h;
char boja;
std::cin >> x >> y >> w >> h >> boja;
matf::popuni_pravougaonik(p, x, y, w, h, boja);
} else if (op == 'm') {
char osa;
std::cin >> osa;
matf::preslikaj(p, osa);
} else if (op == 't') {
matf::rotiraj90(p);
} else if (op == 'p') {
matf::ispisi_platno(p);
} else if (op == 'n') {
std::cout << matf::broj_razlicitih_boja(p) << std::endl;
}
}
return 0;
}