Line data Source code
1 : #include <shared.hpp>
2 : #include <math.h>
3 : #include <ctime>
4 : #include <variant>
5 : #include <iostream>
6 :
7 : #define NUMBER_OF_FIELDS 5
8 : #define PERLIN_NOISE_WIDTH 10
9 : #define PERLIN_NOISE_PARAM 0.8
10 :
11 : using namespace shared;
12 :
13 : typedef std::variant<Caravan, Barbarian, BarbarianVillage, ControlPawn, City> variantElement;
14 :
15 : const FieldLevel wonderList[] = {FieldLevel::WonderEverest, FieldLevel::WonderGalapagos, FieldLevel::WonderKilimanjaro,
16 : FieldLevel::WonderMessa, FieldLevel::WonderPantanal, FieldLevel::WonderVolcanic};
17 :
18 : std::vector<CityStateEnum> stateCityField = {
19 : CityStateEnum::carthage,
20 : CityStateEnum::kaboul,
21 : CityStateEnum::mohenjoDaro,
22 : CityStateEnum::kumasi,
23 : CityStateEnum::seoul,
24 : CityStateEnum::geneva,
25 : CityStateEnum::buenosAires,
26 : CityStateEnum::bruxelles};
27 :
28 : /*!
29 : * @brief Map constructor
30 : * @param width Width of the map to instantiate
31 : * @param height Height of the map to instantiate
32 : */
33 14 : Map::Map(unsigned width, unsigned height)
34 : {
35 14 : this->height = height;
36 14 : this->width = width;
37 14 : }
38 :
39 12 : void Map::init()
40 : {
41 12 : if (isInizialize)
42 : {
43 0 : return;
44 : }
45 142 : for (unsigned i = 0; i < this->height; i++)
46 : {
47 1730 : for (unsigned j = 0; j < this->width; j++)
48 : {
49 1600 : mapOfTheGame.push_back(std::make_shared<Hexagon>());
50 : }
51 : }
52 12 : isInizialize = true;
53 : }
54 :
55 2 : void Map::setMapHeight(unsigned height)
56 : {
57 2 : this->height = height;
58 2 : }
59 :
60 2 : void Map::setMapWidth(unsigned width)
61 : {
62 2 : this->width = width;
63 2 : }
64 :
65 18 : unsigned Map::getMapHeight()
66 : {
67 18 : return this->height;
68 : }
69 :
70 117 : unsigned Map::getMapWidth()
71 : {
72 117 : return this->width;
73 : }
74 :
75 500 : bool wonderCondition(std::shared_ptr<Hexagon> hex, std::vector<FieldLevel> &remWonder)
76 : {
77 500 : return hex->getFieldLevel() != FieldLevel::Water &&
78 586 : remWonder.empty() == false &&
79 1086 : hex->hexResource == nullptr &&
80 764 : rand() % 1000 < 5;
81 : }
82 :
83 : /*!
84 : * @brief Function to generate a random map based on Perlin Noise
85 : * @param seed Seed to use for the random generation
86 : */
87 3 : void Map::generateRandomMap(int seed)
88 : {
89 :
90 3 : if (!isInizialize)
91 : {
92 3 : init();
93 : }
94 :
95 3 : PerlinNoise pn(seed);
96 3 : srand(time(NULL));
97 :
98 3 : std::vector<FieldLevel> remainingWonders(wonderList, wonderList + sizeof(wonderList) / sizeof(wonderList[0]));
99 3 : std::vector<bool> remainingCity(stateCityField.size(), true);
100 :
101 38 : for (unsigned i = 0; i < this->height; i++)
102 : {
103 535 : for (unsigned j = 0; j < this->width; j++)
104 : {
105 500 : double x = (double)j / ((double)this->width);
106 500 : double y = (double)i / ((double)this->height);
107 :
108 500 : double n = pn.noise(PERLIN_NOISE_WIDTH * x, PERLIN_NOISE_WIDTH * y, PERLIN_NOISE_PARAM);
109 500 : int field = (int)round(n * (NUMBER_OF_FIELDS + 1));
110 :
111 500 : std::array<unsigned, 2> position = {i, j};
112 :
113 500 : switch (field)
114 : {
115 0 : case 0:
116 0 : setWater(i, j);
117 0 : break;
118 8 : case 1:
119 8 : mapOfTheGame[i * this->width + j]->setFieldType(FieldLevel::Grassland);
120 8 : addResource(i, j, 2, ResourceEnum::stone);
121 8 : addResource(i, j, 2, ResourceEnum::antiquity);
122 8 : break;
123 125 : case 2:
124 125 : mapOfTheGame[i * this->width + j]->setFieldType(FieldLevel::Hill);
125 125 : addResource(i, j, 2, ResourceEnum::stone);
126 125 : addResource(i, j, 2, ResourceEnum::antiquity);
127 125 : break;
128 253 : case 3:
129 253 : mapOfTheGame[i * this->width + j]->setFieldType(FieldLevel::Forest);
130 253 : addResource(i, j, 2, ResourceEnum::stone);
131 253 : addResource(i, j, 2, ResourceEnum::antiquity);
132 253 : break;
133 99 : case 4:
134 99 : mapOfTheGame[i * this->width + j]->setFieldType(FieldLevel::Desert);
135 99 : addResource(i, j, 12, ResourceEnum::oil);
136 99 : addResource(i, j, 6, ResourceEnum::antiquity);
137 99 : break;
138 15 : case 5:
139 15 : mapOfTheGame[i * this->width + j]->setFieldType(FieldLevel::Mountain);
140 15 : addResource(i, j, 12, ResourceEnum::diamond);
141 15 : addResource(i, j, 6, ResourceEnum::stone);
142 15 : break;
143 0 : default:
144 0 : mapOfTheGame[i * this->width + j]->setFieldType(FieldLevel::Water);
145 0 : break;
146 : }
147 :
148 500 : if (i == 0 || i == this->height - 1 || j == 0 || j == this->width - 1)
149 : {
150 138 : setWater(i, j);
151 : }
152 : // 50% chance to be water
153 362 : else if (rand() % 10 < 5 && (i == 1 || i == this->height - 2 || j == 1 || j == this->width - 2))
154 : {
155 58 : setWater(i, j);
156 : }
157 : // 10% chance to be water
158 304 : else if (rand() % 10 < 1 && (i == 2 || i == this->height - 3 || j == 2 || j == this->width - 3))
159 : {
160 11 : setWater(i, j);
161 : }
162 :
163 500 : if (wonderCondition(mapOfTheGame[i * this->width + j], remainingWonders))
164 : {
165 4 : int wonderIndex = rand() % remainingWonders.size(); // remainingWonders is not empty here
166 4 : FieldLevel wonder = remainingWonders[wonderIndex];
167 4 : remainingWonders.erase(remainingWonders.begin() + wonderIndex);
168 4 : mapOfTheGame[i * this->width + j]->setFieldType(wonder);
169 : }
170 :
171 500 : if (mapOfTheGame[i * this->width + j]->hexResource != nullptr || mapOfTheGame[i * this->width + j]->getFieldLevel() == FieldLevel::Water)
172 : {
173 247 : continue;
174 : }
175 :
176 264 : if (rand() % 100 < 5)
177 : {
178 11 : std::shared_ptr<shared::BarbarianVillage> barbareVillage = std::make_shared<shared::BarbarianVillage>();
179 11 : std::shared_ptr<shared::Barbarian> barbare = std::make_shared<shared::Barbarian>();
180 11 : mapOfTheGame[i * this->width + j]->addElement(std::make_shared<variantElement>(*barbare));
181 11 : mapOfTheGame[i * this->width + j]->addElement(std::make_shared<variantElement>(*barbareVillage));
182 11 : continue;
183 11 : }
184 :
185 253 : if (rand() % 100 < 3)
186 : {
187 9 : std::vector<int> remainingIndex;
188 81 : for (unsigned k = 0; k < stateCityField.size(); k++)
189 : {
190 72 : if (remainingCity[k])
191 : {
192 62 : remainingIndex.push_back(k);
193 : }
194 : }
195 9 : if (remainingIndex.empty() == false)
196 : {
197 9 : int index = remainingIndex[rand() % remainingIndex.size()]; // remainingIndex is not empty
198 9 : std::shared_ptr<shared::City> city = std::make_shared<shared::City>(position, "not defined"); // TODO: check if we place random cities
199 9 : city->setStateCity(stateCityField[index]);
200 9 : remainingCity[index] = false;
201 9 : mapOfTheGame[i * this->width + j]->addElement(std::make_shared<variantElement>(*city));
202 9 : }
203 9 : }
204 : }
205 : }
206 3 : }
207 :
208 1000 : void Map::addResource(int x, int y, int procent, ResourceEnum resource)
209 : {
210 1000 : if (rand() % 100 < procent)
211 : {
212 42 : mapOfTheGame[x * this->width + y]->hexResource = std::make_shared<Resource>(resource);
213 : }
214 1000 : }
215 :
216 207 : void Map::setWater(int x, int y)
217 : {
218 207 : mapOfTheGame[x * this->width + y]->setFieldType(FieldLevel::Water);
219 207 : mapOfTheGame[x * this->width + y]->clearElement();
220 207 : mapOfTheGame[x * this->width + y]->hexResource = nullptr;
221 207 : }
222 :
223 : /*!
224 : * @brief Operator to access a specific hexagon of the map
225 : * @param x X coordinate of the hexagon
226 : * @param y Y coordinate of the hexagon
227 : * @return Pointer to the hexagon
228 : */
229 1383 : std::shared_ptr<Hexagon> Map::operator()(unsigned x, unsigned y)
230 : {
231 1383 : if (x < this->width && y < this->height && mapOfTheGame.size() > 0)
232 : {
233 1378 : return mapOfTheGame[y * this->width + x];
234 : }
235 : else
236 : {
237 5 : return nullptr;
238 : }
239 : }
|