diff --git a/android/gradle.properties b/android/gradle.properties
index bc2d95e8567abcfd41c26ebeb95fced48f43e773..818e87b23b224ced309ae5c147e5ed827826e237 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.0.1
-app.versionCode=1
+app.versionName=0.0.2
+app.versionCode=2
diff --git a/assets/skins/default_0.png b/assets/skins/default_0.png
new file mode 100644
index 0000000000000000000000000000000000000000..604bda78fcc44f91482257e4580b5d84dd1cbfd9
Binary files /dev/null and b/assets/skins/default_0.png differ
diff --git a/assets/skins/images_0.png b/assets/skins/images_0.png
new file mode 100644
index 0000000000000000000000000000000000000000..604bda78fcc44f91482257e4580b5d84dd1cbfd9
Binary files /dev/null and b/assets/skins/images_0.png differ
diff --git a/icons/build_game_icons.sh b/icons/build_game_icons.sh
index 52ab3a2edaa884fd39e30626c1499104b6b8bf03..98777175206de66950ed0c0f556c3a07edcf55b7 100755
--- a/icons/build_game_icons.sh
+++ b/icons/build_game_icons.sh
@@ -33,6 +33,7 @@ AVAILABLE_SKINS="
 
 # Images per skin
 SKIN_IMAGES="
+  0
   1
   2
   3
