Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 5.00/3: Рейтинг темы: голосов - 3, средняя оценка - 5.00
1 / 1 / 1
Регистрация: 11.08.2016
Сообщений: 16
1

Дали задание - змейка

14.08.2019, 20:56. Показов 540. Ответов 1
Метки нет (Все метки)

Всем привет. Я новичок в C++, не так давно изучил списки, дали задание - написать змейку. Ну, я написал, не могли бы вы оценить насколько "грязный" и "костыльный" код получился?
Код
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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
#include <windows.h> //system functions
#include <algorithm> //find, next
#include <iostream> //IO
#include <conio.h> //kbhit, getch
#include <chrono> //exclude cycle delay
#include <string> //set window size correct
#include <thread> //to play sound w\o puase for main function
#include <list> //snake container
 
using namespace std; //it's small project
 
//get console handle
const HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); 
//conosole colors
enum colors { black, blue, green, cyan, red, magenta, brown, lightGray, darkGray, lightBlue, lightGreen, lightCyan, lightRed, lightMagenta, yellow, white };
//control keys
//enum keys { up = 'w', down = 's', left = 'a', right = 'd', err = -32 }; //wasd control
enum keys { up = 72, left = 75, right = 77, down = 80, err = -32 }; //arrows control
 
//system function for placing the cursor, setting a color and etc.
void setColor(int text = colors::lightGray, int background = colors::black) { SetConsoleTextAttribute(hOutput, (WORD)( ( background << 4 ) | text )); }
void setCursor(COORD xy)                                   { SetConsoleCursorPosition(hOutput, xy); }
void setCursor(short x, short y)                              { SetConsoleCursorPosition(hOutput, { x, y }); }
void drawPixel(COORD xy, char symb = 219)                   { SetConsoleCursorPosition(hOutput, xy); cout << symb; }
void drawPixel(COORD xy, colors clr, char symb = 219)       { SetConsoleCursorPosition(hOutput, xy); setColor(clr); cout << symb; }
void drawSqare(COORD corn1, COORD corn2) {
    if(corn1.X >= 0 && corn1.Y >= 0) drawPixel({ corn1.X, corn1.Y }, 201); if(corn1.X >= 0 && corn2.Y >= 0) drawPixel({ corn1.X, corn2.Y }, 200);
    if(corn2.X >= 0 && corn1.Y >= 0) drawPixel({ corn2.X, corn1.Y }, 187); if(corn2.X >= 0 && corn2.Y >= 0) drawPixel({ corn2.X, corn2.Y }, 188);
    for(short x = corn1.X + 1; x < corn2.X; x++) { if(x >= 0 && corn1.Y >= 0) drawPixel({ x, corn1.Y }, 205); if(x >= 0 && corn2.Y >= 0) drawPixel({ x, corn2.Y }, 205); }
    for(short y = corn1.Y + 1; y < corn2.Y; y++) { if(corn1.X >= 0 && y >= 0) drawPixel({ corn1.X, y }, 186); if(corn2.X >= 0 && y >= 0) drawPixel({ corn2.X, y }, 186); }
}
void setTextSize(int sizeH, int sizeW = 0) {
    CONSOLE_FONT_INFOEX cfi;
    cfi.cbSize = sizeof(cfi);
    cfi.nFont = 0;
    cfi.dwFontSize.X = sizeW;                   // Width of each character in the font
    cfi.dwFontSize.Y = sizeH;                // Height
    cfi.FontFamily = FF_DONTCARE;
    cfi.FontWeight = FW_NORMAL;
    *cfi.FaceName = NULL;
    SetCurrentConsoleFontEx(hOutput, FALSE, &cfi);
}
 
//get random short in range [from; to]
short randInt(short from, short to) { return rand() % ( to - from + 1 ) + from; }
 
