for (uint worm = I-------------I; worm >= II; worm -= I-I ) {
cout << '*';
}
uint monsterHP = I-----------------------I; // 12 HP
uint monBossHP = (I-----------------------I) * 10; // 120 HP
cout <<( I-------I
| !
! !
I-------I ).area();
To nie jest mój pomysł - kiedyś natrafiłem na blogu Paczesiowej ciekawy wpis gdzie znalazłem link opisujący w C++ literały analogowe - czyli zamiast podawać wartości naturalne można było narysować sobie linie, prostokąt albo sześcian w ASCII, co następnie było zamieniane na wartość liczbową.
Niestety - strona przestała działać a w cache znalazłem jedynie podgląd jak to wyglądało... więc nie miałem innego wyjścia jak spróbować zaimplementować to samemu ;)
Na razie odpuściłem sobie implementację literałów 3D - zaimplementowałem tylko linie oraz prostokąty co okazało się zaskakująco proste, przy czym nie nakładałem zbyt wysokich wymagań co do poprawności i obsługi sytuacji brzegowych :)
Cała sztuczka polega na odpowiednim przeładowaniu operatorów. Zauważ, że tak naprawdę linię można ograniczyć dwoma obiektami (I), których wartość ulega zmianie poprzez użycie operatora "--" oraz połączenie ich przez binarny operator "-".
Analogicznie jest dla 2D - to po prostu 2 linie z tym, że jedna jest modyfikowana przez "!" (zwiększa wysokość) a potem linia + linia z wysokością są scalane przez operator binarny "|".
Myślę, że rozjaśni się wszystko jak pokażę kod (testowany na VC2k5 i ideone). Kod jest brzydki i prototypowy - używać na własną odpowiedzialność a najlepiej zamknąć oczy czytając ;)
typedef unsigned int uint;
const uint II = 0;
/// Literal analogowy 1D oraz 2D
class _ALiteral
{
public:
_ALiteral() : width(1), height(0) {}
uint len() const { return width; }
uint len2() const { return height; }
float ratio() const { static_cast<float>(width) / height; }
uint area() const { return width * height; }
// niejawna konwersja do uint - czasem moze troche popsuc :(
// ale umozliwia pisanie uint t = I---I; zamiast (I---I).len()
operator uint() { return len(); }
_ALiteral operator-(_ALiteral right) const {
_ALiteral t;
t.width = width + (right.width-1);
t.height = right.height + height;
return t;
}
_ALiteral& operator--() {
width += 1;
return *this;
}
_ALiteral operator | (_ALiteral right) {
height = 1 + right.height; // bo | zastepuje jeden znak !
height >>= 1; // bo ! jest aplikowane 2 razy, mozna dodac sprawdzanie parzystosci
return *this;
}
_ALiteral& operator!() {
height += 1;
return *this;
}
private:
uint width, height;
};
// ukrycie konstrukcji obiektu _ALiteral
#define I _ALiteral()
Brak komentarzy:
Prześlij komentarz