Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 5.00/5: Рейтинг темы: голосов - 5, средняя оценка - 5.00
0 / 0 / 0
Регистрация: 25.07.2019
Сообщений: 2

Нужна конструктивная критика

25.07.2019, 19:38. Показов 999. Ответов 5
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Добрый день, форумчане. Я только сегодня начал проходить ООП. С указателями еще не подружился.
Если можно, вы можете указать на ошибки, которые я допустил при написании простенькой змейки, а так же оценить насколько такой код приемлем в общем(нормально ли он написан).
И не могли бы вы еще подсказать на счет мигания экрана во время работы змейки. Не могу понять почему так происходит.
Заранее спасибо!
Змейка в трех файлах:

Main.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 #include "Snake.h"
#include <iostream>
 
void SLEEP(int TIME); // Задержка изображения на экране
void CLEAR(); // Очищение экрана
 
void GAME_LOOP()
{
    SNAKE_DRAW OBJECT; // Самый нижний объект иерархии
 
    bool IS_OPEN = true;
    int TIME = 100;
 
    OBJECT.COORD_DEFAULT(); // Начальные координаты змейки
    OBJECT.DEFAULT_FOOD(); // Начальные координаты еды
    OBJECT.DISPLAY(); // Начальный вывод
    OBJECT.DEFAULT_DIRECTION(); // Программа ждет нажатия первой кнопки
 
    while (IS_OPEN)
    {
        CLEAR(); // Очищение экрана
        OBJECT.GET_DIRECTION(); // Получение направления движения змейки
        OBJECT.HEAD_MOVEMENT(OBJECT.RETURN_DIRECTION()); // Передвижение Х и У
        OBJECT.TAIL_COPY(); // Копирование хвоста змейки (на случай создания, если она съест еду)
        OBJECT.ETC_MOVEMENT(); // Движение всей змейки, кроме головы
        OBJECT.HEAD_COORD(); // Присвоение координат Х и У к первому элементу змейки
        OBJECT.CHECK_CRASH(); // Смотрим, не врезалась ли змейка в саму себя
        OBJECT.ATE(); // Не съела ли змейка еду
        OBJECT.IS_INCREASE(); // Если съела, то растет
        OBJECT.IS_SET(); // Если еда съедена, то ставим новую
        OBJECT.DISPLAY(); // Вывод змейки и еды на экран
        SLEEP(TIME); // Задержка в 100 миллисекунд
    }
}
 
int main()
{
    GAME_LOOP();
 
    system("pause");
    return 0;
}
Snake.cpp
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#include "Snake.h"
#include <iostream>
#include <Conio.h>
#include <Windows.h>
#include <ctime>
 
void SLEEP(int TIME)
{
    Sleep(TIME);
}
 
void CLEAR()
{
    system("cls");
}
 
void SNAKE::COORD_DEFAULT() // Начальные координаты змейки
{
    X = 3;
    Y = 1;
    X_COORD[0] = 3;
    X_COORD[1] = 2;
    X_COORD[2] = 1;
    Y_COORD[0] = 1;
    Y_COORD[1] = 1;
    Y_COORD[2] = 1;
}
 
void DIRECTION::GET_DIRECTION() // Получение направления движения змейки
{
    if (_kbhit()) // Если нажата клавиша,
    {
        switch (_getch()) // То считываем значение ключа
        {
        case 119: if (BUFFER_DIR != DOWN)  DIR = UP;    break; // Условные операторы чтобы змейка через себя не проходила
        case 115: if (BUFFER_DIR != UP)    DIR = DOWN;  break;
        case 97:  if (BUFFER_DIR != RIGHT) DIR = LEFT;  break;
        case 100: if (BUFFER_DIR != LEFT)  DIR = RIGHT; break;
        }
        BUFFER_DIR = DIR;
    }
    else DIR = BUFFER_DIR;
}
 
int DIRECTION::RETURN_DIRECTION() // Просто возвращаем значение направления
{
    return DIR;
}
 
void DIRECTION::DEFAULT_DIRECTION() // Начальный выбор направления движения змейки
{
    switch (_getch())
    {
    case 119: DIR = UP; break;
    case 115: DIR = DOWN; break;
    case 100: DIR = RIGHT; break;
    default: DEFAULT_DIRECTION(); break;
    }
    BUFFER_DIR = DIR;
}
void MOVEMENT::IS_BROAD() // Проверка выхода змейки за границу карты
{
    if (X > (MAX_MAP_SIZE - 1)) X = 0;
    if (X < 0) X = MAX_MAP_SIZE - 1;
    if (Y > (MAX_MAP_SIZE - 13)) Y = 0;
    if (Y < 0) Y = MAX_MAP_SIZE - 13;
}
 
