Skip to content

Commit ef9a598

Browse files
committed
Added source code
1 parent 4937e51 commit ef9a598

File tree

8 files changed

+476
-0
lines changed

8 files changed

+476
-0
lines changed

Snake.cpp

+284
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
#include "Snake.h"
2+
3+
#include "Utils.h"
4+
#include <conio.h>
5+
6+
#define H_FIELD 25
7+
#define W_FIELD 50
8+
9+
#define FRUIT '@'
10+
#define BODY ' '
11+
#define H_EDGE '='
12+
#define V_EDGE '|'
13+
14+
#include "Utils.h"
15+
16+
Snake::Snake() {
17+
18+
initSnake();
19+
}
20+
21+
void Snake::initSnake() {
22+
23+
Utils::showConsoleCursor(false);
24+
25+
if (!Utils::genRandomInt(0, 1)) {
26+
27+
m_vx = V_NUL;
28+
m_vy = Utils::genRandomInt(0, 1) ? V_POS : V_NEG;
29+
}
30+
else {
31+
32+
m_vy = V_NUL;
33+
m_vx = Utils::genRandomInt(0, 1) ? V_POS : V_NEG;
34+
}
35+
36+
m_fruit = {};
37+
m_countFruit = {};
38+
39+
m_body.clear();
40+
41+
// Vector of field, borders are excluded
42+
for (int y = 1; y < H_FIELD - 1; y++) {
43+
44+
for (int x = 1; x < W_FIELD - 1; x++)
45+
m_field.push_back({x, y});
46+
}
47+
48+
genBody();
49+
genFruit();
50+
}
51+
52+
void Snake::run() {
53+
54+
while (isRunning()) {
55+
56+
readUserInput();
57+
genFruit();
58+
updateBodyCoord();
59+
drawField();
60+
61+
// if (m_deltaT)
62+
// Sleep(m_deltaT);
63+
}
64+
}
65+
66+
bool Snake::isRunning() {
67+
return m_run;
68+
}
69+
70+
void Snake::readUserInput() {
71+
72+
if (_kbhit()) {
73+
74+
switch(_getch()) {
75+
76+
case KEY_W:
77+
78+
setYDirection(V_NEG);
79+
setXDirection(V_NUL);
80+
break;
81+
82+
case KEY_S:
83+
84+
setYDirection(V_POS);
85+
setXDirection(V_NUL);
86+
break;
87+
88+
89+
case KEY_A:
90+
91+
setXDirection(V_NEG);
92+
setYDirection(V_NUL);
93+
break;
94+
95+
case KEY_D:
96+
97+
setXDirection(V_POS);
98+
setYDirection(V_NUL);
99+
break;
100+
}
101+
}
102+
}
103+
104+
void Snake::setXDirection(V vel) {
105+
106+
m_vx = vel;
107+
}
108+
109+
void Snake::setYDirection(V vel) {
110+
111+
m_vy = vel;
112+
}
113+
114+
void Snake::drawField() {
115+
116+
system("cls");
117+
118+
for (int y = 0; y < H_FIELD; y++) {
119+
120+
for (int x = 0; x < W_FIELD; x++) {
121+
122+
if (y == 0 || y == H_FIELD - 1)
123+
Utils::drawElement(H_EDGE);
124+
else {
125+
126+
if (x == 0 || x == W_FIELD - 1)
127+
Utils::drawElement(V_EDGE);
128+
else {
129+
130+
// Here i am in the field
131+
132+
// Spawn or eat fruit
133+
if (checkFruit(x, y)) {
134+
135+
// Spawn
136+
if (!checkHead(x, y)) {
137+
138+
if (m_fruit)
139+
Utils::drawElement(FRUIT, RED_TXT);
140+
else
141+
Utils::drawElement(' ');
142+
}
143+
// Eat
144+
else {
145+
146+
// Generate new fruit coordinates and spawn at next iteration
147+
m_fruit = false;
148+
m_countFruit++;
149+
150+
// Increase speed
151+
// if (m_deltaT)
152+
// m_deltaT - m_countFruit * 5;
153+
154+
// Draw head
155+
Utils::drawElement(BODY, BACKGROUND_GREEN);
156+
}
157+
158+
}
159+
// Color actual snake positions
160+
else if (checkBody(x, y)) {
161+
162+
if (checkHead(x, y))
163+
Utils::drawElement(BODY, m_run ? BACKGROUND_GREEN : BACKGROUND_RED);
164+
else
165+
Utils::drawElement(BODY, HIGHLIGHT_TXT);
166+
}
167+
else
168+
Utils::drawElement(' ');
169+
}
170+
}
171+
if (x == W_FIELD - 1)
172+
std::cout << "" << std::endl;
173+
}
174+
}
175+
176+
std::cout << "" << std::endl;
177+
178+
// Lose condition
179+
if (!m_run) {
180+
181+
Utils::showConsoleCursor(true);
182+
std::cout << "Ouch!" << "\n";
183+
184+
std::string choice = "";
185+
while (choice != "y" && choice != "n") {
186+
187+
std::cout << "Do you wanna play again (y/n)? ";
188+
std::cin >> choice;
189+
190+
if (choice == "y") {
191+
192+
m_run = true;
193+
initSnake();
194+
}
195+
else if (choice == "n")
196+
m_run = false;
197+
}
198+
}
199+
}
200+
201+
void Snake::checkEdges() {
202+
203+
if (m_y < 1)
204+
m_y = H_FIELD - 2;
205+
else if (m_y > H_FIELD - 2)
206+
m_y = 1;
207+
208+
if (m_x < 1)
209+
m_x = W_FIELD - 2;
210+
else if (m_x > W_FIELD - 2)
211+
m_x = 1;
212+
}
213+
214+
bool Snake::checkHead(int x, int y) {
215+
return (x == m_x && y == m_y);
216+
}
217+
218+
bool Snake::checkFruit(int x, int y) {
219+
return (x == m_xFruit && y == m_yFruit);
220+
}
221+
222+
bool Snake::checkBody(int x, int y) {
223+
224+
std::pair<int, int> actualCoord(x, y);
225+
if (std::find(m_body.begin(), m_body.end(), actualCoord) != m_body.end())
226+
return true;
227+
else
228+
return false;
229+
}
230+
231+
void Snake::updateBodyCoord() {
232+
233+
m_x = m_x + m_vx * m_xT;
234+
m_y = m_y + m_vy * m_yT;
235+
236+
checkEdges();
237+
238+
std::pair<int, int> actualCoord(m_x, m_y);
239+
240+
if (find(m_body.begin(), m_body.end(), actualCoord) != m_body.end())
241+
m_run = false;
242+
243+
m_body.push_back(actualCoord);
244+
245+
/* I want to keep m_countFruit + 1 coordinates (head)
246+
Add the new head coordinate and remove tail coordinate
247+
*/
248+
while (m_body.size() > (m_countFruit + 1))
249+
m_body.erase(m_body.begin());
250+
}
251+
252+
void Snake::genBody() {
253+
254+
int randomIndex = Utils::genRandomInt(0, m_field.size() - 1);
255+
m_x = m_field.at(randomIndex).first;
256+
m_y = m_field.at(randomIndex).second;
257+
258+
m_body.push_back(std::pair<int, int>{m_x, m_y});
259+
}
260+
261+
void Snake::genFruit() {
262+
263+
if (!m_fruit) {
264+
265+
// Need to do m_field - m_body and pick a random pair from the result
266+
std::sort(m_field.begin(), m_field.end());
267+
268+
// i do not want the m_body to be sorted
269+
std::vector<std::pair<int, int>> m_bodyCopy = m_body;
270+
std::sort(m_bodyCopy.begin(), m_bodyCopy.end());
271+
272+
std::vector<std::pair<int, int>> availableFruitPos;
273+
std::set_difference(
274+
m_field.begin(), m_field.end(), m_bodyCopy.begin(), m_bodyCopy.end(),
275+
std::back_inserter( availableFruitPos )
276+
);
277+
278+
int randomIndex = Utils::genRandomInt(0, availableFruitPos.size() - 1);
279+
m_xFruit = availableFruitPos.at(randomIndex).first;
280+
m_yFruit = availableFruitPos.at(randomIndex).second;
281+
282+
m_fruit = true;
283+
}
284+
}

