Автор - не я, изначально взято с itblogs. Я немного причесал код, убрал переключения цвета фона и добавил код для Linux/OSX.
В игре, ясное дело, ничего особенного, просто понравилась она мне. К тому же попробовал ascii.io для записи asciicast’a, так что геймплей можно заценить - http://ascii.io/a/1715
Исходник есть на GitHub’е, но можно просто скопировать снизу.
// Originally taken from http://itblogs.org/c-konsolnaya-zmejka/. #include <iostream> #include <cstdio> #include <cstdlib> #include <ctime> #ifdef WINDOWS // Библиотека, нужна для использования функции Sleep(). #include <windows.h> // Библиотека, нужна для использования функций kbhit() и getch(). #include <conio.h> #else #include <unistd.h> #include <termios.h> #include <sys/select.h> #define STDIN_FILENO 0 #define NB_DISABLE 0 #define NB_ENABLE 1 #define Sleep(x) usleep(x*1000) int kbhit() { struct timeval tv; fd_set fds; tv.tv_sec = 0; tv.tv_usec = 0; FD_ZERO(&fds); FD_SET(STDIN_FILENO, &fds); select(STDIN_FILENO+1, &fds, NULL, NULL, &tv); return FD_ISSET(STDIN_FILENO, &fds); } void nonblock(int state) { struct termios ttystate; // Get the terminal state. tcgetattr(STDIN_FILENO, &ttystate); if (state == NB_ENABLE) { // Turn off canonical mode. ttystate.c_lflag &= ~ICANON; // Minimum of number input read. ttystate.c_cc[VMIN] = 1; } else if (state == NB_DISABLE) { // Turn on canonical mode. ttystate.c_lflag |= ICANON; } // Set the terminal attributes. tcsetattr(STDIN_FILENO, TCSANOW, &ttystate); } int getch() { return fgetc(stdin); } #endif // snake_size - размер змейки. // change_x, change_y - в какую сторону движется змейка. // coordinates_x[1000], coordinates_y[1000] - массивы, хранящие координаты // частей тела змейки. // Kоординаты головы змейки хранятся в coordinates_x[1], coordinates_y[1]. // food_x, food_y - координаты еды. int snake_size, change_x, change_y, coordinates_x[1000], coordinates_y[1000]; int food_x = -1, food_y = -1; // symbol - хранит в себе ASCII код нажатой клавиши. // a[1000][1000] - наша таблица, в которой происходит вся игра. char symbol, a[1000][1000]; // Константы: // N - размер таблицы, а именно высота. // M - ширина таблицы. // INTERVAL - интервал в миллисекундах, через каждый этот промежуток // времени змейка будет передвигаться. const int N = 13, M = 17, INTERVAL = 200; // функция, считывающая нажатую клавишу. void change_direction() { // Cчитываем нажатую клавишу с помощью функции getch(). symbol = getch(); switch (symbol) { // Управление змейкой у нас через wasd. case 'w': if (change_x != 1 || change_y != 0) { change_x = -1; change_y = 0; } break; case 'a': if (change_x != 0 || change_y != 1) { change_x = 0; change_y = -1; } break; case 's': if (change_x != -1 || change_y != 0) { change_x = 1; change_y = 0; } break; case 'd': if (change_x != 0 || change_y != -1) { change_x = 0; change_y = 1; } break; #ifndef WINDOWS case 'q': nonblock(NB_DISABLE); std::exit(0); #endif default: break; } } // функция для вывода таблицы void show_table() { // Очищаем консоль. #ifdef WINDOWS system("cls"); #else system("clear"); #endif // Выводим таблицу и края. for (int i = 0; i <= N + 1; ++i) for (int j = 0; j <= M + 1; ++j) std::cout << (i == 0 || j == 0 || i == N + 1 || j == M + 1 ? '#' : a[i][j]) << (j <= M ? "" : "\n"); } // Очищаем координаты, в которых располагалась змейка. void clear_snake_on_table() { for (int i = 1; i <= snake_size; ++i) a[coordinates_x[i]][coordinates_y[i]] = ' '; } // Красим координаты змейки. void show_snake_on_table() { // Изменяем тип головы. if (change_x == 1 && change_y == 0) a[coordinates_x[1]][coordinates_y[1]] = 'v'; if (change_x == -1 && change_y == 0) a[coordinates_x[1]][coordinates_y[1]] = '^'; if (change_x == 0 && change_y == 1) a[coordinates_x[1]][coordinates_y[1]] = '>'; if (change_x == 0 && change_y == -1) a[coordinates_x[1]][coordinates_y[1]] = '<'; // Красим змейку. for (int i = 2; i <= snake_size; ++i) a[coordinates_x[i]][coordinates_y[i]] = '@'; } // Проверяем, съела ли змейка саму себя. bool game_over() { for (int i = 2; i <= snake_size; ++i) // Eсли координаты головы змейки равны координате какой-либо части тела // змейки, то змейка съела саму себя. if (coordinates_x[1] == coordinates_x[i] && coordinates_y[1] == coordinates_y[i]) return true; // Если все координаты различны, то все в порядке - играем дальше. return false; } // Проверяем, не вышла ли змейка за поле, если да то возвращаем ее обратно. void check_coordinates() { if (coordinates_x[1] > N) coordinates_x[1] = 1; if (coordinates_x[1] < 1) coordinates_x[1] = N; if (coordinates_y[1] > M) coordinates_y[1] = 1; if (coordinates_y[1] < 1) coordinates_y[1] = M; } // функция следующего хода, в которой наша змейка сдвигается в сторону // на 1 ячейку. void next_step() { // Чистим таблицу от змейки. clear_snake_on_table(); // Передвигаем тело змейки. for (int i = snake_size; i >= 2; --i) { coordinates_x[i] = coordinates_x[i - 1]; coordinates_y[i] = coordinates_y[i - 1]; } // Передвигаем голову змейки. coordinates_x[1] += change_x; coordinates_y[1] += change_y; // Проверяем в порядке ли координаты. check_coordinates(); // Если голова змейки там же где и еда, то увеличиваем размер змейки // и очищаем координаты змейки. if (coordinates_x[1] == food_x && coordinates_y[1] == food_y) { snake_size++; food_x = -1; food_y = -1; } // Рисуем змейку. show_snake_on_table(); // Если змея укусила себя. if (game_over()) { // Cообщаем всю правду о игроке. std::cout << "You're looser! \n"; // Приостанавливаем игру. #ifdef WINDOWS system("pause"); #endif // Завершаем программу. std::exit(0); } } // функция проверки на наличие еды на карте. bool food_check() { // Если координаты еды неопределенны, то возвращаем true. if (food_x == -1 && food_y == -1) return false; // В остальных случаях false. return true; } // функция добавления еды на карту. void place_food() { std::srand(std::time(NULL)); // Cтавим в рандомное место еду. for (int i = 1; i <= 9; ++i) { int x = std::rand(), y = std::rand(); if (x < 0) x *= -1; if (y < 0) y *= -1; x %= (N + 1); y %= (M + 1); if (x == 0) ++x; if (y == 0) ++y; if (a[x][y] != '@' && a[x][y] != 'v' && a[x][y] != '^' && a[x][y] != '<' && a[x][y] != '>') { food_x = x; food_y = y; a[x][y] = '+'; return; } } } // Начальные установки. void standart_settings() { // Размер змеи - 2. snake_size = 2; // Змейка занимает две клетки вправо от координаты {1,1}. coordinates_x[1] = 1; coordinates_y[1] = 2; coordinates_x[2] = 1; coordinates_y[2] = 1; // Змейка движется вправо. change_x = 0; change_y = 1; } int main() { // Задаем стандартные настройки. standart_settings(); #ifndef WINDOWS std::memset(a, ' ', sizeof(a)); nonblock(NB_ENABLE); #endif // Бесконечный цикл. while (true) { // Если нажата клавиша, обрабатываем нажатую клавишу. if (kbhit() != 0) change_direction(); // Двигаем змейку. next_step(); // Если нет еды, то ставим ее. if (!food_check()) place_food(); // Рисуем змейку. show_table(); // "Усыпляем" программу на заданный интервал. Sleep(INTERVAL); } }
Если у кого есть всякие консольные примочки типа этой - делитесь, не стесняйтесь.