aoc5/aoc5.cpp
2023-12-08 18:18:20 +01:00

254 lines
7.3 KiB
C++

// aoc5.cpp : This file contains the 'main' function. Program execution begins and ends there.
//
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <thread>
#include <chrono>
#include <atomic>
#include <algorithm>
#include <omp.h>
#define NOMINMAX
#include <windows.h>
#define NUM_THREADS 10
typedef uint64_t Numero;
struct MapEntry {
Numero src_start;
Numero src_end;
Numero dest_start;
Numero size;
};
int main() {
std::vector<MapEntry> maps[7];
std::vector<int> tovjemam;
std::ifstream ifs("input_richaj");
std::string hovno;
std::string line;
std::getline(ifs, line);
std::istringstream iss(line);
std::vector<Numero> seeds;
iss >> hovno;
Numero seed;
while (iss >> seed)
seeds.push_back(seed);
int map_idx = -1;
while (std::getline(ifs, line)) {
if (line == "") {
map_idx++;
std::getline(ifs, line);
continue;
}
std::istringstream iss(line);
MapEntry ent;
iss >> ent.dest_start >> ent.src_start >> ent.size;
ent.src_end = ent.src_start + ent.size;
maps[map_idx].push_back(ent);
}
auto start_time = std::chrono::system_clock::now();
for (map_idx = 0; map_idx < 7; ++map_idx) {
std::sort(maps[map_idx].begin(), maps[map_idx].end(), [](MapEntry& a, MapEntry& b) {
return a.src_start < b.src_start;
});
}
int num_ranges = seeds.size() / 2;
Numero min_locs[NUM_THREADS];
std::atomic_int progress[NUM_THREADS];
bool finished = false;
std::atomic_int current_range;
current_range.store(0);
std::thread progress_thread([&progress, &finished, &min_locs, num_ranges, &current_range]() {
HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = { 0, 0 };
while (true) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
SetConsoleCursorPosition(output, pos);
printf("RANGE %d/%d\n", current_range.load() + 1, num_ranges);
for (int i = 0; i < NUM_THREADS; ++i) {
int p = progress[i].load();
char pb[] = " ";
for (int c = 0; c < p; ++c)
pb[c] = '#';
printf("Thread %-2d %3d%% [%s]\n", i + 1, p, pb);
}
printf("\n\n");
if (finished)
break;
}
});
//progress_thread.detach();
omp_set_num_threads(NUM_THREADS);
//Numero thread_start[8];
Numero thread_ranges[NUM_THREADS + 1];
Numero min_loc_total = UINT64_MAX;
for (int r = 0; r < num_ranges; r++) {
Numero start = seeds[r * 2];
Numero end = start + seeds[r * 2 + 1];
Numero seed_count = end - start;
Numero seeds_per_thread = seed_count / NUM_THREADS;
//thread_ranges[0] = start;
for (int i = 0; i < NUM_THREADS; ++i) {
thread_ranges[i] = start + i * seeds_per_thread;
}
thread_ranges[NUM_THREADS] = end;
current_range.store(r);
#pragma omp parallel for
for (int t = 0; t < NUM_THREADS; ++t) {
Numero min_loc = UINT64_MAX;
Numero t_start = thread_ranges[t];
Numero t_end = thread_ranges[t + 1];
progress[t] = 0;
for (Numero seed = t_start; seed < t_end; seed++) {
Numero find_what = seed;
for (int i = 0; i < 7; ++i) {
const auto& map = maps[i];
int range_start = 0;
int range_end = map.size() - 1;
while (range_start <= range_end) {
int range_idx = range_start + (range_end - range_start) / 2;
const auto& range = map[range_idx];
if (find_what < range.src_start) {
range_end = range_idx - 1;
}
else if (find_what >= range.src_end) {
range_start = range_idx + 1;
}
else {
find_what = find_what - range.src_start + range.dest_start;
break;
}
//if (find_what < range.src_start) {
// range_end = range_idx;
// if (range_end - range_start < 2)
// break;
// continue;
//}
//else if (range.src_start + range.size <= find_what) {
// range_start = range_idx;
// if (range_end - range_start < 2)
// break;
// continue;
//}
//else {
// find_what = find_what - range.src_start + range.dest_start;
// break;
//}
}
//for (const auto& range : map) {
// if (range.src_start <= find_what && (range.src_start + range.size) > find_what) {
// find_what = find_what - range.src_start + range.dest_start;
// //skip = std::min(skip, (range.src_start + range.size) - find_what);
// break;
// }
//}
}
min_loc = std::min(min_loc, find_what);
if (seed % 1000000 == 0)
progress[t] = (float)(seed - t_start) / (float)(t_end - t_start) * 100.0f;
//printf("r %d/%d seed %llu (%.2f%%) min_loc %llu\n", r + 1, num_ranges, seed, (float)(seed - start) / (float)(end - start) * 100.0f, min_loc);
//seed += skip;
}
progress[t] = 100;
min_locs[t] = min_loc;
}
for (int i = 0; i < NUM_THREADS; ++i) {
//printf("vysledek thread %d: %llu\n", i, min_locs[i]);
min_loc_total = std::min(min_loc_total, min_locs[i]);
}
//printf("=======\mezivysledek: %llu\n", min_loc_total);
}
auto end_time = std::chrono::system_clock::now();
finished = true;
progress_thread.join();
printf("=======\nvysledek: %llu\n", min_loc_total);
auto time_total = end_time - start_time;
printf("time total: %lld s\n", std::chrono::duration_cast<std::chrono::seconds>(time_total).count());
std::cout << "Hello World!\n";
}
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
// Debug program: F5 or Debug > Start Debugging menu
// Tips for Getting Started:
// 1. Use the Solution Explorer window to add/manage files
// 2. Use the Team Explorer window to connect to source control
// 3. Use the Output window to see build output and other messages
// 4. Use the Error List window to view errors
// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file