Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Snake

.cpp
Скачиваний:
0
Добавлен:
19.06.2023
Размер:
10.99 Кб
Скачать
#include <iostream>
#include <conio.h>
#include <fcntl.h>
#include <io.h>
#include <ctime>
#include <Windows.h>

#define W_MAX			50
#define H_MAX			20

#define KEY_UP			72
#define KEY_LEFT		75
#define KEY_RIGHT		77
#define KEY_DOWN		80
#define CONTROL_KEYS	224
#define FUNC_KEYS		0
#define KEY_ENTER		13
#define KEY_ESCAPE		27

#define EMPTY			0
#define FOOD			-1
#define UP				1
#define RIGHT			2
#define DOWN			3
#define LEFT			4

#define EASY			600
#define NORMAL			400
#define HARD			200

HANDLE consoleHandle = GetStdHandle(STD_OUTPUT_HANDLE);

void goto_xy(int x, int y) {
	COORD coord;
	coord.X = x;
	coord.Y = y;
	SetConsoleCursorPosition(consoleHandle, coord);
}
void set_text_color(int color) {
	SetConsoleTextAttribute(consoleHandle, (WORD)color);
}

struct Point {
	short x, y;
};

struct Snake {
	Point head = { 0, 0 }, tail = { 0, 0 };
	short direction = UP, length = 1;
};

class Field {
private:
	short field[H_MAX][W_MAX];

public:
	short height, width;
	short get_value(Point point) {
		return field[point.y][point.x];
	}
	void set_value(Point point, short value) {
		field[point.y][point.x] = value;
	}
};

Snake snake;
Field field;

void print_cell(Point point, wchar_t symbol, int color) {
	set_text_color(color);
	goto_xy(point.x * 2 + 2, point.y + 1);
	wprintf(L"%c", symbol);
}
void print_head(short snake_direction) {
	if (snake_direction == UP) print_cell(snake.head, L'▲', 14);
	else if (snake_direction == RIGHT) print_cell(snake.head, L'►', 14);
	else if (snake_direction == DOWN) print_cell(snake.head, L'▼', 14);
	else if (snake_direction == LEFT) print_cell(snake.head, L'◄', 14);
}
void print_tail(short tail_direction) {
	if (tail_direction == UP) print_cell(snake.tail, L'▼', 10);
	else if (tail_direction == RIGHT) print_cell(snake.tail, L'◄', 10);
	else if (tail_direction == DOWN) print_cell(snake.tail, L'▲', 10);
	else if (tail_direction == LEFT) print_cell(snake.tail, L'►', 10);
}

void move_point(Point* point, short direction) {
	if (direction == UP) {
		--(*point).y;
		if ((*point).y == -1)
			(*point).y = field.height - 1;
	}
	else if (direction == RIGHT) {
		++(*point).x;
		if ((*point).x == field.width)
			(*point).x = 0;
	}
	else if (direction == DOWN) {
		++(*point).y;
		if ((*point).y == field.height)
			(*point).y = 0;
	}
	else if (direction == LEFT) {
		--(*point).x;
		if ((*point).x == -1)
			(*point).x = field.width - 1;
	}
}

void move_snake(Point next, short snake_direction) {
	short tail_direction = field.get_value(snake.tail);
	field.set_value(snake.tail, EMPTY);
	print_cell(snake.tail, L'·', 8);
	move_point(&snake.tail, tail_direction);
	if (snake.length > 1) {
		print_tail(field.get_value(snake.tail));
		if (snake.length != 2)
			print_cell(snake.head, L'■', 10);
	}
	else
		print_cell(snake.head, L'·', 8);
	snake.head = next;
	field.set_value(snake.head, snake_direction);
	print_head(snake_direction);
}

