Skip to content

Instantly share code, notes, and snippets.

@Ruthenus
Created April 17, 2025 13:41
Show Gist options
  • Save Ruthenus/326c881d0ec8a9a133ca01c027934429 to your computer and use it in GitHub Desktop.
Save Ruthenus/326c881d0ec8a9a133ca01c027934429 to your computer and use it in GitHub Desktop.
Week 17 Homework in IT STEP Academy (maze6.txt refactoring)
#include <iostream>
#include <windows.h>
#include <conio.h> // _getch
#include <ctime>
#include <cstdlib>
using namespace std;
// Розміри ігрового поля (глобальні константи як виняток)
const int HEIGHT = 25;
const int WIDTH = 65;
// Перелік ігрових об'єктів: коридор, стіна, монета, ворог
enum GameObject : short { HALL, WALL, COIN, ENEMY };
// Визначення кольорів для консолі (enum не можна перенести в main())
enum Color : short {
BLACK, DARKBLUE, DARKGREEN, TURQUOISE, DARKRED,
PURPLE, DARKYELLOW, GREY, DARKGREY, BLUE, GREEN,
CYAN, RED, PINK, YELLOW, WHITE
};
// Коди клавіш керування
enum Key : short {
LEFT = 75, RIGHT = 77, UP = 72, DOWN = 80,
// ENTER = 13, SPACE = 32, ESCAPE = 27, BACKSPACE = 8
};
// https://kbdlayout.info/kbdusx/scancodes
// https://kbd-project.org/docs/scancodes/scancodes-5.html#focus
// Функція для приховування курсора
void hideCursor(HANDLE& h)
{
CONSOLE_CURSOR_INFO cursor;
cursor.bVisible = false;
cursor.dwSize = 100;
SetConsoleCursorInfo(h, &cursor);
}
// Функція для моделювання ігрового поля
void modelMap(int map[][WIDTH])
{
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
map[y][x] = rand() % 4;
// HALL = 0, WALL = 1, COIN = 2, ENEMY = 3
// рамка по краях (зовнішні стіни)
if (x == 0 || y == 0 || x == WIDTH - 1 || y == HEIGHT - 1) {
map[y][x] = GameObject::WALL;
}
// отвори для входу і виходу
if (x == 0 && y == 2 ||
x == 1 && y == 2 ||
x == 2 && y == 2 ||
x == WIDTH - 1 && y == HEIGHT - 3 ||
x == WIDTH - 2 && y == HEIGHT - 3 ||
x == WIDTH - 3 && y == HEIGHT - 3) {
map[y][x] = GameObject::HALL;
}
// Щоб уникнути частих зустрічей з ворогом:
if (map[y][x] == GameObject::ENEMY) {
int r = rand() % 10;
if (r != 0) {
map[y][x] = GameObject::HALL;
}
}
}
}
}
// Функція для відображення ігрового поля у консолі
void viewMap(int map[][WIDTH], HANDLE h)
{
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
switch (map[y][x]) {
case GameObject::HALL: // 0
SetConsoleTextAttribute(h, Color::BLACK);
cout << " ";
break;
case GameObject::WALL: // 1
SetConsoleTextAttribute(h, Color::DARKGREEN);
cout << (char)178; // https://www.ascii-code.com/CP437/178
break;
case GameObject::COIN: // 2
SetConsoleTextAttribute(h, Color::YELLOW);
cout << ".";
break;
case GameObject::ENEMY: // 3
SetConsoleTextAttribute(h, Color::RED);
cout << "O";
break;
}
}
cout << "\n";
}
}
// Функція для розміщення героя у висхідній позиції
void deployHero(COORD& hero, HANDLE h)
{
hero.X = 0;
hero.Y = 2;
SetConsoleCursorPosition(h, hero);
SetConsoleTextAttribute(h, Color::BLUE);
cout << "O";
hideCursor(h);
}
// Функція для відображення статистики гравця
void userStatistics(int coins_collected, HANDLE h)
{
COORD coins_info;
coins_info.X = WIDTH + 1;
coins_info.Y = 0;
SetConsoleCursorPosition(h, coins_info);
SetConsoleTextAttribute(h, Color::DARKYELLOW);
cout << "COINS: ";
SetConsoleTextAttribute(h, Color::YELLOW);
cout << coins_collected;
hideCursor(h);
}
// Функція для переміщення героя, збирання монет, обробки зіткнень
void playHero(int map[][WIDTH], COORD& hero, int& coins_collected, HANDLE h)
{
int code = _getch(); // get character
if (code == 224) { // зчитування другого коду клавіші
code = _getch();
}
// https://learn.microsoft.com/ru-ru/cpp/c-runtime-library/reference/getch-getwch?view=msvc-170
COORD old_position = hero;
bool has_been_moved = false; // false - пересування не було
switch (code) {
case Key::LEFT:
if (hero.X > 0 && map[hero.Y][hero.X - 1] != GameObject::WALL) {
has_been_moved = true;
hero.X--;
}
break;
case Key::RIGHT:
if (map[hero.Y][hero.X + 1] != GameObject::WALL) {
has_been_moved = true;
hero.X++;
}
break;
case Key::UP:
if (map[hero.Y - 1][hero.X] != GameObject::WALL) {
has_been_moved = true;
hero.Y--;
}
break;
case Key::DOWN:
if (map[hero.Y + 1][hero.X] != GameObject::WALL) {
has_been_moved = true;
hero.Y++;
}
break;
}
if (has_been_moved) {
// стирання героя в старих координатах
SetConsoleCursorPosition(h, old_position);
SetConsoleTextAttribute(h, Color::BLACK);
cout << " ";
// перемальовка героя в нових координатах
SetConsoleCursorPosition(h, hero);
SetConsoleTextAttribute(h, Color::BLUE);
cout << "O";
}
// перевірка на перетинання з якимось об'єктом в лабірінті
if (map[hero.Y][hero.X] == GameObject::COIN) {
coins_collected++;
map[hero.Y][hero.X] = GameObject::HALL;
userStatistics(coins_collected, h);
}
if (map[hero.Y][hero.X] == GameObject::ENEMY) {
cout << "ENEMY";
}
hideCursor(h);
}
// Функція для ігрового двигунчика
void bomberPerpetuumMobile(int map[][WIDTH], COORD& hero,
int& coins_collected, HANDLE h)
{
while (true) {
playHero(map, hero, coins_collected, h);
}
}
int main()
{
system("title Bomberman"); // встановлення назви вікна
srand(time(0));
// rand(); // попередження C6031 та C4244
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
hideCursor(h);
int map[HEIGHT][WIDTH] = {};
modelMap(map);
viewMap(map, h);
COORD hero;
deployHero(hero, h);
int coins_collected = 0;
userStatistics(coins_collected, h);
playHero(map, hero, coins_collected, h);
bomberPerpetuumMobile(map, hero, coins_collected, h);
Sleep(INFINITE);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment