aboutsummaryrefslogtreecommitdiff
path: root/main.cpp
diff options
context:
space:
mode:
authorroy <[email protected]>2026-07-05 01:11:04 +0300
committerroy <[email protected]>2026-07-05 01:11:04 +0300
commita581945aa7c77251420489f4b22222ec15abcd7a (patch)
tree428e20c9503ca49ca34dea975cd9b8b293963b0b /main.cpp
parentc690c3417dcb6966dc9ab56d41e37427ec1a4e7a (diff)
Basic movement finished.
Diffstat (limited to 'main.cpp')
-rw-r--r--main.cpp347
1 files changed, 235 insertions, 112 deletions
diff --git a/main.cpp b/main.cpp
index ba00d88..7f6a1f3 100644
--- a/main.cpp
+++ b/main.cpp
@@ -1,152 +1,275 @@
#include "terminal-game-utils.hpp"
-#include <format>
+#include <chrono>
+#include <cstdint>
#include <future>
#include <iostream>
+#include <ostream>
#include <poll.h>
#include <queue>
#include <string>
#include <termios.h>
+#include <thread>
+#include <tuple>
#include <unistd.h>
struct termios orig_termios;
class Snake {
-private:
- struct mSnakeUnit {
- int x;
- int y;
- std::string direction;
- std::string appearance;
- };
+ private:
+ struct mSnakeUnit {
+ int x;
+ int y;
+ std::string appearance;
+ };
- const std::string HEAD_ARROWS = "⇐⇓⇑⇒";
- const std::string SNAKE_BODY = "═║╔╗╚╝";
+ const std::map<char, std::string> HEAD_ARROWS = {
+ {'l', "◁"}, {'d', "▽"}, {'u', "△"}, {'r', "▷"}};
- bool mSnakeAteApple = false;
- char mSnakeDirection = 'r';
- bool running = true;
- int mWidth, mHeight, mStartingSpeed;
- double mAcceleration;
- std::queue<mSnakeUnit> mSnake;
- std::queue<TGU::GameKey> mKeyQueue;
+ const std::string SNAKE_BODY = "═║╔╗╚╝";
+ bool mSnakeAteApple = false;
+ char mSnakeDirection = 'r';
+ bool mRunning = true;
+ int mDelay = 500;
+ int mWidth, mHeight, mStartingSpeed;
+ double mAcceleration;
+ mSnakeUnit mLastDequeued;
+ std::deque<mSnakeUnit> mSnake;
+ std::queue<tgu::GameKey> mKeyQueue;
- std::string mRepeat(int times, std::string str) {
- std::string returned;
- for (int i = 0; i < times; i++)
- returned += str;
- return returned;
- }
+ std::string mRepeat(int times, std::string str) {
+ std::string returned;
+ for (int i = 0; i < times; i++)
+ returned += str;
+ return returned;
+ }
- std::string mGetTurningCharacter(std::string ldur) {
- if (ldur.length() != 2)
- return "";
+ std::uint8_t mGetDirectionByte(mSnakeUnit pos, mSnakeUnit goal) {
+ if (pos.x > goal.x)
+ return 0b0001;
+ if (pos.x < goal.x)
+ return 0b1000;
+ if (pos.y > goal.y)
+ return 0b0100;
+ if (pos.y < goal.y)
+ return 0b0010;
+ return 0b0000;
+ }
- if (ldur == "lr")
- return "═";
- if (ldur == "du")
- return "║";
- if (ldur == "dr")
- return "╔";
- if (ldur == "ld")
- return "╗";
- if (ldur == "ur")
- return "╚";
- if (ldur == "lu")
- return "╝";
+ std::string mGetTurningCharacter(mSnakeUnit Before, mSnakeUnit Current,
+ mSnakeUnit After) {
- return "";
- }
+ std::uint8_t BeforeDirection = mGetDirectionByte(Current, Before);
+ std::uint8_t AfterDirection = mGetDirectionByte(Current, After);
- void mPrintBoardOutlines() {
- TGU::MoveCursor(0, 0);
+ std::uint8_t CharacterBytes = BeforeDirection + AfterDirection;
- std::string horizontalLine = mRepeat(mWidth * 2 - 1, "═");
- std::string horizontalSpaces = std::string(mWidth * 2 - 1, ' ');
+ if (CharacterBytes == 0b1001)
+ return "═";
+ if (CharacterBytes == 0b0110)
+ return "║";
+ if (CharacterBytes == 0b1010)
+ return "╔";
+ if (CharacterBytes == 0b0011)
+ return "╗";
+ if (CharacterBytes == 0b1100)
+ return "╚";
+ if (CharacterBytes == 0b0101)
+ return "╝";
- std::cout << "╔" << horizontalLine + "╗" << std::endl;
+ return "";
+ }
- for (int i = 0; i < mHeight; i++) {
- std::cout << "║" + horizontalSpaces << "║" << std::endl;
- }
+ void mPrintBoardOutlines() {
+ tgu::MoveCursor(0, 0);
- std::cout << "╚" << horizontalLine + "╝" << std::endl;
- }
+ std::string horizontalLine = mRepeat(mWidth * 2 - 1, "═");
+ std::string horizontalSpaces = std::string(mWidth * 2 - 1, ' ');
- void mSetSnakeDirection() {
- TGU::GameKey popped = mKeyQueue.front();
- if (popped == TGU::GameKey::W || popped == TGU::GameKey::UPARROW)
- mSnakeDirection = 'u';
- if (popped == TGU::GameKey::A || popped == TGU::GameKey::LEFTARROW)
- mSnakeDirection = 'l';
- if (popped == TGU::GameKey::S || popped == TGU::GameKey::DOWNARROW)
- mSnakeDirection = 'd';
- if (popped == TGU::GameKey::D || popped == TGU::GameKey::RIGHTARROW)
- mSnakeDirection = 'r';
- }
+ std::cout << "╔" << horizontalLine + "╗\n\r";
- void mSnakeStep() {
+ for (int i = 0; i < mHeight; i++) {
+ std::cout << "║" + horizontalSpaces << "║\n\r";
+ }
- if (!mSnakeAteApple)
- mSnake.pop();
- mSnake.push({1, 2, mSnakeDirection, ""})
- }
+ std::cout << "╚" << horizontalLine + "╝\n\r";
+ }
- void mGameTick() {
- if (mKeyQueue.size() != 0) {
- mSetSnakeDirection();
+ char mFlipDirection(char c) {
+ if (c == 'l')
+ return 'r';
+ if (c == 'r')
+ return 'l';
+ if (c == 'd')
+ return 'u';
+ if (c == 'u')
+ return 'd';
+ return ' ';
+ }
- mSnakeStep();
- }
- }
+ void mSetSnakeDirection() {
+ tgu::GameKey popped = mKeyQueue.front();
+ mKeyQueue.pop();
- void mInputLoop() {
- TGU::GameKey key;
- while (running) {
- key = TGU::GetKeyPress();
- }
- }
+ char PotentialSnakeDirection;
- void mGameLoop() {
- while (running) {
- mGameTick();
- }
- }
+ if (popped == tgu::GameKey::W || popped == tgu::GameKey::UPARROW)
+ PotentialSnakeDirection = 'u';
+ else if (popped == tgu::GameKey::A || popped == tgu::GameKey::LEFTARROW)
+ PotentialSnakeDirection = 'l';
+ else if (popped == tgu::GameKey::S || popped == tgu::GameKey::DOWNARROW)
+ PotentialSnakeDirection = 'd';
+ else if (popped == tgu::GameKey::D ||
+ popped == tgu::GameKey::RIGHTARROW) {
+ PotentialSnakeDirection = 'r';
+ } else
+ return;
-public:
- struct GameSettings {
- int width = 14;
- int height = 14;
- int startingSpeed = 3;
- double acceleration = 0.3;
- };
+ if (PotentialSnakeDirection == mFlipDirection(mSnakeDirection))
+ return;
+ else
+ mSnakeDirection = PotentialSnakeDirection;
+ }
- 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;
- }
+ 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')
+ return std::tuple<int, int>(0, 1);
+ if (c == 'u')
+ return std::tuple<int, int>(0, -1);
+ if (c == 'r') {
+ return std::tuple<int, int>(1, 0);
+ }
- void StartGame() {
- mPrintBoardOutlines();
+ std::cout << "Some ting wong. Direction is " << +c;
+ return std::tuple<int, int>(0, 0);
+ }
- mSnake.push({0, 2, "lr", "═"});
- mSnake.push({1, 2, "lr", "═"});
- mSnake.push({2, 2, "lr", "═"});
- mSnake.push({3, 2, "lr", "⇒"});
+ void mSnakeStep() {
+ if (!mSnakeAteApple) {
+ mLastDequeued = mSnake.front();
+ mSnake.pop_front();
+ }
- auto InputLoopResponse =
- std::async(std::launch::async, [this] { mInputLoop(); });
+ std::tuple<int, int> Offset = mGetDirectionOffset(mSnakeDirection);
- mInputLoop();
- }
+ 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;
+
+ if (mSnake[mSnake.size() - 2].x != PotentialX ||
+ mSnake[mSnake.size() - 2].y != PotentialY) {
+
+ mSnake.push_back(
+ {PotentialX, PotentialY, HEAD_ARROWS.at(mSnakeDirection)});
+
+ mSnake[mSnake.size() - 2].appearance = mGetTurningCharacter(
+ mSnake[mSnake.size() - 3], mSnake[mSnake.size() - 2],
+ mSnake[mSnake.size() - 1]);
+ } else {
+ mRunning = false;
+ std::cout << "Stop the game. Snake somehow ate itself????";
+ }
+
+ tgu::MoveCursor(mHeight + 2, 0);
+ std::cout << "Brother. " << mSnake.back().x << ", " << mSnake.back().y;
+ }
+
+ void mGameTick() {
+ if (mKeyQueue.size() != 0) {
+ mSetSnakeDirection();
+ }
+
+ mSnakeStep();
+ }
+
+ void mInputLoop() {
+ tgu::GameKey key;
+ while (mRunning) {
+ key = tgu::GetKeyPress();
+ if (mKeyQueue.size() <= 2)
+ mKeyQueue.push(key);
+ }
+ }
+
+ bool mHorizontalConnectors(mSnakeUnit, mSnakeUnit) { return false; }
+
+ void mDrawSnake() {
+ for (int i = 0; i < mSnake.size(); i++) {
+ mSnakeUnit &s = mSnake[i];
+
+ if (s.appearance == "═") {
+ tgu::MoveCursor(s.y + 2, (s.x * 2) + 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);
+ std::cout << s.appearance;
+ }
+ }
+
+ tgu::MoveCursor(mHeight + 2, 0);
+ std::cout << "Brother. " << mSnake.back().x << ", " << mSnake.back().y;
+
+ tgu::MoveCursor(mLastDequeued.y + 2, (mLastDequeued.x * 2) + 1);
+ std::cout << " ";
+
+ std::cout << std::flush;
+ }
+
+ void mGameLoop() {
+ while (mRunning) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(mDelay));
+ mGameTick();
+
+ mDrawSnake();
+ }
+ }
+
+ public:
+ struct GameSettings {
+ int width = 14;
+ int height = 14;
+ int startingSpeed = 3;
+ double acceleration = 0.3;
+ };
+
+ 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;
+ }
+
+ void StartGame() {
+ tgu::EnableRawMode();
+ tgu::MakeCursorInvisible();
+ tgu::EnterGameBuffer();
+ mPrintBoardOutlines();
+
+ mSnake.push_back({0, 2, "═"});
+ mSnake.push_back({1, 2, "═"});
+ mSnake.push_back({2, 2, "═"});
+ mSnake.push_back({3, 2, "⇒"});
+ mSnakeDirection = 'r';
+
+ auto InputLoopResponse =
+ std::async(std::launch::async, [this] { mInputLoop(); });
+
+ mGameLoop();
+ tgu::LeaveGameBuffer();
+ }
};
int main() {
- TGU::EnableRawMode();
- Snake hi({});
- hi.StartGame();
+ Snake hi({});
+ hi.StartGame();
}