int main() {
	(void)_setmode(_fileno(stdout), _O_U16TEXT);

	// Скрыть курсор
	CONSOLE_CURSOR_INFO info;
	info.dwSize = 100;
	info.bVisible = FALSE;
	SetConsoleCursorInfo(consoleHandle, &info);

	int default_frequency = NORMAL;
	field.width = 7;
	field.height = 7;

	bool working = true;
	while (working) {
		// МЕНЮ
		short cursor = 1;
		bool menu = true;
		system("cls");
		set_text_color(15);
		wprintf(L"  ——= ЗМЕЙКА =—— ");
		set_text_color(7);
		wprintf(L"\n    Ширина поля:   %2d  \n    Высота поля:   %2d  \n    Сложность:   %-7s  \n",
			field.width,
			field.height,
			(default_frequency == EASY) ? L"Низкая" : ((default_frequency == NORMAL) ? L"Средняя" : L"Высокая")
		);
		set_text_color(14);
		wprintf(L"\n [Enter]");
		set_text_color(15);
		wprintf(L" — начать игру");
		while (menu) {
			set_text_color(14);
			goto_xy(1, cursor);
			wprintf(L"—>");
			if (cursor == 1) {
				goto_xy(17, cursor);
				wprintf(L"< %2d >", field.width);
			}
			else if (cursor == 2) {
				goto_xy(17, cursor);
				wprintf(L"< %2d >", field.height);
			}
			else if (cursor == 3) {
				goto_xy(15, cursor);
				wprintf(L"< %-7s >", (default_frequency == EASY)? L"Низкая" : ((default_frequency == NORMAL)? L"Средняя" : L"Высокая"));
			}
			// Управление меню
			wchar_t input = _getwch();
			if (input == FUNC_KEYS)
				(void)_getwch();
			else if (input == CONTROL_KEYS) {
				input = _getwch();
				if (input == KEY_UP or input == KEY_DOWN) {
					goto_xy(1, cursor);
					wprintf(L"  ");
					if (cursor == 1) {
						set_text_color(7);
						goto_xy(17, cursor);
						wprintf(L"  %2d  ", field.width);
					}
					else if (cursor == 2) {
						set_text_color(7);
						goto_xy(17, cursor);
						wprintf(L"  %2d  ", field.height);
					}
					else if (cursor == 3) {
						set_text_color(7);
						goto_xy(15, cursor);
						wprintf(L"  %-7s  ", (default_frequency == EASY) ? L"Низкая" : ((default_frequency == NORMAL) ? L"Средняя" : L"Высокая"));
					}
				}
				if (input == KEY_UP and --cursor == 0) cursor = 3;
				else if (input == KEY_DOWN and ++cursor == 4) cursor = 1;
				else if (input == KEY_RIGHT) {
					if (cursor == 1 and ++field.width > W_MAX) field.width = 3;
					if (cursor == 2 and ++field.height > H_MAX) field.height = 3;
					if (cursor == 3) {
						if (default_frequency == EASY)
							default_frequency = NORMAL;
						else if (default_frequency == NORMAL)
							default_frequency = HARD;
						else if (default_frequency == HARD)
							default_frequency = EASY;
					}
				}
				else if (input == KEY_LEFT) {
					if (cursor == 1 and --field.width < 3) field.width = W_MAX;
					if (cursor == 2 and --field.height < 3) field.height = H_MAX;
					if (cursor == 3) {
						if (default_frequency == HARD)
							default_frequency = NORMAL;
						else if (default_frequency == NORMAL)
							default_frequency = EASY;
						else if (default_frequency == EASY)
							default_frequency = HARD;
					}
				}
			}
			else if (input == KEY_ENTER)
				menu = false;
		}

		int frequency = default_frequency;

		// Генерация пищи и змейки
		Point random_point = {
			rand() % field.width,
			rand() % field.height
		};
		for (short i = 0; i < 5; i++) {
			while (field.get_value(random_point) != EMPTY)
				random_point = {
					rand() % field.width,
					rand() % field.height
			};
			field.set_value(random_point, FOOD);
		}
		while (field.get_value(random_point) != EMPTY)
			random_point = {
				rand() % field.width,
				rand() % field.height
		};
		field.set_value(random_point, UP);
		snake.head = random_point;
		snake.tail = random_point;


		// отображение начального поля
		system("cls");
		set_text_color(15);
		wprintf(L"  ——= ЗМЕЙКА =——\n");
		for (short i = 0; i < field.height; i++) {
			wprintf(L"  ");
			for (short j = 0; j < field.width; j++) {
				Point current = { j, i };
				short value = field.get_value(current);
				if (value == EMPTY) {
					set_text_color(8);
					wprintf(L"· ");
				}
				else if (value == FOOD) {
					set_text_color(12);
					wprintf(L"● ");
				}
				else if (snake.head.x == current.x and snake.head.y == current.y) {
					set_text_color(14);
					wprintf(L"▲ ");
				}

			}
			wprintf(L"\n");
		}

		bool playing = true;
		clock_t started_time = clock();
		clock_t prev_time = clock();

		// ИГРА
		while (playing) {
			// Управление
			if (_kbhit()) {
				wchar_t input = _getwch();
				if (input == FUNC_KEYS)
					(void)_getwch();
				else if (input == CONTROL_KEYS) {
					input = _getwch();
					if (input == KEY_UP and (snake.length == 1 or snake.direction != DOWN))
						field.set_value(snake.head, UP);
					else if (input == KEY_RIGHT and (snake.length == 1 or snake.direction != LEFT))
						field.set_value(snake.head, RIGHT);
					else if (input == KEY_DOWN and (snake.length == 1 or snake.direction != UP))
						field.set_value(snake.head, DOWN);
					else if (input == KEY_LEFT and (snake.length == 1 or snake.direction != RIGHT))
						field.set_value(snake.head, LEFT);
				}
			}

			if (clock() - prev_time > frequency) {
				prev_time = clock();
				//system("cls");

				// Движение
				Point next = snake.head;
				short snake_direction = field.get_value(snake.head);
				move_point(&next, snake_direction);
				short next_value = field.get_value(next);
					// пусто
				if (next_value == EMPTY) {
					move_snake(next, snake_direction);
				}
					//еда
				else if (next_value == FOOD) {
					frequency = (frequency * 99) / 100; // Увеличение скорости
					++snake.length;
					if (snake.length == 2)
						print_tail(snake_direction);
					else
						print_cell(snake.head, L'■', 10);
					snake.head = next;
					field.set_value(snake.head, snake_direction);
					print_head(snake_direction);
					if (snake.length == field.height * field.width)
						playing = false;
					else if (field.height * field.width - snake.length >= 5) {
						while (field.get_value(random_point) != EMPTY)
							random_point = {
								rand() % field.width,
								rand() % field.height
						};
						field.set_value(random_point, FOOD);
						print_cell(random_point, L'●', 12);
					}
				}
					// змейка
				else {
					if (next.x == snake.tail.x and next.y == snake.tail.y) {
						move_snake(next, snake_direction);
					}
					else
						playing = false;
				}
				snake.direction = field.get_value(snake.head);
			}
		}
		// КОНЕЦ ИГРЫ
		int time_elapsed = (clock() - started_time) / CLOCKS_PER_SEC;
		goto_xy(0, field.height + 1);
		set_text_color(14);
		wprintf(L"\n    Игра окончена!");
		set_text_color(7);
		wprintf(L"\n Длина змейки: %d ед.\n Скорость змейки: %.1f ед./с\n Времени затрачено: %d:%s%d",
			snake.length,
			CLOCKS_PER_SEC/(double)frequency,
			time_elapsed / 60,
			((time_elapsed % 60) < 10) ? L"0" : L"",
			time_elapsed % 60
		);
		set_text_color(15);
		wprintf(L"\n\n Сыграть ещё раз? ");
		set_text_color(3);
		wprintf(L"[y/n]");

		// Ожидание [y/n]
		while (true) {
			wchar_t input = _getwch();
			if (input == FUNC_KEYS or input == CONTROL_KEYS)
				(void)_getwch();
			else if (input == 'y' or input == L'н') {
				for (short i = 0; i < field.height; i++)
					for (short j = 0; j < field.width; j++) {
						field.set_value({ j, i }, EMPTY);
					}
				snake.length = 1;
				snake.direction = UP;
				break;
			}
			else if (input == 'n' or input == L'т') {
				working = false;
				break;
			}
		}
	}
}
Соседние файлы в предмете Программирование