#include #include #include #include #include #include #include #include #include #include #ifdef _WIN32 #include #include #endif namespace fs = std::filesystem; // Converts a Latin-1 (ISO-8859-1) string into valid UTF-8 std::string latin1ToUtf8(std::string_view latin1) { std::string utf8; utf8.reserve(latin1.size() + 16); for (unsigned char c : latin1) { if (c < 0x80) { utf8.push_back((char)c); } else { utf8.push_back((char)(0xC0 | (c >> 6))); utf8.push_back((char)(0x80 | (c & 0x3F))); } } return utf8; } struct SectionResult { std::string uf; std::string municipio; int zona = 0; int secao = 0; int local = 0; long long comparecimento = 0; long long lula = 0; long long bolsonaro = 0; long long outros = 0; long long brancos = 0; long long nulos = 0; }; struct AggregateData { std::string uf; std::string municipio; int zona = 0; long long lula = 0; long long bolsonaro = 0; long long outros = 0; long long brancos = 0; long long nulos = 0; long long comparecimento = 0; int total_secoes = 0; long long getValidos() const { return lula + bolsonaro + outros; } double getPctLula() const { long long v = getValidos(); return v > 0 ? (double)lula / v * 100.0 : 0.0; } double getPctBolsonaro() const { long long v = getValidos(); return v > 0 ? (double)bolsonaro / v * 100.0 : 0.0; } std::string getVencedor() const { if (lula > bolsonaro) return "LULA"; if (bolsonaro > lula) return "BOLSONARO"; return "EMPATE"; } }; void splitLine(const std::string& line, std::vector& fields) { fields.clear(); const char* p = line.data(); const char* end = p + line.size(); while (p < end) { const char* fStart = p; while (p < end && *p != ';') p++; std::string_view f(fStart, p - fStart); if (f.size() >= 2 && f.front() == '"' && f.back() == '"') { f.remove_prefix(1); f.remove_suffix(1); } fields.push_back(f); if (p < end && *p == ';') p++; } } std::string escapeJson(const std::string& s) { std::string out; out.reserve(s.size() + 8); for (char c : s) { if (c == '"') out += "\\\""; else if (c == '\\') out += "\\\\"; else if (c == '\b') out += "\\b"; else if (c == '\f') out += "\\f"; else if (c == '\n') out += "\\n"; else if (c == '\r') out += "\\r"; else if (c == '\t') out += "\\t"; else out += c; } return out; } int main(int argc, char* argv[]) { auto tStart = std::chrono::high_resolution_clock::now(); std::cout << "======================================================================\n"; std::cout << " MOTOR ELEICOES C++ (Contagem Completa: Votos, Brancos e Nulos)\n"; std::cout << "======================================================================\n"; fs::path executablePath; fs::path basePath; fs::path outDir; #ifdef _WIN32 // Preserve espaços e acentos independentemente da página de código do terminal. int wideArgc = 0; LPWSTR* wideArgv = CommandLineToArgvW(GetCommandLineW(), &wideArgc); if (!wideArgv || wideArgc < 1) return 1; executablePath = fs::absolute(fs::path(wideArgv[0])).parent_path(); basePath = wideArgc > 1 ? fs::path(wideArgv[1]) : executablePath.parent_path(); outDir = wideArgc > 2 ? fs::path(wideArgv[2]) : executablePath; LocalFree(wideArgv); #else executablePath = fs::absolute(fs::u8path(argv[0])).parent_path(); basePath = argc > 1 ? fs::u8path(argv[1]) : executablePath.parent_path(); outDir = argc > 2 ? fs::u8path(argv[2]) : executablePath; #endif std::vector ufs = { "AC", "AL", "AM", "AP", "BA", "CE", "DF", "ES", "GO", "MA", "MG", "MS", "MT", "PA", "PB", "PE", "PI", "PR", "RJ", "RN", "RO", "RR", "RS", "SC", "SE", "SP", "TO", "ZZ" }; // Valide todo o conjunto antes de processar ou abrir arquivos de saída. for (const auto& turno : {"1_Turno", "2_Turno"}) { for (const auto& uf : ufs) { const fs::path directory = basePath / turno / uf; bool hasCsv = false; std::error_code ec; if (fs::is_directory(directory, ec)) { for (const auto& entry : fs::directory_iterator(directory)) { if (entry.is_regular_file() && entry.path().extension() == ".csv") hasCsv = true; } } if (!hasCsv) { std::cerr << "ERRO: CSV ausente em " << directory.u8string() << ". Extraia os pacotes antes de recompilar. Dados existentes preservados.\n"; return 1; } } } // secoes[turno][chave] -> SectionResult std::map secoes[2]; std::map zonas[2]; std::map cidades[2]; std::map estados[2]; AggregateData nacional[2]; for (int t = 0; t < 2; t++) { std::string turnoPasta = (t == 0) ? "1_Turno" : "2_Turno"; std::cout << "\n>> Processando " << (t + 1) << "o Turno (" << turnoPasta << ")..." << std::endl; for (const auto& uf : ufs) { fs::path ufDir = basePath / turnoPasta / uf; if (!fs::exists(ufDir)) { std::cerr << "AVISO: Diretorio " << ufDir.string() << " nao existe!\n"; return 1; } fs::path csvFile; for (const auto& entry : fs::directory_iterator(ufDir)) { if (entry.path().extension() == ".csv") { csvFile = entry.path(); break; } } if (csvFile.empty()) { std::cerr << "AVISO: CSV para " << uf << " nao encontrado!\n"; return 1; } std::ifstream file(csvFile); if (!file.is_open()) { std::cerr << "ERRO ao abrir " << csvFile.string() << "\n"; return 1; } std::string line; if (!std::getline(file, line)) { std::cerr << "ERRO: CSV vazio. Dados existentes preservados.\n"; return 1; } std::vector fields; fields.reserve(48); while (std::getline(file, line)) { if (line.empty()) continue; splitLine(line, fields); if (fields.size() < 32) continue; if (fields[17] != "Presidente") continue; std::string sgUf(fields[10]); std::string municipio = latin1ToUtf8(fields[12]); int nrZona = std::stoi(std::string(fields[13])); int nrSecao = std::stoi(std::string(fields[14])); int nrLocal = 0; try { nrLocal = std::stoi(std::string(fields[15])); } catch (...) {} long long comparecimento = 0; try { comparecimento = std::stoll(std::string(fields[23])); } catch (...) {} std::string_view numVotavel = fields[29]; std::string nomeVotavel = latin1ToUtf8(fields[30]); long long votos = 0; try { votos = std::stoll(std::string(fields[31])); } catch (...) {} std::string secKey = sgUf + ":" + municipio + ":" + std::to_string(nrZona) + ":" + std::to_string(nrSecao); auto& sec = secoes[t][secKey]; sec.uf = sgUf; sec.municipio = municipio; sec.zona = nrZona; sec.secao = nrSecao; sec.local = nrLocal; sec.comparecimento = comparecimento; bool isLula = (numVotavel == "13" || nomeVotavel.find("LULA") != std::string::npos); bool isBolsonaro = (numVotavel == "22" || nomeVotavel.find("BOLSONARO") != std::string::npos); bool isBranco = (numVotavel == "95" || nomeVotavel == "Branco" || (fields.size() > 28 && fields[28] == "Branco")); bool isNulo = (numVotavel == "96" || nomeVotavel == "Nulo" || (fields.size() > 28 && fields[28] == "Nulo")); if (isLula) { sec.lula += votos; } else if (isBolsonaro) { sec.bolsonaro += votos; } else if (isBranco) { sec.brancos += votos; } else if (isNulo) { sec.nulos += votos; } else { sec.outros += votos; } } std::cout << " - [" << uf << "] OK\n"; } // Aggregate for (const auto& [key, sec] : secoes[t]) { std::string zonaKey = sec.uf + ":" + sec.municipio + ":" + std::to_string(sec.zona); auto& z = zonas[t][zonaKey]; z.uf = sec.uf; z.municipio = sec.municipio; z.zona = sec.zona; z.lula += sec.lula; z.bolsonaro += sec.bolsonaro; z.outros += sec.outros; z.brancos += sec.brancos; z.nulos += sec.nulos; z.comparecimento += sec.comparecimento; z.total_secoes++; std::string cidKey = sec.uf + ":" + sec.municipio; auto& c = cidades[t][cidKey]; c.uf = sec.uf; c.municipio = sec.municipio; c.lula += sec.lula; c.bolsonaro += sec.bolsonaro; c.outros += sec.outros; c.brancos += sec.brancos; c.nulos += sec.nulos; c.comparecimento += sec.comparecimento; c.total_secoes++; auto& e = estados[t][sec.uf]; e.uf = sec.uf; e.lula += sec.lula; e.bolsonaro += sec.bolsonaro; e.outros += sec.outros; e.brancos += sec.brancos; e.nulos += sec.nulos; e.comparecimento += sec.comparecimento; e.total_secoes++; nacional[t].lula += sec.lula; nacional[t].bolsonaro += sec.bolsonaro; nacional[t].outros += sec.outros; nacional[t].brancos += sec.brancos; nacional[t].nulos += sec.nulos; nacional[t].comparecimento += sec.comparecimento; nacional[t].total_secoes++; } } if (secoes[0].empty() || secoes[1].empty()) { std::cerr << "ERRO: nenhum resultado presidencial encontrado em um dos turnos. Dados existentes preservados.\n"; return 1; } struct ZeroUrna { int turno; std::string uf; std::string municipio; int zona; int secao; int local; long long votos_lula; long long votos_bolsonaro; long long comparecimento; }; std::vector zeroLula[2]; std::vector zeroBolsonaro[2]; for (int t = 0; t < 2; t++) { for (const auto& [key, sec] : secoes[t]) { if (sec.comparecimento == 0) continue; if (sec.lula == 0 && sec.bolsonaro > 0) { zeroLula[t].push_back({ t + 1, sec.uf, sec.municipio, sec.zona, sec.secao, sec.local, sec.lula, sec.bolsonaro, sec.comparecimento }); } if (sec.bolsonaro == 0 && sec.lula > 0) { zeroBolsonaro[t].push_back({ t + 1, sec.uf, sec.municipio, sec.zona, sec.secao, sec.local, sec.lula, sec.bolsonaro, sec.comparecimento }); } } } struct MudancaCidade { std::string uf; std::string municipio; long long lula_1t = 0; long long lula_2t = 0; long long bolsonaro_1t = 0; long long bolsonaro_2t = 0; long long outros_1t = 0; long long outros_2t = 0; long long brancos_1t = 0; long long brancos_2t = 0; long long nulos_1t = 0; long long nulos_2t = 0; long long validos_1t = 0; long long validos_2t = 0; long long comparecimento_1t = 0; long long comparecimento_2t = 0; double pct_lula_1t = 0.0; double pct_lula_2t = 0.0; double pct_bolsonaro_1t = 0.0; double pct_bolsonaro_2t = 0.0; long long delta_lula_votos = 0; double delta_lula_pct = 0.0; std::string vencedor_1t; std::string vencedor_2t; bool virada = false; }; std::vector mudancasCidades; for (const auto& [cidKey, c2] : cidades[1]) { auto it1 = cidades[0].find(cidKey); if (it1 == cidades[0].end()) continue; const auto& c1 = it1->second; MudancaCidade mc; mc.uf = c2.uf; mc.municipio = c2.municipio; mc.lula_1t = c1.lula; mc.lula_2t = c2.lula; mc.bolsonaro_1t = c1.bolsonaro; mc.bolsonaro_2t = c2.bolsonaro; mc.outros_1t = c1.outros; mc.outros_2t = c2.outros; mc.brancos_1t = c1.brancos; mc.brancos_2t = c2.brancos; mc.nulos_1t = c1.nulos; mc.nulos_2t = c2.nulos; mc.validos_1t = c1.getValidos(); mc.validos_2t = c2.getValidos(); mc.comparecimento_1t = c1.comparecimento; mc.comparecimento_2t = c2.comparecimento; mc.pct_lula_1t = c1.getPctLula(); mc.pct_lula_2t = c2.getPctLula(); mc.pct_bolsonaro_1t = c1.getPctBolsonaro(); mc.pct_bolsonaro_2t = c2.getPctBolsonaro(); mc.delta_lula_votos = c2.lula - c1.lula; mc.delta_lula_pct = mc.pct_lula_2t - mc.pct_lula_1t; mc.vencedor_1t = c1.getVencedor(); mc.vencedor_2t = c2.getVencedor(); mc.virada = (mc.vencedor_1t != mc.vencedor_2t); mudancasCidades.push_back(mc); } fs::path jsonOutPath = outDir / "dados_eleicoes.json"; fs::create_directories(outDir); std::ofstream out(jsonOutPath); if (!out.is_open()) return 1; out << std::fixed << std::setprecision(2); out << "{\n"; // 1. Resumo Nacional out << " \"nacional\": {\n"; for (int t = 0; t < 2; t++) { std::string tKey = (t == 0) ? "t1" : "t2"; out << " \"" << tKey << "\": {\n"; out << " \"lula\": " << nacional[t].lula << ",\n"; out << " \"bolsonaro\": " << nacional[t].bolsonaro << ",\n"; out << " \"outros\": " << nacional[t].outros << ",\n"; out << " \"brancos\": " << nacional[t].brancos << ",\n"; out << " \"nulos\": " << nacional[t].nulos << ",\n"; out << " \"validos\": " << nacional[t].getValidos() << ",\n"; out << " \"comparecimento\": " << nacional[t].comparecimento << ",\n"; out << " \"pct_lula\": " << nacional[t].getPctLula() << ",\n"; out << " \"pct_bolsonaro\": " << nacional[t].getPctBolsonaro() << ",\n"; out << " \"vencedor\": \"" << nacional[t].getVencedor() << "\"\n"; out << " }" << (t == 0 ? "," : "") << "\n"; } out << " },\n"; // 2. Estados out << " \"estados\": {\n"; bool firstUf = true; for (const auto& uf : ufs) { if (!firstUf) out << ",\n"; firstUf = false; out << " \"" << uf << "\": {\n"; out << " \"uf\": \"" << uf << "\",\n"; for (int t = 0; t < 2; t++) { std::string tKey = (t == 0) ? "t1" : "t2"; const auto& e = estados[t][uf]; out << " \"" << tKey << "\": {\n"; out << " \"lula\": " << e.lula << ",\n"; out << " \"bolsonaro\": " << e.bolsonaro << ",\n"; out << " \"outros\": " << e.outros << ",\n"; out << " \"brancos\": " << e.brancos << ",\n"; out << " \"nulos\": " << e.nulos << ",\n"; out << " \"validos\": " << e.getValidos() << ",\n"; out << " \"comparecimento\": " << e.comparecimento << ",\n"; out << " \"pct_lula\": " << e.getPctLula() << ",\n"; out << " \"pct_bolsonaro\": " << e.getPctBolsonaro() << ",\n"; out << " \"vencedor\": \"" << e.getVencedor() << "\"\n"; out << " },\n"; } const auto& e1 = estados[0][uf]; const auto& e2 = estados[1][uf]; out << " \"comp\": {\n"; out << " \"delta_lula_votos\": " << (e2.lula - e1.lula) << ",\n"; out << " \"delta_lula_pct\": " << (e2.getPctLula() - e1.getPctLula()) << ",\n"; out << " \"delta_bolsonaro_votos\": " << (e2.bolsonaro - e1.bolsonaro) << ",\n"; out << " \"delta_bolsonaro_pct\": " << (e2.getPctBolsonaro() - e1.getPctBolsonaro()) << ",\n"; out << " \"virada\": " << (e1.getVencedor() != e2.getVencedor() ? "true" : "false") << "\n"; out << " }\n"; out << " }"; } out << "\n },\n"; // 3. Cidades out << " \"cidades\": [\n"; bool firstCid = true; for (const auto& mc : mudancasCidades) { if (!firstCid) out << ",\n"; firstCid = false; out << " {\n"; out << " \"uf\": \"" << mc.uf << "\",\n"; out << " \"nome\": \"" << escapeJson(mc.municipio) << "\",\n"; out << " \"t1\": { \"lula\": " << mc.lula_1t << ", \"bolsonaro\": " << mc.bolsonaro_1t << ", \"outros\": " << mc.outros_1t << ", \"brancos\": " << mc.brancos_1t << ", \"nulos\": " << mc.nulos_1t << ", \"validos\": " << mc.validos_1t << ", \"comparecimento\": " << mc.comparecimento_1t << ", \"pct_lula\": " << mc.pct_lula_1t << ", \"pct_bolsonaro\": " << mc.pct_bolsonaro_1t << ", \"vencedor\": \"" << mc.vencedor_1t << "\" },\n"; out << " \"t2\": { \"lula\": " << mc.lula_2t << ", \"bolsonaro\": " << mc.bolsonaro_2t << ", \"outros\": " << mc.outros_2t << ", \"brancos\": " << mc.brancos_2t << ", \"nulos\": " << mc.nulos_2t << ", \"validos\": " << mc.validos_2t << ", \"comparecimento\": " << mc.comparecimento_2t << ", \"pct_lula\": " << mc.pct_lula_2t << ", \"pct_bolsonaro\": " << mc.pct_bolsonaro_2t << ", \"vencedor\": \"" << mc.vencedor_2t << "\" },\n"; out << " \"delta_lula_votos\": " << mc.delta_lula_votos << ",\n"; out << " \"delta_lula_pct\": " << mc.delta_lula_pct << ",\n"; out << " \"virada\": " << (mc.virada ? "true" : "false") << "\n"; out << " }"; } out << "\n ],\n"; // 4. Zonas out << " \"zonas\": [\n"; bool firstZona = true; for (int t = 0; t < 2; t++) { for (const auto& [k, z] : zonas[t]) { if (!firstZona) out << ",\n"; firstZona = false; out << " {\n"; out << " \"turno\": " << (t + 1) << ",\n"; out << " \"uf\": \"" << z.uf << "\",\n"; out << " \"municipio\": \"" << escapeJson(z.municipio) << "\",\n"; out << " \"zona\": " << z.zona << ",\n"; out << " \"lula\": " << z.lula << ",\n"; out << " \"bolsonaro\": " << z.bolsonaro << ",\n"; out << " \"outros\": " << z.outros << ",\n"; out << " \"brancos\": " << z.brancos << ",\n"; out << " \"nulos\": " << z.nulos << ",\n"; out << " \"validos\": " << z.getValidos() << ",\n"; out << " \"comparecimento\": " << z.comparecimento << ",\n"; out << " \"pct_lula\": " << z.getPctLula() << ",\n"; out << " \"pct_bolsonaro\": " << z.getPctBolsonaro() << ",\n"; out << " \"vencedor\": \"" << z.getVencedor() << "\",\n"; out << " \"secoes\": " << z.total_secoes << "\n"; out << " }"; } } out << "\n ],\n"; // 5. Urnas Zero out << " \"urnas_zero\": {\n"; for (int t = 0; t < 2; t++) { std::string tKey = (t == 0) ? "t1" : "t2"; out << " \"" << tKey << "\": {\n"; out << " \"lula\": [\n"; for (size_t i = 0; i < zeroLula[t].size(); i++) { const auto& u = zeroLula[t][i]; out << " { \"uf\": \"" << u.uf << "\", \"municipio\": \"" << escapeJson(u.municipio) << "\", \"zona\": " << u.zona << ", \"secao\": " << u.secao << ", \"local\": " << u.local << ", \"bolsonaro\": " << u.votos_bolsonaro << ", \"comp\": " << u.comparecimento << " }" << (i + 1 < zeroLula[t].size() ? ",\n" : "\n"); } out << " ],\n"; out << " \"bolsonaro\": [\n"; for (size_t i = 0; i < zeroBolsonaro[t].size(); i++) { const auto& u = zeroBolsonaro[t][i]; out << " { \"uf\": \"" << u.uf << "\", \"municipio\": \"" << escapeJson(u.municipio) << "\", \"zona\": " << u.zona << ", \"secao\": " << u.secao << ", \"local\": " << u.local << ", \"lula\": " << u.votos_lula << ", \"comp\": " << u.comparecimento << " }" << (i + 1 < zeroBolsonaro[t].size() ? ",\n" : "\n"); } out << " ]\n"; out << " }" << (t == 0 ? "," : "") << "\n"; } out << " }\n"; out << "}\n"; out.close(); if (out.fail()) { std::cerr << "ERRO ao gravar dados_eleicoes.json.\n"; return 1; } std::cout << "\nSalvando dados.js...\n"; fs::path jsOutPath = outDir / "dados.js"; std::ifstream inJson(jsonOutPath); std::ofstream outJs(jsOutPath); if (!inJson.is_open() || !outJs.is_open()) { std::cerr << "ERRO ao abrir arquivos para gerar dados.js.\n"; return 1; } outJs << "const ELEICOES_DATA = "; outJs << inJson.rdbuf(); outJs << ";\n"; outJs.close(); if (outJs.fail() || inJson.bad()) { std::cerr << "ERRO ao gravar dados.js.\n"; return 1; } auto tEnd = std::chrono::high_resolution_clock::now(); double totalTime = std::chrono::duration(tEnd - tStart).count(); std::cout << "Compilacao e geracao concluidas em " << totalTime << "s!\n"; return 0; }