commit cb7cb424470500c11065ed51fb91e5c1f0c044f8 Author: Alexey Karpov Date: Sun Apr 25 23:00:33 2021 +0400 initial commit diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..810dec2 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +all: + g++ -Wall -o "nmpython" "main.cpp" -lncurses -ltinfo diff --git a/NMPython.pro b/NMPython.pro new file mode 100644 index 0000000..531d45e --- /dev/null +++ b/NMPython.pro @@ -0,0 +1,11 @@ +TEMPLATE = app +CONFIG += console c++11 +CONFIG -= app_bundle +CONFIG -= qt + +SOURCES += \ + main.cpp + +unix|win32: LIBS += -lncurses + +HEADERS += diff --git a/NMPython.pro.user b/NMPython.pro.user new file mode 100644 index 0000000..7c68d29 --- /dev/null +++ b/NMPython.pro.user @@ -0,0 +1,326 @@ + + + + + + EnvironmentId + {8524ac12-a20b-4167-bd46-a88712fc9362} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + true + false + 0 + true + true + 0 + 8 + true + 1 + true + true + true + false + + + + ProjectExplorer.Project.PluginSettings + + + true + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop + {5ba39876-9586-4f52-9b01-31c0a670ad7a} + 0 + 0 + 0 + + /home/nowhereman/projects/CPP/build-NMPython-Desktop-Debug + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + false + false + + + true + Сборка + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + true + Сборка + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Отладка + Отладка + Qt4ProjectManager.Qt4BuildConfiguration + 2 + true + + + /home/nowhereman/projects/CPP/build-NMPython-Desktop-Release + + + true + qmake + + QtProjectManager.QMakeBuildStep + false + + false + false + true + + + true + Сборка + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + true + Сборка + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Выпуск + Выпуск + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + + /home/nowhereman/projects/CPP/build-NMPython-Desktop-Profile + + + true + qmake + + QtProjectManager.QMakeBuildStep + true + + false + true + true + + + true + Сборка + + Qt4ProjectManager.MakeStep + + false + + + false + + 2 + Сборка + + ProjectExplorer.BuildSteps.Build + + + + true + Сборка + + Qt4ProjectManager.MakeStep + + true + clean + + false + + 1 + Очистка + + ProjectExplorer.BuildSteps.Clean + + 2 + false + + Профилирование + Профилирование + Qt4ProjectManager.Qt4BuildConfiguration + 0 + true + + 3 + + + 0 + Установка + + ProjectExplorer.BuildSteps.Deploy + + 1 + Конфигурация установки + + ProjectExplorer.DefaultDeployConfiguration + + 1 + + + false + false + 1000 + + true + + false + false + false + false + true + 0.01 + 10 + true + 1 + 25 + + 1 + true + false + true + valgrind + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + + 2 + + NMPython + + Qt4ProjectManager.Qt4RunConfiguration:/home/nowhereman/projects/CPP/NMPython/NMPython.pro + NMPython.pro + + 3768 + false + true + true + false + false + true + + /home/nowhereman/projects/CPP/build-NMPython-Desktop-Debug + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 20 + + + Version + 20 + + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..0063b1b --- /dev/null +++ b/main.cpp @@ -0,0 +1,316 @@ +#include +#include + +// Пока оно true - будем крутиться в игре, +// если станет false - выходим. +static bool run = false; + +// Если true - значит проиграли и надо нарисовать плашку Game Over +static bool gameOver; + +// Если true - у нас пауза, ничего не происходит, ждем нажатия кнопок +static bool pause; + +//Ширина и высота терминального окна +static int termWidth; +static int termHeight; + +// Координаты головы +static int playerX; +static int playerY; + +// Координаты еды +static int fruitX; +static int fruitY; + +// Смещения по осям - куда бежать +// 1 или -1 - бежим вдоль оси. 0 - не бежим +static int dx; +static int dy; + +// Очки +static int score; + +// Начало и конец питона в массиве +static int pythonStart; +static int pythonEnd; + +// Максимальный размер массива, чтобы можно было теоретически покрыть весь экран +static int maxPythonSize; + +// Предварительное описание, реализация позже будет. +void DropFruit(); + +// Структурка для хранения координат в массиве. +struct coord +{ + int x; + int y; +}; + +// Массив для координат тела - определение +static coord * python; + +// Тут мы инициализируем все что надо +void InitGame() +{ + // Инициализируем ncurses и выставляем ей разное + initscr(); + raw(); + cbreak(); + noecho(); + keypad(stdscr, true); + + // Таймаут ввода, он же скорость игры + timeout(200); + + // Получаем размер терминального окна + getmaxyx(stdscr, termHeight, termWidth); + + // Убираем курсор + curs_set(0); + + //Рисуем рамку + box(stdscr, 0, 0); + + //Инициализируем разные переменные + run = true; + gameOver = false; + pause = false; + + // Голову в центр экрана + playerX = termWidth / 2; + playerY = termHeight / 2; + + // Едем вправо + dx = 1; + dy = 0; + + // Очков пока ноль + score = 0; + + // Высчитываем максимальный размер питона, исходя из размера экрана + // (ну вдруг кто-то умудрится) + maxPythonSize = (termWidth - 2) * (termHeight - 2); + + // Инициализируем массив под координаты частей тела + python = new coord[maxPythonSize](); + + // Задаем начальные координаты + python[0].x = playerX; + python[0].y = playerY; + + // и указатели на хвост и голову + pythonStart = 0; + pythonEnd = 0; + + // Бросаем первую еду + DropFruit(); +} + + +// Тут завершается ncurses +void EndGame() +{ + endwin(); +} + +// Процедура, ловящая ввод и обрабатывающая его +void Input() +{ + // Получаем нажатую клавишу + int c = getch(); + + // в зависимости от нажатой клавиши правим смещения + switch (c) { + + // Если нажали q - ставим run в false, потому как надо выходить + case 'q': + run = false; + break; + case ' ': + pause = !pause; + break; + case KEY_UP: + // На каждый чих надо проверить, не пытается ли игрок поехать в противоположную сторону. + // Если так - нафиг. Ничего не делаем. + if (dy == 1) + break; + dx = 0; + dy = -1; + break; + case KEY_DOWN: + if (dy == -1) + break; + dx = 0; + dy = 1; + break; + case KEY_LEFT: + if (dx == 1) + break; + dx = -1; + dy = 0; + break; + case KEY_RIGHT: + if (dx == -1) + break; + dx = 1; + dy = 0; + } +} + +// Микроскопическая процедурка, печатающая очки в углу +void PrintScore() +{ + mvprintw(0, termWidth - 20, "Score: %5d", score); +} + + +// Тут мы двигаем голову и проверяем все что можно +void Logic() +{ + // Двигаем по X, просто прибавляя к координатам смещение + playerX += dx; + + // Проверяем на выход за рамку + if (playerX > termWidth - 2 || playerX < 1) + { + // Если вылезли - ставим флаг GameOver и run в false, чтобы выйти + gameOver = true; + run = false; + return; + } + + playerY += dy; + if (playerY > termHeight - 2 || playerY < 1) + { + gameOver = true; + run = false; + return; + } + + // Тут мы проходим по куску массива с телом между началом и концом + // чтобы выяснить, не куснули ли сами себя. + int i = pythonStart; + while (i <= pythonEnd) + { + // Если координаты головы совпадают с координатами из массива - Game over + if (playerX == python[i].x && playerY == python[i].y) + { + gameOver = true; + run = false; + return; + } + i++; + } + + // Проверяем, не куснули ли мы еду + if (playerX == fruitX && playerY == fruitY) + { + // Если куснули - выкидываем новую + DropFruit(); + + // Добавляем очков + score++; + + // Сдвигаем хвост + pythonEnd++; + + // Если хвост дошел до конца массива - переставляем его на начало + if (pythonEnd == maxPythonSize) + pythonEnd = 0; + + // Выводим новые очки в угол + PrintScore(); + } + + // Двигаем питона + + // Стираем хвост + mvprintw(python[pythonEnd].y, python[pythonEnd].x, " "); + + // Двигаем указатель головы назад по массиву + pythonStart--; + + // Не забывая его переставить, если он дошел до нуля + if (pythonStart < 0) + pythonStart = maxPythonSize - 1; + + // Тоже и с указателем хвоста + pythonEnd--; + if (pythonEnd < 0) + pythonEnd = maxPythonSize - 1; + + // Записываем новое положение головы по указателю + python[pythonStart].x = playerX; + python[pythonStart].y = playerY; + + // Рисуем по новым координатам голову + mvprintw(playerY, playerX, "@"); +} + +// Жуткая процедура рисования окошка с Game Over +void DrawGameOver() +{ + int winWidth = termWidth / 2 + 10; + int winHeight = 7; + int winX = (termWidth - winWidth) / 2; + int winY = (termHeight - winHeight) / 2; + WINDOW * gameOverWin = newwin(winHeight, winWidth, winY, winX); + box(gameOverWin, 0, 0); + std::string str1 = "GAME OVER!"; + std::string str2 = "Score: " + std::to_string(score); + mvwprintw(gameOverWin, 2, (winWidth - (int)str1.length()) / 2, str1.c_str()); + mvwprintw(gameOverWin, 4, (winWidth - (int)str2.length()) / 2, str2.c_str()); + wrefresh(gameOverWin); + notimeout(gameOverWin, TRUE); + wgetch(gameOverWin); +} + +// Здесь мы крутимся, пока игра идет +void GameLoop() +{ + while (run) + { + // Обрабатываем ввод + Input(); + + if (!pause) + { + // Обрабатываем логику + Logic(); + } + } + + // Сюда мы выйдем, если игра так или иначе кончится + // Если Game over - рисуем плашку с очками + if (gameOver) + DrawGameOver(); +} + +// Выбрасываем новую еду +void DropFruit() +{ + // Новые координаты в переменные + fruitX = (rand() % (termWidth - 2)) + 1; + fruitY = (rand() % (termHeight - 2)) + 1; + + + + // и нарисовать + mvprintw(fruitY, fruitX, "#"); +} + +// Главная функция - просто вызывает все предыдущие последовательно +int main(int argc, const char * argv[]) { + InitGame(); + + getch(); + + PrintScore(); + + GameLoop(); + + EndGame(); + return 0; +} diff --git a/nmpython b/nmpython new file mode 100755 index 0000000..126e707 Binary files /dev/null and b/nmpython differ