From 8f077fc6737abcea63e62f44dfbb7e432b479649 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Beno=C3=AEt=20Harrault?= <benoit@harrault.fr>
Date: Tue, 11 Feb 2025 15:23:12 +0100
Subject: [PATCH] Fix transform/rotate board

---
 .../metadata/android/en-US/changelogs/6.txt   |   1 +
 .../metadata/android/fr-FR/changelogs/6.txt   |   1 +
 lib/cubit/activity/activity_cubit.dart        |  10 +-
 lib/models/activity/activity.dart             |  59 ++++------
 lib/models/activity/board.dart                | 109 ++++++------------
 lib/ui/widgets/game/cell.dart                 |   8 +-
 lib/ui/widgets/game/game_board.dart           |  11 +-
 lib/utils/board_animate.dart                  |  16 +--
 pubspec.yaml                                  |   2 +-
 9 files changed, 80 insertions(+), 137 deletions(-)
 create mode 100644 fastlane/metadata/android/en-US/changelogs/6.txt
 create mode 100644 fastlane/metadata/android/fr-FR/changelogs/6.txt

diff --git a/fastlane/metadata/android/en-US/changelogs/6.txt b/fastlane/metadata/android/en-US/changelogs/6.txt
new file mode 100644
index 0000000..9ca157c
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/6.txt
@@ -0,0 +1 @@
+Fix rotate board.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/6.txt b/fastlane/metadata/android/fr-FR/changelogs/6.txt
new file mode 100644
index 0000000..190ff6e
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/6.txt
@@ -0,0 +1 @@
+Correction sur rotation de la grille.
diff --git a/lib/cubit/activity/activity_cubit.dart b/lib/cubit/activity/activity_cubit.dart
index 08f1f52..5f19af7 100644
--- a/lib/cubit/activity/activity_cubit.dart
+++ b/lib/cubit/activity/activity_cubit.dart
@@ -36,8 +36,6 @@ class ActivityCubit extends HydratedCubit<ActivityState> {
       boardAnimated: state.currentActivity.boardAnimated,
       // Base data
       board: state.currentActivity.board,
-      boardSizeHorizontal: state.currentActivity.boardSizeHorizontal,
-      boardSizeVertical: state.currentActivity.boardSizeVertical,
       // Game data
       boardConflicts: state.currentActivity.boardConflicts,
       selectedCell: state.currentActivity.selectedCell,
@@ -154,8 +152,8 @@ class ActivityCubit extends HydratedCubit<ActivityState> {
   }
 
   void setAnimatedBackground(List animatedCellsPattern) {
-    for (int row = 0; row < state.currentActivity.boardSizeVertical; row++) {
-      for (int col = 0; col < state.currentActivity.boardSizeHorizontal; col++) {
+    for (int row = 0; row < state.currentActivity.board.boardSizeVertical; row++) {
+      for (int col = 0; col < state.currentActivity.board.boardSizeHorizontal; col++) {
         state.currentActivity.boardAnimated[row][col] = animatedCellsPattern[row][col];
       }
     }
@@ -163,8 +161,8 @@ class ActivityCubit extends HydratedCubit<ActivityState> {
   }
 
   void resetAnimatedBackground() {
-    for (int row = 0; row < state.currentActivity.boardSizeVertical; row++) {
-      for (int col = 0; col < state.currentActivity.boardSizeHorizontal; col++) {
+    for (int row = 0; row < state.currentActivity.board.boardSizeVertical; row++) {
+      for (int col = 0; col < state.currentActivity.board.boardSizeHorizontal; col++) {
         state.currentActivity.boardAnimated[row][col] = false;
       }
     }
diff --git a/lib/models/activity/activity.dart b/lib/models/activity/activity.dart
index c633981..ab1f8ae 100644
--- a/lib/models/activity/activity.dart
+++ b/lib/models/activity/activity.dart
@@ -26,8 +26,6 @@ class Activity {
 
     // Base data
     required this.board,
-    required this.boardSizeHorizontal,
-    required this.boardSizeVertical,
 
     // Game data
     this.boardConflicts = const [],
@@ -49,8 +47,6 @@ class Activity {
 
   // Base data
   final Board board;
-  final int boardSizeHorizontal;
-  final int boardSizeVertical;
 
   // Game data
   ConflictsCount boardConflicts;
@@ -65,8 +61,6 @@ class Activity {
       activitySettings: ActivitySettings.createDefault(appConfig: ApplicationConfig.config),
       // Base data
       board: Board.createEmpty(),
-      boardSizeHorizontal: 0,
-      boardSizeVertical: 0,
       // Game data
       givenTipsCount: 0,
     );
@@ -90,15 +84,15 @@ class Activity {
       return Activity.createEmpty();
     }
 
-    final String boardSizeAsString = templateParts[0];
-    final int boardSizeHorizontal = int.parse(boardSizeAsString.split('x')[0]);
-    final int boardSizeVertical = int.parse(boardSizeAsString.split('x')[1]);
+    // Build main game board
+    final Board board = Board.createEmpty();
+    board.createFromTemplate(template: template);
 
     // Build empty conflicts board
     ConflictsCount nonConflictedBoard = [];
-    for (int row = 0; row < boardSizeVertical; row++) {
+    for (int row = 0; row < board.boardSizeVertical; row++) {
       List<int> line = [];
-      for (int col = 0; col < boardSizeHorizontal; col++) {
+      for (int col = 0; col < board.boardSizeHorizontal; col++) {
         line.add(0);
       }
       nonConflictedBoard.add(line);
@@ -106,18 +100,14 @@ class Activity {
 
     // Build empty animated background
     AnimatedBoard notAnimatedBoard = [];
-    for (int row = 0; row < boardSizeVertical; row++) {
+    for (int row = 0; row < board.boardSizeVertical; row++) {
       List<bool> line = [];
-      for (int col = 0; col < boardSizeHorizontal; col++) {
+      for (int col = 0; col < board.boardSizeHorizontal; col++) {
         line.add(false);
       }
       notAnimatedBoard.add(line);
     }
 
-    // Build main game board
-    final Board board = Board.createEmpty();
-    board.createFromTemplate(template: template);
-
     return Activity(
       // Settings
       activitySettings: newActivitySettings,
@@ -126,8 +116,6 @@ class Activity {
       boardAnimated: notAnimatedBoard,
       // Base data
       board: board,
-      boardSizeHorizontal: boardSizeHorizontal,
-      boardSizeVertical: boardSizeVertical,
       // Game data
       boardConflicts: nonConflictedBoard,
       selectedCell: null,
@@ -154,23 +142,23 @@ class Activity {
     final ConflictsCount conflicts = boardConflicts;
 
     // reset conflict states
-    for (int row = 0; row < boardSizeVertical; row++) {
-      for (int col = 0; col < boardSizeHorizontal; col++) {
+    for (int row = 0; row < board.boardSizeVertical; row++) {
+      for (int col = 0; col < board.boardSizeHorizontal; col++) {
         conflicts[row][col] = 0;
       }
     }
 
     // check siblings
-    for (int row = 0; row < boardSizeVertical; row++) {
-      for (int col = 0; col < boardSizeHorizontal; col++) {
+    for (int row = 0; row < board.boardSizeVertical; row++) {
+      for (int col = 0; col < board.boardSizeHorizontal; col++) {
         final int value = cells[row][col].value;
         if (value != 0) {
           for (int deltaRow = -1; deltaRow <= 1; deltaRow++) {
             for (int deltaCol = -1; deltaCol <= 1; deltaCol++) {
               if (row + deltaRow >= 0 &&
-                  row + deltaRow < boardSizeHorizontal &&
+                  row + deltaRow < board.boardSizeHorizontal &&
                   col + deltaCol >= 0 &&
-                  col + deltaCol < boardSizeVertical &&
+                  col + deltaCol < board.boardSizeVertical &&
                   (deltaRow * deltaCol != 0)) {
                 final int siblingValue = cells[row + deltaRow][col + deltaCol].value;
 
@@ -188,8 +176,8 @@ class Activity {
     for (String blockId in board.getBlockIds()) {
       List<int> values = [];
       List<int> duplicateValues = [];
-      for (int row = 0; row < boardSizeVertical; row++) {
-        for (int col = 0; col < boardSizeHorizontal; col++) {
+      for (int row = 0; row < board.boardSizeVertical; row++) {
+        for (int col = 0; col < board.boardSizeHorizontal; col++) {
           if (cells[row][col].blockId == blockId) {
             final int value = cells[row][col].value;
             if (value != 0) {
@@ -203,8 +191,8 @@ class Activity {
         }
       }
       for (int duplicateValue in duplicateValues) {
-        for (int row = 0; row < boardSizeVertical; row++) {
-          for (int col = 0; col < boardSizeHorizontal; col++) {
+        for (int row = 0; row < board.boardSizeVertical; row++) {
+          for (int col = 0; col < board.boardSizeHorizontal; col++) {
             if (cells[row][col].blockId == blockId &&
                 cells[row][col].value == duplicateValue) {
               conflicts[row][col]++;
@@ -289,8 +277,8 @@ class Activity {
 
     List<CellLocation> cellsWithWrongValue = [];
 
-    for (int row = 0; row < boardSizeVertical; row++) {
-      for (int col = 0; col < boardSizeHorizontal; col++) {
+    for (int row = 0; row < board.boardSizeVertical; row++) {
+      for (int col = 0; col < board.boardSizeHorizontal; col++) {
         if (cells[row][col].value != 0 &&
             cells[row][col].value != cellsSolved[row][col].value) {
           cellsWithWrongValue.add(CellLocation.go(row, col));
@@ -304,8 +292,8 @@ class Activity {
   List<CellLocation> getCellsWithConflicts() {
     List<CellLocation> cellsWithConflict = [];
 
-    for (int row = 0; row < boardSizeVertical; row++) {
-      for (int col = 0; col < boardSizeHorizontal; col++) {
+    for (int row = 0; row < board.boardSizeVertical; row++) {
+      for (int col = 0; col < board.boardSizeHorizontal; col++) {
         if (boardConflicts[row][col] != 0) {
           cellsWithConflict.add(CellLocation.go(row, col));
         }
@@ -327,9 +315,6 @@ class Activity {
     printlog('    isStarted: $isStarted');
     printlog('    isFinished: $isFinished');
     printlog('    animationInProgress: $animationInProgress');
-    printlog('  Base data');
-    printlog('    boardSizeHorizontal: $boardSizeHorizontal');
-    printlog('    boardSizeVertical: $boardSizeVertical');
     printlog('  Game data');
     printlog('    selectedCell: ${selectedCell?.toString() ?? ''}');
     printlog('    showConflicts: $showConflicts');
@@ -358,8 +343,6 @@ class Activity {
       'boardAnimated': boardAnimated,
       // Base data
       'board': board.toJson(),
-      'boardSizeHorizontal': boardSizeHorizontal,
-      'boardSizeVertical': boardSizeVertical,
       // Game data
       'boardConflicts': boardConflicts,
       'selectedCell': selectedCell?.toJson(),
diff --git a/lib/models/activity/board.dart b/lib/models/activity/board.dart
index 3b7bc38..532d297 100644
--- a/lib/models/activity/board.dart
+++ b/lib/models/activity/board.dart
@@ -17,10 +17,24 @@ class Board {
   BoardCells cells = const [];
   BoardCells solvedCells = const [];
 
-  factory Board.createEmpty() {
+  factory Board.createEmpty([final int width = 0, final int height = 0]) {
+    final BoardCells cells = [];
+    for (int rowIndex = 0; rowIndex < height; rowIndex++) {
+      final List<Cell> row = [];
+      for (int colIndex = 0; colIndex < width; colIndex++) {
+        row.add(Cell(
+          location: CellLocation.go(rowIndex, colIndex),
+          blockId: '',
+          value: 0,
+          isFixed: false,
+        ));
+      }
+      cells.add(row);
+    }
+
     return Board(
-      cells: [],
-      solvedCells: [],
+      cells: cells,
+      solvedCells: cells,
     );
   }
 
@@ -96,34 +110,12 @@ class Board {
     // cells = solvedCells;
   }
 
-  // Helper to create board from size, with "empty" cells
-  static BoardCells createEmptyBoard(final int width, final int height) {
-    final BoardCells cells = [];
-    for (int rowIndex = 0; rowIndex < height; rowIndex++) {
-      final List<Cell> row = [];
-      for (int colIndex = 0; colIndex < width; colIndex++) {
-        row.add(Cell(
-          location: CellLocation.go(rowIndex, colIndex),
-          blockId: '',
-          value: 0,
-          isFixed: false,
-        ));
-      }
-      cells.add(row);
-    }
-
-    return cells;
-  }
+  int get boardSizeVertical => cells.length;
+  int get boardSizeHorizontal => cells.isNotEmpty ? cells.first.length : 0;
 
   List<CellLocation> getCellLocations([String? blockId]) {
-    if (cells.isEmpty) {
-      return [];
-    }
-
     final List<CellLocation> locations = [];
 
-    final int boardSizeVertical = cells.length;
-    final int boardSizeHorizontal = cells[0].length;
     for (int row = 0; row < boardSizeVertical; row++) {
       for (int col = 0; col < boardSizeHorizontal; col++) {
         if ((blockId == null) || (blockId == get(CellLocation.go(row, col)).blockId)) {
@@ -136,14 +128,13 @@ class Board {
   }
 
   void transformBoard() {
-    final int boardSizeVertical = cells.length;
-    final int boardSizeHorizontal = cells[0].length;
-
     const List<String> allowedFlip = ['none', 'horizontal', 'vertical'];
-    List<String> allowedRotate = ['none', 'left', 'right', 'upsidedown'];
+    List<String> allowedRotate = [];
 
-    // Limit rotation if board is not symetric
-    if (boardSizeVertical != boardSizeHorizontal) {
+    // Force "vertical board"
+    if (boardSizeVertical < boardSizeHorizontal) {
+      allowedRotate = ['left', 'right'];
+    } else {
       allowedRotate = ['none', 'upsidedown'];
     }
 
@@ -167,12 +158,14 @@ class Board {
     switch (rotate) {
       case 'left':
         {
-          transformRotateLeft();
+          transformRotate();
+          transformRotate();
+          transformRotate();
         }
         break;
       case 'right':
         {
-          transformRotateRight();
+          transformRotate();
         }
         break;
       case 'upsidedown':
@@ -186,7 +179,6 @@ class Board {
 
   void transformFlipHorizontal() {
     final BoardCells transformedBoard = copyCells();
-    final int boardSizeVertical = cells.length;
 
     for (CellLocation location in getCellLocations()) {
       final Cell cell = cells[boardSizeVertical - location.row - 1][location.col];
@@ -202,14 +194,8 @@ class Board {
   }
 
   void transformFlipVertical() {
-    if (cells.isEmpty) {
-      return;
-    }
-
     final BoardCells transformedBoard = copyCells();
 
-    final int boardSizeHorizontal = cells[0].length;
-
     for (CellLocation location in getCellLocations()) {
       final Cell cell = cells[location.row][boardSizeHorizontal - location.col - 1];
       transformedBoard[location.row][location.col] = Cell(
@@ -223,43 +209,20 @@ class Board {
     cells = transformedBoard;
   }
 
-  void transformRotateLeft() {
-    final BoardCells transformedBoard = copyCells();
-    final int boardSizeVertical = cells.length;
+  void transformRotate() {
+    final Board transformedBoard = Board.createEmpty(boardSizeVertical, boardSizeHorizontal);
 
     for (CellLocation location in getCellLocations()) {
-      final Cell cell = cells[location.col][boardSizeVertical - location.row - 1];
-      transformedBoard[location.row][location.col] = Cell(
-        location: location,
-        blockId: cell.blockId,
-        value: cell.value,
-        isFixed: false,
-      );
-    }
-
-    cells = transformedBoard;
-  }
-
-  void transformRotateRight() {
-    if (cells.isEmpty) {
-      return;
-    }
-
-    final BoardCells transformedBoard = copyCells();
-
-    final int boardSizeHorizontal = cells[0].length;
-
-    for (CellLocation location in getCellLocations()) {
-      final Cell cell = cells[boardSizeHorizontal - location.col - 1][location.row];
-      transformedBoard[location.row][location.col] = Cell(
-        location: location,
+      final Cell cell = get(location);
+      transformedBoard.cells[location.col][location.row] = Cell(
+        location: CellLocation.go(location.col, location.row),
         blockId: cell.blockId,
         value: cell.value,
         isFixed: false,
       );
     }
 
-    cells = transformedBoard;
+    cells = transformedBoard.cells;
   }
 
   bool inBoard(CellLocation location) {
@@ -521,10 +484,6 @@ class Board {
   }
 
   bool cellHasSiblingWithSameValue(CellLocation cellLocation, [int? candidateValue]) {
-    if (cells.isEmpty) {
-      return false;
-    }
-
     final int value = candidateValue ?? get(cellLocation).value;
     if (value != 0) {
       for (int deltaCol in [-1, 0, 1]) {
diff --git a/lib/ui/widgets/game/cell.dart b/lib/ui/widgets/game/cell.dart
index 8dafbe8..4452b3a 100644
--- a/lib/ui/widgets/game/cell.dart
+++ b/lib/ui/widgets/game/cell.dart
@@ -158,25 +158,25 @@ class CellWidget extends StatelessWidget {
         top: BorderSide(
             width: cellBorderWidth,
             color: (hasBlockBorderTop ||
-                    (((cell.location.row) % activity.boardSizeVertical) == 0))
+                    (((cell.location.row) % activity.board.boardSizeVertical) == 0))
                 ? cellBorderDarkColor
                 : cellBorderLightColor),
         left: BorderSide(
             width: cellBorderWidth,
             color: (hasBlockBorderLeft ||
-                    (((cell.location.col) % activity.boardSizeHorizontal) == 0))
+                    (((cell.location.col) % activity.board.boardSizeHorizontal) == 0))
                 ? cellBorderDarkColor
                 : cellBorderLightColor),
         right: BorderSide(
             width: cellBorderWidth,
             color: (hasBlockBorderRight ||
-                    ((((cell.location.col) + 1) % activity.boardSizeHorizontal) == 0))
+                    ((((cell.location.col) + 1) % activity.board.boardSizeHorizontal) == 0))
                 ? cellBorderDarkColor
                 : cellBorderLightColor),
         bottom: BorderSide(
             width: cellBorderWidth,
             color: (hasBlockBorderBottom ||
-                    ((((cell.location.row) + 1) % activity.boardSizeVertical) == 0))
+                    ((((cell.location.row) + 1) % activity.board.boardSizeVertical) == 0))
                 ? cellBorderDarkColor
                 : cellBorderLightColor),
       );
diff --git a/lib/ui/widgets/game/game_board.dart b/lib/ui/widgets/game/game_board.dart
index 1ec0775..fc1dc77 100644
--- a/lib/ui/widgets/game/game_board.dart
+++ b/lib/ui/widgets/game/game_board.dart
@@ -1,4 +1,3 @@
-
 import 'package:flutter/material.dart';
 import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
 
@@ -38,16 +37,18 @@ class GameBoardWidget extends StatelessWidget {
               Table(
                 defaultColumnWidth: const IntrinsicColumnWidth(),
                 children: [
-                  for (int row = 0; row < currentActivity.boardSizeVertical; row++)
+                  for (int row = 0; row < currentActivity.board.boardSizeVertical; row++)
                     TableRow(
                       children: [
-                        for (int col = 0; col < currentActivity.boardSizeHorizontal; col++)
+                        for (int col = 0;
+                            col < currentActivity.board.boardSizeHorizontal;
+                            col++)
                           Column(
                             children: [
                               CellWidget(
                                 cell: currentActivity.board.get(CellLocation.go(row, col)),
                                 hasBlockBorderBottom:
-                                    row == currentActivity.boardSizeVertical ||
+                                    row == currentActivity.board.boardSizeVertical ||
                                         currentActivity.board
                                                 .get(CellLocation.go(row, col))
                                                 .blockId !=
@@ -62,7 +63,7 @@ class GameBoardWidget extends StatelessWidget {
                                             .get(CellLocation.go(row, col - 1))
                                             .blockId,
                                 hasBlockBorderRight:
-                                    col == currentActivity.boardSizeVertical ||
+                                    col == currentActivity.board.boardSizeVertical ||
                                         currentActivity.board
                                                 .get(CellLocation.go(row, col))
                                                 .blockId !=
diff --git a/lib/utils/board_animate.dart b/lib/utils/board_animate.dart
index b789581..2de63e9 100644
--- a/lib/utils/board_animate.dart
+++ b/lib/utils/board_animate.dart
@@ -13,9 +13,9 @@ class BoardAnimate {
 
     for (int patternIndex = 0; patternIndex < patternsCount; patternIndex++) {
       AnimatedBoard pattern = [];
-      for (int row = 0; row < activity.boardSizeVertical; row++) {
+      for (int row = 0; row < activity.board.boardSizeVertical; row++) {
         List<bool> patternRow = [];
-        for (int col = 0; col < activity.boardSizeHorizontal; col++) {
+        for (int col = 0; col < activity.board.boardSizeHorizontal; col++) {
           patternRow.add(((patternIndex + row + col) % 2 == 0));
         }
         pattern.add(patternRow);
@@ -30,13 +30,13 @@ class BoardAnimate {
   static AnimatedBoardSequence createWinGameAnimationPatterns(Activity activity) {
     AnimatedBoardSequence patterns = [];
 
-    int patternsCount = activity.boardSizeHorizontal + activity.boardSizeVertical;
+    int patternsCount = activity.board.boardSizeHorizontal + activity.board.boardSizeVertical;
 
     for (int patternIndex = 0; patternIndex < patternsCount; patternIndex++) {
       AnimatedBoard pattern = [];
-      for (int row = 0; row < activity.boardSizeVertical; row++) {
+      for (int row = 0; row < activity.board.boardSizeVertical; row++) {
         List<bool> patternRow = [];
-        for (int col = 0; col < activity.boardSizeHorizontal; col++) {
+        for (int col = 0; col < activity.board.boardSizeHorizontal; col++) {
           patternRow.add(row > (patternIndex - 4));
         }
         pattern.add(patternRow);
@@ -51,14 +51,14 @@ class BoardAnimate {
   static AnimatedBoardSequence createDefaultAnimationPatterns(Activity activity) {
     AnimatedBoardSequence patterns = [];
 
-    int boardSideLength = activity.boardSizeHorizontal;
+    int boardSideLength = activity.board.boardSizeHorizontal;
     int patternsCount = boardSideLength;
 
     for (int patternIndex = 0; patternIndex < patternsCount; patternIndex++) {
       AnimatedBoard pattern = [];
-      for (int row = 0; row < activity.boardSizeVertical; row++) {
+      for (int row = 0; row < activity.board.boardSizeVertical; row++) {
         List<bool> patternRow = [];
-        for (int col = 0; col < activity.boardSizeHorizontal; col++) {
+        for (int col = 0; col < activity.board.boardSizeHorizontal; col++) {
           patternRow.add(((patternIndex + row + col) % 4 == 0));
         }
         pattern.add(patternRow);
diff --git a/pubspec.yaml b/pubspec.yaml
index 8baed9f..04dbd79 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: A suguru game application.
 
 publish_to: "none"
 
-version: 0.0.5+5
+version: 0.0.6+6
 
 environment:
   sdk: "^3.0.0"
-- 
GitLab