Snake.exe

252 KB
Binary file not shown.

Snake.h

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#ifndef Snake_H
2+
#define Snake_H
3+
4+
#include <algorithm>
5+
#include <utility>
6+
#include <vector>
7+
8+
typedef enum {
9+
10+
V_NEG = -1,
11+
V_NUL,
12+
V_POS
13+
} V;
14+
15+
class Snake {
16+
17+
public:
18+
19+
Snake();
20+
21+
void run();
22+
23+
private:
24+
25+
void initSnake();
26+
27+
// User intervention
28+
void readUserInput();
29+
void setXDirection(V vel);
30+
void setYDirection(V vel);
31+
32+
bool isRunning();
33+
void drawField();
34+
void checkEdges();
35+
bool checkFruit(int x, int y);
36+
bool checkHead(int x, int y);
37+
bool checkBody(int x, int y);
38+
void updateBodyCoord();
39+
40+
void genFruit();
41+
void genBody();
42+
43+
bool m_run = true;
44+
45+
int m_deltaT = 50;
46+
47+
// Law of motion's components
48+
int m_x{};
49+
int m_y{};
50+
int m_xT = 1;
51+
int m_yT = 1;
52+
V m_vx{};
53+
V m_vy{};
54+
55+
bool m_fruit{};
56+
int m_xFruit{};
57+
int m_yFruit{};
58+
int m_countFruit{};
59+
60+
// Snake's body
61+
std::vector<std::pair<int, int>> m_body;
62+
63+
std::vector<std::pair<int, int>> m_field;
64+
};
65+
66+
#endif

0 commit comments

Comments
 (0)