Advertisement
Guest User

solver.cpp

a guest
Jun 16th, 2013
115
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 11.39 KB | None | 0 0
  1. #include "Configuration.h"
  2. #include "assert.h"
  3. #include "time.h"
  4. #include <algorithm>
  5. #include <deque>
  6. #include <iostream>
  7. #include <fstream>
  8. #include <set>
  9. #include <string>
  10. #include <utility>
  11. #include <vector>
  12. #include <map>
  13. #include <memory>
  14. #include <unistd.h>  // for alarm()
  15.  
  16. static const int DR[8] = { -1,  0, +1,  0, -1, +1, +1, -1 };
  17. static const int DC[8] = {  0, -1,  0, +1, -1, -1, +1, +1 };
  18.  
  19. struct Placement
  20. {
  21.     unsigned index, dirs;
  22. };
  23.  
  24. static unsigned bitcount(unsigned mask)
  25. {
  26.     unsigned res = 0;
  27.     while (mask != 0) ++res, mask &= mask - 1;
  28.     return res;
  29. }
  30.  
  31. template<typename CardIndex>
  32. static void write_output( Configuration &config, std::string &output_path,
  33.     int best_score, const std::vector<CardIndex> &best_board )
  34. {
  35.     std::ofstream ofs;
  36.     if (output_path != "-" && !(ofs.open(output_path), ofs))
  37.     {
  38.         std::cerr << "Failed to open output file `" << output_path << "`!\n";
  39.         output_path = "-";  // write to standard output instead
  40.     }
  41.     std::ostream &os = output_path == "-" ? std::cout : ofs;
  42.     os << "Score:" << best_score << '\n';
  43.     for (int r = config.board_height - 1; r >= 0; --r)
  44.     {
  45.         for (int c = 0; c < (int)config.board_width; ++c)
  46.         {
  47.             unsigned i = config.board_width*r + c;
  48.             os << '[' << config.card_types[best_board[i]].name << ']';
  49.         }
  50.         os << '\n';
  51.     }
  52. }
  53.  
  54. template<typename CardIndex, typename CardCount>
  55. static int solve(Configuration &config, std::string output_path)
  56. {
  57.     std::cerr << "sizeof(CardIndex)=" << sizeof(CardIndex) << std::endl;
  58.     std::cerr << "sizeof(CardCount)=" << sizeof(CardCount) << std::endl;
  59.  
  60.     static const unsigned H = config.board_height,
  61.                           W = config.board_width,
  62.                           HW = H*W;
  63.  
  64.     // Shuffle cards (except last, the empty cards)
  65.     for (size_t i = 0; i < config.card_types.size(); ++i)
  66.     {
  67.         size_t j = i + rand()%(config.card_types.size() - i);
  68.         std::swap(config.card_types[i], config.card_types[j]);
  69.     }
  70.  
  71.     // Add a bunch of empty cards:
  72.     config.card_types.push_back(CardType{ "", HW - 2 });
  73.     // FIXME: this may cause the final board to be not connected!
  74.  
  75.     const unsigned C = config.card_types.size();
  76.  
  77.     // Precalculate placement data
  78.     std::vector<Placement> places;
  79.     {
  80.         std::vector<std::pair<int,int> > queue;
  81.         std::vector<std::vector<int> > seen(H, std::vector<int>(W, -1));
  82.         for (int i = 0; i < 2; ++i)
  83.         {
  84.             seen[config.home_row][config.home_col + i] = i;
  85.             queue.push_back(std::make_pair(config.home_row, config.home_row + i));
  86.         }
  87.  
  88.         for (int pos = 0; pos < (int)queue.size(); ++pos)
  89.         {
  90.             const int r1 = queue[pos].first, c1 = queue[pos].second;
  91.             Placement place = { W*r1 + c1, 0 };
  92.             for (int dir = 0; dir < 8; ++dir)
  93.             {
  94.                 const int dr = DR[dir], dc = DC[dir], r2 = r1 + dr, c2 = c1 + dc;
  95.                 if (r2 >= 0 && r2 < (int)H && c2 >= 0 && c2 < (int)W)
  96.                 {
  97.                     if (seen[r2][c2] < 0)
  98.                     {
  99.                         seen[r2][c2] = (int)queue.size();
  100.                         queue.push_back(std::make_pair(r2, c2));
  101.                     }
  102.                     if (seen[r2][c2] < pos)
  103.                     {
  104.                         // Only count against one house card:
  105.                         if (seen[r2][c2] < 2 && c1 == c2) continue;
  106.                         place.dirs |= 1u << dir;
  107.                     }
  108.                 }
  109.             }
  110.             if (pos >= 2) places.push_back(place);
  111.         }
  112.     }
  113.  
  114.     // Find index for home card:
  115.     int home_index = 0;
  116.     while ( home_index < (int)config.card_types.size() &&
  117.             config.card_types[home_index].name != "huis" ) ++home_index;
  118.     if (home_index == (int)config.card_types.size())
  119.     {
  120.         std::cerr << "Missing home card type!" << std::endl;
  121.         return 1;
  122.     }
  123.  
  124.     // Precalculate card combination scores:
  125.     std::vector<signed char> combis(C*C*8);
  126.     for (size_t c = 0; c < C; ++c)
  127.     {
  128.         const CardType &a = config.card_types[c];
  129.         for (size_t d = 0; d < C; ++d)
  130.         {
  131.             const CardType &b = config.card_types[d];
  132.             for (int dir = 0; dir < 8; ++dir)
  133.             {
  134.                 signed char &score = combis[8*(C*c + d) + dir];
  135.                 assert(score == 0);
  136.                 score += bitcount(a.inputs & b.outputs);
  137.                 score += bitcount(b.inputs & a.outputs);
  138.                 if (DC[dir] > 0)
  139.                 {
  140.                     score += a.wind_provided    && b.wind_required;
  141.                     score += a.shelter_provided && b.shelter_required;
  142.                     score -= a.wind_provided    && b.shelter_required;
  143.                     score -= a.shelter_provided && b.wind_required;
  144.                 }
  145.                 if (DC[dir] < 0)
  146.                 {
  147.                     score += b.wind_provided    && a.wind_required;
  148.                     score += b.shelter_provided && a.shelter_required;
  149.                     score -= b.wind_provided    && a.shelter_required;
  150.                     score -= b.shelter_provided && a.wind_required;
  151.                 }
  152.                 if (DR[dir] > 0)
  153.                 {
  154.                     score += a.sun_provided   && b.sun_required;
  155.                     score += a.shade_provided && b.shade_required;
  156.                     score -= a.sun_provided   && b.shade_required;
  157.                     score -= a.shade_provided && b.sun_required;
  158.                 }
  159.                 if (DR[dir] < 0)
  160.                 {
  161.                     score += b.sun_provided   && a.sun_required;
  162.                     score += b.shade_provided && a.shade_required;
  163.                     score -= b.sun_provided   && a.shade_required;
  164.                     score -= b.shade_provided && a.sun_required;
  165.                 }
  166.             }
  167.         }
  168.     }
  169.  
  170.     // Initialize board array:
  171.     std::vector<CardIndex> initial_board(HW, (CardIndex)-1);
  172.     for (int i = 0; i < 2; ++i)
  173.     {
  174.         initial_board[W*config.home_row + config.home_col + i] = home_index;
  175.     }
  176.     std::vector<CardCount> initial_avail(C);
  177.     for (int c = 0; c < (int)C; ++c)
  178.     {
  179.         if (c != home_index)
  180.         {
  181.             initial_avail[c] = std::min( config.card_types[c].count,
  182.                                          (unsigned)(CardCount)~0 );
  183.         }
  184.     }
  185.  
  186.     int best_score = -999999999;
  187.     for (size_t max_queue_size = 4; ; max_queue_size *= 2)
  188.     {
  189.         time_t iteration_start_time = time(NULL);
  190.  
  191.         // Breadth-first search, keeping the best max_queue_size candidates.
  192.         std::vector<std::deque<std::pair< std::vector<CardIndex>,
  193.                                         std::vector<CardCount> > > > queue;
  194.         // Note: initial score is set to 10 to allow states with negative scores
  195.         //       (up to -10) to be queued initially.
  196.         const int score_offset = -10;
  197.         queue.resize(1 - score_offset);
  198.         queue[-score_offset].push_back(std::make_pair(initial_board, initial_avail));
  199.         for (size_t place_index = 0; place_index < places.size(); ++place_index)
  200.         {
  201.             auto const &place = places[place_index];
  202.             decltype(queue) next_queue;
  203.             int next_queue_min_score = 0;
  204.             size_t next_queue_size = 0;
  205.             for (int score = (int)queue.size() - 1; score >= 0; --score)
  206.             {
  207.                 for (auto const &entry : queue[score])
  208.                 {
  209.                     auto const &board = entry.first;
  210.                     auto const &avail = entry.second;
  211.                     assert(board[place.index] >= C);
  212.                     for (unsigned c = 0; c < C; ++c)
  213.                     {
  214.                         if (avail[c] > 0)
  215.                         {
  216.                             int add_score = 0;
  217.                             for (int dir = 0; dir < 8; ++dir)
  218.                             {
  219.                                 if (place.dirs & 1u<<dir)
  220.                                 {
  221.                                     unsigned d = board[place.index + W*DR[dir] + DC[dir]];
  222.                                     assert(d < C);
  223.                                     add_score += combis[8*(C*c + d) + dir];
  224.                                 }
  225.                             }
  226.                             int new_score = score + add_score;
  227.                             if (next_queue_size == max_queue_size)
  228.                             {
  229.                                 if (new_score <= next_queue_min_score) continue;
  230.                                 next_queue[next_queue_min_score].pop_front();
  231.                                 while (next_queue[next_queue_min_score].empty())
  232.                                     ++next_queue_min_score;
  233.                                 --next_queue_size;
  234.                             }
  235.                             if (new_score >= (int)next_queue.size())
  236.                                 next_queue.resize(new_score + 1);
  237.                             auto &q = next_queue[new_score];
  238.                             q.push_back(entry);
  239.                             auto &new_entry = q.back();
  240.                             new_entry.first[place.index] = c;
  241.                             new_entry.second[c] -= 1;
  242.                             if ( next_queue_size++ == 0 ||
  243.                                  new_score < next_queue_min_score )
  244.                             {
  245.                                 next_queue_min_score = new_score;
  246.                             }
  247.                         }
  248.                     }
  249.                 }
  250.             }
  251.             next_queue.swap(queue);
  252.         }
  253.  
  254.         const int score = (int)queue.size() + score_offset - 1;
  255.         auto const &board = queue.back()[0].first;
  256.         std::cerr << "Queue size " << max_queue_size
  257.                   << " yielded score " << score
  258.                   << " in " << time(NULL) - iteration_start_time << "s.\n";
  259.         if (score > best_score)
  260.         {
  261.             write_output<CardIndex>(config, output_path, score, board);
  262.             best_score = score;
  263.         }
  264.     }
  265. }
  266.  
  267. int main(int argc, const char *argv[])
  268. {
  269.     // Initialize the RNG
  270.     srand(time(NULL));
  271.  
  272.     // Kill our process after 5 minutes:
  273.     alarm(297);
  274.  
  275.     // Read game configuration:
  276.     Configuration config;
  277.     try
  278.     {
  279.         config = read_configuration();
  280.     }
  281.     catch (const char *error)
  282.     {
  283.         std::cerr << "Failed to read configuration: " << error << "!" << std::endl;
  284.         return 1;
  285.     }
  286.  
  287.     // Calculate maximum card count:
  288.     unsigned max_card_count = 0;
  289.     for (auto const &ct : config.card_types)
  290.     {
  291.         max_card_count = std::max(max_card_count, ct.count);
  292.     }
  293.     max_card_count = std::min( max_card_count,
  294.                                config.board_height*config.board_width );
  295.  
  296.     std::string output_path = argc > 1 ? argv[1] : "output.ini";
  297.     if (config.card_types.size() < 256 && max_card_count < 256)
  298.     {
  299.         return solve<unsigned char, unsigned char>(config, output_path);
  300.     }
  301.     if (config.card_types.size() < 256)
  302.     {
  303.         return solve<unsigned char, unsigned short>(config, output_path);
  304.     }
  305.     if (max_card_count < 256)
  306.     {
  307.         return solve<unsigned short, unsigned short>(config, output_path);
  308.     }
  309.     return solve<unsigned short, unsigned short>(config, output_path);
  310. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement