#include #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 int species_limit = 8; 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; char name[SPECIES_NAME_LEN + 1]; int stable_age, age, tactic; Species() : population(), best_w(-1), name{"NULL"}, stable_age(0), age(0), tactic(-1) {} void tick() { age += 1; stable_age += 1; } int size() const { return population.size(); } bool empty() const { return population.empty(); } bool operator<(const Species &o) const { return best_w < o.best_w; } }; 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 %s %d %d %d\n", (int)s.size(), s.best_w, s.name , s.stable_age, 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 %s %d %d %d", &n, &res.best_w, res.name , &res.stable_age, &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'); } } thread_local 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 mutationRowCl(Species &res, const Gene &sc, int rep = 1) { Gene ac = sc; std::uniform_int_distribution rngRow(0, N - rep); int r = rngRow(rng); for (int i = 0; i < rep; ++i) { for (int j = 0; j < N; ++j) ac.m.set(r + i, j, 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, int rep = 1) { Gene ac = sc; std::uniform_int_distribution rngCol(0, N - rep); int c = rngCol(rng); for (int i = 0; i < rep; ++i) { for (int j = 0; j < N; ++j) ac.m.set(j, c + i, 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; const int sz2 = sz / 2; int cx = rng0N(rng), cy = rng0N(rng); 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, 4); Species res; randomName(SPECIES_NAME_LEN, res.name); do { int tactic = rngTacs(rng); res.tactic = tactic; switch (tactic) { case 0: mutationRandomHole(res, sc.population[0], 60); break; case 1: mutationRowCl(res, sc.population[0], 2); break; case 2: mutationColCl(res, sc.population[0], 2); break; case 3: mutationSqrCl(res, sc.population[0], 3); break; case 4: mutationSqrCl(res, sc.population[0], 5); break; } } while (res.empty()); 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(); int ori_best_w = s.best_w; for (const auto &g : nxt) { s.best_w = std::max(s.best_w, g.w); } if (ori_best_w != s.best_w) s.stable_age = 0; 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; # pragma omp parallel for num_threads(8) for (auto &s : biosphere) inherit(s); for (auto &s : biosphere) best_w = std::max(best_w, s.best_w); std::vector Hnxt, Lnxt; for (auto &s : biosphere) { if (s.stable_age <= std::max(5, 15 * s.best_w / best_w) || s.best_w == best_w) { if (s.best_w < best_w || s.age <= 35) 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) biosphere.push_back(std::move(s)); Hnxt.clear(); for (auto &s : biosphere) s.tick(); 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 stable=%d age=%d.\n", s.name , s.tactic, s.best_w, s.stable_age, s.age); } std::FILE *f = fopen("current.txt", "w"); writeBiosphere(biosphere, best_w, f); fclose(f); } } return 0; }