Mati3k01 Temat założony przez niniejszego użytkownika |
» 2018-02-01 23:27:28 #include <iostream> #include <algorithm> #include <vector>
using namespace std; int SIZE = 8;
struct doubleCoords { int x1; int y1; int x2; int y2; };
bool operator <( const doubleCoords & a, const doubleCoords & b ) { if( a.x1 < b.x1 ) return true; else if( a.x1 == b.x1 ) { if( a.y1 < b.y1 ) return true; else if( a.y1 == b.y1 ) { if( a.x2 < b.x2 ) return true; else if( a.x2 == b.x2 ) { if( a.y2 < b.y2 ) return true; else return false; } else return false; } else return false; } else return false; }
struct coords { int x; int y; };
void print( vector < vector < char >> & board ) { for( int i = 0; i < SIZE; i++ ) { for( int j = 0; j < SIZE; j++ ) cout << board[ i ][ j ]; cout << endl; } cout << endl; }
void gravityDrop( vector < vector < char >> & board ) { for( int row = 0; row < SIZE; row++ ) for( int col = 0; col < SIZE; col++ ) if( board[ SIZE - row - 1 ][ col ] == '.' ) { for( int up_row = SIZE - row - 1; up_row >= 0; up_row-- ) { if( board[ up_row ][ col ] != '.' ) { board[ SIZE - row - 1 ][ col ] = board[ up_row ][ col ]; board[ up_row ][ col ] = '.'; break; } } } }
void SimplifyRows( vector < vector < char >> & board, doubleCoords & crds, vector < coords > & toRemove ) { if( crds.y1 == crds.y2 ) { int counter = 1; for( int i = 0; i < SIZE - 1; i++ ) { if( board[ crds.y1 ][ i ] != '.' && board[ crds.y1 ][ i ] == board[ crds.y2 ][ i + 1 ] ) counter++; else counter = 1; if( counter >= 3 ) for( int j = i - counter + 2; j <= i + 1; j++ ) toRemove.push_back( { crds.y1, j } ); } } else { int counter = 1; for( int i = 0; i < SIZE - 1; i++ ) { if( board[ crds.y1 ][ i ] != '.' && board[ crds.y1 ][ i ] == board[ crds.y1 ][ i + 1 ] ) counter++; else counter = 1; if( counter >= 3 ) for( int j = i - counter + 2; j <= i + 1; j++ ) toRemove.push_back( { crds.y1, j } ); } counter = 1; for( int i = 0; i < SIZE - 1; i++ ) { if( board[ crds.y2 ][ i ] != '.' && board[ crds.y2 ][ i ] == board[ crds.y2 ][ i + 1 ] ) counter++; else counter = 1; if( counter >= 3 ) for( int j = i - counter + 2; j <= i + 1; j++ ) toRemove.push_back( { crds.y2, j } ); } } }
void SimplifyCols( vector < vector < char >> & board, doubleCoords & crds, vector < coords > & toRemove ) { if( crds.y1 == crds.y2 ) { int counter = 1; for( int i = 0; i < SIZE - 1; i++ ) { if( board[ i ][ crds.x1 ] != '.' && board[ i ][ crds.x1 ] == board[ i + 1 ][ crds.x1 ] ) counter++; else counter = 1; if( counter >= 3 ) for( int j = i - counter + 2; j <= i + 1; j++ ) toRemove.push_back( { j, crds.x1 } ); } counter = 1; for( int i = 0; i < SIZE - 1; i++ ) { if( board[ i ][ crds.x2 ] != '.' && board[ i ][ crds.x2 ] == board[ i + 1 ][ crds.x2 ] ) counter++; else counter = 1; if( counter >= 3 ) for( int j = i - counter + 2; j <= i + 1; j++ ) toRemove.push_back( { j, crds.x2 } ); } } else { int counter = 1; for( int i = 0; i < SIZE - 1; i++ ) { if( board[ i ][ crds.x1 ] != '.' && board[ i ][ crds.x1 ] == board[ i + 1 ][ crds.x1 ] ) counter++; else counter = 1; if( counter >= 3 ) for( int j = i - counter + 2; j <= i + 1; j++ ) toRemove.push_back( { j, crds.x1 } ); } } }
pair < vector < vector < char >>, int > makeMove( vector < vector < char >> board, doubleCoords & crds, int score ) { swap( board[ crds.y1 ][ crds.x1 ], board[ crds.y2 ][ crds.x2 ] ); vector < coords > toRemove; int removedPositions = 0; do { toRemove.clear(); gravityDrop( board ); SimplifyCols( board, crds, toRemove ); SimplifyRows( board, crds, toRemove ); if( toRemove.size() > 0 ) { removedPositions += toRemove.size(); for( coords remove: toRemove ) { board[ remove.x ][ remove.y ] = '.'; } } } while( toRemove.size() > 0 ); return make_pair( board, score - removedPositions ); }
vector < doubleCoords > solve( vector < vector < char >> & board, int score, vector < doubleCoords > moves = vector < doubleCoords >(), int level = 0 ) { if( score == 0 ) return moves; else if( level == 8 ) return vector < doubleCoords >(); else { vector < doubleCoords > bestSequence( 9 ); doubleCoords tempCoords; for( int i = 0; i < SIZE; i++ ) for( int j = 0; j < SIZE - 1; j++ ) { pair < vector < vector < char >>, int > newBoardPair; vector < doubleCoords > newMoves; if( board[ i ][ j ] != '.' || board[ i ][ j + 1 ] != '.' ) { tempCoords.x1 = j; tempCoords.y1 = i; tempCoords.x2 = j + 1; tempCoords.y2 = i; newBoardPair = makeMove( board, tempCoords, score ); if( newBoardPair.second < score ) { moves.push_back( tempCoords ); newMoves = solve( board, newBoardPair.second, moves, level + 1 ); moves.pop_back(); if( newMoves.size() < bestSequence.size() ) bestSequence = newMoves; else if( newMoves.size() == bestSequence.size() && lexicographical_compare( newMoves.begin(), newMoves.end(), bestSequence.begin(), bestSequence.end() ) ) bestSequence = newMoves; } } if( board[ j ][ i ] != '.' && board[ j + 1 ][ i ] != '.' ) { tempCoords.x1 = i; tempCoords.y1 = j; tempCoords.x2 = i; tempCoords.y2 = j + 1; newBoardPair = makeMove( board, tempCoords, score ); if( newBoardPair.second < score ) { moves.push_back( tempCoords ); newMoves = solve( board, newBoardPair.second, moves, level + 1 ); moves.pop_back(); if( newMoves.size() < bestSequence.size() ) bestSequence = newMoves; else if( newMoves.size() == bestSequence.size() && lexicographical_compare( newMoves.begin(), newMoves.end(), bestSequence.begin(), bestSequence.end() ) ) bestSequence = newMoves; } } } return bestSequence; } }
int main( int argc, const char * argv[] ) { vector < vector < char >> data; int firstScore = 0; for( int y = 0; y < SIZE; y++ ) { vector < char > temp( SIZE ); for( int x = 0; x < SIZE; x++ ) { cin >> temp[ x ]; if( temp[ x ] != '.' ) firstScore++; } data.push_back( temp ); } vector < doubleCoords > result = solve( data, firstScore ); cout << result.size() << endl; for( doubleCoords & crds: result ) cout << crds.y1 + 1 << " " << crds.x1 + 1 << " " << crds.y2 + 1 << " " << crds.x2 + 1 << endl; return 0; }
Tak więc mam już przerobiony kod starałem się go przyśpieszyć, niewiele wymyśliłem raczej jest tu dużo drobnych zmian ale zauważyłem też, że istnieją sytuacje kiedy jedna zamiana jakiś pól może spowodować kilka redukcji i gravity dropów pod rząd z tego powodu w makeMove jest teraz pętla, komentarze są po ang to raczej moja osobista preferencja ale jeśli będzie to komuś przeszkadzało to mogę pozamieniać na polskie. I wciąż mam przekroczone limity.. a pomysłów na przyśpieszenie brak. EDIT: Zapomniałbym SimplifyRows/Cols przeszukuje teraz tylko te wiersze/kolumny w których rzeczywiście może być coś do redukcji, jest to zależne od tego w jakiej płaszczyźnie robiliśmy swap. I uwzględniając pytania, nie musi być to raczej jedna metoda bo przechowuje współrzędne w których oznaczam pozycje do redukcji, dopiero po przeglądnięciu wierszy i kolumn wychodzę z obu funkcji i usuwam(Stąd chyba mogę to rozdzielić na redukcję kolumn i wierszy). Zrobienie tego na koniec raczej nie ma wpływu na wynik algorytmu. Nie rozumiem uwagi numer 5 odnośnie warunku z wcześniej wspomnianych funkcji simplify(dla mnie wydaje się on być prawidłowy jeśli tak nie jest także proszę o wyjaśnienie). Co do uwagi 6 poprawiłem to i teraz jest to odejmowanie w trakcie wykonywania programu(ilość pozostałych obiektów na planszy liczona przy pomocy makeMove). Uwaga 9 też wydaje mi się, że jest to poprawne, po prostu best sequence przechowuje najlepszą sekwencję ruchów, rekurencyjnie wraca kiedy osiągniemy limit(8 poziomów) lub gdy na planszy już nic nie ma. Reasumując ja bym spróbował przyśpieszyć algorytm poprzez ucięcie drzewa przeszukiwań do minimum ale nie wiem czy jest to jeszcze możliwe, i czekam na dalsze uwagi. EDIT2: I przede wszystkim to jest nowy kod, teraz np 2 struktury zastępuje jedna doubleCoords(przedtem mimo tego, że obie wyglądały tak samo to istniały równolegle i stosowałem jakieś bezsensowne funkcje rzutujące, żeby móc przypisać jedną do drugiej.. |