qqwref

Untitled

May 8th, 2021
901
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.63 KB | None | 0 0
  1. // Find the max number of moves for a given shape
  2.  
  3. #include <algorithm>
  4. #include <fstream>
  5. #include <iostream>
  6. #include <list>
  7. #include <map>
  8. #include <queue>
  9. #include <set>
  10. #include <stdint.h>
  11. #include <string>
  12. #include <time.h>
  13. #include <vector>
  14. #include <windows.h>
  15.  
  16. // Define the shape (could be done on command line, or in main?)
  17. #define HH 4
  18. #define WW 5
  19. #define SHAPE "...##....##....##..."
  20.  
  21. typedef unsigned char byte;
  22.  
  23. struct Moves {
  24.     int nMoves;
  25.     std::vector<byte> moves;
  26. };
  27.  
  28. struct SokobanSolver {
  29.     static void printGrid(uint64_t state, uint64_t shape_position) {
  30.         int player = findPlayer(state);
  31.         std::cout << "+";
  32.         for (int j=0; j<WW; j++) std::cout << "-";
  33.         std::cout << "+\n";
  34.         for (int i=0; i<HH; i++) {
  35.             std::cout << "|";
  36.             for (int j=0; j<WW; j++) {
  37.                 if (getPosition(shape_position, i*WW+j) > 0) {
  38.                     std::cout << "#";
  39.                 } else if (i*WW+j == player) {
  40.                     std::cout << "@";
  41.                 } else if (getPosition(state, i*WW+j) > 0) {
  42.                     std::cout << "*";
  43.                 } else {
  44.                     std::cout << " ";
  45.                 }
  46.             }
  47.             std::cout << "|\n";
  48.         }
  49.         std::cout << "+";
  50.         for (int j=0; j<WW; j++) std::cout << "-";
  51.         std::cout << "+\n";
  52.     }
  53.    
  54.     static uint64_t findPlayer(uint64_t state) {
  55.         return state & ((uint64_t)63);
  56.     }
  57.    
  58.     static uint64_t getPosition(uint64_t state, int position) {
  59.         return state & (((uint64_t)64) << position);
  60.     }
  61.    
  62.     static uint64_t setPlayer(uint64_t state, int position) {
  63.         return (state & ~((uint64_t)63)) | ((uint64_t)position);
  64.     }
  65.    
  66.     static uint64_t togglePosition(uint64_t state, int position) {
  67.         return state ^ (((uint64_t)64) << position);
  68.     }
  69.    
  70.     // can we apply this move to this piece?
  71.     static bool isValid(int move, int n, uint64_t shape_position) {
  72.         int w = n + moveAddition(move);
  73.         if (w>=0 && w<62 && (shape_position & (64<<w))) {
  74.             return false;
  75.         }
  76.         if (move == 0) {
  77.             return (n >= WW);
  78.         } else if (move == 1) {
  79.             return (n < WW*(HH-1));
  80.         } else if (move == 2) {
  81.             return (n%WW != 0);
  82.         } else {
  83.             return (n%WW != WW-1);
  84.         }
  85.     }
  86.    
  87.     static uint64_t applyMove(int mov, uint64_t position, uint64_t shape_position) {
  88.         int submov = mov&3;
  89.         int player = findPlayer(position);
  90.         int delta = moveAddition(submov);
  91.        
  92.         if (!isValid(submov, player, shape_position)) return 0;
  93.         if (getPosition(position, player+delta) > 0) return 0;
  94.  
  95.         if (mov>3 && (!isValid(submov^1, player, shape_position) || getPosition(position, player-delta) == 0)) return 0;
  96.         uint64_t newPosition = setPlayer(position, player+delta);
  97.         if (mov>3) {
  98.             newPosition = togglePosition(togglePosition(newPosition, player), player-delta);
  99.         }
  100.         return newPosition;
  101.     }
  102.    
  103.     static int moveAddition(int mov) {
  104.         // -16, 16, -1, 1
  105.         if (mov == 0) {
  106.             return -WW;
  107.         } else if (mov == 1) {
  108.             return WW;
  109.         } else if (mov == 2) {
  110.             return -1;
  111.         } else if (mov == 3) {
  112.             return 1;
  113.         } else {
  114.             return 0;
  115.         }
  116.     }
  117.    
  118.     // solve by enumerating every position with one map per depth
  119.     static int mapSolve(uint64_t puzzle, uint64_t shape_position) {
  120.         // start with empty maps (state -> <depth, movestring>)
  121.         std::set<uint64_t> positions;
  122.         std::set<uint64_t> nextPositions;
  123.         std::set<uint64_t> curPositions;
  124.        
  125.         // get starting positions
  126.         for (int i=0; i<HH*WW; i++) {
  127.             if (getPosition(puzzle, i) > 0) {
  128.                 // try placing player around this
  129.                 for (int j=0; j<4; j++) {
  130.                     int add = moveAddition(j);
  131.                     if (!isValid(j, i, shape_position)) continue;
  132.                     if (getPosition(puzzle, i+add) == 0) {
  133.                         positions.insert(setPlayer(puzzle, i+add));
  134.                         nextPositions.insert(setPlayer(puzzle, i+add));
  135.                     }
  136.                 }
  137.             }
  138.         }
  139.        
  140.         int main_depth = 0;
  141.    
  142.         while (!nextPositions.empty()) {
  143.             // swap maps
  144.             std::swap(curPositions, nextPositions);
  145.             nextPositions.clear();
  146.            
  147.             // iterate over map
  148.             for (std::set<uint64_t>::iterator it=curPositions.begin(); it!=curPositions.end(); ++it) {
  149.                 uint64_t position = *it;
  150.                
  151.                 // loop through moves
  152.                 for (int mov = 0; mov < 8; mov++) {
  153.                     uint64_t newPosition = applyMove(mov, position, shape_position);
  154.                     if (newPosition != 0) {
  155.                         if (positions.count(newPosition) == 0) {
  156.                             positions.insert(newPosition);
  157.                             nextPositions.insert(newPosition);
  158.                         }
  159.                     }
  160.                 }
  161.             }
  162.                
  163.             if (nextPositions.empty()) {
  164.                 return main_depth;
  165.             }
  166.                
  167.             main_depth++;
  168.         }
  169.         return -1;
  170.     }
  171.    
  172.     static int rotate(int num) {
  173.         int rot = 0;
  174.         for (int i=0; i<HH; i++) {
  175.             for (int j=0; j<HH; j++) {
  176.                 int digit = i*HH + j;
  177.                 if ((num & 1<<digit) != 0) {
  178.                     rot += 1<<(j*HH + HH-1 - i);
  179.                 }
  180.             }
  181.         }
  182.         return rot;
  183.     }
  184.     static int flip(int num) {
  185.         int rot = 0;
  186.         for (int i=0; i<HH; i++) {
  187.             for (int j=0; j<WW; j++) {
  188.                 int digit = i*WW + j;
  189.                 if ((num & (1<<digit)) != 0) {
  190.                     rot += 1<<(i*WW + WW-1 - j);
  191.                 }
  192.             }
  193.         }
  194.         return rot;
  195.     }
  196.     static int flip2(int num) {
  197.         int rot = 0;
  198.         for (int i=0; i<HH; i++) {
  199.             for (int j=0; j<WW; j++) {
  200.                 int digit = i*WW + j;
  201.                 if ((num & (1<<digit)) != 0) {
  202.                     rot += 1<<((HH-1-i)*WW + j);
  203.                 }
  204.             }
  205.         }
  206.         return rot;
  207.     }
  208.     // uflip and uflip2 - flip uint64_t without a player
  209.     static uint64_t uflip(uint64_t num) {
  210.         uint64_t rot = 0;
  211.         for (int i=0; i<HH; i++) {
  212.             for (int j=0; j<WW; j++) {
  213.                 int digit = i*WW + j;
  214.                 if ((num & (((uint64_t)1)<<digit)) != 0) {
  215.                     rot += ((uint64_t)1)<<(i*WW + WW-1 - j);
  216.                 }
  217.             }
  218.         }
  219.         return rot;
  220.     }
  221.     static uint64_t uflip2(uint64_t num) {
  222.         uint64_t rot = 0;
  223.         for (int i=0; i<HH; i++) {
  224.             for (int j=0; j<WW; j++) {
  225.                 int digit = i*WW + j;
  226.                 if ((num & (((uint64_t)1)<<digit)) != 0) {
  227.                     rot += ((uint64_t)1)<<((HH-1-i)*WW + j);
  228.                 }
  229.             }
  230.         }
  231.         return rot;
  232.     }
  233.  
  234.     // moveAddition to array?
  235.    
  236.     static int solve() {
  237.         clock_t startTime = clock();
  238.         //int maxMoves = 0;
  239.         //int h = 4;
  240.         //int w = 5;
  241.         //uint64_t basePuzzle = 63;
  242.        
  243.         // process shape into a puzzle or whatever
  244.         uint64_t shape_position = 0;
  245.         for (int i=0; i<(HH*WW); i++) {
  246.             if (SHAPE[i] == '#') {
  247.                 shape_position += (64LL << i);
  248.             }
  249.         }
  250.        
  251.         int overallMax = 0;
  252.        
  253.         for (int nCrates=1; nCrates<(HH*WW); nCrates++) {
  254.             std::cout << "Trying " << nCrates << " crates\n";
  255.             int max = 0;
  256.             uint64_t position = (((uint64_t)1) << nCrates) - ((uint64_t)1);
  257.             // generate all possible moves for every position?
  258.             // for each position with this number of crates...
  259.             while (position < (((uint64_t)1) << (HH*WW))) {
  260.                 uint64_t curPosition = position;
  261.                 // get next
  262.                 // https://graphics.stanford.edu/~seander/bithacks.html#NextBitPermutation
  263.                 uint64_t t = (position | (position - 1)) + 1;
  264.                 uint64_t ww = t | ((((t & -t) / (position & -position)) >> 1) - 1);
  265.                 position = ww;
  266.                 // check that curPosition is ok
  267.                 if ((curPosition*64) & shape_position) continue;
  268.                 // solve
  269.                 int z = mapSolve(curPosition*64, shape_position);
  270.                 // print maximum
  271.                 if (z > max) {
  272.                     max = z;
  273.                     if (z > overallMax) {
  274.                         overallMax = z;
  275.                         double secs = double(clock() - startTime) / (double)CLOCKS_PER_SEC;
  276.                         std::cout << "Puzzle " << curPosition << " solved in " << z << " moves (" << secs << ")\n"  << std::flush;
  277.                         printGrid(curPosition*64+63, shape_position);
  278.                     }
  279.                 }
  280.             }
  281.             std::cout << nCrates << " crates had max of " << max << " moves\n";
  282.         }
  283.        
  284.         double secs = double(clock() - startTime) / (double)CLOCKS_PER_SEC;
  285.         std::cout << "Done (" << secs << ")\n" << std::flush;
  286.         std::cout << "Overall max moves was " << overallMax << "\n" << std::flush;
  287.        
  288.         return EXIT_SUCCESS;
  289.     }
  290. };
  291.  
  292. // g++ sokoban_4x4_bb2dt_shape.cpp -o sokoban_4x4_bb2dt_shape.exe -Wall -O3 --std=c++0x
  293. int main(int argc, char *argv[]) {
  294.     SokobanSolver::solve();
  295. }
Advertisement
Add Comment
Please, Sign In to add comment