aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xmainbin270200 -> 505752 bytes
-rw-r--r--main.cpp298
-rw-r--r--terminal-game-utils.hpp253
3 files changed, 361 insertions, 190 deletions
diff --git a/main b/main
index f64248b..0b31826 100755
--- a/main
+++ b/main
Binary files differ
diff --git a/main.cpp b/main.cpp
index 7f6a1f3..537750c 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,4 +1,5 @@
#include "terminal-game-utils.hpp"
+#include <algorithm>
#include <chrono>
#include <cstdint>
#include <future>
@@ -22,20 +23,39 @@ class Snake {
std::string appearance;
};
+ struct mCell {
+ int x;
+ int y;
+
+ bool operator==(const mCell &other) const {
+ return (x == other.x) && (y == other.y);
+ }
+ };
+
const std::map<char, std::string> HEAD_ARROWS = {
{'l', "◁"}, {'d', "▽"}, {'u', "△"}, {'r', "▷"}};
- const std::string SNAKE_BODY = "═║╔╗╚╝";
- bool mSnakeAteApple = false;
- char mSnakeDirection = 'r';
- bool mRunning = true;
- int mDelay = 500;
- int mWidth, mHeight, mStartingSpeed;
- double mAcceleration;
+ const int GRACE_FRAMES = 3;
+ const int BOARD_OFFSET_X = 2;
+ const int BOARD_OFFSET_Y = 1;
+ const int WIDTH, HEIGHT, STARTING_DELAY, MAX_SPEED;
+ const double ACCELERATION = 0;
+
mSnakeUnit mLastDequeued;
+ mSnakeUnit mApple;
+
std::deque<mSnakeUnit> mSnake;
std::queue<tgu::GameKey> mKeyQueue;
+ std::vector<mCell> mUnoccupied;
+ std::vector<mCell> mOccupied;
+
+ int mGraceFrames = GRACE_FRAMES;
+ char mSnakeDirection = 'r';
+ int mApplesAte = 0;
+
+ bool mRunning = true;
+
std::string mRepeat(int times, std::string str) {
std::string returned;
for (int i = 0; i < times; i++)
@@ -55,9 +75,48 @@ class Snake {
return 0b0000;
}
+ mSnakeUnit mPopSnake() {
+ mSnakeUnit tr = mSnake.front();
+ mCell val(tr.x, tr.y);
+
+ mUnoccupy(val);
+ mSnake.pop_front();
+ return tr;
+ }
+
+ void mPushSnake(mSnakeUnit input) {
+ mCell val(input.x, input.y);
+
+ mOccupy(val);
+ mSnake.push_back(input);
+ }
+
+ void mOccupy(int x, int y) {
+ mCell val(x, y);
+
+ std::erase(mUnoccupied, val);
+ mOccupied.push_back(val);
+ }
+
+ void mOccupy(mCell val) {
+ std::erase(mUnoccupied, val);
+ mOccupied.push_back(val);
+ }
+
+ void mUnoccupy(int x, int y) {
+ mCell val(x, y);
+
+ std::erase(mOccupied, val);
+ mUnoccupied.push_back(val);
+ }
+
+ void mUnoccupy(mCell val) {
+ std::erase(mOccupied, val);
+ mUnoccupied.push_back(val);
+ }
+
std::string mGetTurningCharacter(mSnakeUnit Before, mSnakeUnit Current,
mSnakeUnit After) {
-
std::uint8_t BeforeDirection = mGetDirectionByte(Current, Before);
std::uint8_t AfterDirection = mGetDirectionByte(Current, After);
@@ -79,31 +138,35 @@ class Snake {
return "";
}
- void mPrintBoardOutlines() {
+ void mDrawBoardOutlines() {
+ tgu::MoveCursor(0, 0);
+ tgu::ClearTerminal();
+ tgu::ClearTerminal();
tgu::MoveCursor(0, 0);
- std::string horizontalLine = mRepeat(mWidth * 2 - 1, "═");
- std::string horizontalSpaces = std::string(mWidth * 2 - 1, ' ');
+ std::string horizontalLine = mRepeat(WIDTH * 2 + 1, "═");
+ std::string horizontalSpaces = std::string(WIDTH * 2 - 1, ' ');
std::cout << "╔" << horizontalLine + "╗\n\r";
- for (int i = 0; i < mHeight; i++) {
- std::cout << "║" + horizontalSpaces << "║\n\r";
+ for (int i = 0; i < HEIGHT; i++) {
+ std::cout << "║ " + horizontalSpaces << " ║\n\r";
}
- std::cout << "╚" << horizontalLine + "╝\n\r";
+ std::cout << "╚" << horizontalLine + "╝";
}
char mFlipDirection(char c) {
if (c == 'l')
return 'r';
- if (c == 'r')
- return 'l';
- if (c == 'd')
+ else if (c == 'd')
return 'u';
- if (c == 'u')
+ else if (c == 'u')
return 'd';
- return ' ';
+ else if (c == 'r')
+ return 'l';
+ else
+ return ' ';
}
void mSetSnakeDirection() {
@@ -121,6 +184,10 @@ class Snake {
else if (popped == tgu::GameKey::D ||
popped == tgu::GameKey::RIGHTARROW) {
PotentialSnakeDirection = 'r';
+ } else if (popped == tgu::GameKey::Q) {
+ tgu::ClearTerminal();
+ tgu::MoveCursor(0, 0);
+ exit(0);
} else
return;
@@ -132,7 +199,6 @@ class Snake {
std::tuple<int, int> mGetDirectionOffset(char c) {
tgu::MoveCursor(30, 30);
- std::cout << c;
if (c == 'l')
return std::tuple<int, int>(-1, 0);
if (c == 'd')
@@ -143,40 +209,78 @@ class Snake {
return std::tuple<int, int>(1, 0);
}
- std::cout << "Some ting wong. Direction is " << +c;
+ std::cout << "Some ting wong. Direction is " << c;
return std::tuple<int, int>(0, 0);
}
- void mSnakeStep() {
- if (!mSnakeAteApple) {
- mLastDequeued = mSnake.front();
- mSnake.pop_front();
+ void mDie() {
+ std::cout << "Die about it";
+ tgu::ClearTerminal();
+ tgu::MoveCursor(0, 0);
+ exit(0);
+ }
+
+ bool mProcessApple(int &PotentialX, int &PotentialY) {
+ if (mApple.x == PotentialX && mApple.y == PotentialY) {
+ mAddApple();
+ return true;
+ } else {
+ return false;
}
+ }
+
+ void mAdvanceSnake(int &PotentialX, int &PotentialY) {
+ mPushSnake({PotentialX, PotentialY, HEAD_ARROWS.at(mSnakeDirection)});
+ mSnake[mSnake.size() - 2].appearance = mGetTurningCharacter(
+ mSnake[mSnake.size() - 3], mSnake[mSnake.size() - 2],
+ mSnake[mSnake.size() - 1]);
+ }
+ bool IsInSnake(int x, int y) {
+ for (mSnakeUnit &u : mSnake) {
+ if (u.x == x && u.y == y)
+ return true;
+ }
+ return false;
+ }
+
+ bool mCheckDeathTick(int &PotentialX, int &PotentialY) {
+ if (PotentialX <= -1 || PotentialY <= -1 || PotentialX >= WIDTH ||
+ PotentialY >= HEIGHT || IsInSnake(PotentialX, PotentialY)) {
+ if (mGraceFrames <= 0) {
+ mRunning = false;
+ mDie();
+ } else {
+ mGraceFrames = 0;
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void mSnakeStep() {
std::tuple<int, int> Offset = mGetDirectionOffset(mSnakeDirection);
int PotentialX = mSnake.back().x + std::get<0>(Offset);
int PotentialY = mSnake.back().y + std::get<1>(Offset);
- std::cout << "Potentials: " << PotentialX << ", " << PotentialY;
- std::cout << "Actual: " << mSnake.back().x << ", " << mSnake.back().y;
+ bool AteApple = mProcessApple(PotentialX, PotentialY);
- if (mSnake[mSnake.size() - 2].x != PotentialX ||
- mSnake[mSnake.size() - 2].y != PotentialY) {
+ bool DeathTicked = mCheckDeathTick(PotentialX, PotentialY);
- mSnake.push_back(
- {PotentialX, PotentialY, HEAD_ARROWS.at(mSnakeDirection)});
+ if (!DeathTicked) {
+ mGraceFrames = mGraceFrames + 1 >= GRACE_FRAMES ? GRACE_FRAMES
+ : mGraceFrames + 1;
+ mAdvanceSnake(PotentialX, PotentialY);
- mSnake[mSnake.size() - 2].appearance = mGetTurningCharacter(
- mSnake[mSnake.size() - 3], mSnake[mSnake.size() - 2],
- mSnake[mSnake.size() - 1]);
+ if (!AteApple) {
+ mLastDequeued = mPopSnake();
+ }
} else {
- mRunning = false;
- std::cout << "Stop the game. Snake somehow ate itself????";
+ mSnake.back().appearance = HEAD_ARROWS.at(mSnakeDirection);
+ mLastDequeued = mSnakeUnit(-1, -1, " ");
}
-
- tgu::MoveCursor(mHeight + 2, 0);
- std::cout << "Brother. " << mSnake.back().x << ", " << mSnake.back().y;
}
void mGameTick() {
@@ -196,35 +300,81 @@ class Snake {
}
}
- bool mHorizontalConnectors(mSnakeUnit, mSnakeUnit) { return false; }
+ bool mHorizontalConnectors(mSnakeUnit a, mSnakeUnit b) {
+ std::string horizontals = "╔╗╚╝◁▷";
+ if (a.y != b.y)
+ return false;
+
+ if (horizontals.find(a.appearance) != std::string::npos &&
+ horizontals.find(b.appearance) != std::string::npos)
+ return true;
+
+ return false;
+ }
void mDrawSnake() {
+ tgu::TextRGB(0, 255, 0);
+ if (mLastDequeued.x != -1) {
+ tgu::MoveCursor(mLastDequeued.y + BOARD_OFFSET_Y,
+ (mLastDequeued.x * 2) + BOARD_OFFSET_X - 1);
+ std::cout << " ";
+ }
+
for (int i = 0; i < mSnake.size(); i++) {
mSnakeUnit &s = mSnake[i];
if (s.appearance == "═") {
- tgu::MoveCursor(s.y + 2, (s.x * 2) + 1);
+ tgu::MoveCursor(s.y + BOARD_OFFSET_Y,
+ (s.x * 2) + BOARD_OFFSET_X - 1);
std::cout << mRepeat(3, s.appearance);
- } else if (i != 0 && mHorizontalConnectors(s, mSnake[i - 1])) {
- std::cout << "";
} else {
- tgu::MoveCursor(s.y + 2, (s.x * 2) + 2);
+ tgu::MoveCursor(s.y + BOARD_OFFSET_Y,
+ (s.x * 2) + BOARD_OFFSET_X);
std::cout << s.appearance;
}
- }
- tgu::MoveCursor(mHeight + 2, 0);
- std::cout << "Brother. " << mSnake.back().x << ", " << mSnake.back().y;
+ if (i != 0 && mHorizontalConnectors(s, mSnake[i - 1])) {
+ int x = std::max(s.x, mSnake[i - 1].x) * 2 + BOARD_OFFSET_X - 1;
+ tgu::MoveCursor(s.y + BOARD_OFFSET_Y, x);
+ std::cout << "═";
+ }
+ }
- tgu::MoveCursor(mLastDequeued.y + 2, (mLastDequeued.x * 2) + 1);
- std::cout << " ";
+ tgu::TextRed();
+ tgu::MoveCursor(mApple.y + BOARD_OFFSET_Y,
+ mApple.x * 2 + BOARD_OFFSET_X);
+ std::cout << mApple.appearance;
+ tgu::TerminalColorReset();
std::cout << std::flush;
}
+ void mInitializeApple() {
+ int iPos = rand() % mUnoccupied.size();
+ mCell apple(mUnoccupied[iPos].x, mUnoccupied[iPos].y);
+
+ mOccupy(apple.x, apple.y);
+
+ mApple = {apple.x, apple.y, "■"};
+ }
+
+ void mAddApple() {
+ mApplesAte++;
+ int iPos = rand() % mUnoccupied.size();
+ mCell apple(mUnoccupied[iPos].x, mUnoccupied[iPos].y);
+
+ mUnoccupy(mApple.x, mApple.y);
+ mOccupy(apple.x, apple.y);
+
+ mApple = {mUnoccupied[iPos].x, mUnoccupied[iPos].y, mApple.appearance};
+ }
+
void mGameLoop() {
while (mRunning) {
- std::this_thread::sleep_for(std::chrono::milliseconds(mDelay));
+ int CalculatedDelay = STARTING_DELAY - (mApplesAte * ACCELERATION);
+ int TickDelay =
+ CalculatedDelay >= MAX_SPEED ? CalculatedDelay : MAX_SPEED;
+ std::this_thread::sleep_for(std::chrono::milliseconds(TickDelay));
mGameTick();
mDrawSnake();
@@ -235,41 +385,57 @@ class Snake {
struct GameSettings {
int width = 14;
int height = 14;
- int startingSpeed = 3;
- double acceleration = 0.3;
+ int startingdelay = 400;
+ int maxspeed = 200;
+ int acceleration = 10;
};
Snake(const GameSettings &settings)
- : mWidth(settings.width), mHeight(settings.height),
- mStartingSpeed(settings.startingSpeed),
- mAcceleration(settings.acceleration) {
- if (mWidth < 5)
- mWidth = 5;
- if (mHeight < 5)
- mHeight = 5;
+ : WIDTH(settings.width), HEIGHT(settings.height),
+ STARTING_DELAY(settings.startingdelay),
+ ACCELERATION(settings.acceleration), MAX_SPEED(settings.maxspeed) {
+ if (WIDTH < 5 || HEIGHT < 5) {
+ std::cout << "Minimum board size of 5x5 not met.";
+ return;
+ }
+ }
+
+ void mFillUnoccupied() {
+ for (int i = 0; i < WIDTH; i++) {
+ for (int j = 0; j < HEIGHT; j++) {
+ mUnoccupied.push_back({i, j});
+ }
+ }
}
void StartGame() {
tgu::EnableRawMode();
tgu::MakeCursorInvisible();
tgu::EnterGameBuffer();
- mPrintBoardOutlines();
+ tgu::ClearTerminal();
+ std::cout << std::flush;
+
+ mDrawBoardOutlines();
- mSnake.push_back({0, 2, "═"});
- mSnake.push_back({1, 2, "═"});
- mSnake.push_back({2, 2, "═"});
- mSnake.push_back({3, 2, "⇒"});
+ mFillUnoccupied();
+ mPushSnake({1, 2, "═"});
+ mPushSnake({2, 2, "═"});
+ mPushSnake({3, 2, "═"});
+ mPushSnake({4, 2, "⇒"});
mSnakeDirection = 'r';
+ mInitializeApple();
+
+ mDrawSnake();
+
auto InputLoopResponse =
std::async(std::launch::async, [this] { mInputLoop(); });
mGameLoop();
- tgu::LeaveGameBuffer();
}
};
int main() {
- Snake hi({});
+ Snake hi({.startingdelay = 100});
hi.StartGame();
}
diff --git a/terminal-game-utils.hpp b/terminal-game-utils.hpp
index d7d9522..aa540bb 100644
--- a/terminal-game-utils.hpp
+++ b/terminal-game-utils.hpp
@@ -14,142 +14,142 @@ inline struct termios orig_termios;
inline std::string newline = "\n\r";
enum class GameKey {
- INVALID,
- LEFTARROW,
- DOWNARROW,
- UPARROW,
- RIGHTARROW,
- ESCAPE,
- A,
- B,
- C,
- D,
- E,
- F,
- G,
- H,
- I,
- J,
- K,
- L,
- M,
- N,
- O,
- P,
- Q,
- R,
- S,
- T,
- U,
- V,
- W,
- X,
- Y,
- Z,
- SPACE,
+ INVALID,
+ LEFTARROW,
+ DOWNARROW,
+ UPARROW,
+ RIGHTARROW,
+ ESCAPE,
+ A,
+ B,
+ C,
+ D,
+ E,
+ F,
+ G,
+ H,
+ I,
+ J,
+ K,
+ L,
+ M,
+ N,
+ O,
+ P,
+ Q,
+ R,
+ S,
+ T,
+ U,
+ V,
+ W,
+ X,
+ Y,
+ Z,
+ SPACE,
};
inline std::map<std::string, GameKey> KeyMap = {{"a", GameKey::A},
- {"b", GameKey::B},
- {"c", GameKey::C},
- {"d", GameKey::D},
- {"e", GameKey::E},
- {"f", GameKey::F},
- {"g", GameKey::G},
- {"h", GameKey::H},
- {"i", GameKey::I},
- {"j", GameKey::J},
- {"k", GameKey::K},
- {"l", GameKey::L},
- {"m", GameKey::M},
- {"n", GameKey::N},
- {"o", GameKey::O},
- {"p", GameKey::P},
- {"q", GameKey::Q},
- {"r", GameKey::R},
- {"s", GameKey::S},
- {"t", GameKey::T},
- {"u", GameKey::U},
- {"v", GameKey::V},
- {"w", GameKey::W},
- {"x", GameKey::X},
- {"y", GameKey::Y},
- {"z", GameKey::Z},
- {"A", GameKey::A},
- {"B", GameKey::B},
- {"C", GameKey::C},
- {"D", GameKey::D},
- {"E", GameKey::E},
- {"F", GameKey::F},
- {"G", GameKey::G},
- {"H", GameKey::H},
- {"I", GameKey::I},
- {"J", GameKey::J},
- {"K", GameKey::K},
- {"L", GameKey::L},
- {"M", GameKey::M},
- {"N", GameKey::N},
- {"O", GameKey::O},
- {"P", GameKey::P},
- {"Q", GameKey::Q},
- {"R", GameKey::R},
- {"S", GameKey::S},
- {"T", GameKey::T},
- {"U", GameKey::U},
- {"V", GameKey::V},
- {"W", GameKey::W},
- {"X", GameKey::X},
- {"Y", GameKey::Y},
- {"Z", GameKey::Z},
- {"\x1b", GameKey::ESCAPE},
- {"\x1b[D", GameKey::LEFTARROW},
- {"\x1b[B", GameKey::DOWNARROW},
- {"\x1b[A", GameKey::UPARROW},
- {"\x1b[C", GameKey::RIGHTARROW},
- {" ", GameKey::SPACE}};
+ {"b", GameKey::B},
+ {"c", GameKey::C},
+ {"d", GameKey::D},
+ {"e", GameKey::E},
+ {"f", GameKey::F},
+ {"g", GameKey::G},
+ {"h", GameKey::H},
+ {"i", GameKey::I},
+ {"j", GameKey::J},
+ {"k", GameKey::K},
+ {"l", GameKey::L},
+ {"m", GameKey::M},
+ {"n", GameKey::N},
+ {"o", GameKey::O},
+ {"p", GameKey::P},
+ {"q", GameKey::Q},
+ {"r", GameKey::R},
+ {"s", GameKey::S},
+ {"t", GameKey::T},
+ {"u", GameKey::U},
+ {"v", GameKey::V},
+ {"w", GameKey::W},
+ {"x", GameKey::X},
+ {"y", GameKey::Y},
+ {"z", GameKey::Z},
+ {"A", GameKey::A},
+ {"B", GameKey::B},
+ {"C", GameKey::C},
+ {"D", GameKey::D},
+ {"E", GameKey::E},
+ {"F", GameKey::F},
+ {"G", GameKey::G},
+ {"H", GameKey::H},
+ {"I", GameKey::I},
+ {"J", GameKey::J},
+ {"K", GameKey::K},
+ {"L", GameKey::L},
+ {"M", GameKey::M},
+ {"N", GameKey::N},
+ {"O", GameKey::O},
+ {"P", GameKey::P},
+ {"Q", GameKey::Q},
+ {"R", GameKey::R},
+ {"S", GameKey::S},
+ {"T", GameKey::T},
+ {"U", GameKey::U},
+ {"V", GameKey::V},
+ {"W", GameKey::W},
+ {"X", GameKey::X},
+ {"Y", GameKey::Y},
+ {"Z", GameKey::Z},
+ {"\x1b", GameKey::ESCAPE},
+ {"\x1b[D", GameKey::LEFTARROW},
+ {"\x1b[B", GameKey::DOWNARROW},
+ {"\x1b[A", GameKey::UPARROW},
+ {"\x1b[C", GameKey::RIGHTARROW},
+ {" ", GameKey::SPACE}};
inline void DisableRawMode() { tcsetattr(0, TCSAFLUSH, &orig_termios); }
inline void EnableRawMode() {
- tcgetattr(0, &orig_termios);
+ tcgetattr(0, &orig_termios);
- atexit(DisableRawMode);
- struct termios raw = orig_termios;
- raw.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON);
- raw.c_oflag &= ~(OPOST);
- raw.c_cflag |= (CS8);
- raw.c_lflag &= ~(ECHO | ICANON | IEXTEN);
- raw.c_cc[VMIN] = 1;
- raw.c_cc[VTIME] = 0;
+ atexit(DisableRawMode);
+ struct termios raw = orig_termios;
+ raw.c_iflag &= ~(ICRNL | INPCK | ISTRIP | IXON);
+ raw.c_oflag &= ~(OPOST);
+ raw.c_cflag |= (CS8);
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN);
+ raw.c_cc[VMIN] = 1;
+ raw.c_cc[VTIME] = 0;
- tcsetattr(0, TCSAFLUSH, &raw);
+ tcsetattr(0, TCSAFLUSH, &raw);
}
inline bool InputAvailable(int timeout_ms) {
- pollfd pfd{};
- pfd.fd = STDIN_FILENO;
- pfd.events = POLLIN;
+ pollfd pfd{};
+ pfd.fd = STDIN_FILENO;
+ pfd.events = POLLIN;
- return poll(&pfd, 1, timeout_ms) > 0;
+ return poll(&pfd, 1, timeout_ms) > 0;
}
inline GameKey GetKeyPress() {
- std::string keypress_string;
- char c;
+ std::string keypress_string;
+ char c;
- read(STDIN_FILENO, &c, 1);
- keypress_string += c;
+ read(STDIN_FILENO, &c, 1);
+ keypress_string += c;
- if (c == 27)
- while (InputAvailable(10)) {
- read(STDIN_FILENO, &c, 1);
- keypress_string += c;
- }
+ if (c == 27)
+ while (InputAvailable(10)) {
+ read(STDIN_FILENO, &c, 1);
+ keypress_string += c;
+ }
- if (KeyMap.find(keypress_string) != KeyMap.end())
- return KeyMap[keypress_string];
- return GameKey::INVALID;
+ if (KeyMap.find(keypress_string) != KeyMap.end())
+ return KeyMap[keypress_string];
+ return GameKey::INVALID;
}
// Text printers:
@@ -161,7 +161,7 @@ inline void TextRed() { std::cout << "\033[31m"; }
inline void TextBlue() { std::cout << "\033[34m"; }
inline void TextRGB(int r, int g, int b) {
- std::cout << std::format("\033[38;2;{};{};{}m", r, g, b);
+ std::cout << std::format("\033[38;2;{};{};{}m", r, g, b);
};
// Background printers:
@@ -173,26 +173,31 @@ inline void BGRed() { std::cout << "\033[41m"; }
inline void BGBlue() { std::cout << "\033[44m"; }
inline void BGRGB(int r, int g, int b) {
- std::cout << std::format("\033[48;2;{};{};{}m", r, g, b);
+ std::cout << std::format("\033[48;2;{};{};{}m", r, g, b);
}
inline void TerminalColorReset() { std::cout << "\033[0m"; }
// Game buffer printers:
-
-inline void EnterGameBuffer() { std::cout << "\033[?1049h"; }
-
+//
inline void LeaveGameBuffer() { std::cout << "\033[?1049l"; }
+inline void EnterGameBuffer() {
+ std::cout << "\033[?1049h";
+ atexit(LeaveGameBuffer);
+}
+
inline void MoveCursor(int row, int col) {
- std::cout << "\033[" << (row + 1) << ";" << (col + 1) << "H" << std::flush;
+ std::cout << "\033[" << (row + 1) << ";" << (col + 1) << "H" << std::flush;
}
inline void MakeCursorVisible() { std::cout << "\033[?25h"; }
inline void MakeCursorInvisible() {
- std::cout << "\033[?25l";
- atexit(MakeCursorVisible);
+ std::cout << "\033[?25l";
+ atexit(MakeCursorVisible);
}
+inline void ClearTerminal() { std::cout << "\033[H\033[J"; }
+
}; // namespace tgu