void MOVEMENT::HEAD_MOVEMENT(int DIR) // Непосредственно изменение координат Х и У
{
    switch (DIR)
    {
    case UP: Y--; break;
    case DOWN: Y++; break;
    case LEFT: X--; break;
    case RIGHT: X++; break;
    }
    IS_BROAD();
}
 
void MOVEMENT::TAIL_COPY() // Копирование хвоста змейки
{
    X_BUFFER = X_COORD[SNAKE_SIZE];
    Y_BUFFER = Y_COORD[SNAKE_SIZE];
}
 
void MOVEMENT::HEAD_COORD() // Присвоение первому элементу змейки значений Х и У
{
    X_COORD[0] = X;
    Y_COORD[0] = Y;
}
 
void MOVEMENT::ETC_MOVEMENT() // Изменение координат всего тела змейки, кроме перового элемента
{
    for (int i = MAX_SNAKE_SIZE - 1; i > 0; i--)
    {
        X_COORD[i] = X_COORD[i - 1];
        Y_COORD[i] = Y_COORD[i - 1];
    }
}
 
void INCREASE::SNAKE_INCREASE() // Рост змейки
{
    X_COORD[SNAKE_SIZE + 1] = X_BUFFER;
    Y_COORD[SNAKE_SIZE + 1] = Y_BUFFER;
}
 
bool SNAKE_DRAW::SNAKE_CHECK(int x, int y) // Проверка: есть ли в этой точке змейка
{
    bool IS_CHECKED = false;
    for (int i = 0; i < SNAKE_SIZE; i++) if ((X_COORD[i] == x) && (Y_COORD[i] == y)) { IS_CHECKED = true; break; }
    return IS_CHECKED;
}
 
bool SNAKE_DRAW::FOOD_CHECK(int x, int y) // Проверка: есть ли в этой точке еда
{
    bool IS_CHECKED = false;
    if ((X_FOOD == x) && (Y_FOOD == y)) IS_CHECKED = true;
    return IS_CHECKED;
}
 
void SNAKE_DRAW::COORD_DISPLAY(int x, int y) // Проверка: какой символ нужно напечатать
{
    if (SNAKE_CHECK(x, y) == true) std::cout << SNAKE_SYM; else
        if (FOOD_CHECK(x, y) == true) std::cout << '@'; else std::cout << ' ';
}
 
void SNAKE_DRAW::DISPLAY() // Непосредственно сам вывод на экран
{
    for (int y = 0; y < MAX_MAP_SIZE - 12; y++)
    {
        for (int x = 0; x < MAX_MAP_SIZE; x++) COORD_DISPLAY(x, y);
        std::cout << std::endl;
    }
}
 
bool EATING::IS_EAT() // Съедено ли
{
    if (IS_EATING == true) { IS_EATING = false; return true; } else return false;
}
 
bool EATING::IS_PUT() // Поставлена ли еда
{
    if (IS_PUTTING == false) { IS_PUTTING = true; return true; } else return false;
}
 
void INCREASE::IS_INCREASE() // Если еда съедена, то растем
{
    if (IS_EAT() == true) { SNAKE_INCREASE(); SNAKE_SIZE++; IS_PUTTING = false; }
}
 
void EATING::ATE() // Проверка на съедение еды
{
    if ((X_FOOD == X) && (Y_FOOD == Y)) IS_EATING = true;
}
 
void FOOD_PUT::IS_SET() // Если еда не поставлена, то ставим ее
{
    if (IS_PUT() == true) { FOOD_SET(); IS_PUTTING = true; }
}
 
void FOOD_PUT::FOOD_SET() // Рандомная генерация координат еды и проверка: задевает ли она змейку. Если да, то все по новой
{
    srand(time(NULL));
 
    bool IS_OPEN = true;
    int COUNTER;
 
    while (IS_OPEN)
    {
        COUNTER = 0;
        X_FOOD = 0 + rand() % (MAX_MAP_SIZE - 1);
        Y_FOOD = 0 + rand() % (MAX_MAP_SIZE - 13);
 
        for (int i = 0; i < SNAKE_SIZE; i++)
            if ((X_FOOD != X_COORD[i]) || (Y_FOOD != Y_COORD[i])) COUNTER++;
        
        if (COUNTER == SNAKE_SIZE) IS_OPEN = false;
    }
}
 
void EATING::DEFAULT_FOOD() // Начальные координаты еды
{
    X_FOOD = 7;
    Y_FOOD = 9;
}
 
bool MOVEMENT::SNAKE_CRASH() // Разбилась ли змейка
{
    bool CRASHED = false;
 
    for (int i = 1; i < SNAKE_SIZE; i++) 
        if ((X == X_COORD[i]) && (Y == Y_COORD[i]))
        {
            CRASHED = true;
            break;
        }
    return CRASHED;
}
 
