marius7122

Untitled

Jan 9th, 2022
74
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.78 KB | None | 0 0
  1. #include <iostream>
  2. #include <fstream>
  3. #include <vector>
  4. #include <algorithm>
  5.  
  6. using namespace std;
  7.  
  8. enum Direction
  9. {
  10.     None,
  11.     Up,
  12.     Down,
  13.     Left,
  14.     Right
  15. };
  16.  
  17. struct State
  18. {
  19.     vector<vector<int>> mat;    
  20.     int emptySpaceI, emptySpaceJ;      // pozitia spatiului liber
  21.     Direction lastMove;
  22.     State *parent;
  23.  
  24.     void Resize(int n)
  25.     {
  26.         mat.resize(n, vector<int>(n));
  27.     }
  28. };
  29.  
  30. void printState(State &state)
  31. {
  32.     for(int i = 0; i < state.mat.size(); i++)
  33.     {
  34.         for(int j = 0; j < state.mat.size(); j++)
  35.             cout << state.mat[i][j] << ' ';
  36.         cout << '\n';
  37.     }
  38. }
  39.  
  40.  
  41. // pleaca de la o stare si genereaza cele maixim 4 stari in care se poate ajunge
  42. // (muta spatiul in cele maxim 4 directii)
  43. int diri[] = {1, -1, 0, 0};
  44. int dirj[] = {0, 0, 1, -1};
  45. Direction dir[] = {Down, Up, Right, Left};
  46. vector<State> generateNextStates(State &currentState)
  47. {
  48.     vector<State> nextStates;
  49.     int spaceI = currentState.emptySpaceI;
  50.     int spaceJ = currentState.emptySpaceJ;
  51.     int nextSpaceI, nextSpaceJ;
  52.     int dim = currentState.mat.size();
  53.     for(int i = 0; i < 4; i++)
  54.     {
  55.         // diri[i] = cum se modifica pozitia spatiului pe i
  56.         // dirj[i] = cum se modifica pozitia spatiului pe j
  57.         // dir[i] = in ce directie merg
  58.         nextSpaceI = spaceI + diri[i];
  59.         nextSpaceJ = spaceJ + dirj[i];
  60.  
  61.         // nextSpaceI si nextSpaceJ sunt inca in matrice
  62.         if(nextSpaceI < 0 || nextSpaceI >= dim ||
  63.             nextSpaceJ < 0 || nextSpaceJ >= dim)
  64.             continue;
  65.  
  66.         // genereaza noua stare
  67.         State nextState = currentState;
  68.         swap(nextState.mat[spaceI][spaceJ], nextState.mat[nextSpaceI][nextSpaceJ]);
  69.         nextState.emptySpaceI = nextSpaceI;
  70.         nextState.emptySpaceJ = nextSpaceJ;
  71.         nextState.parent = &currentState;
  72.         nextState.lastMove = dir[i];
  73.  
  74.         nextStates.push_back(nextState);
  75.     }
  76.  
  77.     return nextStates;
  78. }
  79.  
  80. // verifica daca o stare anume este o stare finala (puzzle rezolvat)
  81. bool isFinalState(State &state)
  82. {
  83.     int index = 1;
  84.     int dim = state.mat.size();
  85.     for(int i = 0; i < dim; i++)
  86.         for(int j = 0; j < dim; j++)
  87.         {
  88.             if(i == dim - 1 && j == dim - 1)
  89.                 continue;
  90.            
  91.             if(state.mat[i][j] != index)
  92.                 return false;
  93.            
  94.             index++;
  95.         }
  96.  
  97.     return true;
  98. }
  99.  
  100. // returneaza directia complementara (pentru sus -> jos; pentru stanga -> dreapta)
  101. Direction complementaryDirection(Direction d)
  102. {
  103.     if(d == Left)
  104.         return Right;
  105.     if(d == Right)
  106.         return Left;
  107.     if(d == Up)
  108.         return Down;
  109.     if(d == Down)
  110.         return Up;
  111.     return None;
  112. }
  113.  
  114. // functie care rezolva puzzle-ul; returneaza un vector cu
  115. // directiile in care trebuie mutat vectorul
  116. vector<Direction> solvePuzzle(State &initialState)
  117. {
  118.     initialState.lastMove = None;
  119.     initialState.parent = NULL;         // nu are nici un parinte => NULL
  120.  
  121.     vector<vector<State>> tree;
  122.  
  123.     // adaugam in arborele de cautare radacina (nodul cu starea initiala)
  124.     tree.push_back({initialState});
  125.  
  126.     bool solved = false;
  127.     State solution;
  128.     // level = nivelul in arbore pe care cautam
  129.     for(int level = 1; !solved; level++)
  130.     {
  131.         // adaugam un vector gol pentru nivelul actual
  132.         // (nivelul actual nu contine nici o stare, urmeaza sa adaugam)
  133.         tree.push_back({});
  134.  
  135.         // pentru fiecare stare de pe nivelul anterior generam si adaugam
  136.         // la nivelul actual toate mutarile posibile
  137.         for(int i = 0; i < tree[level - 1].size(); i++)
  138.         {
  139.  
  140.             // generam mutarile urmatoare pentru o stare de pe nivelul anterior
  141.             vector<State> genereratedStates = generateNextStates(tree[level-1][i]);
  142.             for(int j = 0; j < genereratedStates.size(); j++)
  143.             {
  144.                 // daca directia starii actuale este complementara cu ultima directie in care am fost (se anuleaza)
  145.                 // atunci nu lua starea in considerare (ea deja exista)
  146.                 if(genereratedStates[j].lastMove == complementaryDirection(tree[level-1][i].lastMove))
  147.                 {
  148.                     continue;
  149.                 }
  150.  
  151.                 // adaugam pe nivelul actual starea genereratedStates[i] (starea actuala generata)
  152.                 tree[level].push_back(genereratedStates[j]);
  153.  
  154.                 // am gasit solutia
  155.                 if(isFinalState(genereratedStates[j]))
  156.                 {
  157.                     solved = true;
  158.                     solution = genereratedStates[j];
  159.                 }
  160.             }
  161.         }
  162.  
  163.         cout << "Done level " << level << "; " << tree[level].size() << " moves" << endl;
  164.     }
  165.  
  166.  
  167.     // construim solutia
  168.     vector<Direction> solutionSteps;
  169.     vector<State> solutionStates;
  170.     State *current = &solution;
  171.  
  172.     while(current != NULL)
  173.     {
  174.         // *var => varibila trebuie sa fie pointer; face din pointer catre tip de data direct tipul de data
  175.         // &var => varibila trebuie sa fie tip de data; face din tipul de data pointer catre tipul de data
  176.         State currentState = *current;
  177.         solutionSteps.push_back(currentState.lastMove);
  178.         solutionStates.push_back(currentState);
  179.         current = currentState.parent;
  180.     }
  181.  
  182.  
  183.     // inversez solutionSteps si SolutionStates
  184.     for(int st = 0, dr = solutionSteps.size() - 1; st < dr; st++, dr--)
  185.     {
  186.         swap(solutionSteps[st], solutionSteps[dr]);
  187.         swap(solutionStates[st], solutionStates[dr]);
  188.     }
  189.  
  190.     // cout << "Steps: \n";
  191.     // for(int i = 0; i < solutionStates.size(); i++)
  192.     // {
  193.     //     printState(solutionStates[i]);
  194.     //     cout << endl;
  195.     // }
  196.  
  197.     return solutionSteps;
  198. }
  199.  
  200. bool isSolvable(State &s)
  201. {
  202.     vector<int> v;
  203.     int dim = s.mat.size();
  204.     for(int i = 0; i < dim; i++)
  205.         for(int j = 0; j < dim; j++)
  206.             v.push_back(s.mat[i][j]);
  207.    
  208.     int nrInversiuni = 0;
  209.     for(int i = 0; i < v.size(); i++)
  210.     {
  211.         if(v[i] == 0)
  212.             continue;
  213.         for(int j = i + 1; j < v.size(); j++)
  214.             if(v[j] < v[i] && v[j] != 0)
  215.                 nrInversiuni++;
  216.     }
  217.  
  218.     // Caz1: matrice de dimensiune impara => nr inversiuni par
  219.     if(dim % 2 == 1)
  220.     {
  221.         return nrInversiuni % 2 == 0;
  222.     }
  223.    
  224.     int linieSpatiu;
  225.     bool gasit = false;
  226.     int linieSpatiuDeJos = 1;
  227.     for(int i = dim - 1; i >= 0 && !gasit; i--)
  228.     {
  229.         for(int j = 0; j < dim && !gasit; j++)
  230.             if(s.mat[i][j] == 0)
  231.             {
  232.                 linieSpatiu = i + 1;
  233.                 gasit = true;
  234.             }
  235.        
  236.         if(!gasit)
  237.             linieSpatiuDeJos++;
  238.     }
  239.  
  240.     // Caz2: matrice de dimensiune para si spatiul se afla pe o linie para inumarand de jos in sus (ex: penultima) =>
  241.     //          nr de inversiuni trebuie sa fie impar
  242.     if(linieSpatiuDeJos % 2 == 0)
  243.         return nrInversiuni % 2 == 1;
  244.  
  245.     // Caz3: matrice de dimensiune para si spatiul se afla pe o linie impara inumarand de jos in sus (ex: ultima, antepenultima) =>
  246.     //          nr de inversiuni trebuie sa fie par
  247.     return nrInversiuni % 2 == 0;
  248.  
  249. }
  250.  
  251. State readState(const char fileName[])
  252. {
  253.     State s;
  254.     ifstream fin(fileName);
  255.     int n;
  256.     fin >> n;
  257.     s.Resize(n);
  258.     for(int i = 0; i < n; i++)
  259.         for(int j = 0; j < n; j++)
  260.         {
  261.             fin >> s.mat[i][j];
  262.             if(s.mat[i][j] == 0)
  263.             {
  264.                 s.emptySpaceI = i;
  265.                 s.emptySpaceJ = j;
  266.             }
  267.         }
  268.     fin.close();
  269.     return s;
  270. }
  271.  
  272. void printStateInFile(const char fileName[], State &s)
  273. {
  274.     ofstream fout(fileName);
  275.     for(int i = 0; i < s.mat.size(); i++)
  276.     {
  277.         for(int j = 0; j < s.mat.size(); j++)
  278.             fout << s.mat[i][j] << ' ';
  279.         fout << '\n';
  280.     }
  281.     fout.close();
  282. }
  283.  
  284. bool duplicateExists(vector<State> &states)
  285. {
  286.     for(int i = 0; i < states.size(); i++)
  287.         for(int j = i + 1; j < states.size(); j++)
  288.         {    
  289.             if(states[i].mat == states[j].mat)
  290.                 return true;
  291.         }
  292.     return false;
  293. }
  294.  
  295. int main()
  296. {
  297.     State initialState = readState("date.in");
  298.  
  299.     if(!isSolvable(initialState))
  300.     {
  301.         cout << "Cannot sove\n";
  302.         return 0;
  303.     }
  304.  
  305.     vector<Direction> solutionMoves = solvePuzzle(initialState);
  306.     cout << "Moves to solve the puzzle: \n";
  307.     for(int i = 0; i < solutionMoves.size(); i++)
  308.     {
  309.         if(solutionMoves[i] == Left)
  310.             cout << "Left\n";
  311.            
  312.         if(solutionMoves[i] == Right)
  313.             cout << "Right\n";
  314.  
  315.         if(solutionMoves[i] == Up)
  316.             cout << "Up\n";
  317.  
  318.         if(solutionMoves[i] == Down)
  319.             cout << "Down\n";
  320.     }
  321.  
  322.  
  323.     return 0;
  324. }
Add Comment
Please, Sign In to add comment