Initial commit
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.10.0)
|
||||||
|
project(SimulateurFranceVote VERSION 0.1.0 LANGUAGES C CXX)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE
|
||||||
|
SRCS
|
||||||
|
src/*
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(SimulateurFranceVote ${SRCS})
|
||||||
+392
@@ -0,0 +1,392 @@
|
|||||||
|
#include "iostream"
|
||||||
|
#include "array"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
#include <random>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
constexpr size_t VotantsInscrits = 49339714;
|
||||||
|
std::mt19937 rng(std::random_device{}());
|
||||||
|
|
||||||
|
// Nouveau : Géographie
|
||||||
|
/*enum class Region {
|
||||||
|
// Grandes régions culturelles/politiques
|
||||||
|
ILE_DE_FRANCE, // Métropole parisienne
|
||||||
|
BASSIN_PARISIEN, // Picardie, Centre, Normandie
|
||||||
|
GRAND_EST, // Alsace, Lorraine, Champagne
|
||||||
|
HAUTS_DE_FRANCE, // Nord - ancien bassin minier
|
||||||
|
NORMANDIE,
|
||||||
|
BRETAGNE,
|
||||||
|
PAYS_DE_LOIRE,
|
||||||
|
CENTRE_VAL_LOIRE,
|
||||||
|
NOUVELLE_AQUITAINE,
|
||||||
|
OCCITANIE,
|
||||||
|
PROVENCE_ALPES_COTE_AZUR,
|
||||||
|
AUVERGNE_RHONE_ALPES,
|
||||||
|
BOURGOGNE_FRANCHE_COMTE,
|
||||||
|
CORSE,
|
||||||
|
DOM_TOM
|
||||||
|
};*/
|
||||||
|
|
||||||
|
// Ou version plus simple : typologie urbaine
|
||||||
|
enum class TypeZone {
|
||||||
|
METROPOLE_GRANDE, // Paris, Lyon, Marseille, Lille, Bordeaux
|
||||||
|
METROPOLE_MOYENNE, // 100k-500k
|
||||||
|
VILLE_MOYENNE, // 20k-100k
|
||||||
|
VILLE_PETITE, // 2k-20k
|
||||||
|
RURAL_PROFOND, // <2k
|
||||||
|
PERIURBAIN, // Couronne des métropoles
|
||||||
|
BANLIEUE_SENSIBLE // Quartiers politique de la ville + défavorisée
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Candidat
|
||||||
|
enum class Bord
|
||||||
|
{
|
||||||
|
EXTREME_GAUCHE,
|
||||||
|
GAUCHE,
|
||||||
|
CENTRE_GAUCHE,
|
||||||
|
CENTRE_DROIT,
|
||||||
|
DROITE,
|
||||||
|
EXTREME_DROITE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Candidat
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
Bord bord;
|
||||||
|
|
||||||
|
double position_economique; // -1 = collectivisme, +1 = libéralisme
|
||||||
|
double position_societale; // -1 = progressiste, +1 = conservateur
|
||||||
|
double position_europe; // -1 = fédéraliste, +1 = eurosceptique
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class TrancheAge
|
||||||
|
{
|
||||||
|
MOINS_25, // 18-24 ans
|
||||||
|
_25_34, // 25-34 ans
|
||||||
|
_35_49, // 35-49 ans
|
||||||
|
_50_64, // 50-64 ans
|
||||||
|
_65_79, // 65-79 ans
|
||||||
|
_80_PLUS // 80 ans et plus
|
||||||
|
};
|
||||||
|
|
||||||
|
//Population
|
||||||
|
enum class CategorieSocioPro
|
||||||
|
{
|
||||||
|
Agriculteurs,
|
||||||
|
ArtisansCommerçants,
|
||||||
|
CadresCadresSup,
|
||||||
|
ProfessionsIntermediaires,
|
||||||
|
EmployesQualifies,
|
||||||
|
EmployesNonQualifies,
|
||||||
|
OuvriersQualifies,
|
||||||
|
OuvriersNonQualifies,
|
||||||
|
JamaisTravaille
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class NiveauDiplome
|
||||||
|
{
|
||||||
|
AUCUN,
|
||||||
|
BREVET,
|
||||||
|
BAC,
|
||||||
|
BACPLUS
|
||||||
|
};
|
||||||
|
|
||||||
|
// Structure pour une strate de population
|
||||||
|
struct Strate {
|
||||||
|
CategorieSocioPro csp;
|
||||||
|
TrancheAge age;
|
||||||
|
NiveauDiplome diplome;
|
||||||
|
TypeZone zone;
|
||||||
|
//Region region;
|
||||||
|
double population; // nombre d'individus
|
||||||
|
double probabiliteParticipation;
|
||||||
|
|
||||||
|
// Position politique moyenne de la strate
|
||||||
|
double position_economique;
|
||||||
|
double position_societale;
|
||||||
|
double position_europe;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Result {
|
||||||
|
std::unordered_map<std::string, unsigned int> countVotePerCand;
|
||||||
|
unsigned int totalVotes = 0;
|
||||||
|
unsigned int totalAbs = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<Candidat> candidats;
|
||||||
|
std::vector<Strate> strates;
|
||||||
|
|
||||||
|
|
||||||
|
// Calcule la distance politique entre un électeur (strate) et un candidat
|
||||||
|
double distancePolitique(const Strate& strate, const Candidat& candidat) {
|
||||||
|
double diff_economic = strate.position_economique - candidat.position_economique;
|
||||||
|
double diff_societal = strate.position_societale - candidat.position_societale;
|
||||||
|
double diff_europe = strate.position_europe - candidat.position_europe;
|
||||||
|
|
||||||
|
// Pondération : le sociétal et l'europe sont plus clivants qu'avant
|
||||||
|
return std::sqrt(
|
||||||
|
0.4 * diff_economic * diff_economic +
|
||||||
|
0.4 * diff_societal * diff_societal +
|
||||||
|
0.1 * diff_europe * diff_europe
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Détermine la position politique d'une strate selon ses caractéristiques
|
||||||
|
void calculerPositionStrate(Strate& strate) {
|
||||||
|
double eco = 0.0, soc = 0.0, eu = 0.0;
|
||||||
|
|
||||||
|
// Effet CSP
|
||||||
|
switch(strate.csp) {
|
||||||
|
case CategorieSocioPro::Agriculteurs:
|
||||||
|
eco = -0.2; soc = 0.5; eu = 0.6; break;
|
||||||
|
case CategorieSocioPro::OuvriersNonQualifies:
|
||||||
|
eco = -0.4; soc = 0.4; eu = 0.5; break;
|
||||||
|
case CategorieSocioPro::CadresCadresSup:
|
||||||
|
eco = 0.4; soc = -0.3; eu = -0.1; break;
|
||||||
|
case CategorieSocioPro::EmployesQualifies:
|
||||||
|
eco = 0.0; soc = 0.1; eu = 0.2; break;
|
||||||
|
default:
|
||||||
|
eco = 0.0; soc = 0.0; eu = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Effet âge
|
||||||
|
switch(strate.age) {
|
||||||
|
case TrancheAge::MOINS_25:
|
||||||
|
soc -= 0.3; eco -= 0.2; eu -= 0.2; break;
|
||||||
|
case TrancheAge::_65_79:
|
||||||
|
soc += 0.2; break;
|
||||||
|
case TrancheAge::_80_PLUS:
|
||||||
|
soc += 0.3; eco += 0.1; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Effet diplôme
|
||||||
|
switch(strate.diplome) {
|
||||||
|
case NiveauDiplome::BACPLUS:
|
||||||
|
eco += 0.2; soc -= 0.2; eu -= 0.2; break;
|
||||||
|
case NiveauDiplome::AUCUN:
|
||||||
|
eco -= 0.1; soc += 0.3; eu += 0.3; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Effet géographique
|
||||||
|
switch(strate.zone) {
|
||||||
|
case TypeZone::METROPOLE_GRANDE:
|
||||||
|
eco += 0.3; soc -= 0.2; eu -= 0.1; break;
|
||||||
|
case TypeZone::RURAL_PROFOND:
|
||||||
|
eco -= 0.2; soc += 0.4; eu += 0.3; break;
|
||||||
|
case TypeZone::BANLIEUE_SENSIBLE:
|
||||||
|
eco -= 0.3; soc += 0.1; eu -= 0.1; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(strate.region) {
|
||||||
|
case Region::PROVENCE_ALPES_COTE_AZUR:
|
||||||
|
soc += 0.2; eu += 0.2; break;
|
||||||
|
case Region::ILE_DE_FRANCE:
|
||||||
|
eco += 0.2; soc -= 0.1; eu += 0.1; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clamping entre -1 et 1
|
||||||
|
strate.position_economique = std::max(-1.0, std::min(1.0, eco));
|
||||||
|
strate.position_societale = std::max(-1.0, std::min(1.0, soc));
|
||||||
|
strate.position_europe = std::max(-1.0, std::min(1.0, eu));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vote avec un modèle probabiliste
|
||||||
|
std::string voter(const Strate& strate, std::mt19937& gen) {
|
||||||
|
// Calcule les distances à tous les candidats
|
||||||
|
std::vector<std::pair<std::string, double>> scores;
|
||||||
|
|
||||||
|
for (const auto& candidat : candidats) {
|
||||||
|
double distance = distancePolitique(strate, candidat);
|
||||||
|
// La probabilité est inversement proportionnelle à la distance
|
||||||
|
// avec un facteur de bruit (température)
|
||||||
|
double temperature = 0.05; // Plus c'est grand, plus le vote est aléatoire
|
||||||
|
double score = std::exp(-distance / temperature);
|
||||||
|
scores.push_back({candidat.name, score});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tirage aléatoire pondéré par les scores
|
||||||
|
std::uniform_real_distribution<> dis(0, 1);
|
||||||
|
double r = dis(gen);
|
||||||
|
double cumul = 0.0;
|
||||||
|
|
||||||
|
for (const auto& [nom, score] : scores) {
|
||||||
|
cumul += score;
|
||||||
|
if (r < cumul) return nom;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scores.back().first;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initStrates()
|
||||||
|
{
|
||||||
|
struct sousStrate{
|
||||||
|
TypeZone zone;
|
||||||
|
TrancheAge age;
|
||||||
|
CategorieSocioPro csp;
|
||||||
|
double pop;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::tuple<CategorieSocioPro, TrancheAge, NiveauDiplome, TypeZone, double>> rawData = {
|
||||||
|
// Format : CSP, Age, Diplome, Zone, Region, population (en millions)
|
||||||
|
|
||||||
|
//Ile de france
|
||||||
|
{CategorieSocioPro::CadresCadresSup, TrancheAge::MOINS_25, NiveauDiplome::BACPLUS,
|
||||||
|
TypeZone::METROPOLE_GRANDE, 2.3},
|
||||||
|
|
||||||
|
{CategorieSocioPro::CadresCadresSup, TrancheAge::MOINS_25, NiveauDiplome::BACPLUS,
|
||||||
|
TypeZone::METROPOLE_GRANDE, 2.3},
|
||||||
|
|
||||||
|
|
||||||
|
{CategorieSocioPro::CadresCadresSup, TrancheAge::MOINS_25, NiveauDiplome::BACPLUS,
|
||||||
|
TypeZone::METROPOLE_GRANDE, 2.3},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
double total = 0;
|
||||||
|
for (const auto& [csp, age, diplome, zone, pop] : rawData) {
|
||||||
|
Strate s;
|
||||||
|
s.csp = csp;
|
||||||
|
s.age = age;
|
||||||
|
s.diplome = diplome;
|
||||||
|
s.zone = zone;
|
||||||
|
//s.region = region;
|
||||||
|
s.population = pop * 1e6; // Convertir en individus
|
||||||
|
total += s.population;
|
||||||
|
|
||||||
|
// Taux de participation selon âge et CSP
|
||||||
|
switch (age) {
|
||||||
|
|
||||||
|
case TrancheAge::MOINS_25: s.probabiliteParticipation = 0.58;
|
||||||
|
case TrancheAge::_25_34: s.probabiliteParticipation = 0.54;
|
||||||
|
case TrancheAge::_35_49: s.probabiliteParticipation = 0.78;
|
||||||
|
case TrancheAge::_50_64: s.probabiliteParticipation = 0.84;
|
||||||
|
case TrancheAge::_65_79: s.probabiliteParticipation = 0.88;
|
||||||
|
case TrancheAge::_80_PLUS: s.probabiliteParticipation = 0.77;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
calculerPositionStrate(s);
|
||||||
|
strates.push_back(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normaliser pour atteindre exactement VotantsInscrits
|
||||||
|
double facteur = (double)VotantsInscrits / total;
|
||||||
|
for (auto& s : strates) {
|
||||||
|
s.population *= facteur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void simulateElection()
|
||||||
|
{
|
||||||
|
Result result;
|
||||||
|
|
||||||
|
// Initialiser les compteurs pour chaque candidat
|
||||||
|
for (const auto& c : candidats) {
|
||||||
|
result.countVotePerCand[c.name] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "=== SIMULATION ÉLECTION PRÉSIDENTIELLE ===\n";
|
||||||
|
std::cout << "Population totale: " << VotantsInscrits << " inscrits\n\n";
|
||||||
|
|
||||||
|
int total_votants_simules = 0;
|
||||||
|
|
||||||
|
// Pour chaque strate
|
||||||
|
for (const auto& strate : strates) {
|
||||||
|
// Nombre de votants dans cette strate (binomial)
|
||||||
|
std::binomial_distribution<int> dist_votants(strate.population,
|
||||||
|
strate.probabiliteParticipation);
|
||||||
|
int votants = dist_votants(rng);
|
||||||
|
int abstention = (int)strate.population - votants;
|
||||||
|
|
||||||
|
result.totalAbs += abstention;
|
||||||
|
|
||||||
|
// Faire voter chaque électeur
|
||||||
|
for (int i = 0; i < votants; ++i) {
|
||||||
|
std::string vote = voter(strate, rng);
|
||||||
|
result.countVotePerCand[vote]++;
|
||||||
|
result.totalVotes++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug : affichage par strate
|
||||||
|
std::cout << "Strate: " << (int)strate.csp << "/" << (int)strate.age
|
||||||
|
<< " - Pop: " << (int)strate.population
|
||||||
|
<< " - Votants: " << votants << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Affichage des résultats
|
||||||
|
std::cout << "\n=== RÉSULTATS ===\n";
|
||||||
|
std::cout << "Total votants: " << result.totalVotes << "\n";
|
||||||
|
std::cout << "Total abstentions: " << result.totalAbs << "\n";
|
||||||
|
std::cout << "Taux participation: "
|
||||||
|
<< (100.0 * result.totalVotes / VotantsInscrits) << "%\n\n";
|
||||||
|
|
||||||
|
// Trier les candidats par nombre de voix
|
||||||
|
std::vector<std::pair<std::string, unsigned int>> sorted;
|
||||||
|
for (const auto& [nom, voix] : result.countVotePerCand) {
|
||||||
|
sorted.push_back({nom, voix});
|
||||||
|
}
|
||||||
|
std::sort(sorted.begin(), sorted.end(),
|
||||||
|
[](auto& a, auto& b) { return a.second > b.second; });
|
||||||
|
|
||||||
|
std::cout << "Scores du premier tour:\n";
|
||||||
|
for (const auto& [nom, voix] : sorted) {
|
||||||
|
double pct = 100.0 * voix / result.totalVotes;
|
||||||
|
std::cout << " " << nom << ": " << voix << " voix (" << pct << "%)\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulation second tour (top 2)
|
||||||
|
std::string qualif1 = sorted[0].first;
|
||||||
|
std::string qualif2 = sorted[1].first;
|
||||||
|
|
||||||
|
std::cout << "\n=== SECOND TOUR ===\n";
|
||||||
|
std::cout << qualif1 << " vs " << qualif2 << "\n\n";
|
||||||
|
|
||||||
|
// Re-simuler le second tour avec reports de voix
|
||||||
|
//simulerSecondTour(qualif1, qualif2, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void initCandidats()
|
||||||
|
{
|
||||||
|
candidats = {
|
||||||
|
// Extrême gauche
|
||||||
|
{"L'Arthaud", Bord::EXTREME_GAUCHE, -0.8, -0.7, -0.3},
|
||||||
|
{"Poutou", Bord::EXTREME_GAUCHE, -0.9, -0.6, -0.4},
|
||||||
|
|
||||||
|
// Gauche
|
||||||
|
{"Mélenchon", Bord::GAUCHE, -0.6, -0.4, -0.2},
|
||||||
|
{"Ruffin", Bord::GAUCHE, -0.5, -0.3, -0.1},
|
||||||
|
|
||||||
|
// Centre gauche
|
||||||
|
{"Glucksmann", Bord::CENTRE_GAUCHE, -0.2, -0.3, 0.1},
|
||||||
|
{"Rousseau", Bord::CENTRE_GAUCHE, -0.1, -0.2, 0.0},
|
||||||
|
|
||||||
|
// Centre droit
|
||||||
|
{"Macron", Bord::CENTRE_DROIT, 0.3, 0.0, 0.4},
|
||||||
|
{"Philippe", Bord::CENTRE_DROIT, 0.2, 0.1, 0.3},
|
||||||
|
|
||||||
|
// Droite
|
||||||
|
{"Wauquiez", Bord::DROITE, 0.4, 0.5, 0.2},
|
||||||
|
{"Bertrand", Bord::DROITE, 0.3, 0.4, 0.1},
|
||||||
|
|
||||||
|
// Extrême droite
|
||||||
|
{"Le Pen", Bord::EXTREME_DROITE, 0.2, 0.7, 0.8},
|
||||||
|
{"Zemmour", Bord::EXTREME_DROITE, 0.5, 0.9, 0.9}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
initCandidats();
|
||||||
|
initStrates();
|
||||||
|
simulateElection();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user