void MOVEMENT::CHECK_CRASH() // Если разбилась, то выходим
{
    if (SNAKE_CRASH() == true) exit(0);
}
Snake.h
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#ifndef SNAKE_H
#define SNAKE_H
 
class SNAKE
{
public:
    const int MAX_MAP_SIZE = 24;
protected:
    static const int MAX_SNAKE_SIZE = 64;
 
    int SNAKE_SIZE = 3;
    int X, Y;
    int X_COORD[MAX_SNAKE_SIZE];
    int Y_COORD[MAX_SNAKE_SIZE];
    char SNAKE_SYM = '*';
public:
    void COORD_DEFAULT();
};
 
class DIRECTION : public SNAKE
{
 
protected:
    enum DIRECTIONS { UP, LEFT, DOWN, RIGHT } DIR, BUFFER_DIR;
public:
    void GET_DIRECTION();
    int RETURN_DIRECTION();
    void DEFAULT_DIRECTION();
};
 
class MOVEMENT : public DIRECTION
{
private:
    void IS_BROAD();
    bool SNAKE_CRASH();
protected:
    int X_BUFFER;
    int Y_BUFFER;
public:
    void HEAD_MOVEMENT(int DIR);
    void TAIL_COPY();
    void HEAD_COORD();
    void ETC_MOVEMENT();
    void CHECK_CRASH();
};
 
class EATING : public MOVEMENT
{
protected:
    bool IS_EATING = false;
    bool IS_PUTTING = true;
    int X_FOOD;
    int Y_FOOD;
 
    bool IS_EAT();
    bool IS_PUT();
public:
    void DEFAULT_FOOD();
    void ATE();
};
 
class FOOD_PUT : public EATING
{
private:
    void FOOD_SET();
public:
    void IS_SET();
};
 
class INCREASE : public FOOD_PUT
{
private:
    void SNAKE_INCREASE();
public:
    void IS_INCREASE();
};
 
class SNAKE_DRAW : public INCREASE
{
private:
    bool SNAKE_CHECK(int x, int y);
    bool FOOD_CHECK(int x, int y);
    void COORD_DISPLAY(int x, int y);
public:
    void DISPLAY();
};
 
void SLEEP(int TIME);
void CLEAR();
 
#endif // SNAKE_H
P.S.: Прошу прощение за столь малое количество комментариев. Не смог нормально дописать, т.к. уже 2.30 ночи. Еле дописал этот пост.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
25.07.2019, 19:38
Ответы с готовыми решениями:

Нужна конструктивная критика: советы, замечания по заданному фрагменту кода
Есть входные данные, которые я кладу в вектор 5 1 2 3 4 5 Ваша критика #include &lt;iostream&gt; #include &lt;vector&gt;

Нужна конструктивная критика по оформлению и читабельности кода (Game Trainer C++)
Относительно недавно начал изучать C++. Для обучения решил написать трейнер попутно изучая язык/читая необходимую литературу разного рода. ...

Нужна конструктивная критика: удалось ли мне уловить хоть частицу ООП в моём проекте?
Добрый день, дорогие форумчане. Меня, как и многих, волнует мое будущее, и поэтому же меня волнует понимание ООП, я написал змейку и хотел...

5
 Аватар для zayats80888
6352 / 3523 / 1428
Регистрация: 07.02.2019
Сообщений: 8,995
25.07.2019, 19:42
Цитата Сообщение от vsglhs Посмотреть сообщение
нормально ли он написан
Не вникая в суть, первое что бросается в глаза - все имена прописными буквами. Так не принято, прописными принято именовать макросы.
1
 Аватар для Andrey B
170 / 122 / 61
Регистрация: 06.02.2015
Сообщений: 300
25.07.2019, 20:14
Не вижу конструктора и деструктора. Про них не стоит забывать. Здесь может и не нужно, но в другом..
Дело вкуса, но мне код в таком виде читать тяжело
1
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
25.07.2019, 21:48
Цитата Сообщение от vsglhs Посмотреть сообщение
Добрый день, форумчане. Я только сегодня начал проходить ООП. С указателями еще не подружился.
Смотрю, сразу с Бейсика решил перескочить на С++. Похвально, но лучше начинать с каких-нибудь более простых задач.