//get new direction if possible
char updateDir(char lastDir) {
    char curDir = getch(); //get pressed button
    //if you use arrows firsts getch() return some symbol with code -32, 
    //so to get correct button we need call getch() again
    if(curDir == keys::err) curDir = getch();
    return //if current button is an arrow key and if it's not equal to opposite of old direction when return it, else return old direction
        (
            curDir == keys::up   && lastDir != keys::down  || curDir == keys::down  && lastDir != keys::up ||
            curDir == keys::left && lastDir != keys::right || curDir == keys::right && lastDir != keys::left
        ) ? curDir : lastDir;
}
 
//get next head postion according to current direction
COORD nextHeadPostion(COORD head, char direction) {
    switch(direction) {
    case keys::up:    head.Y--; break;
    case keys::down:  head.Y++; break;
    case keys::left:  head.X--; break;
    case keys::right: head.X++; break;
    }
    return head;
}
 
//overloaded compare for 2 COORD structs
bool operator==(COORD a, COORD b) { return a.X == b.X && a.Y == b.Y; }
 
//redraw current score
void updateScore(unsigned score) {
    setCursor(1, 0);
    setColor(colors::white);
    cout << "Score: " << score << (char)205 << (char)205 << (char)205; //erase old symbols
}
 
//redraw current timer
void updateDeathTimer(int timer, short height) {
    setCursor(1, height + 1);
    //set different colors for each of time
         if(timer < 10) setColor(colors::lightRed);
    else if(timer < 20) setColor(colors::red);
    else if(timer < 35) setColor(colors::magenta);
    else if(timer < 60) setColor(colors::lightMagenta);
    else if(timer < 80) setColor(colors::yellow);
    else if(timer < 150) setColor(colors::lightGreen);
    else setColor(colors::white);
    cout << "Till your death: " << (timer > 0 ? timer : 0);
    
    setColor(colors::white); //erase old symbols
    cout << (char)205 << (char)205;
}
 
bool playAnotherGame(short width, short height) {
    char accept;
    //cycle if player enters anything except 'y' or 'n'
    do {
        setCursor(width / 2 - 7, height / 2 + 2); //set cursor below "Again..."
        cout << ">>         "; //clear old input
        setCursor(width / 2 - 5, height / 2 + 2); //set cursor back to ">> "
        accept = tolower(cin.get()); //get the answer
    } while(accept != 'y' && accept != 'n');
    return accept == 'y';
}
 
//correctly redraw old head with body block
void redrawHead(
                char direction, char prevDirection, 
                COORD prevHead, 
                colors snakeBodyTextColor, colors snakeBodyBackgroundColor, 
                bool skeletonStyle = true, char snakeBody = 219
               ) {
    if(skeletonStyle) {
        //draw correct skeleton part based on last and current direction
        if(direction == prevDirection) drawPixel(prevHead, snakeBodyTextColor, snakeBodyBackgroundColor,
                                                 direction == keys::left || direction == keys::right ? 205 : 186);
        else switch(prevDirection) {
        case keys::left:  drawPixel(prevHead, snakeBodyTextColor, snakeBodyBackgroundColor, direction == keys::up ? 200 : 201); break;
        case keys::right: drawPixel(prevHead, snakeBodyTextColor, snakeBodyBackgroundColor, direction == keys::up ? 188 : 187); break;
        case keys::up:    drawPixel(prevHead, snakeBodyTextColor, snakeBodyBackgroundColor, direction == keys::left ? 187 : 201); break;
        case keys::down:  drawPixel(prevHead, snakeBodyTextColor, snakeBodyBackgroundColor, direction == keys::left ? 188 : 200); break;
        }
    }
    else drawPixel(prevHead, snakeBodyBackgroundColor, snakeBody); //common snake w/o skelet
 
}
 
void playTail() { Beep(900, 500); }
 
int main() {
    short width = 40, height = 40; //current field size
    COORD apple; //apple coordinates
    bool again; //tells if user ready to play another game
    //objects' colors
    colors snakeHeadClr = colors::blue; //head
    colors snakeBodyBClr = colors::lightBlue; //body background
    colors snakeBodyTClr = colors::white; //body text
    colors appleClr = colors::lightRed; //apple
    colors borderClr = colors::white; //border
    //objects' symmbols
    char snakeHead = 219;
    char snakeBody = 219;
    char appleSymb = '@';
    int scoreGoal = 120;
    //calculate cycle time
    chrono::steady_clock::time_point cycleBegin, cycleEnd;
    chrono::duration<double> elapsedTime;
    
    //yep, macros aren't good, but who cares 
    #define randCrd { randInt((short)1, width), randInt((short)1, height) }
    //set window size
    system(("mode " + to_string(width + 2) + ", " + to_string(height + 2)).c_str());
    //make text sqare-look
    setTextSize(15, 15);
do { //game loop
    char direction = keys::up, prevDir = keys::up;
    bool alive = true, won = false;
    int size = 3, deathTimerAdd = 50, deathTimer = 50;
    list<COORD> snake;
    DWORD time = 200;
    list<COORD>::iterator fnd; //needs to remeber which element should be deleted
 
    system("cls"); //clear console before game
    setColor(borderClr); //draw border
    drawSqare({ 0, 0 }, { width + 1, height + 1 });
    
    //placing snake head and apple in random places on the map
    snake.push_front(randCrd);
    apple = randCrd;
    //drawing them
    drawPixel(apple, appleClr, appleSymb);
    drawPixel(snake.front(), snakeHeadClr, snakeHead);
    //updating score
    updateScore(size);
 
    //start game till player dies or wins
    while(alive && !won) {
        cycleBegin = chrono::high_resolution_clock::now(); //getting cycle start time
        if(kbhit()) //if user hit keyboard...
            direction = updateDir(direction); //get pressed button if possible
        snake.push_front(nextHeadPostion(snake.front(), direction)); //push next head position into snake
 
        //teleport snake if it hits border
        if(snake.front().X < 1)           snake.front().X = width;
        else if(snake.front().X > width)  snake.front().X = 1;
        else if(snake.front().Y < 1)      snake.front().Y = height;
        else if(snake.front().Y > height) snake.front().Y = 1;
 
        //trying detect if snake bite it self
        //next - bc we're searching for head
        //prev - bc tail isn't more viable after move
        fnd = find(next(snake.begin()), prev(snake.end()), snake.front());
        if(fnd != prev(snake.end())) {//if it does...
            thread beep(playTail); //yep, it's kinda messy but idk how to do it another way
            beep.detach(); //play sound
            
            while(fnd != snake.end()) {
                drawPixel(*fnd, colors::black, snakeBody); //erase every drawed block
                fnd++; //get next el
                snake.erase(prev(fnd)); //erase coords in snake
            }
            size = snake.size(); //updating size and score
            updateScore(size);
        }
 
        if(snake.front() == apple) { //if player hits an apple...
            //find new coord for apple (not in the snake)
            do apple = randCrd; while(find(snake.begin(), snake.end(), apple) != snake.end());
            drawPixel(apple, appleClr, appleSymb); //draw this apple
            size += 3; //increase size by 3
            if(time - 10 > 50) time -= 10; //drop time by 10 point if possible
            updateScore(size); //update score
            deathTimer += deathTimerAdd; //add to death timer some time
            if(size >= scoreGoal) won = true; //if player get more then 'scoreGoal' (120) points, he wins
        }
        
        //if deathTimer drops below 0 when player dies
        if(deathTimer <= 0) alive = false;
        
        //redraw old snake haed - add skelet to it.
        redrawHead(direction, prevDir, *next(snake.begin()), snakeBodyTClr, snakeBodyBClr);
        //erase tail if snake were drawed completly of it's size 
        //("+ 1" bc tail is not relly a part of the snake after it's move but it's still inside of the list)
        if(snake.size() == size + 1 && alive) { drawPixel(snake.back(), colors::black, snakeBody); snake.pop_back(); }
        //draw current snake head
        drawPixel(snake.front(), snakeHeadClr, snakeHead);
 
        //decrease and update death timer
        updateDeathTimer(--deathTimer, height);
 
        //remeber previous direction for better visualisation of the snake
        prevDir = direction;
 
        //get time after cycle pass
        cycleEnd = chrono::high_resolution_clock::now();
        //calculate elapsed time
        elapsedTime = cycleEnd - cycleBegin;
        //subtrack this time of default dealy time (elapsedTime.count() returns seconds, so it needs to be multiplied by 1000)
        Sleep(time - (DWORD)(elapsedTime.count() * 1000.0));
    }
 
    //output message for player
    setColor(colors::white);
    if(alive) { //if he won
        setCursor(width / 2 - 12, height / 2);
        cout << "Wow, you won! somehow...";
    }
    else { //if he lost
        setCursor(width / 2 - 8, height / 2);
        cout << "Lol. you lose :P";
    }
 
    //waiting till player hits any other button except arrow keys
    do direction = getch();
    while(direction == keys::up || direction == keys::down || direction == keys::left || direction == keys::right || direction == keys::err);
 
    //ask player if he want to play another game or exit
    setCursor(width / 2 - 7, height / 2 + 1);
    cout << "Again? (y / n)";
    again = playAnotherGame(width, height);
 
    //repeat game if again is true
}while(again);
    return 0;
}

Старался комментировать все, что только можно (на своем корявом английском, чтобы проблем с кодировкой кириллицы не возникало и она не превращалась в краказябру).
Знаю, код получился длинноват, но я буду признателен, если вы прочтете его и высказажите свою критику к нему.
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
14.08.2019, 20:56
Ответы с готовыми решениями:

Дали задание.не могу его оформить
Описать абстрактный класс Животное. Класс должен содержать характеристики животных: название, вид,...

Дали лабораторную вот задание нужно написать код
Для заданных x, \varepsilon, вводимых с клавиатуры: a) вычислить сумму тех слагаемых, которые по...

Задание змейка
Нужно решение этой задачи Игра проходит на бесконечной поверхности После каждого корректного...

Дали Задание
Всем доброго времени суток. Вот на собеседовании дали задание. 8. Регистр «Взаиморасчеты»...

1
6738 / 4537 / 1839
Регистрация: 07.05.2019
Сообщений: 13,725
Записей в блоге: 1
14.08.2019, 22:10 2
Цитата Сообщение от Fojen Посмотреть сообщение
fnd++; //get next el
* * * * * * * * snake.erase(prev(fnd)); //erase coords in snake
snake.erase(fnd++)

Добавлено через 18 минут
Цитата Сообщение от Fojen Посмотреть сообщение
Ну, я написал, не могли бы вы оценить насколько "грязный" и "костыльный" код получился?
Код как код, ничего криминального.
Вообще, здесь не мешало бы сделать класс "Змейка" с соответствующими методами и данными. Попробуй реализовать эту игру с двумя змейками, думаю, сразу заметно станет, как это сделать.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
14.08.2019, 22:10

дали задание по exel
Привет всем! Помогите решить задание. Все мозги уже поломомал,дальше 6 пункта не могу уйти. Заранее...

Дали мне задание
Добрый день! Сразу хочу сказать спасибо автору сайта за его труд и жителям форума за столь хорошую...

Дали задание сделать проект
Здравствуйте, я учусь на первом курсе Бизнес-информатики изучаю дисциплину называемую &quot;Основы...

Дали задание сверстать по картинке
Всем доброе утро. Знакомой задали задание сделать сайт. Прислали фото и что должно получится. В...


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

Или воспользуйтесь поиском по форуму:
2
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.