// El adversario contra inserción y contra mergesort: la entrada mala depende del algoritmo.
#include <iomanip>
#include <iostream>
#include <vector>

#include "adversary.h"
#include "comparison_sorts.h"

namespace {

template <typename Sorter>
void play(const char* name, int n, Sorter sorter) {
    Adversary adversary(n);
    std::cout << "  " << std::left << std::setw(11) << name << std::right;
    const auto ask = [&](int i, int j) { return adversary.less(i, j); };
    sorter(n, ask);
    std::cout << std::setw(3) << adversary.count() << " comparaciones, posibles al final: " << adversary.alive()
              << ", entrada:";
    for (int value : adversary.witness()) std::cout << ' ' << value;
    std::cout << '\n';
}

}  // namespace

int main() {
    // Cómo se van acabando las permutaciones, pregunta a pregunta.
    Adversary adversary(4);
    std::cout << "n = 4, inserción. Permutaciones posibles: " << adversary.alive() << '\n';
    insertion_order(4, [&](int i, int j) {
        const bool answer = adversary.less(i, j);
        std::cout << "  ¿e" << i << " < e" << j << "? " << (answer ? "sí" : "no") << ", quedan " << adversary.alive() << '\n';
        return answer;
    });
    std::cout << '\n';

    for (int n : {5, 8}) {
        std::cout << "n = " << n << ", cota " << ceil_log2_factorial(n) << '\n';
        play("inserción", n, [](int size, auto ask) { return insertion_order(size, ask); });
        play("mergesort", n, [](int size, auto ask) { return merge_order(size, ask); });
    }
}
