Перевел на C ибо нефиг
This commit is contained in:
341
main.c
Normal file
341
main.c
Normal file
@@ -0,0 +1,341 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ncurses.h>
|
||||
|
||||
// Пока оно 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;
|
||||
};
|
||||
|
||||
struct 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 = (struct coord*)malloc(maxPythonSize * sizeof(struct coord));
|
||||
if (python == NULL) {
|
||||
// Обработка ошибки выделения памяти
|
||||
printf("Memory allocation failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Задаем начальные координаты
|
||||
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);
|
||||
char str1[] = "GAME OVER!";
|
||||
char str2[50];
|
||||
sprintf(str2, "Score: %d", score);
|
||||
mvwprintw(gameOverWin, 2, (winWidth - (int)strlen(str1)) / 2, str1);
|
||||
mvwprintw(gameOverWin, 4, (winWidth - (int)strlen(str2)) / 2, str2);
|
||||
wrefresh(gameOverWin);
|
||||
notimeout(gameOverWin, TRUE);
|
||||
wgetch(gameOverWin);
|
||||
}
|
||||
|
||||
// Здесь мы крутимся, пока игра идет
|
||||
void GameLoop()
|
||||
{
|
||||
while (run)
|
||||
{
|
||||
// Обрабатываем ввод
|
||||
Input();
|
||||
|
||||
if (!pause)
|
||||
{
|
||||
// Обрабатываем логику
|
||||
Logic();
|
||||
}
|
||||
}
|
||||
|
||||
// Сюда мы выйдем, если игра так или иначе кончится
|
||||
// Если Game over - рисуем плашку с очками
|
||||
if (gameOver)
|
||||
DrawGameOver();
|
||||
}
|
||||
|
||||
// Выбрасываем новую еду
|
||||
void DropFruit()
|
||||
{
|
||||
// Делаем флаг про то, что координаты не пересекаются с питоном
|
||||
bool goodCoords = true;
|
||||
|
||||
// Крутимся до тех пор, пока флаг не будет true
|
||||
// (Он сразу true, но если координаты попадут на змею, он станет false
|
||||
// и все уйдет на второй круг. А если не попадут - не уйдет.)
|
||||
do
|
||||
{
|
||||
// Новые координаты в переменные
|
||||
fruitX = (rand() % (termWidth - 2)) + 1;
|
||||
fruitY = (rand() % (termHeight - 2)) + 1;
|
||||
|
||||
// Тут мы проходим по куску массива с телом между началом и концом
|
||||
// чтобы выяснить, не попадает ли новая еда поперек змеи.
|
||||
for (int i = 0; i < pythonEnd; i++)
|
||||
{
|
||||
if (fruitX == python[i].x && fruitY == python[i].y)
|
||||
{
|
||||
// Если попали - сбрасываем флаг и выходим из цикла.
|
||||
goodCoords = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (!goodCoords);
|
||||
|
||||
// и нарисовать
|
||||
mvprintw(fruitY, fruitX, "#");
|
||||
}
|
||||
|
||||
// Главная функция - просто вызывает все предыдущие последовательно
|
||||
int main(int argc, const char * argv[]) {
|
||||
InitGame();
|
||||
|
||||
getch();
|
||||
|
||||
PrintScore();
|
||||
|
||||
GameLoop();
|
||||
|
||||
EndGame();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user