Get started with this tutorial series here!

Before we can add a `Gui` to `GameStateEditor`, we’ll need to create our final class; `City`. The `City` class will contain a `Map`, and will manage the actual gameplay. Yes, finally we’ll have an actual playable game! This goes in `city.hpp`, as the header guard says.

1. ```#ifndef CITY_HPP ```
2. ```#define CITY_HPP ```
3. ` `
4. ```#include <vector> ```
5. ```#include <map> ```
6. ` `
7. ```#include "map.hpp" ```
8. ` `
9. ```class City ```
10. ```{ ```
11. ```    private: ```
12. ` `
13. ```    float currentTime; ```
14. ```    float timePerDay; ```
15. ` `
16. ```    std::vector<int> shuffledTiles; ```
17. ` `
18. ```    /* Number of residents who are not in a residential zone. */ ```
19. ```    double populationPool; ```
20. ` `
21. ```    /* Number of residents who are not currently employed but can work. */ ```
22. ```    double employmentPool; ```
23. ` `
24. ```    /* Proportion of citizens who can work. */ ```
25. ```    float propCanWork; ```
26. ` `
27. ```    /* Proportion of residents who die/give birth each day. ```
28. ```     * Estimate for death rate = 1 / (life expectancy * 360) ```
29. ```     * Current world values are 0.000055 and 0.000023, respectively */ ```
30. ```    double birthRate; ```
31. ```    double deathRate; ```
32. ` `
33. ```    double distributePool(double& pool, Tile& tile, double rate); ```
34. ` `
35. ```    public: ```
36. ` `
37. ```    Map map; ```
38. ` `
39. ```    double population; ```
40. ```    double employable; ```
41. ` `
42. ```    double residentialTax; ```
43. ```    double commercialTax; ```
44. ```    double industrialTax; ```
45. ` `
46. ```    /* Running total of city earnings (from tax etc) this month. */ ```
47. ```    double earnings; ```
48. ```    double funds; ```
49. ` `
50. ```    int day; ```
51. ` `
52. ```    City() ```
53. ```    { ```
54. ```        this->birthRate = 0.00055; ```
55. ```        this->deathRate = 0.00023; ```
56. ```        this->propCanWork = 0.50; ```
57. ```        this->populationPool = 0; ```
58. ```        this->population = populationPool; ```
59. ```        this->employmentPool = 0; ```
60. ```        this->employable = employmentPool; ```
61. ```        this->residentialTax = 0.05; ```
62. ```        this->commercialTax = 0.05; ```
63. ```        this->industrialTax = 0.05; ```
64. ```        this->earnings = 0; ```
65. ```        this->funds = 0; ```
66. ```        this->currentTime = 0.0; ```
67. ```        this->timePerDay = 1.0; ```
68. ```        this->day = 0; ```
69. ```    } ```
70. ` `
71. ```    City(std::string cityName, int tileSize, std::map<std::string, Tile>& tileAtlas) : City() ```
72. ```    { ```
73. ```        this->map.tileSize = tileSize; ```
74. ```        load(cityName, tileAtlas); ```
75. ```    } ```
76. ` `
77. ```    void load(std::string cityName, std::map<std::string, Tile>& tileAtlas); ```
78. ```    void save(std::string cityName); ```
79. ` `
80. ```    void update(float dt); ```
81. ```    void bulldoze(const Tile& tile); ```
82. ```    void shuffleTiles(); ```
83. ```    void tileChanged(); ```
84. ` `
85. ```    double getHomeless() { return this->populationPool; } ```
86. ```    double getUnemployed() { return this->employmentPool; } ```
87. ```}; ```
88. ` `
89. `#endif /* CITY_HPP */`

Quite a big class, although it is mostly declarations. `currentTime` is the real world time (in seconds) since the day updated, and `timePerDay` is the amount of real world time each day should last. We’ve set this to 1.0 in the constructor to get a 1:1 correspondence of seconds to days. The game world will update at the end of each day, so the lower this value the faster the game will go. We then have `shuffledTiles`, which has an interesting use; if we were to update the tiles by iterating over them they would update from left to right and top to bottom on the map.

