@@ -158,6 +158,107 @@ namespace RUL0 {
158158 return translated;
159159 }
160160
161+ // Keep '<' (center row) on the right edge and '^' (center column) on the bottom edge
162+ void NormalizeCenterMarkers (Grid& grid, const char fillChar = kEmptyLayoutCell ) {
163+ if (grid.empty ()) {
164+ return ;
165+ }
166+
167+ grid = NormalizeGrid (grid, fillChar);
168+ const size_t originalWidth = grid.front ().size ();
169+ size_t height = grid.size ();
170+ size_t width = grid.front ().size ();
171+
172+ auto hasCenterRow = false ;
173+ size_t centerRow = 0 ;
174+ auto hasCenterCol = false ;
175+ size_t centerCol = 0 ;
176+
177+ for (size_t y = 0 ; y < height; ++y) {
178+ for (size_t x = 0 ; x < width; ++x) {
179+ const char cell = grid[y][x];
180+ if (cell == ' <' ) {
181+ hasCenterRow = true ;
182+ centerRow = y;
183+ grid[y][x] = fillChar;
184+ }
185+ else if (cell == ' ^' ) {
186+ hasCenterCol = true ;
187+ centerCol = x;
188+ grid[y][x] = fillChar;
189+ }
190+ }
191+ }
192+
193+ if (!hasCenterRow && !hasCenterCol) {
194+ return ;
195+ }
196+
197+ const auto isRowEmpty = [&](const size_t rowIndex) -> bool {
198+ return std::ranges::all_of (grid[rowIndex], [&](const char c) {
199+ return c == fillChar;
200+ });
201+ };
202+
203+ const auto isColEmpty = [&](size_t colIndex) -> bool {
204+ return std::ranges::all_of (grid, [&](const auto & row) {
205+ return colIndex < row.size () && row[colIndex] == fillChar;
206+ });
207+ };
208+
209+ if (hasCenterRow && centerRow < grid.size () && isRowEmpty (centerRow)) {
210+ grid.erase (grid.begin () + centerRow);
211+ }
212+
213+ if (grid.empty ()) {
214+ grid.emplace_back (std::max<size_t >(1 , originalWidth), fillChar);
215+ }
216+
217+ if (hasCenterCol && centerCol < grid.front ().size () && isColEmpty (centerCol)) {
218+ for (auto & row : grid) {
219+ if (row.empty ()) {
220+ row.assign (std::max<size_t >(1 , originalWidth), fillChar);
221+ }
222+ if (centerCol < row.size ()) {
223+ row.erase (row.begin () + centerCol);
224+ }
225+ }
226+ }
227+
228+ if (grid.empty ()) {
229+ grid.emplace_back (std::max<size_t >(1 , originalWidth), fillChar);
230+ }
231+
232+ if (!grid.empty () && grid.front ().empty ()) {
233+ for (auto & row : grid) {
234+ row.assign (std::max<size_t >(1 , originalWidth), fillChar);
235+ }
236+ }
237+
238+ height = grid.size ();
239+ width = grid.front ().size ();
240+
241+ const size_t placementRow = std::min (centerRow, height - 1 );
242+ const size_t placementCol = std::min (centerCol, width - 1 );
243+
244+ for (auto & row : grid) {
245+ row.push_back (fillChar);
246+ }
247+ ++width;
248+
249+ grid.push_back (std::string (width, fillChar));
250+ const size_t bottomRow = grid.size () - 1 ;
251+ const size_t rightmostCol = width - 1 ;
252+
253+ if (hasCenterRow) {
254+ grid[placementRow][rightmostCol] = ' <' ;
255+ }
256+
257+ if (hasCenterCol) {
258+ grid[bottomRow][placementCol] = ' ^' ;
259+ }
260+ }
261+
161262 uint32_t TransposeEdgeFlags (const uint32_t flags) {
162263 const uint32_t south = (flags >> 24 ) & 0xFF ;
163264 const uint32_t east = (flags >> 16 ) & 0xFF ;
@@ -701,9 +802,11 @@ namespace RUL0 {
701802 // Rotate layouts
702803 if (!piece.cellLayout .empty ()) {
703804 piece.cellLayout = RotateGrid (piece.cellLayout , times);
805+ NormalizeCenterMarkers (piece.cellLayout );
704806 }
705807 if (!piece.consLayout .empty ()) {
706808 piece.consLayout = RotateGrid (piece.consLayout , times);
809+ NormalizeCenterMarkers (piece.consLayout );
707810 }
708811
709812 // Rotate preview effect position and rotation
@@ -747,10 +850,12 @@ namespace RUL0 {
747850
748851 if (!piece.cellLayout .empty ()) {
749852 piece.cellLayout = TransposeGrid (piece.cellLayout );
853+ NormalizeCenterMarkers (piece.cellLayout );
750854 }
751855
752856 if (!piece.consLayout .empty ()) {
753857 piece.consLayout = TransposeGrid (piece.consLayout );
858+ NormalizeCenterMarkers (piece.consLayout );
754859 }
755860
756861 // Update effect flip state
0 commit comments