Цитата Сообщение от vsglhs Посмотреть сообщение
И не могли бы вы еще подсказать на счет мигания экрана во время работы змейки. Не могу понять почему так происходит.
Ну так ты сначала очищаешь экран, потом ждёшь нажатия клавиши
Цитата Сообщение от vsglhs Посмотреть сообщение
CLEAR(); // Очищение экрана
* * * * OBJECT.GET_DIRECTION(); // Получение направления движения змейки
1
0 / 0 / 0
Регистрация: 25.07.2019
Сообщений: 2
26.07.2019, 10:18  [ТС]
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Смотрю, сразу с Бейсика решил перескочить на С++. Похвально, но лучше начинать с каких-нибудь более простых задач.
Я с Бейсиком не знаком. С программированием (в школе паскаль проходили, а там уже с++ заинтересовался) познакомился 2 года назад, но через пару месяцев забросил из-за определенных проблем. Сейчас снова начинаю писать.
Цитата Сообщение от oleg-m1973 Посмотреть сообщение
Ну так ты сначала очищаешь экран, потом ждёшь нажатия клавиши
Я попробовал переставить и так, и сяк, но практически не получилось исправить...
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while (IS_OPEN)
    {
        CLEAR(); // Очищение экрана
        OBJECT.DISPLAY(); // Вывод змейки и еды на экран
        SLEEP(TIME); // Задержка в 100 миллисекунд
        OBJECT.GET_DIRECTION(); // Получение направления движения змейки
        OBJECT.HEAD_MOVEMENT(OBJECT.RETURN_DIRECTION()); // Передвижение Х и У
        OBJECT.TAIL_COPY(); // Копирование хвоста змейки (на случай создания, если она съест еду)
        OBJECT.ETC_MOVEMENT(); // Движение всей змейки, кроме головы
        OBJECT.HEAD_COORD(); // Присвоение координат Х и У к первому элементу змейки
        OBJECT.CHECK_CRASH(); // Смотрим, не врезалась ли змейка в саму себя
        OBJECT.ATE(); // Не съела ли змейка еду
        OBJECT.IS_INCREASE(); // Если съела, то растет
        OBJECT.IS_SET(); // Если еда съедена, то ставим новую
    }
Я нашел функцию SetConsoleCursorPosition. С ней мерцания полностью ушли.

И еще вопрос про организацию иерархии классов. Я хотел реализовать несколько иначе.
Что-то по типу:
1. Змея:
1.1. Передвигается:
1.1.1. Двигает свое тело
1.1.2. Изменяет направление движения
1.2. Ест:
1.2.1 Растет
1.2.2 Размещает еду
1.3. Рисует себя
1.3.1 Рисует голову ( символ головы хотел сделать в зависимости от направления движения )
1.3.2 Рисует остальное тело
Но не получилось, т.к. не знаю как можно получить доступ к методу из пункта 1.2 в метод в пункте 1.1. В итоге получилась, на мой взгляд, не очень хорошая иерархическая лесенка.
0
6772 / 4565 / 1844
Регистрация: 07.05.2019
Сообщений: 13,726
26.07.2019, 10:47
Цитата Сообщение от vsglhs Посмотреть сообщение
Я попробовал переставить и так, и сяк, но практически не получилось исправить...
Обычно для этого используется двойной буфер - нувую картинку рисуешь не на экране, а в буфере. Потом выводишь этот буфер не экран, поверх старого изображения.
Цитата Сообщение от vsglhs Посмотреть сообщение
Но не получилось, т.к. не знаю как можно получить доступ к методу из пункта 1.2 в метод в пункте 1.1. В итоге получилась, на мой взгляд, не очень хорошая иерархическая лесенка.
Ну да не очень - Движение наследуется от Змеи. Это как вообще? Скорее надоборот - Змея должна наследоваться от всех этих классов.
Хотя, я бы не заморачивался и сделал один класс - Змея, всё остальное движение, еда, рост и т.д. - его методы
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
26.07.2019, 10:47
Помогаю со студенческими работами здесь

Собственная реализация паттерна "Слушатель" - нужна конструктивная критика
Добрый день, наворотил код по работе с паттерном слушатель - есть класс контейнер данных и при их изменении всех кто подписался должен...

Требуется конструктивная критика
Я не волшебник, только учусь. Для обучения выбрал алгоритм поиска пути A*. Вот собственно моя реализация: Заголовочный файл A_search.h ...

Поиск популярного триплета. Конструктивная критика
Добрый день. Недавно помогал решать задачу про триплеты, и захотелось услышать критики по своему коду :D. все-таки только учусь, и она я...

Разработал класс Money денежного счета, нужна критика и совет с функцией
Доброго времени суток! Очень прошу помоши, прошу бегло взглянуть на мой гавнокод и посоветовать, до чего тут можно доебатся. Мой опыт...

[Нужна критика] Как правильно копировать объект-потомок по ссылке\указателю на родителя? + Пара мелких уточнений
Захотелось провести эксперимент и создать функцию для работы с обёрткой массива на стеке. Функция должна работать как с прямыми, так и с...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Как объединить две одинаковые БД Access с разными данными
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru