diff --git a/android/gradle.properties b/android/gradle.properties
index 53b891875db3301fbb76f2326d54e95a4e936155..c0b881d1dd585e55b5d7819caee1bafac587748e 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx1536M
 android.useAndroidX=true
 android.enableJetifier=true
-app.versionName=0.1.16
-app.versionCode=65
+app.versionName=0.1.17
+app.versionCode=66
diff --git a/fastlane/metadata/android/en-US/changelogs/66.txt b/fastlane/metadata/android/en-US/changelogs/66.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9dc5d6607e58b7f51562cda67edeb8054845a6ef
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/66.txt
@@ -0,0 +1 @@
+Improve game architecture.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/66.txt b/fastlane/metadata/android/fr-FR/changelogs/66.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4707814df041e7b418257e0ab5472ee7fd3a45b4
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/66.txt
@@ -0,0 +1 @@
+Amélioration de la conception du jeu.
diff --git a/lib/entities/cell.dart b/lib/entities/cell.dart
index bec985d77c2f61c26dacfddf39b845004bd5f1a3..8767c741b7b3edf0380b48e12a9bbe2b1becf009 100644
--- a/lib/entities/cell.dart
+++ b/lib/entities/cell.dart
@@ -5,27 +5,30 @@ import 'package:sudoku/utils/board_animate.dart';
 import 'package:sudoku/utils/board_utils.dart';
 
 class Cell {
-  int value;
-  bool isFixed;
-  int conflictsCount = 0;
+  const Cell({
+    required this.row,
+    required this.col,
+    required this.value,
+    required this.isFixed,
+  });
 
-  bool isAnimated = false;
+  final int row;
+  final int col;
+  final int value;
+  final bool isFixed;
 
-  Cell(
-    this.value,
-    this.isFixed,
-  );
+  static const Cell none = Cell(row: 0, col: 0, value: 0, isFixed: true);
 
   /*
   * Build widget for board cell, with interactions
   */
-  Container widget(Data myProvider, int row, int col) {
+  Widget widget(Data myProvider) {
     final String imageAsset = getImageAssetName(myProvider);
 
     return Container(
       decoration: BoxDecoration(
         color: getBackgroundColor(myProvider),
-        border: getCellBorders(myProvider, row, col),
+        border: getCellBorders(myProvider),
       ),
       child: GestureDetector(
         child: AnimatedSwitcher(
@@ -40,7 +43,7 @@ class Cell {
           ),
         ),
         onTap: () {
-          if (col != myProvider.currentCellCol || row != myProvider.currentCellRow) {
+          if (col != myProvider.selectedCellCol || row != myProvider.selectedCellRow) {
             myProvider.selectCell(col, row);
           } else {
             myProvider.selectCell(null, null);
@@ -62,14 +65,14 @@ class Cell {
     Color backgroundColor = Colors.grey.shade200;
 
     if (myProvider.showConflicts &&
-        myProvider.currentCellCol != null &&
-        myProvider.currentCellRow != null) {
-      final List<List<Cell>> cells = myProvider.cells;
+        myProvider.selectedCellCol != null &&
+        myProvider.selectedCellRow != null) {
+      final Board cells = myProvider.board;
       final int blockSizeHorizontal = myProvider.blockSizeHorizontal;
       final int blockSizeVertical = myProvider.blockSizeVertical;
 
       if (!BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical,
-          myProvider.currentCellCol, myProvider.currentCellRow, value)) {
+          myProvider.selectedCellCol, myProvider.selectedCellRow, value)) {
         backgroundColor = Colors.pink.shade100;
       }
     }
@@ -85,9 +88,9 @@ class Cell {
         child: GestureDetector(
           child: Image(image: AssetImage(imageAsset), fit: BoxFit.fill),
           onTap: () {
-            if (myProvider.currentCellCol != null && myProvider.currentCellRow != null) {
+            if (myProvider.selectedCellCol != null && myProvider.selectedCellRow != null) {
               myProvider.updateCellValue(
-                  myProvider.currentCellCol, myProvider.currentCellRow, value);
+                  myProvider.selectedCellCol, myProvider.selectedCellRow, value);
             }
             myProvider.selectCell(null, null);
             if (BoardUtils.checkBoardIsSolved(myProvider)) {
@@ -126,6 +129,8 @@ class Cell {
       backgroundColor = fixedCellColor;
     }
 
+    final int conflictsCount = myProvider.boardConflicts[row][col];
+
     if (myProvider.showConflicts && (conflictsCount != 0)) {
       if (isFixed) {
         backgroundColor = fixedCellColorConflict;
@@ -134,7 +139,7 @@ class Cell {
       }
     }
 
-    if (myProvider.showConflicts && (value == myProvider.currentCellValue)) {
+    if (myProvider.showConflicts && (value == myProvider.selectedCellValue)) {
       if (isFixed) {
         backgroundColor = fixedSelectedValueColor;
       } else {
@@ -142,6 +147,8 @@ class Cell {
       }
     }
 
+    final bool isAnimated = myProvider.boardAnimated[row][col];
+
     if (isAnimated) {
       if (isFixed) {
         backgroundColor = fixedAnimated;
@@ -154,7 +161,9 @@ class Cell {
   }
 
   // Compute cell borders, from board size and cell state
-  Border getCellBorders(Data myProvider, int row, int col) {
+  Border getCellBorders(Data myProvider) {
+    // final int row = , int col;
+
     final int blockSizeHorizontal = myProvider.blockSizeHorizontal;
     final int blockSizeVertical = myProvider.blockSizeVertical;
 
@@ -184,7 +193,7 @@ class Cell {
     );
 
     // Update cell borders if not currently selected cell
-    if (col != myProvider.currentCellCol || row != myProvider.currentCellRow) {
+    if (col != myProvider.selectedCellCol || row != myProvider.selectedCellRow) {
       borders = Border(
         top: BorderSide(
             width: cellBorderWidth,
diff --git a/lib/layout/board.dart b/lib/layout/board.dart
deleted file mode 100644
index 9ad79f26143580b2586409fb5b0c647f0120de51..0000000000000000000000000000000000000000
--- a/lib/layout/board.dart
+++ /dev/null
@@ -1,41 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:sudoku/entities/cell.dart';
-import 'package:sudoku/provider/data.dart';
-
-class Board {
-  static Container buildGameBoard(Data myProvider) {
-    const Color borderColor = Colors.black;
-
-    return Container(
-      margin: const EdgeInsets.all(2),
-      padding: const EdgeInsets.all(2),
-      decoration: BoxDecoration(
-        color: borderColor,
-        borderRadius: BorderRadius.circular(2),
-        border: Border.all(
-          color: borderColor,
-          width: 2,
-        ),
-      ),
-      child: Column(
-        children: [
-          buildGameTileset(myProvider),
-        ],
-      ),
-    );
-  }
-
-  static Widget buildGameTileset(Data myProvider) {
-    final int boardSize = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
-    final List<List<Cell>> cells = myProvider.cells;
-
-    return Table(defaultColumnWidth: const IntrinsicColumnWidth(), children: [
-      for (int row = 0; row < boardSize; row++)
-        TableRow(children: [
-          for (int col = 0; col < boardSize; col++)
-            Column(children: [cells[row][col].widget(myProvider, row, col)]),
-        ]),
-    ]);
-  }
-}
diff --git a/lib/layout/game.dart b/lib/layout/game.dart
deleted file mode 100644
index a24deeafe90adc139ab86f0e1ee87d5d4586c418..0000000000000000000000000000000000000000
--- a/lib/layout/game.dart
+++ /dev/null
@@ -1,111 +0,0 @@
-import 'dart:math';
-
-import 'package:flutter/material.dart';
-
-import 'package:sudoku/entities/cell.dart';
-import 'package:sudoku/layout/board.dart';
-import 'package:sudoku/provider/data.dart';
-import 'package:sudoku/utils/board_utils.dart';
-import 'package:sudoku/utils/game_utils.dart';
-
-class Game {
-  static Widget buildGameWidget(Data myProvider) {
-    final bool gameIsFinished = BoardUtils.checkBoardIsSolved(myProvider);
-
-    return Column(
-      mainAxisAlignment: MainAxisAlignment.start,
-      crossAxisAlignment: CrossAxisAlignment.center,
-      children: [
-        Board.buildGameBoard(myProvider),
-        const SizedBox(height: 2),
-        gameIsFinished
-            ? Game.buildEndGameMessage(myProvider)
-            : Game.buildSelectCellValueBar(myProvider),
-      ],
-    );
-  }
-
-  static Container buildSelectCellValueBar(Data myProvider) {
-    final List<List<Cell>> cells = myProvider.cells;
-
-    final bool isCellSelected =
-        (myProvider.currentCellCol != null && myProvider.currentCellRow != null);
-    final bool isUpdatableCellSelected = isCellSelected
-        ? !cells[myProvider.currentCellRow ?? 0][myProvider.currentCellCol ?? 0].isFixed
-        : false;
-    final int maxValue = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
-
-    const int maxItemsPerLine = 10;
-    final int linesCount = (maxValue / maxItemsPerLine).floor() + 1;
-    final int itemsCountPerLine = min(maxItemsPerLine, maxValue + 1);
-
-    return Container(
-      margin: const EdgeInsets.all(2),
-      padding: const EdgeInsets.all(2),
-      child: Table(
-        defaultColumnWidth: const IntrinsicColumnWidth(),
-        children: [
-          for (int lineIndex = 0; lineIndex < linesCount; lineIndex++)
-            TableRow(
-              children: [
-                for (int value = lineIndex * itemsCountPerLine;
-                    value < (lineIndex + 1) * itemsCountPerLine;
-                    value++)
-                  Column(
-                    children: [
-                      Cell(isUpdatableCellSelected ? (value <= maxValue ? value : -1) : -1,
-                              false)
-                          .widgetUpdateValue(myProvider)
-                    ],
-                  ),
-              ],
-            ),
-        ],
-      ),
-    );
-  }
-
-  static Widget buildRestartGameButton(Data myProvider) {
-    return TextButton(
-      child: const Image(
-        image: AssetImage('assets/icons/button_back.png'),
-        fit: BoxFit.fill,
-      ),
-      onPressed: () => GameUtils.quitGame(myProvider),
-    );
-  }
-
-  static Container buildEndGameMessage(Data myProvider) {
-    const Image decorationImage = Image(
-      image: AssetImage('assets/icons/game_win.png'),
-      fit: BoxFit.fill,
-    );
-
-    return Container(
-      margin: const EdgeInsets.all(2),
-      padding: const EdgeInsets.all(2),
-      child: Table(
-        defaultColumnWidth: const IntrinsicColumnWidth(),
-        children: [
-          TableRow(
-            children: [
-              const Column(
-                children: [decorationImage],
-              ),
-              Column(
-                children: [
-                  myProvider.animationInProgress
-                      ? decorationImage
-                      : buildRestartGameButton(myProvider)
-                ],
-              ),
-              const Column(
-                children: [decorationImage],
-              ),
-            ],
-          ),
-        ],
-      ),
-    );
-  }
-}
diff --git a/lib/main.dart b/lib/main.dart
index 285517806e7383aed247fd7fa1b656f6a329ee36..a1fc31fe9c887e17017e8450e8740e2dd2b7c8b7 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -4,7 +4,7 @@ import 'package:provider/provider.dart';
 import 'package:overlay_support/overlay_support.dart';
 
 import 'package:sudoku/provider/data.dart';
-import 'package:sudoku/screens/home.dart';
+import 'package:sudoku/ui/screens/home.dart';
 
 void main() {
   WidgetsFlutterBinding.ensureInitialized();
@@ -27,9 +27,6 @@ class MyApp extends StatelessWidget {
               visualDensity: VisualDensity.adaptivePlatformDensity,
             ),
             home: const Home(),
-            routes: {
-              Home.id: (context) => const Home(),
-            },
           ),
         );
       }),
diff --git a/lib/provider/data.dart b/lib/provider/data.dart
index b03d01be04307940e04998a3789a29f75d53138c..64585c0117478b18cee5e868cbf04042b5064a93 100644
--- a/lib/provider/data.dart
+++ b/lib/provider/data.dart
@@ -6,6 +6,11 @@ import 'package:shared_preferences/shared_preferences.dart';
 import 'package:sudoku/entities/cell.dart';
 import 'package:sudoku/utils/tools.dart';
 
+typedef Board = List<List<Cell>>;
+typedef ConflictsCount = List<List<int>>;
+typedef AnimatedBoard = List<List<bool>>;
+typedef AnimatedBoardSequence = List<AnimatedBoard>;
+
 class Data extends ChangeNotifier {
   // Configuration available values
   final List<String> _availableParameters = ['level', 'size', 'skin'];
@@ -39,15 +44,17 @@ class Data extends ChangeNotifier {
   bool _animationInProgress = false;
   int _blockSizeVertical = 0;
   int _blockSizeHorizontal = 0;
-  List<List<Cell>> _cells = [];
-  List<List<Cell>> _cellsSolved = [];
+  Board _board = [];
+  Board _boardSolved = [];
+  ConflictsCount _boardConflicts = [];
+  AnimatedBoard _boardAnimated = [];
   List<int> _shuffledCellValues = [];
-  int? _currentCellCol;
-  int? _currentCellRow;
-  int? _currentCellValue;
+  int? _selectedCellCol;
+  int? _selectedCellRow;
+  int? _selectedCellValue;
   bool _showConflicts = false;
   int _givenTipsCount = 0;
-  String _currentState = '';
+  String _currentSavedState = '';
 
   void updateParameterLevel(String parameterLevel) {
     _parameterLevel = parameterLevel;
@@ -115,15 +122,15 @@ class Data extends ChangeNotifier {
     setParameterValue('skin', prefs.getString('skin') ?? _parameterSkinDefault);
   }
 
-  String get currentState => _currentState;
+  String get currentSavedState => _currentSavedState;
 
   String computeCurrentGameState() {
     String cellsValues = '';
     const String stringValues = '0123456789ABCDEFG';
-    for (int rowIndex = 0; rowIndex < _cells.length; rowIndex++) {
-      for (int colIndex = 0; colIndex < _cells[rowIndex].length; colIndex++) {
-        cellsValues += stringValues[_cells[rowIndex][colIndex].value];
-        cellsValues += _cells[rowIndex][colIndex].isFixed ? 'x' : ' ';
+    for (int rowIndex = 0; rowIndex < _board.length; rowIndex++) {
+      for (int colIndex = 0; colIndex < _board[rowIndex].length; colIndex++) {
+        cellsValues += stringValues[_board[rowIndex][colIndex].value];
+        cellsValues += _board[rowIndex][colIndex].isFixed ? 'x' : ' ';
       }
     }
 
@@ -140,35 +147,35 @@ class Data extends ChangeNotifier {
 
   void saveCurrentGameState() async {
     if (_gameIsRunning) {
-      _currentState = computeCurrentGameState();
+      _currentSavedState = computeCurrentGameState();
 
       final prefs = await SharedPreferences.getInstance();
-      prefs.setString('savedState', _currentState);
+      prefs.setString('savedState', _currentSavedState);
     } else {
       resetCurrentSavedState();
     }
   }
 
   void resetCurrentSavedState() async {
-    _currentState = '';
+    _currentSavedState = '';
 
     final prefs = await SharedPreferences.getInstance();
-    prefs.setString('savedState', _currentState);
+    prefs.setString('savedState', _currentSavedState);
     notifyListeners();
   }
 
   void loadCurrentSavedState() async {
     final prefs = await SharedPreferences.getInstance();
-    _currentState = prefs.getString('savedState') ?? '';
+    _currentSavedState = prefs.getString('savedState') ?? '';
   }
 
   bool hasCurrentSavedState() {
-    return (_currentState != '');
+    return (_currentSavedState != '');
   }
 
   Map<String, dynamic> getCurrentSavedState() {
-    if (_currentState != '') {
-      Map<String, dynamic> savedState = json.decode(_currentState);
+    if (_currentSavedState != '') {
+      Map<String, dynamic> savedState = json.decode(_currentSavedState);
       if (savedState.isNotEmpty) {
         return savedState;
       }
@@ -187,17 +194,20 @@ class Data extends ChangeNotifier {
     _assetsPreloaded = assetsPreloaded;
   }
 
-  List<List<Cell>> get cells => _cells;
-  void updateCells(List<List<Cell>> cells) {
-    _cells = cells;
+  Board get board => _board;
+  void updateCells(Board board) {
+    _board = board;
     notifyListeners();
   }
 
-  List<List<Cell>> get cellsSolved => _cellsSolved;
-  void updateCellsSolved(List<List<Cell>> cells) {
-    _cellsSolved = cells;
+  Board get boardSolved => _boardSolved;
+  void updateCellsSolved(Board boardSolved) {
+    _boardSolved = boardSolved;
   }
 
+  AnimatedBoard get boardAnimated => _boardAnimated;
+  ConflictsCount get boardConflicts => _boardConflicts;
+
   void shuffleCellValues() {
     const int maxCellValue = 16;
     final List<int> values = List<int>.generate(maxCellValue, (i) => i + 1);
@@ -218,21 +228,21 @@ class Data extends ChangeNotifier {
     return _shuffledCellValues[originalValue - 1];
   }
 
-  int? get currentCellCol => _currentCellCol;
-  set updateCurrentCellCol(int? currentCellCol) {
-    _currentCellCol = currentCellCol;
+  int? get selectedCellCol => _selectedCellCol;
+  set updateCelectedCellCol(int? selectedCellCol) {
+    _selectedCellCol = selectedCellCol;
     notifyListeners();
   }
 
-  int? get currentCellRow => _currentCellRow;
-  set updateCurrentCellRow(int? currentCellRow) {
-    _currentCellRow = currentCellRow;
+  int? get selectedCellRow => _selectedCellRow;
+  set updateSelectedCellRow(int? selectedCellRow) {
+    _selectedCellRow = selectedCellRow;
     notifyListeners();
   }
 
-  int? get currentCellValue => _currentCellValue;
-  set updateCurrentCellValue(int? currentCellValue) {
-    _currentCellValue = currentCellValue;
+  int? get selectedCellValue => _selectedCellValue;
+  set updateSelectedCellValue(int? selectedCellValue) {
+    _selectedCellValue = selectedCellValue;
     notifyListeners();
   }
 
@@ -253,21 +263,43 @@ class Data extends ChangeNotifier {
   }
 
   selectCell(int? col, int? row) {
-    _currentCellCol = col;
-    _currentCellRow = row;
-    _currentCellValue = null;
+    _selectedCellCol = col;
+    _selectedCellRow = row;
+    _selectedCellValue = null;
     if (row != null && col != null) {
-      if (_cells[row][col].value != 0) {
-        _currentCellValue = _cells[row][col].value;
+      if (_board[row][col].value != 0) {
+        _selectedCellValue = _board[row][col].value;
       }
     }
     notifyListeners();
   }
 
+  void initConflictsBoard() {
+    ConflictsCount nonConflictedBoard = [];
+    final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical;
+    for (int row = 0; row < boardSideLength; row++) {
+      List<int> line = [];
+      for (int col = 0; col < boardSideLength; col++) {
+        line.add(0);
+      }
+      nonConflictedBoard.add(line);
+    }
+    _boardConflicts = nonConflictedBoard;
+  }
+
+  void updateConflicts(ConflictsCount conflictsCount) {
+    _boardConflicts = conflictsCount;
+  }
+
   updateCellValue(int? col, int? row, int value) {
     if ((col != null) && (row != null)) {
-      if (!_cells[row][col].isFixed) {
-        _cells[row][col].value = value;
+      if (!_board[row][col].isFixed) {
+        _board[row][col] = Cell(
+          row: row,
+          col: col,
+          value: value,
+          isFixed: false,
+        );
 
         saveCurrentGameState();
         notifyListeners();
@@ -292,11 +324,24 @@ class Data extends ChangeNotifier {
     notifyListeners();
   }
 
+  void initAnimatedBackground() {
+    AnimatedBoard staticBoard = [];
+    final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical;
+    for (int row = 0; row < boardSideLength; row++) {
+      List<bool> line = [];
+      for (int col = 0; col < boardSideLength; col++) {
+        line.add(false);
+      }
+      staticBoard.add(line);
+    }
+    _boardAnimated = staticBoard;
+  }
+
   void setAnimatedBackground(List animatedCellsPattern) {
     final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical;
     for (int row = 0; row < boardSideLength; row++) {
       for (int col = 0; col < boardSideLength; col++) {
-        _cells[row][col].isAnimated = animatedCellsPattern[row][col];
+        _boardAnimated[row][col] = animatedCellsPattern[row][col];
       }
     }
     notifyListeners();
@@ -306,7 +351,7 @@ class Data extends ChangeNotifier {
     final int boardSideLength = _blockSizeHorizontal * _blockSizeVertical;
     for (int row = 0; row < boardSideLength; row++) {
       for (int col = 0; col < boardSideLength; col++) {
-        _cells[row][col].isAnimated = false;
+        _boardAnimated[row][col] = false;
       }
     }
   }
diff --git a/lib/ui/layout/board.dart b/lib/ui/layout/board.dart
new file mode 100644
index 0000000000000000000000000000000000000000..069557ef249bea8deb463c029133df17f038fd13
--- /dev/null
+++ b/lib/ui/layout/board.dart
@@ -0,0 +1,48 @@
+import 'package:flutter/material.dart';
+
+import 'package:sudoku/provider/data.dart';
+
+class BoardLayout extends StatelessWidget {
+  const BoardLayout({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Container build(BuildContext context) {
+    const Color borderColor = Colors.black;
+    final int boardSize = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
+
+    final Widget gameTileset = Table(
+      defaultColumnWidth: const IntrinsicColumnWidth(),
+      children: [
+        for (int row = 0; row < boardSize; row++)
+          TableRow(
+            children: [
+              for (int col = 0; col < boardSize; col++)
+                Column(
+                  children: [myProvider.board[row][col].widget(myProvider)],
+                ),
+            ],
+          ),
+      ],
+    );
+
+    return Container(
+      margin: const EdgeInsets.all(2),
+      padding: const EdgeInsets.all(2),
+      decoration: BoxDecoration(
+        color: borderColor,
+        borderRadius: BorderRadius.circular(2),
+        border: Border.all(
+          color: borderColor,
+          width: 2,
+        ),
+      ),
+      child: Column(
+        children: [
+          gameTileset,
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/ui/layout/game.dart b/lib/ui/layout/game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..e6cc4ee582875b63e60d5ed2b8951580277a9af0
--- /dev/null
+++ b/lib/ui/layout/game.dart
@@ -0,0 +1,30 @@
+import 'package:flutter/material.dart';
+
+import 'package:sudoku/ui/layout/board.dart';
+import 'package:sudoku/ui/widgets/message_game_end.dart';
+import 'package:sudoku/ui/widgets/bar_select_cell_value.dart';
+import 'package:sudoku/provider/data.dart';
+import 'package:sudoku/utils/board_utils.dart';
+
+class Game extends StatelessWidget {
+  const Game({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    final bool gameIsFinished = BoardUtils.checkBoardIsSolved(myProvider);
+
+    return Column(
+      mainAxisAlignment: MainAxisAlignment.start,
+      crossAxisAlignment: CrossAxisAlignment.center,
+      children: [
+        BoardLayout(myProvider: myProvider),
+        const SizedBox(height: 2),
+        gameIsFinished
+            ? EndGameMessage(myProvider: myProvider)
+            : SelectCellValueBar(myProvider: myProvider),
+      ],
+    );
+  }
+}
diff --git a/lib/layout/parameters.dart b/lib/ui/layout/parameters.dart
similarity index 61%
rename from lib/layout/parameters.dart
rename to lib/ui/layout/parameters.dart
index 7a3e5f1e515ba0dc81092bdc3758736e2a0ed138..abd8b9c25df646b7e7c4e75bb53aeacc7585d3de 100644
--- a/lib/layout/parameters.dart
+++ b/lib/ui/layout/parameters.dart
@@ -1,9 +1,14 @@
 import 'package:flutter/material.dart';
 
 import 'package:sudoku/provider/data.dart';
-import 'package:sudoku/utils/game_utils.dart';
+import 'package:sudoku/ui/widgets/button_game_resume.dart';
+import 'package:sudoku/ui/widgets/button_game_start_new.dart';
+
+class Parameters extends StatelessWidget {
+  const Parameters({super.key, required this.myProvider});
+
+  final Data myProvider;
 
-class Parameters {
   static const double separatorHeight = 2.0;
   static const double blockMargin = 3.0;
   static const double blockPadding = 2.0;
@@ -15,7 +20,8 @@ class Parameters {
   static const double buttonPadding = 0.0;
   static const double buttonMargin = 0.0;
 
-  static Widget buildParametersSelector(Data myProvider) {
+  @override
+  Widget build(BuildContext context) {
     List<Widget> lines = [];
 
     List<String> parameters = myProvider.availableParameters;
@@ -26,8 +32,8 @@ class Parameters {
 
     myProvider.loadCurrentSavedState();
     Widget buttonsBlock = myProvider.hasCurrentSavedState()
-        ? buildResumeGameButton(myProvider)
-        : buildStartNewGameButton(myProvider);
+        ? ResumeGameButton(myProvider: myProvider)
+        : StartNewGameButton(myProvider: myProvider);
 
     return Column(
       mainAxisAlignment: MainAxisAlignment.start,
@@ -73,66 +79,7 @@ class Parameters {
     );
   }
 
-  static Container buildStartNewGameButton(Data myProvider) {
-    return Container(
-      margin: const EdgeInsets.all(blockMargin),
-      padding: const EdgeInsets.all(blockPadding),
-      child: Table(
-        defaultColumnWidth: const IntrinsicColumnWidth(),
-        children: [
-          TableRow(
-            children: [
-              buildDecorationImageWidget(),
-              Column(
-                children: [
-                  TextButton(
-                    child: buildImageContainerWidget('button_start'),
-                    onPressed: () => GameUtils.startNewGame(myProvider),
-                  ),
-                ],
-              ),
-              buildDecorationImageWidget(),
-            ],
-          ),
-        ],
-      ),
-    );
-  }
-
-  static Container buildResumeGameButton(Data myProvider) {
-    return Container(
-      margin: const EdgeInsets.all(blockMargin),
-      padding: const EdgeInsets.all(blockPadding),
-      child: Table(
-        defaultColumnWidth: const IntrinsicColumnWidth(),
-        children: [
-          TableRow(
-            children: [
-              Column(
-                children: [
-                  TextButton(
-                    child: buildImageContainerWidget('button_delete_saved_game'),
-                    onPressed: () => GameUtils.deleteSavedGame(myProvider),
-                  ),
-                ],
-              ),
-              Column(
-                children: [
-                  TextButton(
-                    child: buildImageContainerWidget('button_resume_game'),
-                    onPressed: () => GameUtils.resumeSavedGame(myProvider),
-                  ),
-                ],
-              ),
-              buildDecorationImageWidget(),
-            ],
-          ),
-        ],
-      ),
-    );
-  }
-
-  static Widget buildParameterSelector(Data myProvider, String parameterCode) {
+  Widget buildParameterSelector(Data myProvider, String parameterCode) {
     List<String> availableValues = myProvider.getParameterAvailableValues(parameterCode);
 
     if (availableValues.length == 1) {
@@ -156,8 +103,7 @@ class Parameters {
     );
   }
 
-  static Widget _buildParameterButton(
-      Data myProvider, String parameterCode, String parameterValue) {
+  Widget _buildParameterButton(Data myProvider, String parameterCode, String parameterValue) {
     String currentValue = myProvider.getParameterValue(parameterCode).toString();
 
     bool isActive = (parameterValue == currentValue);
diff --git a/lib/screens/home.dart b/lib/ui/screens/home.dart
similarity index 93%
rename from lib/screens/home.dart
rename to lib/ui/screens/home.dart
index 90b6ffbfd9ad735c14dbb847ce3854c76c1f01db..af2cfa1f08d8c050725e7bf1425b56e9115d9f5d 100644
--- a/lib/screens/home.dart
+++ b/lib/ui/screens/home.dart
@@ -3,14 +3,12 @@ import 'package:provider/provider.dart';
 import 'package:badges/badges.dart' as badges;
 import 'package:overlay_support/overlay_support.dart';
 
-import 'package:sudoku/layout/game.dart';
-import 'package:sudoku/layout/parameters.dart';
+import 'package:sudoku/ui/layout/game.dart';
+import 'package:sudoku/ui/layout/parameters.dart';
 import 'package:sudoku/provider/data.dart';
 import 'package:sudoku/utils/game_utils.dart';
 
 class Home extends StatefulWidget {
-  static const String id = 'home';
-
   const Home({super.key});
 
   @override
@@ -69,7 +67,7 @@ class HomeState extends State<Home> {
     final Data myProvider = Provider.of<Data>(context);
 
     if (!myProvider.assetsPreloaded) {
-      List<String> assets = getImagesAssets(myProvider);
+      final List<String> assets = getImagesAssets(myProvider);
       for (String asset in assets) {
         precacheImage(AssetImage(asset), context);
       }
@@ -155,8 +153,8 @@ class HomeState extends State<Home> {
       body: SafeArea(
         child: Center(
           child: myProvider.gameIsRunning
-              ? Game.buildGameWidget(myProvider)
-              : Parameters.buildParametersSelector(myProvider),
+              ? Game(myProvider: myProvider)
+              : Parameters(myProvider: myProvider),
         ),
       ),
     );
diff --git a/lib/ui/widgets/bar_select_cell_value.dart b/lib/ui/widgets/bar_select_cell_value.dart
new file mode 100644
index 0000000000000000000000000000000000000000..581b36491edb1d2ce4d8f9be313ccdfd2df51e08
--- /dev/null
+++ b/lib/ui/widgets/bar_select_cell_value.dart
@@ -0,0 +1,56 @@
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+
+import 'package:sudoku/entities/cell.dart';
+import 'package:sudoku/provider/data.dart';
+
+class SelectCellValueBar extends StatelessWidget {
+  const SelectCellValueBar({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    final Board cells = myProvider.board;
+
+    final bool isCellSelected =
+        (myProvider.selectedCellCol != null && myProvider.selectedCellRow != null);
+    final bool isUpdatableCellSelected = isCellSelected
+        ? !cells[myProvider.selectedCellRow ?? 0][myProvider.selectedCellCol ?? 0].isFixed
+        : false;
+    final int maxValue = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
+
+    const int maxItemsPerLine = 10;
+    final int linesCount = (maxValue / maxItemsPerLine).floor() + 1;
+    final int itemsCountPerLine = min(maxItemsPerLine, maxValue + 1);
+
+    return Container(
+      margin: const EdgeInsets.all(2),
+      padding: const EdgeInsets.all(2),
+      child: Table(
+        defaultColumnWidth: const IntrinsicColumnWidth(),
+        children: [
+          for (int lineIndex = 0; lineIndex < linesCount; lineIndex++)
+            TableRow(
+              children: [
+                for (int value = lineIndex * itemsCountPerLine;
+                    value < (lineIndex + 1) * itemsCountPerLine;
+                    value++)
+                  Column(
+                    children: [
+                      Cell(
+                        row: 1,
+                        col: value,
+                        value: isUpdatableCellSelected ? (value <= maxValue ? value : -1) : -1,
+                        isFixed: false,
+                      ).widgetUpdateValue(myProvider)
+                    ],
+                  ),
+              ],
+            ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/ui/widgets/button_game_restart.dart b/lib/ui/widgets/button_game_restart.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a2e8b670a6cb3ebe8753baf5a7a331a53b3a5286
--- /dev/null
+++ b/lib/ui/widgets/button_game_restart.dart
@@ -0,0 +1,21 @@
+import 'package:flutter/material.dart';
+
+import 'package:sudoku/provider/data.dart';
+import 'package:sudoku/utils/game_utils.dart';
+
+class RestartGameButton extends StatelessWidget {
+  const RestartGameButton({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    return TextButton(
+      child: const Image(
+        image: AssetImage('assets/icons/button_back.png'),
+        fit: BoxFit.fill,
+      ),
+      onPressed: () => GameUtils.quitGame(myProvider),
+    );
+  }
+}
diff --git a/lib/ui/widgets/button_game_resume.dart b/lib/ui/widgets/button_game_resume.dart
new file mode 100644
index 0000000000000000000000000000000000000000..41cb5688656aecce2faa0238717b9bb5d653eb9d
--- /dev/null
+++ b/lib/ui/widgets/button_game_resume.dart
@@ -0,0 +1,42 @@
+import 'package:flutter/material.dart';
+
+import 'package:sudoku/ui/layout/parameters.dart';
+import 'package:sudoku/utils/game_utils.dart';
+
+class ResumeGameButton extends Parameters {
+  const ResumeGameButton({super.key, required super.myProvider});
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      margin: const EdgeInsets.all(Parameters.blockMargin),
+      padding: const EdgeInsets.all(Parameters.blockPadding),
+      child: Table(
+        defaultColumnWidth: const IntrinsicColumnWidth(),
+        children: [
+          TableRow(
+            children: [
+              Column(
+                children: [
+                  TextButton(
+                    child: Parameters.buildImageContainerWidget('button_delete_saved_game'),
+                    onPressed: () => GameUtils.deleteSavedGame(myProvider),
+                  ),
+                ],
+              ),
+              Column(
+                children: [
+                  TextButton(
+                    child: Parameters.buildImageContainerWidget('button_resume_game'),
+                    onPressed: () => GameUtils.resumeSavedGame(myProvider),
+                  ),
+                ],
+              ),
+              Parameters.buildDecorationImageWidget(),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/ui/widgets/button_game_start_new.dart b/lib/ui/widgets/button_game_start_new.dart
new file mode 100644
index 0000000000000000000000000000000000000000..88e004d9a4bd18f317c22f774762916b635ac568
--- /dev/null
+++ b/lib/ui/widgets/button_game_start_new.dart
@@ -0,0 +1,38 @@
+import 'package:flutter/material.dart';
+
+import 'package:sudoku/provider/data.dart';
+import 'package:sudoku/ui/layout/parameters.dart';
+import 'package:sudoku/utils/game_utils.dart';
+
+class StartNewGameButton extends StatelessWidget {
+  const StartNewGameButton({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      margin: const EdgeInsets.all(Parameters.blockMargin),
+      padding: const EdgeInsets.all(Parameters.blockPadding),
+      child: Table(
+        defaultColumnWidth: const IntrinsicColumnWidth(),
+        children: [
+          TableRow(
+            children: [
+              Parameters.buildDecorationImageWidget(),
+              Column(
+                children: [
+                  TextButton(
+                    child: Parameters.buildImageContainerWidget('button_start'),
+                    onPressed: () => GameUtils.startNewGame(myProvider),
+                  ),
+                ],
+              ),
+              Parameters.buildDecorationImageWidget(),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/ui/widgets/message_game_end.dart b/lib/ui/widgets/message_game_end.dart
new file mode 100644
index 0000000000000000000000000000000000000000..168e055e50074f24ad953566e5c52d9df8633e5d
--- /dev/null
+++ b/lib/ui/widgets/message_game_end.dart
@@ -0,0 +1,45 @@
+import 'package:flutter/material.dart';
+
+import 'package:sudoku/ui/widgets/button_game_restart.dart';
+import 'package:sudoku/provider/data.dart';
+
+class EndGameMessage extends StatelessWidget {
+  const EndGameMessage({super.key, required this.myProvider});
+
+  final Data myProvider;
+
+  @override
+  Widget build(BuildContext context) {
+    const Image decorationImage = Image(
+      image: AssetImage('assets/icons/game_win.png'),
+      fit: BoxFit.fill,
+    );
+
+    return Container(
+      margin: const EdgeInsets.all(2),
+      padding: const EdgeInsets.all(2),
+      child: Table(
+        defaultColumnWidth: const IntrinsicColumnWidth(),
+        children: [
+          TableRow(
+            children: [
+              const Column(
+                children: [decorationImage],
+              ),
+              Column(
+                children: [
+                  myProvider.animationInProgress
+                      ? decorationImage
+                      : RestartGameButton(myProvider: myProvider)
+                ],
+              ),
+              const Column(
+                children: [decorationImage],
+              ),
+            ],
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/utils/board_animate.dart b/lib/utils/board_animate.dart
index e3f7a93e1b9bde590e5ea10d58c71a1507217908..dd28298a282b09ec9ce4b7d1ce82903616b46dee 100644
--- a/lib/utils/board_animate.dart
+++ b/lib/utils/board_animate.dart
@@ -4,14 +4,14 @@ import 'package:sudoku/provider/data.dart';
 
 class BoardAnimate {
   // Start game animation: blinking tiles
-  static List<List<List<bool>>> createStartGameAnimationPatterns(Data myProvider) {
-    List<List<List<bool>>> patterns = [];
+  static AnimatedBoardSequence createStartGameAnimationPatterns(Data myProvider) {
+    AnimatedBoardSequence patterns = [];
 
     int patternsCount = 3;
     int boardSideLength = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
 
     for (int patternIndex = 0; patternIndex < patternsCount; patternIndex++) {
-      List<List<bool>> pattern = [];
+      AnimatedBoard pattern = [];
       for (int row = 0; row < boardSideLength; row++) {
         List<bool> patternRow = [];
         for (int col = 0; col < boardSideLength; col++) {
@@ -26,14 +26,14 @@ class BoardAnimate {
   }
 
   // Win game animation: fill board with colored rows, from bottom to top
-  static List<List<List<bool>>> createWinGameAnimationPatterns(Data myProvider) {
-    List<List<List<bool>>> patterns = [];
+  static AnimatedBoardSequence createWinGameAnimationPatterns(Data myProvider) {
+    AnimatedBoardSequence patterns = [];
 
     int boardSideLength = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
     int patternsCount = boardSideLength + 6;
 
     for (int patternIndex = 0; patternIndex < patternsCount; patternIndex++) {
-      List<List<bool>> pattern = [];
+      AnimatedBoard pattern = [];
       for (int row = 0; row < boardSideLength; row++) {
         List<bool> patternRow = [];
         for (int col = 0; col < boardSideLength; col++) {
@@ -48,14 +48,14 @@ class BoardAnimate {
   }
 
   // Default multi-purpose animation: sliding stripes, from top left to right bottom
-  static List<List<List<bool>>> createDefaultAnimationPatterns(Data myProvider) {
-    List<List<List<bool>>> patterns = [];
+  static AnimatedBoardSequence createDefaultAnimationPatterns(Data myProvider) {
+    AnimatedBoardSequence patterns = [];
 
     int boardSideLength = myProvider.blockSizeHorizontal * myProvider.blockSizeVertical;
     int patternsCount = boardSideLength;
 
     for (int patternIndex = 0; patternIndex < patternsCount; patternIndex++) {
-      List<List<bool>> pattern = [];
+      AnimatedBoard pattern = [];
       for (int row = 0; row < boardSideLength; row++) {
         List<bool> patternRow = [];
         for (int col = 0; col < boardSideLength; col++) {
@@ -70,7 +70,7 @@ class BoardAnimate {
   }
 
   static void startAnimation(Data myProvider, String animationType) {
-    List<List<List<bool>>> patterns = [];
+    AnimatedBoardSequence patterns = [];
 
     switch (animationType) {
       case 'start':
diff --git a/lib/utils/board_utils.dart b/lib/utils/board_utils.dart
index 624814daff232231479c0f4286c03e79bfd7a00b..8f0a835da2297b5fafebf68e5ba164ba718a8bee 100644
--- a/lib/utils/board_utils.dart
+++ b/lib/utils/board_utils.dart
@@ -6,7 +6,7 @@ import 'package:sudoku/utils/random_pick_grid.dart';
 import 'package:sudoku/utils/tools.dart';
 
 class BoardUtils {
-  static printGrid(List<List<Cell>> cells, List<List<Cell>> solvedCells) {
+  static printGrid(Board cells, Board solvedCells) {
     String stringValues = '0123456789ABCDEFG';
     printlog('');
     printlog('-------');
@@ -42,16 +42,21 @@ class BoardUtils {
       myProvider.updateCellsSolved(BoardUtils.getSolvedGrid(myProvider));
       myProvider.selectCell(null, null);
 
-      printGrid(myProvider.cells, myProvider.cellsSolved);
+      printGrid(myProvider.board, myProvider.boardSolved);
     }
   }
 
-  static List<List<Cell>> createEmptyBoard(final int boardSize) {
-    final List<List<Cell>> cells = [];
+  static Board createEmptyBoard(final int boardSize) {
+    final Board cells = [];
     for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
       final List<Cell> row = [];
       for (int colIndex = 0; colIndex < boardSize; colIndex++) {
-        row.add(Cell(0, false));
+        row.add(Cell(
+          row: rowIndex,
+          col: colIndex,
+          value: 0,
+          isFixed: false,
+        ));
       }
       cells.add(row);
     }
@@ -59,8 +64,8 @@ class BoardUtils {
     return cells;
   }
 
-  static List<List<Cell>> createBoardFromSavedState(Data myProvider, String savedBoard) {
-    final List<List<Cell>> cells = [];
+  static Board createBoardFromSavedState(Data myProvider, String savedBoard) {
+    final Board cells = [];
     final int boardSize = int.parse(pow((savedBoard.length / 2), 1 / 2).toStringAsFixed(0));
 
     const String stringValues = '0123456789ABCDEFG';
@@ -75,7 +80,12 @@ class BoardUtils {
         final String isFixedString = savedBoard[index++];
         final bool isFixed = (isFixedString != ' ');
 
-        row.add(Cell(value, isFixed));
+        row.add(Cell(
+          row: rowIndex,
+          col: colIndex,
+          value: value,
+          isFixed: isFixed,
+        ));
       }
       cells.add(row);
     }
@@ -83,12 +93,17 @@ class BoardUtils {
     return cells;
   }
 
-  static List<List<Cell>> copyBoard(List cells) {
-    final List<List<Cell>> copiedGrid = [];
+  static Board copyBoard(List cells) {
+    final Board copiedGrid = [];
     for (int rowIndex = 0; rowIndex < cells.length; rowIndex++) {
       final List<Cell> row = [];
       for (int colIndex = 0; colIndex < cells[rowIndex].length; colIndex++) {
-        row.add(Cell(cells[rowIndex][colIndex].value, false));
+        row.add(Cell(
+          row: rowIndex,
+          col: colIndex,
+          value: cells[rowIndex][colIndex].value,
+          isFixed: false,
+        ));
       }
       copiedGrid.add(row);
     }
@@ -96,8 +111,8 @@ class BoardUtils {
     return copiedGrid;
   }
 
-  static List<List<Cell>> createBoardFromTemplate(String grid, bool isSymetric) {
-    List<List<Cell>> cells = [];
+  static Board createBoardFromTemplate(String grid, bool isSymetric) {
+    Board cells = [];
     final int boardSize = int.parse(pow(grid.length, 1 / 2).toStringAsFixed(0));
 
     const String stringValues = '0123456789ABCDEFG';
@@ -108,7 +123,12 @@ class BoardUtils {
       for (int colIndex = 0; colIndex < boardSize; colIndex++) {
         final String stringValue = grid[index++];
         final int value = stringValues.indexOf(stringValue);
-        row.add(Cell(value, (value != 0)));
+        row.add(Cell(
+          row: rowIndex,
+          col: colIndex,
+          value: value,
+          isFixed: (value != 0),
+        ));
       }
       cells.add(row);
     }
@@ -131,11 +151,15 @@ class BoardUtils {
     switch (flip) {
       case 'horizontal':
         {
-          final List<List<Cell>> transformedBoard = createEmptyBoard(boardSize);
+          final Board transformedBoard = createEmptyBoard(boardSize);
           for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
             for (int colIndex = 0; colIndex < boardSize; colIndex++) {
-              transformedBoard[rowIndex][colIndex].value =
-                  cells[boardSize - rowIndex - 1][colIndex].value;
+              transformedBoard[rowIndex][colIndex] = Cell(
+                row: rowIndex,
+                col: colIndex,
+                value: cells[boardSize - rowIndex - 1][colIndex].value,
+                isFixed: false,
+              );
             }
           }
           cells = transformedBoard;
@@ -143,11 +167,15 @@ class BoardUtils {
         break;
       case 'vertical':
         {
-          final List<List<Cell>> transformedBoard = createEmptyBoard(boardSize);
+          final Board transformedBoard = createEmptyBoard(boardSize);
           for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
             for (int colIndex = 0; colIndex < boardSize; colIndex++) {
-              transformedBoard[rowIndex][colIndex].value =
-                  cells[rowIndex][boardSize - colIndex - 1].value;
+              transformedBoard[rowIndex][colIndex] = Cell(
+                row: rowIndex,
+                col: colIndex,
+                value: cells[rowIndex][boardSize - colIndex - 1].value,
+                isFixed: false,
+              );
             }
           }
           cells = transformedBoard;
@@ -158,11 +186,15 @@ class BoardUtils {
     switch (rotate) {
       case 'left':
         {
-          final List<List<Cell>> transformedBoard = createEmptyBoard(boardSize);
+          final Board transformedBoard = createEmptyBoard(boardSize);
           for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
             for (int colIndex = 0; colIndex < boardSize; colIndex++) {
-              transformedBoard[rowIndex][colIndex].value =
-                  cells[colIndex][boardSize - rowIndex - 1].value;
+              transformedBoard[rowIndex][colIndex] = Cell(
+                row: rowIndex,
+                col: colIndex,
+                value: cells[colIndex][boardSize - rowIndex - 1].value,
+                isFixed: false,
+              );
             }
           }
           cells = transformedBoard;
@@ -170,11 +202,15 @@ class BoardUtils {
         break;
       case 'right':
         {
-          final List<List<Cell>> transformedBoard = createEmptyBoard(boardSize);
+          final Board transformedBoard = createEmptyBoard(boardSize);
           for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
             for (int colIndex = 0; colIndex < boardSize; colIndex++) {
-              transformedBoard[rowIndex][colIndex].value =
-                  cells[boardSize - colIndex - 1][rowIndex].value;
+              transformedBoard[rowIndex][colIndex] = Cell(
+                row: rowIndex,
+                col: colIndex,
+                value: cells[boardSize - colIndex - 1][rowIndex].value,
+                isFixed: false,
+              );
             }
           }
           cells = transformedBoard;
@@ -185,8 +221,12 @@ class BoardUtils {
     // Fix cells fixed states
     for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
       for (int colIndex = 0; colIndex < boardSize; colIndex++) {
-        cells[rowIndex][colIndex].isFixed =
-            (cells[rowIndex][colIndex].value != 0) ? true : false;
+        cells[rowIndex][colIndex] = Cell(
+          row: rowIndex,
+          col: colIndex,
+          value: cells[rowIndex][colIndex].value,
+          isFixed: (cells[rowIndex][colIndex].value != 0) ? true : false,
+        );
       }
     }
 
@@ -194,7 +234,8 @@ class BoardUtils {
   }
 
   static bool checkBoardIsSolved(Data myProvider) {
-    final List<List<Cell>> cells = myProvider.cells;
+    final Board cells = myProvider.board;
+    final ConflictsCount conflicts = myProvider.boardConflicts;
 
     final int blockSizeHorizontal = myProvider.blockSizeHorizontal;
     final int blockSizeVertical = myProvider.blockSizeVertical;
@@ -207,7 +248,7 @@ class BoardUtils {
     // check grid is fully completed and does not contain conflict
     for (int row = 0; row < boardSize; row++) {
       for (int col = 0; col < boardSize; col++) {
-        if (cells[row][col].value == 0 || cells[row][col].conflictsCount != 0) {
+        if (cells[row][col].value == 0 || conflicts[row][col] != 0) {
           return false;
         }
       }
@@ -219,7 +260,7 @@ class BoardUtils {
   }
 
   static bool isValueAllowed(
-    List<List<Cell>> cells,
+    Board cells,
     int blockSizeHorizontal,
     int blockSizeVertical,
     int? candidateCol,
@@ -300,7 +341,8 @@ class BoardUtils {
   }
 
   static void computeConflictsInBoard(Data myProvider) {
-    final List<List<Cell>> cells = myProvider.cells;
+    final Board cells = myProvider.board;
+    final ConflictsCount conflicts = myProvider.boardConflicts;
 
     final int blockSizeHorizontal = myProvider.blockSizeHorizontal;
     final int blockSizeVertical = myProvider.blockSizeVertical;
@@ -310,7 +352,7 @@ class BoardUtils {
     // reset conflict states
     for (int row = 0; row < boardSize; row++) {
       for (int col = 0; col < boardSize; col++) {
-        cells[row][col].conflictsCount = 0;
+        conflicts[row][col] = 0;
       }
     }
 
@@ -328,7 +370,7 @@ class BoardUtils {
         printlog('line $row contains duplicates');
         // Add line to cells in conflict
         for (int col = 0; col < boardSize; col++) {
-          cells[row][col].conflictsCount++;
+          conflicts[row][col]++;
         }
       }
     }
@@ -347,7 +389,7 @@ class BoardUtils {
         printlog('column $col contains duplicates');
         // Add column to cells in conflict
         for (int row = 0; row < boardSize; row++) {
-          cells[row][col].conflictsCount++;
+          conflicts[row][col]++;
         }
       }
     }
@@ -378,17 +420,19 @@ class BoardUtils {
             for (int colInBlock = 0; colInBlock < blockSizeHorizontal; colInBlock++) {
               int row = (blockRow * blockSizeVertical) + rowInBlock;
               int col = (blockCol * blockSizeHorizontal) + colInBlock;
-              cells[row][col].conflictsCount++;
+              conflicts[row][col]++;
             }
           }
         }
       }
     }
+
+    myProvider.updateConflicts(conflicts);
   }
 
   static List<List<int>> getCellsWithWrongValue(
-    final List<List<Cell>> cells,
-    final List<List<Cell>> cellsSolved,
+    final Board cells,
+    final Board cellsSolved,
     final int blockSizeHorizontal,
     final int blockSizeVertical,
   ) {
@@ -407,31 +451,8 @@ class BoardUtils {
     return cellsWithWrongValue;
   }
 
-  static List<List<int>> getConflictingCells(
-    final List<List<Cell>> cells,
-    final int blockSizeHorizontal,
-    final int blockSizeVertical,
-  ) {
-    final List<List<int>> conflictingCells = [];
-    final int boardSize = blockSizeHorizontal * blockSizeVertical;
-
-    for (int row = 0; row < boardSize; row++) {
-      for (int col = 0; col < boardSize; col++) {
-        if (!cells[row][col].isFixed && cells[row][col].value != 0) {
-          if (cells[row][col].conflictsCount != 0 &&
-              !BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical, col,
-                  row, cells[row][col].value)) {
-            conflictingCells.add([col, row]);
-          }
-        }
-      }
-    }
-
-    return conflictingCells;
-  }
-
   static List<List<int>> getCellsWithUniqueAvailableValue(
-    List<List<Cell>> cells,
+    Board cells,
     final int blockSizeHorizontal,
     final int blockSizeVertical,
   ) {
@@ -460,8 +481,8 @@ class BoardUtils {
     return candidateCells;
   }
 
-  static List<List<Cell>> getSolvedGrid(Data myProvider) {
-    final List<List<Cell>> cells = copyBoard(myProvider.cells);
+  static Board getSolvedGrid(Data myProvider) {
+    final Board cells = copyBoard(myProvider.board);
     final int blockSizeHorizontal = myProvider.blockSizeHorizontal;
     int blockSizeVertical = myProvider.blockSizeVertical;
 
@@ -479,7 +500,12 @@ class BoardUtils {
         int col = cellsWithUniqueAvailableValue[i][0];
         int row = cellsWithUniqueAvailableValue[i][1];
         int value = cellsWithUniqueAvailableValue[i][2];
-        cells[row][col].value = value;
+        cells[row][col] = Cell(
+          row: row,
+          col: col,
+          value: value,
+          isFixed: cells[row][col].isFixed,
+        );
       }
     } while (true);
 
diff --git a/lib/utils/game_utils.dart b/lib/utils/game_utils.dart
index a9eca6faf37345f66753bbf7f8afb49ac982e9ae..4de2454cd2d382bc54cbe327f308ed9a7546a278 100644
--- a/lib/utils/game_utils.dart
+++ b/lib/utils/game_utils.dart
@@ -1,4 +1,3 @@
-import 'package:sudoku/entities/cell.dart';
 import 'package:sudoku/provider/data.dart';
 import 'package:sudoku/utils/board_animate.dart';
 import 'package:sudoku/utils/board_utils.dart';
@@ -19,6 +18,8 @@ class GameUtils {
     myProvider.shuffleCellValues();
     myProvider.updateCells(BoardUtils.createEmptyBoard(
         myProvider.blockSizeHorizontal * myProvider.blockSizeVertical));
+    myProvider.initAnimatedBackground();
+    myProvider.initConflictsBoard();
     BoardUtils.pickGrid(myProvider);
     BoardAnimate.startAnimation(myProvider, 'start');
   }
@@ -57,7 +58,7 @@ class GameUtils {
   }
 
   static void showTip(Data myProvider) {
-    if (myProvider.currentCellCol == null || myProvider.currentCellRow == null) {
+    if (myProvider.selectedCellCol == null || myProvider.selectedCellRow == null) {
       // no selected cell -> pick one
       GameUtils.helpSelectCell(myProvider);
     } else {
@@ -68,14 +69,14 @@ class GameUtils {
   }
 
   static void helpSelectCell(Data myProvider) {
-    final List<List<Cell>> cells = myProvider.cells;
+    final Board cells = myProvider.board;
     final int blockSizeHorizontal = myProvider.blockSizeHorizontal;
     final int blockSizeVertical = myProvider.blockSizeVertical;
 
     // pick one of wrong value cells, if found
     final List<List<int>> wrongValueCells = BoardUtils.getCellsWithWrongValue(
       cells,
-      myProvider.cellsSolved,
+      myProvider.boardSolved,
       blockSizeHorizontal,
       blockSizeVertical,
     );
@@ -116,7 +117,7 @@ class GameUtils {
   }
 
   static void helpFillCell(Data myProvider) {
-    final List<List<Cell>> cells = myProvider.cells;
+    final Board cells = myProvider.board;
     final int blockSizeHorizontal = myProvider.blockSizeHorizontal;
     final int blockSizeVertical = myProvider.blockSizeVertical;
 
@@ -129,13 +130,13 @@ class GameUtils {
     int allowedValuesCount = 0;
     for (int value = 1; value <= boardSize; value++) {
       if (BoardUtils.isValueAllowed(cells, blockSizeHorizontal, blockSizeVertical,
-          myProvider.currentCellCol, myProvider.currentCellRow, value)) {
+          myProvider.selectedCellCol, myProvider.selectedCellRow, value)) {
         allowedValuesCount++;
         eligibleValue = value;
       }
     }
 
-    myProvider.updateCellValue(myProvider.currentCellCol, myProvider.currentCellRow,
+    myProvider.updateCellValue(myProvider.selectedCellCol, myProvider.selectedCellRow,
         allowedValuesCount == 1 ? eligibleValue : 0);
     myProvider.selectCell(null, null);
     if (BoardUtils.checkBoardIsSolved(myProvider)) {
diff --git a/pubspec.yaml b/pubspec.yaml
index 3194707d5756e45b34d8409013fe10fb0073a57d..e4e9a93338de0349d8a000d521a06c44834b5092 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,7 +1,7 @@
 name: sudoku
 description: A sudoku game application.
 publish_to: 'none'
-version: 0.1.16+65
+version: 0.1.17+66
 
 environment:
   sdk: '^3.0.0'