As you’ll see when we program the `update` function this means that citizens will move into houses in the top left before they move into those in the bottom right. To fix this we use `shuffledTiles`, which is filled with array indices corresponding to `Tile`s in the `map`. The indices are stored in a random order and instead of iterating through the `Tile`s in `map` we iterate over `shuffledTiles`and use the indices to choose the `Tile`s in a “random” order. The order will be the same each day, but we’ll have fixed the problem!

Now for a brief explanation on how population will work. The `City` has a `populationPool`, which stores the number of citizens who do not have a home. Each `Tile` has a `population` value (as we’ve seen) that stores the number of citizens living within. So to move people into houses we decrease `populationPool` and increase `population`. The total population of the `City` is calculated as the sum of all the `Tile`s’ populations and the `populationPool`. The same applies for `employable` and `employmentPool`, but those are for commercial and industrial zones and not residential ones.

We then have `propCanWork`, which is the proportion of the population that can work and thus can be employed. Thus `employable` is approximately equal to `propCanWork * population`. Next we have `birthRate` and `deathRate`, which are set to be 100 times the real world value in order to speed up gameplay. Or you could just make the days run faster and keep them the same, of course.

We then have the three tax variables which store the proportion of income from each zone that is taxed by the `City`, and are all set to `5%` in the constructor. The calculations using them are entirely unrealistic, but they work well for the game. (We’ll see them in `update`.) Finally there’s the `City`‘s funds which are used to build new `Tile`s, the `earnings` (due to tax) amassed since last month, and the number of days that have passed since the game was started. `earnings` is moved into `funds`after every 30 days.

As for the functions, `load` and `save` will load and save the `City` from files respectively (loading and saving the `map` too), `update` will move people around, calculate income, move goods around and so on, `bulldoze` will replace the selected (and valid) area of `map` with `tile``shuffleTiles`will generate the `shuffledTiles` `std::vector``tileChanged` will update the regions and directions of tiles and should of course be called whenever a `Tile` is changed, and finally `distributePool` will be used in `update` to move citizens around. Now let’s create these function in `city.cpp`

1. ```#include <cmath> ```
2. ```#include <cstdlib> ```
3. ```#include <iostream> ```
4. ```#include <algorithm> ```
5. ```#include <vector> ```
6. ```#include <fstream> ```
7. ```#include <sstream> ```
8. ` `
9. ```#include "city.hpp" ```
10. ```#include "tile.hpp" ```
11. ` `
12. ```double City::distributePool(double& pool, Tile& tile, double rate = 0.0) ```
13. ```{ ```
14. ```    const static int moveRate = 4; ```
15. ` `
16. ```    unsigned int maxPop = tile.maxPopPerLevel * (tile.tileVariant+1); ```
17. ` `
18. ```    /* If there is room in the zone, move up to 4 people from the ```
19. ```     * pool into the zone */ ```
20. ```    if(pool > 0) ```
21. ```    { ```
22. ```        int moving = maxPop - tile.population; ```
23. ```        if(moving > moveRate) moving = moveRate; ```
24. ```        if(pool - moving < 0) moving = pool; ```
25. ```        pool -= moving; ```
26. ```        tile.population += moving; ```
27. ```    } ```
28. ` `
29. ```    /* Adjust the tile population for births and deaths */ ```
30. ```    tile.population += tile.population * rate; ```
31. ` `
32. ```    /* Move population that cannot be sustained by the tile into ```
33. ```     * the pool */ ```
34. ```    if(tile.population > maxPop) ```
35. ```    { ```
36. ```        pool += tile.population - maxPop; ```
37. ```        tile.population = maxPop; ```
38. ```    } ```
39. ` `
40. ```    return tile.population; ```
41. `}`

`distributePool` works by moving up to 4 people from the `pool` into the `tile`, and then adjusts the `tile.population` according to the `rate` passed as an argument. `rate` will be a birth rate if it’s positive and a death rate if it’s negative. Most of the code in this function is just to ensure that the right amount of people move and the overall `population` remains the same.

Next let’s look at the `bulldoze``shuffleTiles`, and `tileChanged` functions.