diff --git a/icons/skins/default/0.svg b/icons/skins/default/0.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b69eb3732c1ebb884905c66b135f0b2db67cf217
--- /dev/null
+++ b/icons/skins/default/0.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="2" fill="none"/><rect width="100" height="100" fill="#fff" stroke="#505050" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.6"/></svg>
diff --git a/icons/skins/images/0.svg b/icons/skins/images/0.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b69eb3732c1ebb884905c66b135f0b2db67cf217
--- /dev/null
+++ b/icons/skins/images/0.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 100 100" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect width="100" height="100" ry="2" fill="none"/><rect width="100" height="100" fill="#fff" stroke="#505050" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.6"/></svg>
diff --git a/lib/entities/cell.dart b/lib/entities/cell.dart
new file mode 100644
index 0000000000000000000000000000000000000000..57d927aba28b3c2e846740674bec0fd20979d3cf
--- /dev/null
+++ b/lib/entities/cell.dart
@@ -0,0 +1,62 @@
+import 'package:flutter/material.dart';
+
+import '../provider/data.dart';
+import '../utils/board_utils.dart';
+
+class Cell {
+  int value;
+
+  Cell(
+    @required this.value,
+  );
+
+  Container widget(Data myProvider, int row, int col) {
+    String imageAsset = this.getImageAssetName(myProvider);
+
+    return Container(
+      child: AnimatedSwitcher(
+        duration: const Duration(milliseconds: 100),
+        transitionBuilder: (Widget child, Animation<double> animation) {
+          return ScaleTransition(child: child, scale: animation);
+        },
+        child: Image(
+          image: AssetImage(imageAsset),
+          fit: BoxFit.fill,
+          key: ValueKey<int>(imageAsset.hashCode),
+        ),
+      ),
+    );
+  }
+
+  Container widgetFillBoardWithColor(Data myProvider) {
+    String imageAsset = this.getImageAssetName(myProvider);
+
+    return Container(
+      margin: EdgeInsets.all(2),
+      decoration: BoxDecoration(
+        border: Border.all(
+          color: Colors.black,
+          width: 4,
+        ),
+      ),
+      child: GestureDetector(
+        child: Image(
+          image: AssetImage(imageAsset),
+          fit: BoxFit.fill
+        ),
+        onTap: () {
+          BoardUtils.fillBoardFromFirstCell(myProvider, this.value);
+          if (BoardUtils.checkBoardIsSolved(myProvider)) {
+            myProvider.updateGameWon(true);
+          }
+        },
+      )
+    );
+  }
+
+  String getImageAssetName(Data myProvider) {
+    int cellValue = this.value;
+    return 'assets/skins/' + myProvider.skin + '_' + cellValue.toString() + '.png';
+  }
+
+}
diff --git a/lib/layout/board.dart b/lib/layout/board.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f8ae151b9887f8cdcae8c4f08fdde0e11106e248
--- /dev/null
+++ b/lib/layout/board.dart
@@ -0,0 +1,41 @@
+import 'package:flutter/material.dart';
+
+import '../provider/data.dart';
+
+class Board {
+
+  static Container buildGameBoard(Data myProvider) {
+    return Container(
+      margin: EdgeInsets.all(4),
+      padding: EdgeInsets.all(4),
+      child: Column(
+        children: [
+          buildGameTileset(myProvider),
+        ],
+      ),
+    );
+  }
+
+  static Table buildGameTileset(Data myProvider) {
+    int boardSize = myProvider.boardSize;
+    List cells = myProvider.cells;
+
+    return Table(
+      defaultColumnWidth: IntrinsicColumnWidth(),
+      children: [
+        for (var row = 0; row < boardSize; row++)
+          TableRow(children: [
+            for (var 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
index f479032ea69257d844223f749a72aefdcaa66bd6..b2720f65cb133a1e237dbb2c58ac66792dac0a17 100644
--- a/lib/layout/game.dart
+++ b/lib/layout/game.dart
@@ -2,6 +2,8 @@ import 'dart:math';
 
 import 'package:flutter/material.dart';
 
+import '../entities/cell.dart';
+import '../layout/board.dart';
 import '../provider/data.dart';
 import '../utils/game_utils.dart';
 
@@ -16,21 +18,50 @@ class Game {
         crossAxisAlignment: CrossAxisAlignment.center,
         children: [
           Expanded(
-            child: Text('❇️'),
+            child: Board.buildGameBoard(myProvider),
           ),
           SizedBox(height: 2),
           Container(
-            height: 150,
-            width: double.maxFinite,
             child: gameIsFinished
               ? Game.buildEndGameMessage(myProvider)
-              : Text('❇️'),
+              : Game.buildSelectColorBar(myProvider),
           ),
         ],
       ),
     );
   }
 
+  static Container buildSelectColorBar(Data myProvider) {
+    List cells = myProvider.cells;
+
+    int maxValue = myProvider.colorsCount;
+
+    return Container(
+      margin: EdgeInsets.all(2),
+      padding: EdgeInsets.all(2),
+
+      child: Table(
+        defaultColumnWidth: IntrinsicColumnWidth(),
+        children: [
+          TableRow(
+            children: [
+              for (
+                int value = 1;
+                value <= maxValue;
+                value++
+              )
+                Column(
+                  children: [
+                    Cell(value).widgetFillBoardWithColor(myProvider)
+                  ]
+                ),
+            ]
+          ),
+        ]
+      ),
+    );
+  }
+
   static FlatButton buildRestartGameButton(Data myProvider) {
     return FlatButton(
       child: Container(
diff --git a/lib/main.dart b/lib/main.dart
index f4e8d27fb5fb887c9185aa132a18e36b21263aa9..7f448662ed2c1ea856492d67bacbf56f62d81c3a 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -29,7 +29,8 @@ class MyApp extends StatelessWidget {
             routes: {
               Home.id: (context) => Home(),
             },
-          ));
+          ),
+        );
       }),
     );
   }
diff --git a/lib/provider/data.dart b/lib/provider/data.dart
index cd696e5ffecd5a21496706e398018b5076df3615..c42130184fe17cfd3aca840a359abd7b2a066439 100644
--- a/lib/provider/data.dart
+++ b/lib/provider/data.dart
@@ -19,10 +19,17 @@ class Data extends ChangeNotifier {
   // Game data
   bool _gameIsRunning = false;
   bool _gameWon = false;
+  int _boardSize = 0;
+  int _colorsCount = 0;
+  List _cells = [];
 
   String get level => _level;
   void updateLevel(String level) {
     _level = level;
+
+    updateBoardSize(getBoardSizeFromLevel(level));
+    updateColorsCount(getColorsCountFromLevel(level));
+
     notifyListeners();
   }
 
@@ -39,6 +46,7 @@ class Data extends ChangeNotifier {
       case 'skin': { return _skin; }
       break;
     }
+    return '';
   }
 
   List getParameterAvailableValues(String parameterCode) {
@@ -68,6 +76,55 @@ class Data extends ChangeNotifier {
     setParameterValue('skin', prefs.getString('skin') ?? _skinDefault);
   }
 
+  int get boardSize => _boardSize;
+  void updateBoardSize(int boardSize) {
+    _boardSize = boardSize;
+  }
+
+  int get colorsCount => _colorsCount;
+  void updateColorsCount(int colorsCount) {
+    _colorsCount = colorsCount;
+  }
+
+  int getBoardSizeFromLevel(String level) {
+    switch(level) {
+      case 'easy': { return 6; }
+      break;
+      case 'normal': { return 10; }
+      break;
+      case 'hard': { return 14; }
+      break;
+      case 'nightmare': { return 20; }
+      break;
+    }
+    return 8;
+  }
+
+  int getColorsCountFromLevel(String level) {
+    switch(level) {
+      case 'easy': { return 4; }
+      break;
+      case 'normal': { return 5; }
+      break;
+      case 'hard': { return 6; }
+      break;
+      case 'nightmare': { return 7; }
+      break;
+    }
+    return 4;
+  }
+
+  List get cells => _cells;
+  void updateCells(List cells) {
+    _cells = cells;
+    notifyListeners();
+  }
+
+  updateCellValue(int col, int row, int value) {
+    _cells[row][col].value = value;
+    notifyListeners();
+  }
+
   bool get gameIsRunning => _gameIsRunning;
   void updateGameIsRunning(bool gameIsRunning) {
     _gameIsRunning = gameIsRunning;
@@ -75,10 +132,14 @@ class Data extends ChangeNotifier {
   }
 
   bool isGameFinished() {
-    return false;
+    return _gameWon;
   }
 
   bool get gameWon => _gameWon;
+  void updateGameWon(bool gameWon) {
+    _gameWon = gameWon;
+    notifyListeners();
+  }
 
   void resetGame() {
     _gameIsRunning = false;
diff --git a/lib/utils/board_utils.dart b/lib/utils/board_utils.dart
new file mode 100644
index 0000000000000000000000000000000000000000..61848e3a0c76fea4819eb1e352e52bf3a9fb919c
--- /dev/null
+++ b/lib/utils/board_utils.dart
@@ -0,0 +1,113 @@
+import 'dart:math';
+
+import '../entities/cell.dart';
+import '../provider/data.dart';
+
+class BoardUtils {
+
+  static printGrid(List cells) {
+    String stringValues = '01234567';
+    print('');
+    print('-------');
+    for (var rowIndex = 0; rowIndex < cells.length; rowIndex++) {
+      String row = '';
+      for (var colIndex = 0; colIndex < cells[rowIndex].length; colIndex++) {
+        row += stringValues[cells[rowIndex][colIndex].value];
+      }
+      print(row);
+    }
+    print('-------');
+    print('');
+  }
+
+  static createNewBoard(Data myProvider) {
+    int boardSize = myProvider.boardSize;
+    int maxValue = myProvider.colorsCount;
+
+    var rand = new Random();
+
+    List grid = [];
+    for (var rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+      List row = [];
+      for (var colIndex = 0; colIndex < boardSize; colIndex++) {
+        int value = 1 + rand.nextInt(maxValue);
+        row.add(Cell(value));
+      }
+      grid.add(row);
+    }
+    printGrid(grid);
+
+    myProvider.resetGame();
+    myProvider.updateCells(grid);
+  }
+
+  static fillBoardFromFirstCell(Data myProvider, int value) {
+    List cellsToFill = BoardUtils.getSiblingFillableCells(myProvider, 0, 0, [[0, 0]]);
+
+    for (var cellIndex = 0; cellIndex < cellsToFill.length; cellIndex++) {
+      myProvider.updateCellValue(cellsToFill[cellIndex][1], cellsToFill[cellIndex][0], value);
+    }
+  }
+
+  static List getSiblingFillableCells(Data myProvider, row, col, siblingCells) {
+    List cells = myProvider.cells;
+    int boardSize = myProvider.boardSize;
+
+    int referenceValue = cells[row][col].value;
+
+    for (var deltaRow = -1; deltaRow <= 1; deltaRow++) {
+      for (var deltaCol = -1; deltaCol <= 1; deltaCol++) {
+        if (deltaCol == 0 || deltaRow == 0) {
+          int candidateRow = row + deltaRow;
+          int candidateCol = col + deltaCol;
+
+          if (
+            (candidateRow >= 0 && candidateRow < boardSize)
+            &&
+            (candidateCol >= 0 && candidateCol < boardSize)
+          ) {
+            if (cells[candidateRow][candidateCol].value == referenceValue) {
+              bool alreadyFound = false;
+              for (var index = 0; index < siblingCells.length; index++) {
+                if (
+                  (siblingCells[index][0] == candidateRow)
+                  &&
+                  (siblingCells[index][1] == candidateCol)
+                ) {
+                  alreadyFound = true;
+                }
+              }
+              if (!alreadyFound) {
+                siblingCells.add([candidateRow, candidateCol]);
+                siblingCells = getSiblingFillableCells(myProvider, candidateRow, candidateCol, siblingCells);
+              }
+            }
+          }
+        }
+      }
+    }
+
+    return siblingCells;
+  }
+
+  static bool checkBoardIsSolved(Data myProvider) {
+    List cells = myProvider.cells;
+    int boardSize = myProvider.boardSize;
+
+    // check grid is fully completed and does not contain conflict
+    int previousValue = cells[0][0].value;
+    for (var row = 0; row < boardSize; row++) {
+      for (var col = 0; col < boardSize; col++) {
+        if (cells[row][col].value == 0 || cells[row][col].value != previousValue) {
+          return false;
+        }
+        previousValue = cells[row][col].value;
+      }
+    }
+
+    print('-> ok grid solved!');
+
+    return true;
+  }
+
+}
diff --git a/lib/utils/game_utils.dart b/lib/utils/game_utils.dart
index 58e9792f1553e6defa99e30a712efe8e26508346..a7005ece43ead123009791c0eb6478cc1e93dd16 100644
--- a/lib/utils/game_utils.dart
+++ b/lib/utils/game_utils.dart
@@ -1,4 +1,5 @@
 import '../provider/data.dart';
+import '../utils/board_utils.dart';
 
 class GameUtils {
 
@@ -9,8 +10,10 @@ class GameUtils {
   static Future<void> startGame(Data myProvider) async {
     print('Starting game');
     print('- level: ' + myProvider.level);
+    print('- size: ' + myProvider.boardSize.toString());
+    print('- colors: ' + myProvider.colorsCount.toString());
 
-    myProvider.resetGame();
+    BoardUtils.createNewBoard(myProvider);
 
     myProvider.updateGameIsRunning(true);
   }
diff --git a/pubspec.yaml b/pubspec.yaml
index 56bfd6d372640f2bc5b53ee5ad72adef0fb21664..c16bdce6d4a9d525c68d051b2a5ca97cd4baefa9 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -21,3 +21,4 @@ flutter:
   uses-material-design: true
   assets:
     - assets/icons/
+    - assets/skins/