// Cuenta comparaciones de claves completas: linear probing contra una Swiss Table de juguete, en la
// misma cantidad de casillas y con las mismas palabras. swiss_counts <palabras.txt>
#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <random>
#include <string>
#include <vector>

#include "mini_swiss.h"

namespace {

constexpr std::size_t kSlots = std::size_t{1} << 20;

void compare(const std::vector<std::string>& words, double alpha) {
    const std::size_t n = static_cast<std::size_t>(alpha * static_cast<double>(kSlots));
    CountingLinear linear(kSlots);
    MiniSwiss swiss(kSlots / MiniSwiss::kGroupSlots);
    for (std::size_t i = 0; i < n; i++) {
        linear.insert(words[i]);
        swiss.insert(words[i]);
    }
    const double total = static_cast<double>(n);
    for (std::size_t i = 0; i < n; i++) {
        linear.contains(words[i]);
        swiss.contains(words[i]);
    }
    const double linear_hit = static_cast<double>(linear.comparisons()) / total;
    const double swiss_hit = static_cast<double>(swiss.comparisons()) / total;
    const double groups_hit = static_cast<double>(swiss.groups_read()) / total;
    linear.reset();
    swiss.reset();
    for (std::size_t i = 0; i < n; i++) {
        linear.contains(words[i] + "#");  // ninguna palabra lleva #
        swiss.contains(words[i] + "#");
    }
    std::printf("%5.2f %12.2f %12.2f %8.2f %12.2f %12.4f %8.2f\n", alpha, linear_hit, swiss_hit, groups_hit,
                static_cast<double>(linear.comparisons()) / total, static_cast<double>(swiss.comparisons()) / total,
                static_cast<double>(swiss.groups_read()) / total);
}

}  // namespace

int main(int argc, char** argv) {
    if (argc < 2) {
        std::cerr << "uso: swiss_counts <palabras.txt>\n";
        return 2;
    }
    std::ifstream in(argv[1]);
    if (!in) {
        std::cerr << "no se pudo abrir " << argv[1] << "\n";
        return 2;
    }
    std::vector<std::string> words;
    std::string word;
    while (std::getline(in, word)) {
        words.push_back(word);
    }
    std::mt19937 rng(2026);
    std::shuffle(words.begin(), words.end(), rng);

    std::printf("%zu casillas. Promedios por búsqueda.\n", kSlots);
    std::printf("%5s %25s %8s %25s %8s\n", "", "--- con éxito: compara ---", "", "--- sin éxito: compara ---", "");
    std::printf("%5s %12s %12s %8s %12s %12s %8s\n", "alfa", "linear", "swiss", "grupos", "linear", "swiss", "grupos");
    for (double alpha : {0.25, 0.50, 0.70, 0.80, 0.875}) {
        compare(words, alpha);
    }
    return 0;
}
