pushbox-quest/optimizer/box-breaker.cpp
szdytom 893ebef103 extract include
Signed-off-by: szdytom <szdytom@qq.com>
2024-01-20 15:48:57 +08:00

200 lines
4.8 KiB
C++

#include <bits/stdc++.h>
#include "pushbox.h"
#include "box-solver.h"
using namespace std;
mt19937 rng(random_device{}());
uniform_real_distribution<float> d01(0, 1);
uniform_int_distribution<int> rng10(0, 9);
uniform_int_distribution<int> rngN(0, 19);
#define compiler_assume(condition) \
do { \
if (!(condition)) \
__builtin_unreachable(); \
} while (false); \
const float initial_temperature = 10;
const float initial_temperature_pv = 60;
const float termperature_delta = .97;
const int population_limit = 30;
struct Gene {
Maze m;
int w;
float T, eT;
Gene() {}
Gene(const Maze &m, int w, float T) : m(m), w(w), T(T) {}
};
inline void expand(const Maze &q, std::vector<Gene> &res, float t) {
int s = Solve::solve(q);
if (s != -1)
res.emplace_back(q, s, t);
}
inline void expandAll(Maze q, std::vector<Gene> &res, float t = initial_temperature) {
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, t);
}
}
}
}
for (int i = 0; i < 25; i++) {
compiler_assume(q.isValid());
int x = rngN(rng), y = rngN(rng);
q.flip(x, y);
if (q.isValid())
expand(q, res, t);
q.flip(x, y);
}
for (int i = 0; i < 4; ++i) {
Maze qq = q;
for (int j = 0; j < 60; ++j) {
int x = rngN(rng), y = rngN(rng);
qq.set(x, y, 1);
}
expand(qq, res, initial_temperature_pv);
}
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
int x = (rng10(rng) <= 2);
if (x)
q.flip(i, j);
}
}
for (int i = 0; i < POI_EXCEED; ++i) {
q.set(q.poi[i][0], q.poi[i][1], 1);
}
if (q.isValid())
expand(q, res, t);
};
inline void writeGene(const Gene &g, std::FILE *f) {
std::fprintf(f, "%d %lf\n", g.w, g.T);
writeMaze(g.m, f);
}
inline Gene loadGene(std::FILE *f) {
Gene g;
std::fscanf(f, "%d %f", &g.w, &g.T);
g.m = loadMaze(f);
return g;
}
inline void writePopulation(const std::vector<Gene> &p, int best_w, std::FILE *f) {
std::fprintf(f, "%d %d\n", (int)p.size(), best_w);
for (const auto &g : p) {
writeGene(g, f);
}
}
inline void loadPopulation(std::vector<Gene> &p, int &best_w, std::FILE *f) {
int pn;
std::fscanf(f, "%d %d", &pn, &best_w);
p.resize(pn);
for (int i = 0; i < pn; ++i) {
p[i] = loadGene(f);
}
}
inline void constructMain() {
std::vector<Gene> population;
int history_best_w;
auto frecord = std::fopen("current.txt", "r");
loadPopulation(population, history_best_w, frecord);
std::fclose(frecord);
for (int iter_id = 1; ; ++iter_id) {
std::vector<Gene> nxt;
for (auto &gene : population) {
expandAll(gene.m, nxt, std::max(gene.T, initial_temperature));
nxt.push_back(std::move(gene));
}
population.clear();
int best_w = 0, hbest_w = 0;
for (const auto &gene : nxt) {
best_w = std::max(best_w, gene.w);
if (gene.T > initial_temperature)
hbest_w = std::max(hbest_w, gene.w);
}
std::vector<Gene> Hpopulation, Lpopulation;
for (auto &gene : nxt) {
const bool is_ht = gene.T > initial_temperature;
const float dE = (is_ht ? hbest_w + 1 : best_w) - gene.w;
gene.eT = exp(-dE / gene.T);
if (gene.eT > d01(rng)) {
gene.T *= termperature_delta;
if (is_ht)
Hpopulation.push_back(std::move(gene));
else
Lpopulation.push_back(std::move(gene));
}
}
nxt.clear();
auto cmpET = [](const Gene &a, const Gene &b) {
return a.eT > b.eT;
};
if (Hpopulation.size() > population_limit) {
sort(Hpopulation.begin(), Hpopulation.end(), cmpET);
Hpopulation.resize(population_limit);
}
if (Lpopulation.size() > population_limit) {
sort(Lpopulation.begin(), Lpopulation.end(), cmpET);
Lpopulation.resize(population_limit);
}
population = std::move(Lpopulation);
for (auto &g : Hpopulation) {
population.push_back(std::move(g));
}
Lpopulation.clear();
Hpopulation.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");
writePopulation(population, best_w, f);
fclose(f);
}
if (true) {
printf("Iterated for %d times.\n", iter_id);
printf("Current Best=%d, History Best=%d, Population Size=%d\n"
, best_w, history_best_w, (int)population.size());
std::FILE *f = fopen("current.txt", "w");
writePopulation(population, best_w, f);
fclose(f);
}
}
}
int main() {
constructMain();
return 0;
}