#include #include "pushbox.h" #include "box-solver.h" std::mt19937 rng(std::random_device{}()); #define compiler_assume(condition) \ do { \ if (!(condition)) \ __builtin_unreachable(); \ } while (false); \ const float temperature_initial = 60; const float temperature_low = 10; const float temperature_delta = .97; const int species_limit = 5; const int population_limit = 10; const int SPECIES_NAME_LEN = 4; struct Gene { Maze m; int w; Gene() {} Gene(const Maze &m, int w) : m(m), w(w) {} }; struct Species { std::vector population; int best_w; float T, eT; char name[SPECIES_NAME_LEN + 1]; int age, tactic; Species() : population(), best_w(-1), T(1.), eT(-1), name{"NULL"}, age(0) {} int size() const { return population.size(); } bool empty() const { return population.empty(); } bool operator<(const Species &o) const { return eT < o.eT; } }; inline void writeGene(const Gene &g, std::FILE *f) { std::fprintf(f, "%d\n", g.w); writeMaze(g.m, f); } inline Gene loadGene(std::FILE *f) { Gene g; std::fscanf(f, "%d", &g.w); g.m = loadMaze(f); return g; } inline void writeSpecies(const Species &s, std::FILE *f) { std::fprintf(f, "%d %d %.12f %s %d %d\n", s.size(), s.best_w, s.T, s.name, s.age, s.tactic); for (const auto &g : s.population) { writeGene(g, f); } } inline Species loadSpecies(std::FILE *f) { Species res; int n; std::fscanf(f, "%d %d %f %s %d %d", &n, &res.best_w, &res.T, res.name, &res.age, &res.tactic); res.population.reserve(n); for (int i = 0; i < n; ++i) { res.population.push_back(loadGene(f)); } return res; } inline void loadBiosphere(std::vector &species, int &best_w, std::FILE *f) { int n; std::fscanf(f, "%d %d", &n, &best_w); species.reserve(n); for (int i = 0; i < n; ++i) species.push_back(loadSpecies(f)); } inline void writeBiosphere(const std::vector &species, int &best_w, std::FILE *f) { int n = species.size(); std::fprintf(f, "%d %d\n", n, best_w); for (int i = 0; i < n; ++i) writeSpecies(species[i], f); } inline void randomName(int n, char res[]) { static std::uniform_int_distribution ld(0, 35); for (int i = 0; i < n; ++i) { int c = ld(rng); res[i] = (c < 26 ? c + 'a' : c - 26 + '0'); } } static std::uniform_int_distribution rng0N(0, N - 1); inline void mutationRandomHole(Species &res, const Gene &sc, int clear_cnt) { Gene ac = sc; for (int i = 0; i < clear_cnt; ++i) { int x = rng0N(rng), y = rng0N(rng); ac.m.set(x, y, SQR_SPACE); } ac.w = Solve::solve(ac.m); res.best_w = ac.w; res.population.push_back(std::move(ac)); } inline void mutationReselectPOI(Species &res, const Gene &sc) { Gene ac = sc; for (int i = 0; i < POI_EXCEED; ++i) { int x = rng0N(rng), y = rng0N(rng); while (true) { bool flag = false; for (int j = 0; j < POI_EXCEED; ++j) flag |= (x == ac.m.poi[j][0] && y == ac.m.poi[j][1]); if (!flag) break; x = rng0N(rng); y = rng0N(rng); } ac.m.poi[i][0] = x; ac.m.poi[i][1] = y; for (int dx = -1; dx <= 1; ++dx) { for (int dy = -1; dy <= 1; ++dy) { int xx = x + dx, yy = y + dy; if (0 <= xx && xx < N && 0 <= yy && yy < N) ac.m.set(xx, yy, SQR_SPACE); } } } ac.w = Solve::solve(ac.m); if (ac.w != -1) { res.best_w = ac.w; res.population.push_back(std::move(ac)); } } inline void mutationLineCl(Species &res, const Gene &sc) { Gene ac = sc; int r = rng0N(rng); for (int i = 0; i < N; ++i) { ac.m.set(r, i, SQR_SPACE); } ac.w = Solve::solve(ac.m); res.best_w = ac.w; res.population.push_back(std::move(ac)); } inline void mutationColCl(Species &res, const Gene &sc) { Gene ac = sc; int c = rng0N(rng); for (int i = 0; i < N; ++i) { ac.m.set(i, c, SQR_SPACE); } ac.w = Solve::solve(ac.m); res.best_w = ac.w; res.population.push_back(std::move(ac)); } inline void mutationSqrCl(Species &res, const Gene &sc, int sz) { Gene ac = sc; int cx = rng0N(rng), cy = rng0N(rng); int sz2 = sz / 2; for (int dx = -sz2; dx <= sz2; ++dx) { for (int dy = -sz2; dy <= sz2; ++dy) { int xx = cx + dx, yy = cy + dy; if (0 <= xx && xx < N && 0 <= yy && yy < N) ac.m.set(xx, yy, SQR_SPACE); } } ac.w = Solve::solve(ac.m); res.best_w = ac.w; res.population.push_back(std::move(ac)); } inline Species mutation(const Species &sc) { static std::uniform_int_distribution rngTacs(0, 6); Species res; randomName(SPECIES_NAME_LEN, res.name); res.T = temperature_initial; do { int tactic = rngTacs(rng); res.tactic = tactic; switch (tactic) { case 0: mutationRandomHole(res, sc.population[0], 60); break; case 1: mutationRandomHole(res, sc.population[0], 40); break; case 2: mutationReselectPOI(res, sc.population[0]); break; case 3: mutationLineCl(res, sc.population[0]); break; case 4: mutationColCl(res, sc.population[0]); break; case 5: mutationSqrCl(res, sc.population[0], 3); mutationSqrCl(res, sc.population[0], 3); break; case 6: mutationSqrCl(res, sc.population[0], 5); break; } } while (res.size() == 0); return res; } inline void expand(const Maze &q, std::vector &res) { int s = Solve::solve(q); if (s != -1) res.emplace_back(q, s); } inline void inheritGene(Maze q, std::vector &res) { for (int i = 0; i < POI_EXCEED; ++i) { for (int j : {0, 1}) { for (int d : {-1, 1}) { compiler_assume(q.poi[i][j] >= 0 && q.poi[i][j] < N); q.poi[i][j] += d; if (0 <= q.poi[i][j] && q.poi[i][j] < N) { bool flag = false; for (int k = 0; k < POI_EXCEED; ++k) flag |= (q.poi[i][0] == q.poi[k][0] && q.poi[i][1] == q.poi[k][1]); if (!flag) expand(q, res); } q.poi[i][j] -= d; } } } for (int i = 0; i < 25; i++) { compiler_assume(q.isValid()); int x = rng0N(rng), y = rng0N(rng); q.flip(x, y); if (q.isValid()) expand(q, res); q.flip(x, y); } } inline void inherit(Species &s) { std::vector nxt; for (auto &g : s.population) { inheritGene(g.m, nxt); nxt.push_back(std::move(g)); } s.population.clear(); for (const auto &g : nxt) { s.best_w = std::max(s.best_w, g.w); } for (auto &g : nxt) { if (g.w == s.best_w) s.population.push_back(std::move(g)); } nxt.clear(); std::shuffle(s.population.begin(), s.population.end(), rng); if (s.population.size() > population_limit) s.population.resize(population_limit); } int main() { std::vector biosphere; int history_best_w; auto frecord = std::fopen("current.txt", "r"); loadBiosphere(biosphere, history_best_w, frecord); std::fclose(frecord); std::uniform_real_distribution d01(0, 1); for (int iter_id = 1; ; ++iter_id) { int best_w = 0, hbest_w = 0; for (auto &s : biosphere) { inherit(s); best_w = std::max(best_w, s.best_w); if (s.T > temperature_low) hbest_w = std::max(hbest_w, s.best_w); } std::vector Hnxt, Lnxt; for (auto &s : biosphere) { const bool is_ht = s.T > temperature_low; const float dE = (is_ht ? hbest_w : best_w) - s.best_w; s.eT = exp(-dE / s.T); if (s.eT >= d01(rng) || s.age <= 15) { if (is_ht) Hnxt.push_back(std::move(s)); else Lnxt.push_back(std::move(s)); } } biosphere.clear(); if (Lnxt.size()) { biosphere.push_back(std::move(*std::max_element(Lnxt.begin(), Lnxt.end()))); } while (Hnxt.size() + biosphere.size() < species_limit) { if (biosphere.size()) { Hnxt.push_back(mutation(biosphere[0])); } else { int sc = std::uniform_int_distribution{0, (int)Hnxt.size() - 1}(rng); Hnxt.push_back(mutation(Hnxt[sc])); } } for (auto &s : Hnxt) { s.age += 1; s.T = std::max(s.T * temperature_delta, temperature_low); biosphere.push_back(std::move(s)); } Hnxt.clear(); bool broke_record = best_w > history_best_w; if (broke_record) { history_best_w = best_w; printf("New Record: %d!\n", best_w); std::FILE *f = fopen("best.txt", "w"); writeBiosphere(biosphere, best_w, f); fclose(f); } if (true) { printf("Iterated for %d times.\n", iter_id); printf("Current Best=%d, History Best=%d, Species:\n", best_w, history_best_w); for (auto &s : biosphere) { printf(" - %s[%d]: best=%d T=%.3f age=%d.\n", s.name, s.tactic, s.best_w, s.T, s.age); } std::FILE *f = fopen("current.txt", "w"); writeBiosphere(biosphere, best_w, f); fclose(f); } } return 0; }