1. ```void City::bulldoze(const Tile& tile) ```
2. ```{ ```
3. ```    /* Replace the selected tiles on the map with the tile and ```
4. ```     * update populations etc accordingly */ ```
5. ```    for(int pos = 0; pos < this->map.width * this->map.height; ++pos) ```
6. ```    { ```
7. ```        if(this->map.selected[pos] == 1) ```
8. ```        { ```
9. ```            if(this->map.tiles[pos].tileType == TileType::RESIDENTIAL) ```
10. ```            { ```
11. ```                this->populationPool += this->map.tiles[pos].population; ```
12. ```            } ```
13. ```            else if(this->map.tiles[pos].tileType == TileType::COMMERCIAL) ```
14. ```            { ```
15. ```                this->employmentPool += this->map.tiles[pos].population; ```
16. ```            } ```
17. ```            else if(this->map.tiles[pos].tileType == TileType::INDUSTRIAL) ```
18. ```            { ```
19. ```                this->employmentPool += this->map.tiles[pos].population; ```
20. ```            } ```
21. ```            this->map.tiles[pos] = tile; ```
22. ```        } ```
23. ```    } ```
24. ` `
25. ```    return; ```
26. ```} ```
27. ` `
28. ```void City::shuffleTiles() ```
29. ```{ ```
30. ```    while(this->shuffledTiles.size() < this->map.tiles.size()) ```
31. ```    { ```
32. ```        this->shuffledTiles.push_back(0); ```
33. ```    } ```
34. ```    std::iota(shuffledTiles.begin(), shuffledTiles.end(), 1); ```
35. ```    std::random_shuffle(shuffledTiles.begin(), shuffledTiles.end()); ```
36. ` `
37. ```    return; ```
38. ```} ```
39. ` `
40. ```void City::tileChanged() ```
41. ```{ ```
42. ```    this->map.updateDirection(TileType::ROAD); ```
43. ```    this->map.findConnectedRegions( ```
44. ```    { ```
45. ```        TileType::ROAD, TileType::RESIDENTIAL, ```
46. ```        TileType::COMMERCIAL, TileType::INDUSTRIAL ```
47. ```    }, 0); ```
48. ` `
49. ```    return; ```
50. `}`

In the `bulldoze` function we iterate over every tile in the `map`. If the tile is selected then we replace it with the given tile and adjust the `populationPoo`l if the tile that was destroyed had a population. `shuffleTiles` is simple but without the aid of `std::iota` and `std::random_shuffle` it would be more complicated; first `shuffledTiles` is created to have the same number of tiles as the map, then `std::iota` is used to fill `shuffledTiles` from start to finish with increasing values (starting at 0) before `std::random_shuffle` is used to randomly move the values about. Finally `tileChanged` first updates all of the roads to face the correct way, before creating regions where roads and zones are connected. Excellent!

There are but two functions left to examine (other than `update`), `save` and `load`. Unlike `Map`, which is stored as binary, the `City` will be saved as a text file with syntax like

