Advertisement
Guest User

Untitled

a guest
Nov 5th, 2019
212
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.60 KB | None | 0 0
  1. #include <algorithm>
  2. #include <bitset>
  3. #include <cstdint>
  4. #include <iostream>
  5. #include <random>
  6. #include <thread>
  7. #include <set>
  8. #include <vector>
  9. #include <mutex>
  10.  
  11. /*
  12.     Positions:
  13.  
  14.         8, 10, 12
  15.         16, 18, 20
  16.         24, 26, 28
  17.  
  18.     By defining as enum respectively N, W, E, S as 0, 1, 2, 3 we get:
  19.  
  20.         N: -8, E: 2, S: 8, W: -2
  21.         0: -8, 1: -2, 2: 2, 3: 8
  22.  
  23.     To get the indices for the walls, average the numbers of the positions it
  24.     would be blocking. This gives the following indices:
  25.  
  26.         9, 11, 12, 14, 16, 17, 19, 20, 22, 24, 25, 27
  27.  
  28.     We'll construct a wall mask with a 1 bit for every position that does not
  29.     have a wall. Then if a 1 shifted by the average of the positions AND'd with
  30.     the wall mask is zero, we have hit a wall.
  31. */
  32.  
  33. enum { N = -4, W = -1, E = 1, S = 4 };
  34. static const int encoded_pos[] = { 8, 10, 12, 16, 18, 20, 24, 26, 28 };
  35. static const int wall_idx[] = { 9, 11, 12, 14, 16, 17, 19, 20, 22, 24, 25, 27 };
  36. static const int move_offsets[] = { N, W, E, S };
  37.  
  38. int do_move(uint32_t walls, int pos, int halfmove) {
  39.     int idx = pos + halfmove;
  40.     return walls & (1ull << idx) ? pos + halfmove + halfmove : pos;
  41. }
  42.  
  43. struct Maze {
  44.     uint32_t walls;
  45.     int start, end;
  46.  
  47.     Maze(uint32_t maze_id, int start, int end) {
  48.         walls = 0;
  49.         for (int i = 0; i < 12; ++i) {
  50.             if (maze_id & (1 << i)) walls |= 1 << wall_idx[i];
  51.         }
  52.         this->start = encoded_pos[start];
  53.         this->end = encoded_pos[end];
  54.     }
  55.  
  56.     uint32_t reachable() {
  57.         if (start == end) return false;
  58.  
  59.         uint32_t reached = 0;
  60.         std::vector<int> fill; fill.reserve(8); fill.push_back(start);
  61.         while (fill.size()) {
  62.             int pos = fill.back(); fill.pop_back();
  63.             if (reached & (1 << pos)) continue;
  64.             reached |= 1 << pos;
  65.             for (int m : move_offsets) fill.push_back(do_move(walls, pos, m));
  66.         }
  67.  
  68.         return reached;
  69.     }
  70.  
  71.     bool interesting() {
  72.         uint32_t reached = reachable();
  73.         if (!(reached & (1 << end))) return false;
  74.         if (std::bitset<32>(reached).count() <= 4) return false;
  75.  
  76.         int max_deg = 0;
  77.         uint32_t ends = 0;
  78.         for (int p = 0; p < 9; ++p) {
  79.             int pos = encoded_pos[p];
  80.             if (reached & (1 << pos)) {
  81.                 int deg = 0;
  82.                 for (int m : move_offsets) {
  83.                     if (pos != do_move(walls, pos, m)) ++deg;
  84.                 }
  85.                 if (deg == 1) ends |= 1 << pos;
  86.                 max_deg = std::max(deg, max_deg);
  87.             }
  88.         }
  89.  
  90.         if (max_deg <= 2 && ends != ((1u << start) | (1u << end))) return false;
  91.  
  92.         return true;
  93.     }
  94. };
  95.  
  96. std::vector<Maze> gen_valid_mazes() {
  97.     std::vector<Maze> mazes;
  98.     for (int maze_id = 0; maze_id < (1 << 12); maze_id++) {
  99.         for (int points = 0; points < 9 * 9; ++points) {
  100.             Maze maze(maze_id, points % 9, points / 9);
  101.             if (!maze.interesting()) continue;
  102.             mazes.push_back(maze);
  103.         }
  104.     }
  105.  
  106.     return mazes;
  107. }
  108.  
  109. bool is_solution(const std::vector<int>& moves, Maze maze) {
  110.     int pos = maze.start;
  111.     for (auto move : moves) {
  112.         pos = do_move(maze.walls, pos, move);
  113.         if (pos == maze.end) return true;
  114.     }
  115.  
  116.     return false;
  117. }
  118.  
  119. std::vector<int> str_to_moves(std::string str) {
  120.     std::vector<int> moves;
  121.     for (auto c : str) {
  122.         switch (c) {
  123.         case 'N': moves.push_back(N); break;
  124.         case 'E': moves.push_back(E); break;
  125.         case 'S': moves.push_back(S); break;
  126.         case 'W': moves.push_back(W); break;
  127.         }
  128.     }
  129.  
  130.     return moves;
  131. }
  132.  
  133. std::string moves_to_str(const std::vector<int>& moves) {
  134.     std::string result;
  135.     for (auto move : moves) {
  136.         if (move == N) result += "N";
  137.         else if (move == E) result += "E";
  138.         else if (move == S) result += "S";
  139.         else if (move == W) result += "W";
  140.     }
  141.     return result;
  142. }
  143.  
  144. bool solves_all(const std::vector<int>& moves, std::vector<Maze>& mazes) {
  145.     for (size_t i = 0; i < mazes.size(); ++i) {
  146.         if (!is_solution(moves, mazes[i])) {
  147.             // Bring failing maze closer to begin.
  148.             std::swap(mazes[i], mazes[i / 2]);
  149.             return false;
  150.         }
  151.     }
  152.     return true;
  153. }
  154.  
  155. int solves_n(const std::vector<int>& moves, std::vector<Maze>& mazes) {
  156.     int n = 0;
  157.     for(auto&& maze : mazes)
  158.     {
  159.         n += is_solution(moves, maze);
  160.     }
  161.     return n;
  162. }
  163.  
  164. template<class Gen>
  165. int randint(int lo, int hi, Gen& gen) {
  166.     return std::uniform_int_distribution<int>(lo, hi)(gen);
  167. }
  168.  
  169. template<class Gen>
  170. int randmove(Gen& gen) { return move_offsets[randint(0, 3, gen)]; }
  171.  
  172. constexpr double mutation_p = 0.35; // Chance to mutate.
  173. constexpr double grow_p = 0.1; // Chance to grow.
  174. constexpr double swap_p = 0.2; // Chance to swap.
  175. constexpr int num_threads = 4;
  176. constexpr int initial_length = 500;
  177.  
  178. void work()
  179. {
  180.     static std::mutex mutex;
  181.     static size_t best_seen = initial_length;
  182.     static std::set<std::vector<int>> printed;
  183.  
  184.     std::random_device rnd;
  185.     std::mt19937 rng(rnd());
  186.     std::uniform_real_distribution<double> real;
  187.     std::exponential_distribution<double> exp_big(0.5);
  188.     std::exponential_distribution<double> exp_small(2);
  189.  
  190.     std::vector<Maze> mazes = gen_valid_mazes();
  191.  
  192.     std::vector<int> moves;
  193.     while (!solves_all(moves, mazes)) {
  194.         moves.clear();
  195.         for (int m = 0; m < initial_length; m++) moves.push_back(randmove(rng));
  196.     }
  197.     while (true) {
  198.         std::vector<int> new_moves;
  199.         {
  200.             std::unique_lock lock(mutex);
  201.             new_moves = moves;
  202.         }
  203.         double p = real(rng);
  204.  
  205.         if (p < grow_p && new_moves.size() < best_seen + 10) {
  206.             int idx = randint(0, new_moves.size() - 1, rng);
  207.             new_moves.insert(new_moves.begin() + idx, randmove(rng));
  208.         }
  209.         else if (p < swap_p) {
  210.             int num_swap = std::min<int>(1 + exp_big(rng), new_moves.size() / 2);
  211.             for (int i = 0; i < num_swap; ++i) {
  212.                 int a = randint(0, new_moves.size() - 1, rng);
  213.                 int b = randint(0, new_moves.size() - 1, rng);
  214.                 std::swap(new_moves[a], new_moves[b]);
  215.             }
  216.         }
  217.         else if (p < mutation_p) {
  218.             int num_mut = std::min<int>(1 + exp_big(rng), new_moves.size());
  219.             for (int i = 0; i < num_mut; ++i) {
  220.                 int idx = randint(0, new_moves.size() - 1, rng);
  221.                 new_moves[idx] = randmove(rng);
  222.             }
  223.         }
  224.         else {
  225.             int num_shrink = std::min<int>(1 + exp_small(rng), new_moves.size());
  226.             for (int i = 0; i < num_shrink; ++i) {
  227.                 int idx = randint(0, new_moves.size() - 1, rng);
  228.                 new_moves.erase(new_moves.begin() + idx);
  229.             }
  230.         }
  231.  
  232.         if (solves_all(new_moves, mazes)) {
  233.             std::unique_lock lock(mutex);
  234.  
  235.             moves = new_moves;
  236.  
  237.             if (moves.size() <= best_seen && !printed.count(moves)) {
  238.                 std::cout << moves.size() << " " << moves_to_str(moves) << "\n";
  239.                 if (moves.size() < best_seen) {
  240.                     printed.clear(); best_seen = moves.size();
  241.                 }
  242.                 printed.insert(moves);
  243.             }
  244.         }
  245.     }
  246. }
  247.  
  248. int main(int argc, char** argv) {
  249.  
  250.     std::vector<std::thread> threads;
  251.     for (int i = 0; i < num_threads; ++i)
  252.     {
  253.         threads.emplace_back(work);
  254.     }
  255.  
  256.     for (auto&& th : threads)
  257.     {
  258.         th.join();
  259.     }
  260.  
  261.     return 0;
  262. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement