C++ is hard

This commit is contained in:
2024-07-13 15:12:05 +02:00
commit dd5fe910d8
11 changed files with 405 additions and 0 deletions
+259
View File
@@ -0,0 +1,259 @@
#include <SFML/Graphics.hpp>
#include <vector>
#include <random>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <iostream>
#include <limits>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
// Constants
const int GRID_SIZE = 256;
const float CELL_SIZE = 5.0f;
// Vegetation types
enum class CellType {
NormalForest,
DryGrass,
DenseTrees,
Water,
Burning,
Burned
};
// Simulation parameters
struct SimParams {
float p = 0.8f;
float pstart = 0.01f;
float w_speed = 0.5f;
float w_direction = 30.0f;
float water_ratio = 0.175f;
};
// Grid class
class Grid {
public:
Grid() : size(0) {}
Grid(int size, float water_ratio) : size(size), cells(size, std::vector<CellType>(size, CellType::NormalForest)) {
initializeGrid(water_ratio);
}
void initializeGrid(float water_ratio) {
// Initialize grid similar to Python version
cells[size / 2][size / 2] = CellType::Burning;
cells[size / 4][size / 4] = CellType::DryGrass;
cells[3 * size / 4][3 * size / 4] = CellType::DenseTrees;
// Implement water initialization
int num_water_cells = static_cast<int>(size * size * water_ratio);
for (int i = 0; i < num_water_cells; ++i) {
int x = rand() % size;
int y = rand() % size;
cells[y][x] = CellType::Water;
}
}
void update(float p, float pstart, float w_speed, float w_direction) {
std::vector<std::vector<CellType>> new_cells = cells;
for (int y = 0; y < size; ++y) {
for (int x = 0; x < size; ++x) {
new_cells[y][x] = updateCell(x, y, p, pstart, w_speed, w_direction);
}
}
cells = new_cells;
}
CellType getCell(int x, int y) const {
return cells[y][x];
}
private:
int size;
std::vector<std::vector<CellType>> cells;
CellType updateCell(int x, int y, float p, float pstart, float w_speed, float w_direction) {
CellType current = cells[y][x];
if (current == CellType::Burning) return CellType::Burned;
if (current == CellType::Burned || current == CellType::Water) return current;
for (const auto& neighbor : getNeighbors(x, y)) {
if (cells[neighbor.second][neighbor.first] == CellType::Burning) {
float angle = calculateAngle(x, y, neighbor.first, neighbor.second);
float directional_influence = calculateDirectionalInfluence(w_direction, angle);
float vegetation_factor = getVegetationFactor(current);
// Implement probability calculation and fire spread logic here
float adjusted_p = p * vegetation_factor * (1 + 0.1f * w_speed * directional_influence);
if (static_cast<float>(rand()) / RAND_MAX < adjusted_p) {
return CellType::Burning;
}
}
}
if (static_cast<float>(rand()) / RAND_MAX < pstart) {
return CellType::Burning;
}
return current;
}
std::vector<std::pair<int, int>> getNeighbors(int x, int y) {
std::vector<std::pair<int, int>> neighbors;
for (int dx = -1; dx <= 1; ++dx) {
for (int dy = -1; dy <= 1; ++dy) {
if (dx == 0 && dy == 0) continue;
int nx = x + dx, ny = y + dy;
if (nx >= 0 && nx < size && ny >= 0 && ny < size) {
neighbors.emplace_back(nx, ny);
}
}
}
return neighbors;
}
float calculateAngle(int x1, int y1, int x2, int y2) {
return std::atan2(y2 - y1, x2 - x1) * 180 / M_PI;
}
float calculateDirectionalInfluence(float w_direction, float angle) {
float angle_diff = std::abs(w_direction - angle);
angle_diff = std::min(angle_diff, 360.0f - angle_diff);
return 1.0f - (angle_diff / 180.0f);
}
float getVegetationFactor(CellType type) {
switch (type) {
case CellType::NormalForest: return 1.0f;
case CellType::DryGrass: return 1.5f;
case CellType::DenseTrees: return 0.5f;
case CellType::Water: return 0.0f;
default: return 1.0f;
}
}
};
// Main application class
class ForestFireSim {
public:
void getSimulationParameters() {
std::cout << "Enter simulation parameters:\n";
std::cout << "Probability of fire spread (0.0 - 1.0): ";
std::cin >> params.p;
std::cout << "Probability of spontaneous ignition (0.0 - 1.0): ";
std::cin >> params.pstart;
std::cout << "Wind speed (0.0 - 1.0): ";
std::cin >> params.w_speed;
std::cout << "Wind direction in degrees (0 - 360): ";
std::cin >> params.w_direction;
std::cout << "Water ratio (0.0 - 1.0): ";
std::cin >> params.water_ratio;
}
ForestFireSim() : window(sf::VideoMode(800, 600), "Forest Fire Simulation"),
view(window.getDefaultView()),
grid(GRID_SIZE, params.water_ratio) {
window.setView(view);
getSimulationParameters();
grid = Grid(GRID_SIZE, params.water_ratio);
}
void run() {
while (window.isOpen()) {
handleEvents();
update();
render();
}
}
void startSimulation() {
std::cout << "Press Enter to start the simulation...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.get();
run();
}
private:
sf::RenderWindow window;
Grid grid;
sf::View view;
SimParams params;
sf::Vector2f lastMousePos;
float zoomLevel = 1.0f;
void handleEvents() {
sf::Event event;
while (window.pollEvent(event)) {
if (event.type == sf::Event::Closed)
window.close();
else if (event.type == sf::Event::MouseButtonPressed) {
if (event.mouseButton.button == sf::Mouse::Left) {
lastMousePos = window.mapPixelToCoords(sf::Vector2i(event.mouseButton.x, event.mouseButton.y));
}
}
else if (event.type == sf::Event::MouseMoved) {
if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
sf::Vector2f newMousePos = window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y));
sf::Vector2f deltaPos = lastMousePos - newMousePos;
view.move(deltaPos);
lastMousePos = newMousePos;
}
}
else if (event.type == sf::Event::MouseWheelScrolled) {
if (event.mouseWheelScroll.delta > 0)
zoomLevel *= 1.1f;
else if (event.mouseWheelScroll.delta < 0)
zoomLevel /= 1.1f;
view.setSize(window.getDefaultView().getSize());
view.zoom(zoomLevel);
}
}
}
void update() {
grid.update(params.p, params.pstart, params.w_speed, params.w_direction);
}
void render() {
window.clear(sf::Color::White);
window.setView(view);
// Draw grid
for (int y = 0; y < GRID_SIZE; ++y) {
for (int x = 0; x < GRID_SIZE; ++x) {
sf::RectangleShape cell(sf::Vector2f(CELL_SIZE, CELL_SIZE));
cell.setPosition(x * CELL_SIZE, y * CELL_SIZE);
cell.setFillColor(getCellColor(grid.getCell(x, y)));
window.draw(cell);
}
}
window.display();
}
sf::Color getCellColor(CellType type) {
switch (type) {
case CellType::NormalForest: return sf::Color::Green;
case CellType::DryGrass: return sf::Color::Yellow;
case CellType::DenseTrees: return sf::Color(0, 100, 0); // Dark Green
case CellType::Water: return sf::Color::Blue;
case CellType::Burning: return sf::Color::Red;
case CellType::Burned: return sf::Color::Black;
default: return sf::Color::White;
}
}
};
int main() {
srand(static_cast<unsigned int>(time(0)));
ForestFireSim sim;
sim.startSimulation();
return 0;
}