1. ```void City::load(std::string cityName, std::map<std::string, Tile>& tileAtlas) ```
2. ```{ ```
3. ```    int width = 0; ```
4. ```    int height = 0; ```
5. ` `
6. ```    std::ifstream inputFile(cityName + "_cfg.dat", std::ios::in); ```
7. ` `
8. ```    std::string line; ```
9. ` `
10. ```    while(std::getline(inputFile, line)) ```
11. ```    { ```
12. ```        std::istringstream lineStream(line); ```
13. ```        std::string key; ```
14. ```        if(std::getline(lineStream, key, '=')) ```
15. ```        { ```
16. ```            std::string value; ```
17. ```            if(std::getline(lineStream, value)) ```
18. ```            { ```
19. ```                if(key == "width")                  width                   = std::stoi(value); ```
20. ```                else if(key == "height")            height                  = std::stoi(value); ```
21. ```                else if(key == "day")               this->day               = std::stoi(value); ```
22. ```                else if(key == "populationPool")    this->populationPool    = std::stod(value); ```
23. ```                else if(key == "employmentPool")    this->employmentPool    = std::stod(value); ```
24. ```                else if(key == "population")        this->population        = std::stod(value); ```
25. ```                else if(key == "employable")        this->employable        = std::stod(value); ```
26. ```                else if(key == "birthRate")         this->birthRate         = std::stod(value); ```
27. ```                else if(key == "deathRate")         this->deathRate         = std::stod(value); ```
28. ```                else if(key == "residentialTax")    this->residentialTax    = std::stod(value); ```
29. ```                else if(key == "commercialTax")     this->commercialTax     = std::stod(value); ```
30. ```                else if(key == "industrialTax")     this->industrialTax     = std::stod(value); ```
31. ```                else if(key == "funds")             this->funds             = std::stod(value); ```
32. ```                else if(key == "earnings")          this->earnings          = std::stod(value); ```
33. ```            } ```
34. ```            else ```
35. ```            { ```
36. ```                std::cerr << "Error, no value for key " << key << std::endl; ```
37. ```            } ```
38. ```        } ```
39. ```    } ```
40. ` `
41. ```    inputFile.close(); ```
42. ` `
43. ```    this->map.load(cityName + "_map.dat", width, height, tileAtlas); ```
44. ```    tileChanged(); ```
45. ` `
46. ```    return; ```
47. ```} ```
48. ` `
49. ```void City::save(std::string cityName) ```
50. ```{ ```
51. ```    std::ofstream outputFile(cityName + "_cfg.dat", std::ios::out); ```
52. ` `
53. ```    outputFile << "width="              << this->map.width          << std::endl; ```
54. ```    outputFile << "height="             << this->map.height         << std::endl; ```
55. ```    outputFile << "day="                << this->day                << std::endl; ```
56. ```    outputFile << "populationPool="     << this->populationPool     << std::endl; ```
57. ```    outputFile << "employmentPool="     << this->employmentPool     << std::endl; ```
58. ```    outputFile << "population="         << this->population         << std::endl; ```
59. ```    outputFile << "employable="         << this->employable         << std::endl; ```
60. ```    outputFile << "birthRate="          << this->birthRate          << std::endl; ```
61. ```    outputFile << "deathRate="          << this->deathRate          << std::endl; ```
62. ```    outputFile << "residentialTax="     << this->residentialTax     << std::endl; ```
63. ```    outputFile << "commercialTax="      << this->commercialTax      << std::endl; ```
64. ```    outputFile << "industrialTax="      << this->industrialTax      << std::endl; ```
65. ```    outputFile << "funds="              << this->funds              << std::endl; ```
66. ```    outputFile << "earnings="           << this->earnings           << std::endl; ```
67. ` `
68. ```    outputFile.close(); ```
69. ` `
70. ```    this->map.save(cityName + "_map.dat"); ```
71. ` `
72. ```    return; ```
73. `}`

In `load`, we first open an input file stream like we did with `Map::load`, but this time we don’t mark it as a binary file. We then iterate over every line in the file, and create an `std::istringstream`from the `line`. This allows us to easily extract data from it. (`std::istringstream` is like `std::ifstream`, but for strings and not files.) The file will look like:

1. ```width=64 ```
2. ```height=64 ```
3. `population=101234`

We need to split each line up into two parts; one before the `'='`, and one after. To do this we use the `std::getline` function again but we pass an extra argument called a delimiter. A delimiter is the character that marks the end of a line, and by default that is just the newline character `'\n'`. If we set it to `'='` however then `std::getline` will put the first section into the `key` variable. By calling `std::getline` once more (with the default delimiter again) we store the second section in `value`.

All that’s left is to check `key` against the possible values and convert the `value` (which is currently an `std::string`) into the correct type using `std::stod` (string to `double`) and `std::stoi`(string to `int`). Once every line has been read we close the file and then load the map. See the `"+_map.dat"` and `"+_cfg.dat"``load` should take the name of the `City` we want to load, say `london`, and will load the files `london_map.dat` and `london_cfg.dat``save` is far simpler and just outputs the correct `key` and `value` before saving the `map`.

In the next tutorial we’ll examine the most complicated function in `City`, the `update` function.

Source code for this section

Author: Daniel Mansfield