diff --git a/collaborative/src/components/Cell.test.tsx b/collaborative/src/components/Cell.test.tsx
index 2b043e74a694e5459c20f21bbadd631fb493abe0..2ea8d7dd30ac35e10326ff152c40f9fc3e0c4e79 100644
--- a/collaborative/src/components/Cell.test.tsx
+++ b/collaborative/src/components/Cell.test.tsx
@@ -22,7 +22,6 @@
  * SOFTWARE.
  */
 
-import React from "react";
 import { configure } from "enzyme";
 import Adapter from "enzyme-adapter-react-16";
 import { mount } from "enzyme";
@@ -36,58 +35,14 @@ beforeEach(() => {
 
 describe("Testing UI", () => {
   /**
-   * This test evaluates that the cell displays the initial value.
+   * This test evaluates that the cell displays the value.
    * Here it should display 6.
    */
-  test("Cell value initialization", () => {
+  test("Cell value", () => {
     const wrapper = mount(
-      <Cell index={3} value={"6"} onChange={() => ({})} lock={false} />
+      <Cell index={3} value={"6"} onChange={() => ({})} error={false} />
     );
-    expect(wrapper.find("textarea").text()).toBe("6");
-  });
-
-  /**
-   * This test evaluates that after updating the cell value,
-   * the cell display the right value.
-   * Here it should display 2.
-   */
-  test("Cell value changed", () => {
-    const wrapper = mount(
-      <Cell index={3} value={"6"} onChange={() => ({})} lock={false} />
-    );
-    expect(wrapper.find("textarea").text()).toBe("6");
-    wrapper.find("textarea").simulate("change", { target: { value: "2" } });
-    expect(wrapper.find("textarea").text()).toBe("2");
-  });
-
-  /**
-   * This test evaluates that the value of a locked cell cannot be modified.
-   * Here it should display 2 even if we try to modify it.
-   */
-  test("Cell locked", () => {
-    const wrapper = mount(
-      <Cell index={3} value={"6"} onChange={() => ({})} lock={true} />
-    );
-    expect(wrapper.find("textarea").text()).toBe("6");
-    wrapper.find("textarea").simulate("change", { target: { value: "2" } });
-    expect(wrapper.find("textarea").text()).toBe("6");
-  });
-
-  /**
-   * This test evaluates that the value of a cell can only be modified with integers from 1 to 9.
-   */
-  test("Cell wrong value", () => {
-    const wrapper = mount(
-      <Cell index={3} value={"6"} onChange={() => ({})} lock={false} />
-    );
-    expect(wrapper.find("textarea").text()).toBe("6");
-    wrapper.find("textarea").simulate("change", { target: { value: "0" } });
-    expect(wrapper.find("textarea").text()).toBe("6");
-    wrapper.find("textarea").simulate("change", { target: { value: "10" } });
-    expect(wrapper.find("textarea").text()).toBe("6");
-    wrapper.find("textarea").simulate("change", { target: { value: "1.1" } });
-    expect(wrapper.find("textarea").text()).toBe("6");
-    wrapper.find("textarea").simulate("change", { target: { value: "abc" } });
-    expect(wrapper.find("textarea").text()).toBe("6");
+    const input = wrapper.find('input');
+    expect(input.instance().value).toBe("6");
   });
 });
diff --git a/collaborative/src/components/Cell.tsx b/collaborative/src/components/Cell.tsx
index da8a936bca4732a452d5ace8a7ad0abc9e9bfb64..567a9cc120235b44f9849e87c74da535b853ed37 100644
--- a/collaborative/src/components/Cell.tsx
+++ b/collaborative/src/components/Cell.tsx
@@ -51,10 +51,6 @@ class Cell extends React.Component<ICellProps> {
     }
     if (event.target.value === "" || validInput.test(event.target.value)) {
       this.props.onChange(this.props.index, event.target.value);
-    } else {
-      console.error(
-        "Invalid input in cell " + this.props.index + " : " + event.target.value
-      );
     }
   }
 
diff --git a/collaborative/src/components/Game.test.tsx b/collaborative/src/components/Game.test.tsx
new file mode 100644
index 0000000000000000000000000000000000000000..4253d0431bd19066a33e4a499fd7eb0fd041af88
--- /dev/null
+++ b/collaborative/src/components/Game.test.tsx
@@ -0,0 +1,551 @@
+/**
+ * MIT License
+ *
+ * Copyright (c) 2020, Concordant and contributors
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import React from "react";
+import { configure } from "enzyme";
+import Adapter from "enzyme-adapter-react-16";
+import { shallow, mount } from "enzyme";
+import Game from "./Game";
+import { crdtlib } from "@concordant/c-crdtlib";
+
+configure({ adapter: new Adapter() });
+
+beforeEach(() => {
+  jest.spyOn(console, "log").mockImplementation(() => ({}));
+});
+
+/**
+ * This test evaluates that checkLine return true only if
+ * the array contains all numbers from 1 to 9 without repeat.
+ */
+ describe("checkLine", () => {
+  test("checkLine", () => {
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkLine(3)).toBe(true);
+    game.handleChange(35, "1")
+    expect(game.checkLine(3)).toBe(false);
+    game.handleChange(35, "2")
+    expect(game.checkLine(3)).toBe(true);
+  });
+});
+
+/**
+ * This test evaluates that checkColumn return true only if
+ * the array contains all numbers from 1 to 9 without repeat.
+ */
+describe("checkColumn", () => {
+  test("checkColumn", () => {
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkColumn(8)).toBe(true);
+    game.handleChange(35, "1")
+    expect(game.checkColumn(8)).toBe(false);
+    game.handleChange(35, "2")
+    expect(game.checkColumn(8)).toBe(true);
+  });
+});
+
+/**
+ * This test evaluates that checkBlock return true only if
+ * the array contains all numbers from 1 to 9 without repeat.
+ */
+describe("checkBlock", () => {
+  test("checkBlock", () => {
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkBlock(5)).toBe(true);
+    game.handleChange(35, "1")
+    expect(game.checkBlock(5)).toBe(false);
+    game.handleChange(35, "2")
+    expect(game.checkBlock(5)).toBe(true);
+  });
+});
+
+/**
+ * This test evaluates that validateLine return false if a line contains an error.
+ */
+describe("validateLine", () => {
+  /**
+   * This test evaluates that validateLine return true with a line containing full empty cell.
+   */
+  test("validateLine empty", () => {
+    // prettier-ignore
+    const initVal = ["","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","",""]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+    
+    expect(game.checkLines()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkLines()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateLine return true with a line containing all numbers
+   * from 1 to 9 without repeat.
+   */
+  test("validateLine complete", () => {
+    // prettier-ignore
+    const initVal = ["6","5","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","6","4","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "9","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkLines()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkLines()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateLine return true if a line is missing a value.
+   */
+  test("validateLine with missing values", () => {
+    // prettier-ignore
+    const initVal = ["6","","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","","","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkLines()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkLines()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateLine return false when a value is dupplicated.
+   */
+  test("validateLine with wrongs values", () => {
+    // prettier-ignore
+    const initVal = ["6","2","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","6","4","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "9","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkLines()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkLines()).toStrictEqual([0, 1, 2, 3, 4, 5, 6, 7, 8]);
+  });
+
+  /**
+   * This test evaluates that validateLine return true when a cell has multiple values.
+   */
+  test("validateLine with multiples values", () => {
+    // prettier-ignore
+    const initVal = ["1 6","5","","3","8","7","9","1","4",
+                       "7","1","9","4","5","2","3","6","8",
+                       "3","4","8","1","9","6","2","5","7",
+                       "8","2","1","9","3","5","4","7","6",
+                       "5","9","6","2","7","4","8","3","1",
+                       "4","7","3","8","6","1","5","2","9",
+                       "1","8","7","5","2","9","","","3",
+                       "2","3","4","6","1","8","7","9","5",
+                       "","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkLines()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkLines()).toStrictEqual([]);
+  });
+});
+
+/**
+ * This test evaluates that validateColumn return false if a column contains an error.
+ */
+describe("validateColumn", () => {
+  /**
+   * This test evaluates that validateColumn return true with a column containing full empty cell.
+   */
+  test("validateColumn empty", () => {
+    // prettier-ignore
+    const initVal = ["","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","",""]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkColumns()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkColumns()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateColumn return true with a column containing all numbers
+   * from 1 to 9 without repeat.
+   */
+  test("validateColumn complete", () => {
+    // prettier-ignore
+    const initVal = ["6","5","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","6","4","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "9","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkColumns()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkColumns()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateColumn return true if a column is missing a value.
+   */
+  test("validateColumn with missing values", () => {
+    // prettier-ignore
+    const initVal = ["6","","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","","","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkColumns()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkColumns()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateColumn return false when a value is dupplicated.
+   */
+  test("validateColumn with wrongs values", () => {
+    // prettier-ignore
+    const initVal = ["6","2","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","6","4","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "9","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkColumns()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkColumns()).toStrictEqual([1, 10, 19, 28, 37, 46, 55, 64, 73]);
+  });
+
+  /**
+   * This test evaluates that validateColumn return true when a cell has multiple values.
+   */
+  test("validateColumn with multiples values", () => {
+    // prettier-ignore
+    const initVal = ["1 6","5","","3","8","7","9","1","4",
+                       "7","1","9","4","5","2","3","6","8",
+                       "3","4","8","1","9","6","2","5","7",
+                       "8","2","1","9","3","5","4","7","6",
+                       "5","9","6","2","7","4","8","3","1",
+                       "4","7","3","8","6","1","5","2","9",
+                       "1","8","7","5","2","9","","","3",
+                       "2","3","4","6","1","8","7","9","5",
+                       "","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkColumns()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkColumns()).toStrictEqual([]);
+  });
+});
+
+/**
+ * This test evaluates that validateBlock return false if a line contains an error.
+ */
+describe("validateBlock", () => {
+  /**
+   * This test evaluates that validateBlock return true with a line containing full empty cell.
+   */
+  test("validateBlock empty", () => {
+    // prettier-ignore
+    const initVal = ["","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","",""]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkBlocks()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkBlocks()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateBlock return true with a line containing all numbers
+   * from 1 to 9 without repeat.
+   */
+  test("validateBlock complete", () => {
+    // prettier-ignore
+    const initVal = ["6","5","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","6","4","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "9","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkBlocks()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkBlocks()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateBlock return true if a line is missing a value.
+   */
+  test("validateBlock with missing values", () => {
+    // prettier-ignore
+    const initVal = ["6","","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","","","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkBlocks()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkBlocks()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateBlock return false when a value is dupplicated.
+   */
+  test("validateBlock with wrongs values", () => {
+    // prettier-ignore
+    const initVal = ["6","2","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","6","4","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "9","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkBlocks()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkBlocks()).toStrictEqual([0, 1, 2, 9, 10, 11, 18, 19, 20]);
+  });
+
+  /**
+   * This test evaluates that validateBlock return true when a cell has multiple values.
+   */
+  test("validateBlock with multiples values", () => {
+    // prettier-ignore
+    const initVal = ["1 6","5","","3","8","7","9","1","4",
+                       "7","1","9","4","5","2","3","6","8",
+                       "3","4","8","1","9","6","2","5","7",
+                       "8","2","1","9","3","5","4","7","6",
+                       "5","9","6","2","7","4","8","3","1",
+                       "4","7","3","8","6","1","5","2","9",
+                       "1","8","7","5","2","9","","","3",
+                       "2","3","4","6","1","8","7","9","5",
+                       "","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkBlocks()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkBlocks()).toStrictEqual([]);
+  });
+});
+
+/**
+ * This test evaluates that validateSudoku return false if a line, column or block contains an error.
+ */
+describe("validateSudoku", () => {
+  /**
+   * This test evaluates that validateSudoku return true with a full empty game.
+   */
+  test("validateSudoku empty", () => {
+    // prettier-ignore
+    const initVal = ["","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","","",
+                        "","","","","","","","",""]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkCells()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkCells()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateSudoku return true with all lines, columns and blocks
+   * containing all numbers from 1 to 9 without repeat.
+   */
+  test("validateSudoku complete", () => {
+    // prettier-ignore
+    const initVal = ["6","5","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","6","4","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "9","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkCells()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkCells()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateSudoku return true if the grid is missing a value.
+   */
+  test("validateSudoku with missing values", () => {
+    // prettier-ignore
+    const initVal = ["6","","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","","","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+    
+    expect(game.checkCells()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkCells()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateSudoku return false when a value is dupplicated.
+   */
+  test("validateSudoku with wrongs values", () => {
+    // prettier-ignore
+    const initVal = ["6","2","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","6","4","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "9","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+    
+    expect(game.checkCells()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkCells()).toStrictEqual([]);
+  });
+
+  /**
+   * This test evaluates that validateSudoku return true when a cell has multiple values.
+   */
+  test("validateSudoku with multiples values", () => {
+    // prettier-ignore
+    const initVal = ["1 6","5 2","","3","8","7","9","1","4",
+                       "7","1","9","4","5","2","3","6","8",
+                       "3","4","8","1","9","6","2","5","7",
+                       "8","2","1","9","3","5","4","7","6",
+                       "5","9","6","2","7","4","8","3","1",
+                       "4","7","3","8","6","1","5","2","9",
+                       "1","8","7","5","2","9","","","3",
+                       "2","3","4","6","1","8","7","9","5",
+                       "","6","5","7","4","3","1","8","2"]
+    const wrapper = shallow(<Game />);
+    const game = wrapper.instance();
+
+    expect(game.checkCells()).toStrictEqual([]);
+    game.updateState(initVal.map(val =>({ value: val, modifiable: false, error: false })))
+    expect(game.checkCells()).toStrictEqual([0, 1]);
+  });
+});
diff --git a/collaborative/src/components/Game.tsx b/collaborative/src/components/Game.tsx
index 52dc1d5ae0eeed98b032608a4f2fa40e4cb69b2d..1f90cba7e1b8c2e945275e3fc459bb67a8075bc0 100644
--- a/collaborative/src/components/Game.tsx
+++ b/collaborative/src/components/Game.tsx
@@ -23,43 +23,419 @@
  */
 
 import React from "react";
-import Grid from "./Grid";
+import assert from "assert";
+import Grid, { cellsIndexOfBlock } from "./Grid";
+import { validInput, GRIDS } from "../constants";
 import { client } from "@concordant/c-client";
+import Submit1Input from "./Submit1Input";
 
 import CONFIG from "../config.json";
 
+const session = client.Session.Companion.connect(
+  CONFIG.dbName,
+  CONFIG.serviceUrl,
+  CONFIG.credentials
+);
+const collection = session.openCollection("sudoku", false);
+
 /**
  * Interface for the state of a Game.
  * Keep a reference to the opened session and opened MVMap.
  */
 interface IGameState {
-  session: client.Session;
-  collection: client.Collection;
+  gridNum: string;
+  mvmap: any; // eslint-disable-line @typescript-eslint/no-explicit-any
+  cells: { value: string; modifiable: boolean; error: boolean }[];
+  isConnected: boolean;
+  isFinished: boolean;
 }
 
 /**
  * This class represent the Game that glues all components together.
  */
 class Game extends React.Component<Record<string, unknown>, IGameState> {
+  timerID!: NodeJS.Timeout;
+  modifiedCells: string[];
+
   constructor(props: Record<string, unknown>) {
     super(props);
-    const session = client.Session.Companion.connect(
-      CONFIG.dbName,
-      CONFIG.serviceUrl,
-      CONFIG.credentials
+    const cells = new Array(81)
+      .fill(null)
+      .map(() => ({ value: "", modifiable: false, error: false }));
+    this.modifiedCells = new Array(81).fill(null);
+    const gridNum = "1";
+    const mvmap = collection.open(
+      "grid" + gridNum,
+      "MVMap",
+      false,
+      function () {
+        return;
+      }
     );
-    const collection = session.openCollection("sudoku", false);
     this.state = {
-      session: session,
-      collection: collection,
+      gridNum: gridNum,
+      mvmap: mvmap,
+      cells: cells,
+      isConnected: true,
+      isFinished: false,
     };
   }
 
+  /**
+   * Called after the component is rendered.
+   * It set a timer to refresh cells values.
+   */
+   componentDidMount(): void {
+    this.initFrom(generateStaticGrid(this.state.gridNum));
+    this.timerID = setInterval(() => this.updateGrid(), 1000);
+  }
+
+  /**
+   * Called when the compenent is about to be removed from the DOM.
+   * It remove the timer set in componentDidMount().
+   */
+  componentWillUnmount(): void {
+    clearInterval(this.timerID);
+  }
+
+  /**
+   * Update cells values from C-Client.
+   */
+  updateGrid(): void {
+    const cells = this.state.cells;
+    if (!this.state.isConnected) {
+      console.error("updateGrid() called while not connected.");
+      return;
+    }
+    for (let index = 0; index < 81; index++) {
+      if (cells[index].modifiable) {
+        cells[index].value = "";
+      }
+    }
+    session.transaction(client.utils.ConsistencyLevel.None, () => {
+      const itString = this.state.mvmap.iteratorString();
+      while (itString.hasNext()) {
+        const val = itString.next();
+        cells[val.first].value = hashSetToString(val.second);
+      }
+    });
+    this.updateState(cells);
+  }
+
+  /**
+   * This function is used to simulate the offline mode.
+   */
+  switchConnection(): void {
+    if (this.state.isConnected) {
+      this.modifiedCells = new Array(81).fill(null);
+      clearInterval(this.timerID);
+    } else {
+      for (let index = 0; index < 81; index++) {
+        if (
+          this.state.cells[index].modifiable &&
+          this.modifiedCells[index] !== null
+        ) {
+          session.transaction(
+            client.utils.ConsistencyLevel.None,
+            () => {
+              this.state.mvmap.setString(index, this.modifiedCells[index]);
+            }
+          );
+        }
+      }
+      this.timerID = setInterval(() => this.updateGrid(), 1000);
+    }
+    this.setState({ isConnected: !this.state.isConnected });
+  }
+
+  /**
+   * Initialize the grid with the given values.
+   * @param values values to be set in the grid.
+   */
+  initFrom(values: string): void {
+    assert.ok(values.length === 81);
+    const cells = this.state.cells;
+    for (let index = 0; index < 81; index++) {
+      cells[index].value = values[index] === "." ? "" : values[index];
+      cells[index].modifiable = values[index] === "." ? true : false;
+    }
+    this.updateState(cells);
+  }
+
+  /**
+   * Reset the value of all modifiable cells.
+   */
+  reset(): void {
+    const cells = this.state.cells;
+    for (let index = 0; index < 81; index++) {
+      if (cells[index].modifiable) {
+        cells[index].value = "";
+        if (this.state.isConnected) {
+          session.transaction(
+            client.utils.ConsistencyLevel.None,
+            () => {
+              this.state.mvmap.setString(index, cells[index].value);
+            }
+          );
+        } else {
+          this.modifiedCells[index] = "";
+        }
+      }
+    }
+    this.updateState(cells);
+  }
+
+  /**
+   * This handler is called when the value of a cell is changed.
+   * @param index The index of the cell changed.
+   * @param value The new value of the cell.
+   */
+  handleChange(index: number, value: string): void {
+    assert.ok(value === "" || (Number(value) >= 1 && Number(value) <= 9));
+    assert.ok(index >= 0 && index < 81);
+    if (!this.state.cells[index].modifiable) {
+      console.error(
+        "Trying to change an non modifiable cell. Should not happend"
+      );
+    }
+
+    const cells = this.state.cells;
+    cells[index].value = value;
+    this.updateState(cells);
+
+    if (this.state.isConnected) {
+      session.transaction(client.utils.ConsistencyLevel.None, () => {
+        this.state.mvmap.setString(index, value);
+      });
+    } else {
+      this.modifiedCells[index] = value;
+    }
+  }
+
+  /**
+   * This handler is called when a new grid number is submit.
+   * @param gridNum Desired grid number.
+   */
+  handleSubmit(gridNum: string): void {
+    if (
+      Number(gridNum) < 1 ||
+      Number(gridNum) > 100 ||
+      gridNum === this.state.gridNum
+    ) {
+      return;
+    }
+    const mvmap = collection.open(
+      "grid" + gridNum,
+      "MVMap",
+      false,
+      function () {
+        return;
+      }
+    );
+    this.setState({ gridNum: gridNum, mvmap: mvmap });
+    this.initFrom(generateStaticGrid(gridNum));
+  }
+  
   render(): JSX.Element {
     return (
-      <Grid session={this.state.session} collection={this.state.collection} />
+      <div className="sudoku">
+        <div>Current grid : {this.state.gridNum}</div>
+        <Submit1Input
+          inputName="Grid"
+          onSubmit={this.handleSubmit.bind(this)}
+        />
+        <div>
+          Difficulty levels: easy (1-20), medium (21-40), hard (41-60),
+          very-hard (61-80), insane (81-100)
+        </div>
+        <br />
+        <div>
+          <button onClick={this.reset.bind(this)}>Reset</button>
+        </div>
+        <br />
+        <div>
+          <button onClick={() => this.switchConnection()}>
+            {this.state.isConnected ? "Disconnect" : "Connect"}
+          </button>
+        </div>
+        <br />
+        <Grid cells={this.state.cells} isFinished={this.state.isFinished} 
+          onChange={(index: number, value: string) => this.handleChange(index, value)} />
+      </div>
     );
   }
+
+  /**
+   * Check if a line respect Sudoku lines rules.
+   * @param line The line number to be checked.
+   */
+   checkLine(line: number): boolean {
+    assert.ok(line >= 0 && line < 9);
+    const cpt = Array(9).fill(0);
+    for (let column = 0; column < 9; column++) {
+      const index = line * 9 + column;
+      const val = this.state.cells[index].value;
+      if (val.length === 0 || val.length > 1) {
+        continue;
+      }
+      cpt[Number(val) - 1]++;
+    }
+    return cpt.every((c) => c <= 1);
+  }
+
+  /**
+   * Check if a column respect Sudoku columns rules.
+   * @param column The column number to be checked.
+   */
+  checkColumn(column: number): boolean {
+    assert.ok(column >= 0 && column < 9);
+    const cpt = Array(9).fill(0);
+    for (let line = 0; line < 9; line++) {
+      const index = line * 9 + column;
+      const val = this.state.cells[index].value;
+      if (val.length === 0 || val.length > 1) {
+        continue;
+      }
+      cpt[Number(val) - 1]++;
+    }
+    return cpt.every((c) => c <= 1);
+  }
+
+  /**
+   * Check if a block respect Sudoku blocks rules.
+   * @param block The block number to be checked.
+   */
+  checkBlock(block: number): boolean {
+    assert.ok(block >= 0 && block < 9);
+    const cpt = Array(9).fill(0);
+    const indexList = cellsIndexOfBlock(block);
+    for (const index of indexList) {
+      const val = this.state.cells[index].value;
+      if (val.length === 0 || val.length > 1) {
+        continue;
+      }
+      cpt[Number(val) - 1]++;
+    }
+    return cpt.every((c) => c <= 1);
+  }
+
+  /**
+   * This function check if all lines respect Sudoku lines rules.
+   */
+  checkLines(): number[] {
+    const indexList = [];
+    for (let line = 0; line < 9; line++) {
+      if (this.checkLine(line) === false) {
+        for (let column = 0; column < 9; column++) {
+          indexList.push(line * 9 + column);
+        }
+      }
+    }
+    return indexList;
+  }
+
+  /**
+   * This function check if all columns respect Sudoku columns rules.
+   */
+  checkColumns(): number[] {
+    const indexList = [];
+    for (let column = 0; column < 9; column++) {
+      if (this.checkColumn(column) === false) {
+        for (let line = 0; line < 9; line++) {
+          indexList.push(line * 9 + column);
+        }
+      }
+    }
+    return indexList;
+  }
+
+  /**
+   * This function check if all blocks respect Sudoku blocks rules.
+   */
+  checkBlocks(): number[] {
+    let indexList: number[] = [];
+    for (let block = 0; block < 9; block++) {
+      if (this.checkBlock(block) === false) {
+        indexList = indexList.concat(cellsIndexOfBlock(block));
+      }
+    }
+    return indexList;
+  }
+
+  /**
+   * This function check if cells contains multiple values.
+   */
+  checkCells(): number[] {
+    const indexList = [];
+    for (let cell = 0; cell < 81; cell++) {
+      const val = this.state.cells[cell].value;
+      if (val.length > 1) {
+        indexList.push(cell);
+      }
+    }
+    return indexList;
+  }
+
+  /**
+   * Check if all cells respect Sudoku rules and update cells.
+   * @param cells Current cells values.
+   */
+  updateState(
+    cells: { value: string; modifiable: boolean; error: boolean }[]
+  ): void {
+    let errorIndexList = this.checkLines();
+    errorIndexList = errorIndexList.concat(this.checkColumns());
+    errorIndexList = errorIndexList.concat(this.checkBlocks());
+    errorIndexList = errorIndexList.concat(this.checkCells());
+
+    const errorIndexSet = new Set(errorIndexList);
+
+    for (let index = 0; index < 81; index++) {
+      if (errorIndexSet.has(index)) {
+        cells[index].error = true;
+      } else {
+        cells[index].error = false;
+      }
+    }
+
+    if (errorIndexSet.size) {
+      this.setState({ cells: cells, isFinished: false });
+      return;
+    }
+
+    for (let index = 0; index < 81; index++) {
+      if (!validInput.test(this.state.cells[index].value)) {
+        this.setState({ cells: cells, isFinished: false });
+        return;
+      }
+    }
+    this.setState({ cells: cells, isFinished: true });
+  }
+}
+
+/**
+ * Return a predefined Sudoku grid as a string.
+ * @param gridNum Desired grid number
+ */
+ function generateStaticGrid(gridNum: string) {
+  return GRIDS[gridNum];
+}
+
+/**
+ * Concatenates all values of a HashSet as a String.
+ * @param set HashSet to be concatenated.
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function hashSetToString(set: any): string {
+  const res = new Set();
+  const it = set.iterator();
+  while (it.hasNext()) {
+    const val = it.next();
+    if (val !== "") {
+      res.add(val);
+    }
+  }
+  return Array.from(res).sort().join(" ");
 }
 
 export default Game;
diff --git a/collaborative/src/components/Grid.test.tsx b/collaborative/src/components/Grid.test.tsx
index 2d069c9aca025dc8635af48f59ce690074bacf99..68e8d4898e68d58cccbeaa1688e5f989a484d078 100644
--- a/collaborative/src/components/Grid.test.tsx
+++ b/collaborative/src/components/Grid.test.tsx
@@ -22,13 +22,10 @@
  * SOFTWARE.
  */
 
-import React from "react";
 import { configure } from "enzyme";
 import Adapter from "enzyme-adapter-react-16";
-import { shallow, mount, render } from "enzyme";
-import Grid from "./Grid";
-import { checkArray, firstCellOfBlock, blockIndex } from "./Grid";
-import { crdtlib } from "@concordant/c-crdtlib";
+import { shallow, mount } from "enzyme";
+import Grid, { cellsIndexOfBlock } from "./Grid";
 
 configure({ adapter: new Adapter() });
 
@@ -36,2934 +33,82 @@ beforeEach(() => {
   jest.spyOn(console, "log").mockImplementation(() => ({}));
 });
 
-/**
- * This test evaluates that checkArray return true only if the array contains only integers equal to 0 or 1.
- */
-describe("checkArray", () => {
-  test("checkArray", () => {
-    expect(checkArray([0, 1, 2, 3])).toBe(false);
-    expect(checkArray([0, 1, 0, 1])).toBe(true);
-    expect(checkArray([0, -1, 0, 1])).toBe(false);
-  });
-});
-
-/**
- * This test evaluates that firstCellOfBlock return the position of the top-left cell of the block.
- */
-describe("firstCellOfBlock", () => {
-  test("firstCellOfBlock", () => {
-    expect(firstCellOfBlock(0)).toStrictEqual([0, 0]);
-    expect(firstCellOfBlock(1)).toStrictEqual([0, 3]);
-    expect(firstCellOfBlock(2)).toStrictEqual([0, 6]);
-    expect(firstCellOfBlock(4)).toStrictEqual([3, 3]);
-    expect(firstCellOfBlock(8)).toStrictEqual([6, 6]);
-  });
-});
-
-/**
- * This test evaluates that blockIndex return a list containing index of all cells of the same block.
- */
-describe("blockIndex", () => {
-  test("blockIndex", () => {
-    expect(blockIndex(0)).toStrictEqual([0, 1, 2, 9, 10, 11, 18, 19, 20]);
-    expect(blockIndex(1)).toStrictEqual([3, 4, 5, 12, 13, 14, 21, 22, 23]);
-    expect(blockIndex(2)).toStrictEqual([6, 7, 8, 15, 16, 17, 24, 25, 26]);
-    expect(blockIndex(4)).toStrictEqual([30, 31, 32, 39, 40, 41, 48, 49, 50]);
-    expect(blockIndex(8)).toStrictEqual([60, 61, 62, 69, 70, 71, 78, 79, 80]);
-  });
-});
-
 /**
  * This test evaluates that getValue return the right initial value.
  */
-describe("getValue", () => {
-  test("getValue", () => {
-    const initVal = [
-      "6",
-      "",
-      "",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-
-    const envs = Array(9);
-    const newvals = Array(9);
-    for (let i = 0; i < 9; i++) {
-      envs[i] = new crdtlib.utils.SimpleEnvironment(
-        new crdtlib.utils.ClientUId("myClientId" + i)
-      );
-      newvals[i] = new crdtlib.crdt.MVRegister();
-      newvals[i].set(String(i + 1), envs[i].tick());
-      grid.state.cells[1].merge(newvals[i]);
-    }
-    expect(grid.getValue(0)).toBe("6");
-    expect(grid.getValue(1)).toBe("1 2 3 4 5 6 7 8 9");
-    expect(grid.getValue(2)).toBe("");
-  });
-});
-
-/**
- * This test evaluates that handleChange change the value of the cell.
- * Call to getValue should return the new value (2).
- */
-describe("handleChange", () => {
-  test("handleChange", () => {
-    const initVal = [
-      "6",
-      "5",
-      "",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-
-    const wrapper = mount(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.getValue(4)).toBe("8");
-    grid.handleChange(4, "2");
-    expect(grid.getValue(4)).toBe("2");
-  });
-});
-
-/**
- * This test evaluates that checkLine return true only if
- * the array contains all numbers from 1 to 9 without repeat.
- */
-describe("checkLine", () => {
-  test("checkLine", () => {
-    const initVal = [
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "1",
-      "2",
-      "3",
-      "4",
-      "5",
-      "6",
-      "7",
-      "8",
-      "9",
-      "1",
-      "2",
-      "3",
-      "",
-      "5",
-      "6",
-      "7",
-      "8",
-      "9",
-      "1",
-      "1",
-      "3",
-      "4",
-      "5",
-      "6",
-      "7",
-      "8",
-      "9",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-
-    const env = new crdtlib.utils.SimpleEnvironment(
-      new crdtlib.utils.ClientUId("myClientId1")
-    );
-    const newval = new crdtlib.crdt.MVRegister();
-    newval.set("1", env.tick());
-    grid.state.cells[45].merge(newval);
-
-    expect(grid.checkLine(0)).toBe(true);
-    expect(grid.checkLine(1)).toBe(true);
-    expect(grid.checkLine(2)).toBe(true);
-    expect(grid.checkLine(3)).toBe(false);
-    expect(grid.checkLine(4)).toBe(true);
-    expect(grid.checkLine(5)).toBe(true);
-  });
-});
-
-/**
- * This test evaluates that checkColumn return true only if
- * the array contains all numbers from 1 to 9 without repeat.
- */
-describe("checkColumn", () => {
-  test("checkColumn", () => {
-    const initVal = [
-      "",
-      "1",
-      "1",
-      "1",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "",
-      "2",
-      "2",
-      "1",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "",
-      "3",
-      "3",
-      "3",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "",
-      "4",
-      "",
-      "4",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "",
-      "5",
-      "5",
-      "5",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "",
-      "6",
-      "6",
-      "6",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "",
-      "7",
-      "7",
-      "7",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "",
-      "8",
-      "8",
-      "8",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "9",
-      "9",
-      "9",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-
-    const env = new crdtlib.utils.SimpleEnvironment(
-      new crdtlib.utils.ClientUId("myClientId1")
-    );
-    const newval = new crdtlib.crdt.MVRegister();
-    newval.set("1", env.tick());
-    grid.state.cells[5].merge(newval);
-
-    expect(grid.checkColumn(0)).toBe(true);
-    expect(grid.checkColumn(1)).toBe(true);
-    expect(grid.checkColumn(2)).toBe(true);
-    expect(grid.checkColumn(3)).toBe(false);
-    expect(grid.checkColumn(4)).toBe(true);
-    expect(grid.checkColumn(5)).toBe(true);
-  });
-});
-
-/**
- * This test evaluates that checkBlock return true only if
- * the array contains all numbers from 1 to 9 without repeat.
- */
-describe("checkBlock", () => {
-  test("checkBlock", () => {
-    const initVal = [
-      "",
-      "",
-      "",
-      "1",
-      "2",
-      "3",
-      "1",
-      "2",
-      "3",
-      "",
-      "",
-      "",
-      "4",
-      "5",
-      "6",
-      "4",
-      "5",
-      "",
-      "",
-      "",
-      "",
-      "7",
-      "8",
-      "9",
-      "7",
-      "8",
-      "9",
-      "1",
-      "1",
-      "2",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "3",
-      "4",
-      "5",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "6",
-      "7",
-      "8",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-
-    const env = new crdtlib.utils.SimpleEnvironment(
-      new crdtlib.utils.ClientUId("myClientId")
-    );
-    const newval = new crdtlib.crdt.MVRegister();
-    newval.set("1", env.tick());
-    grid.state.cells[3].merge(newval);
-
-    expect(grid.checkBlock(0)).toBe(true);
-    expect(grid.checkBlock(1)).toBe(true);
-    expect(grid.checkBlock(2)).toBe(true);
-    expect(grid.checkBlock(3)).toBe(false);
-    expect(grid.checkBlock(4)).toBe(true);
-    expect(grid.checkBlock(5)).toBe(true);
-  });
-});
-
-/**
- * This test evaluates that validateLine return false if a line contains an error.
- */
-describe("validateLine", () => {
-  /**
-   * This test evaluates that validateLine return true with a line containing full empty cell.
-   */
-  test("validateLine empty", () => {
-    const initVal = [
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateLine()).toBe(true);
-  });
-
-  /**
-   * This test evaluates that validateLine return true with a line containing all numbers
-   * from 1 to 9 without repeat.
-   */
-  test("validateLine complete", () => {
-    const initVal = [
-      "6",
-      "5",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateLine()).toBe(true);
-  });
-
-  /**
-   * This test evaluates that validateLine return true if a line is missing a value.
-   */
-  test("validateLine with missing values", () => {
-    const initVal = [
-      "6",
-      "",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateLine()).toBe(true);
-  });
-
-  /**
-   * This test evaluates that validateLine return false when a value is dupplicated.
-   */
-  test("validateLine with wrongs values", () => {
-    const initVal = [
-      "6",
-      "2",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateLine()).toBe(false);
-  });
-
-  /**
-   * This test evaluates that validateLine return true when a cell has multiple values.
-   */
-  test("validateLine with multiples values", () => {
-    const initVal = [
-      "6",
-      "5",
-      "",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-
-    const env = new crdtlib.utils.SimpleEnvironment(
-      new crdtlib.utils.ClientUId("myClientId")
-    );
-    const newval = new crdtlib.crdt.MVRegister();
-    newval.set("1", env.tick());
-    grid.state.cells[1].merge(newval);
-
-    expect(grid.validateLine()).toBe(true);
+describe("Cells initialization", () => {
+  test("Cells initialization", () => {
+    // prettier-ignore
+    const initVal = ["6","","","3","8","7","9","1","4",
+                       "7","1","9","4","5","2","3","6","8",
+                       "3","4","8","1","9","6","2","5","7",
+                       "8","2","1","9","3","5","4","7","6",
+                       "5","9","6","2","7","4","8","3","1",
+                       "4","7","3","8","6","1","5","2","9",
+                       "1","8","7","5","2","9","","","3",
+                       "2","3","4","6","1","8","7","9","5",
+                       "","6","5","7","4","3","1","8","2"]
+    const wrapper = mount(<Grid cells={initVal.map(val =>({ value: val, modifiable: false, error: false }))} isFinished={false} onChange={() => ({})} />);
+
+    expect(wrapper.find({ id: "0" }).instance().value).toBe("6");
+    expect(wrapper.find({ id: "1" }).instance().value).toBe("");
+    expect(wrapper.find({ id: "3" }).instance().value).toBe("3");
   });
 });
 
-/**
- * This test evaluates that validateColumn return false if a column contains an error.
- */
-describe("validateColumn", () => {
-  /**
-   * This test evaluates that validateColumn return true with a column containing full empty cell.
-   */
-  test("validateColumn empty", () => {
-    const initVal = [
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateColumn()).toBe(true);
-  });
-
-  /**
-   * This test evaluates that validateColumn return true with a column containing all numbers
-   * from 1 to 9 without repeat.
-   */
-  test("validateColumn complete", () => {
-    const initVal = [
-      "6",
-      "5",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateColumn()).toBe(true);
-  });
-
-  /**
-   * This test evaluates that validateColumn return true if a column is missing a value.
-   */
-  test("validateColumn with missing values", () => {
-    const initVal = [
-      "6",
-      "",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateColumn()).toBe(true);
-  });
-
-  /**
-   * This test evaluates that validateColumn return false when a value is dupplicated.
-   */
-  test("validateColumn with wrongs values", () => {
-    const initVal = [
-      "6",
-      "2",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateColumn()).toBe(false);
-  });
-
-  /**
-   * This test evaluates that validateColumn return true when a cell has multiple values.
-   */
-  test("validateColumn with multiples values", () => {
-    const initVal = [
-      "6",
-      "5",
-      "",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-
-    const env = new crdtlib.utils.SimpleEnvironment(
-      new crdtlib.utils.ClientUId("myClientId")
-    );
-    const newval = new crdtlib.crdt.MVRegister();
-    newval.set("1", env.tick());
-    grid.state.cells[1].merge(newval);
-
-    expect(grid.validateColumn()).toBe(true);
-  });
-});
-
-/**
- * This test evaluates that validateBlock return false if a line contains an error.
- */
-describe("validateBlock", () => {
-  /**
-   * This test evaluates that validateBlock return true with a line containing full empty cell.
-   */
-  test("validateBlock empty", () => {
-    const initVal = [
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateBlock()).toBe(true);
-  });
-
-  /**
-   * This test evaluates that validateBlock return true with a line containing all numbers
-   * from 1 to 9 without repeat.
-   */
-  test("validateBlock complete", () => {
-    const initVal = [
-      "6",
-      "5",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateBlock()).toBe(true);
-  });
-
-  /**
-   * This test evaluates that validateBlock return true if a line is missing a value.
-   */
-  test("validateBlock with missing values", () => {
-    const initVal = [
-      "6",
-      "",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateBlock()).toBe(true);
-  });
-
-  /**
-   * This test evaluates that validateBlock return false when a value is dupplicated.
-   */
-  test("validateBlock with wrongs values", () => {
-    const initVal = [
-      "6",
-      "2",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateBlock()).toBe(false);
-  });
-
-  /**
-   * This test evaluates that validateBlock return true when a cell has multiple values.
-   */
-  test("validateBlock with multiples values", () => {
-    const initVal = [
-      "6",
-      "5",
-      "",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-
-    const env = new crdtlib.utils.SimpleEnvironment(
-      new crdtlib.utils.ClientUId("myClientId")
-    );
-    const newval = new crdtlib.crdt.MVRegister();
-    newval.set("1", env.tick());
-    grid.state.cells[1].merge(newval);
-
-    expect(grid.validateBlock()).toBe(true);
-  });
-});
-
-/**
- * This test evaluates that validateSudoku return false if a line, column or block contains an error.
- */
-describe("validateSudoku", () => {
-  /**
-   * This test evaluates that validateSudoku return true with a full empty grid.
-   */
-  test("validateSudoku empty", () => {
-    const initVal = [
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-      "",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateSudoku()).toBe("Continue");
-  });
-
-  /**
-   * This test evaluates that validateSudoku return true with all lines, columns and blocks
-   * containing all numbers from 1 to 9 without repeat.
-   */
-  test("validateSudoku complete", () => {
-    const initVal = [
-      "6",
-      "5",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateSudoku()).toBe("Complete");
-  });
-
-  /**
-   * This test evaluates that validateSudoku return true if the grid is missing a value.
-   */
-  test("validateSudoku with missing values", () => {
-    const initVal = [
-      "6",
-      "",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateSudoku()).toBe("Continue");
-  });
-
-  /**
-   * This test evaluates that validateSudoku return false when a value is dupplicated.
-   */
-  test("validateSudoku with wrongs values", () => {
-    const initVal = [
-      "6",
-      "2",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-    expect(grid.validateSudoku()).toBe("Error");
-  });
-
+describe("Testing cells", () => {
   /**
-   * This test evaluates that validateSudoku return true when a cell has multiple values.
+   * This test evaluates that the grid display the right numbers of Cell.
    */
-  test("validateSudoku with multiples values", () => {
-    const initVal = [
-      "6",
-      "5",
-      "",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const grid = wrapper.instance();
-
-    const env = new crdtlib.utils.SimpleEnvironment(
-      new crdtlib.utils.ClientUId("myClientId")
-    );
-    const newval = new crdtlib.crdt.MVRegister();
-    newval.set("1", env.tick());
-    grid.state.cells[1].merge(newval);
-
-    expect(grid.validateSudoku()).toBe("Continue");
+  test("Number of cells", () => {
+    // prettier-ignore
+    const initVal = ["6","5","","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","","","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "","6","5","7","4","3","1","8","2"]
+
+    const wrapper = shallow(<Grid cells={initVal.map(val =>({ value: val, modifiable: false, error: false }))} isFinished={false} onChange={() => ({})} />);
+    expect(wrapper.find("Cell")).toHaveLength(81);
   });
 });
 
 describe("Testing status", () => {
-  /**
-   * This test evaluates that the status field display "Continue" when the grid
-   * is missing a value without wrong entries.
-   */
-  test("UI status continue", () => {
-    const initVal = [
-      "",
-      "5",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const status = wrapper.find(".status");
-    expect(status.text()).toBe("Status : Continue");
-  });
-
-  /**
-   * This test evaluates that the status field display "Error" when the grid
-   * contains an error.
-   */
-  test("UI status error", () => {
-    const initVal = [
-      "6",
-      "2",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const status = wrapper.find(".status");
-    expect(status.text()).toBe("Status : Error");
-  });
-
   /**
    * This test evaluates that the status field display "Complete" when the grid
    * is complete without errors.
    */
-  test("UI status complete", () => {
-    const initVal = [
-      "6",
-      "5",
-      "2",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "6",
-      "4",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "9",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-
-    const wrapper = shallow(<Grid initial={initVal} />);
-    const status = wrapper.find(".status");
-    expect(status.text()).toBe("Status : Complete");
+  test("Completed grid", () => {
+    // prettier-ignore
+    const initVal = ["6","5","2","3","8","7","9","1","4",
+                        "7","1","9","4","5","2","3","6","8",
+                        "3","4","8","1","9","6","2","5","7",
+                        "8","2","1","9","3","5","4","7","6",
+                        "5","9","6","2","7","4","8","3","1",
+                        "4","7","3","8","6","1","5","2","9",
+                        "1","8","7","5","2","9","6","4","3",
+                        "2","3","4","6","1","8","7","9","5",
+                        "9","6","5","7","4","3","1","8","2"]
+
+    const wrapper = mount(<Grid cells={initVal.map(val =>({ value: val, modifiable: false, error: false }))} isFinished={true} onChange={() => ({})} />);
+    const status = wrapper.find({ id: "status" });
+    expect(status.text()).toBe("Sudoku completed");
   });
 });
 
-describe("Testing cells", () => {
-  /**
-   * This test evaluates that the grid display the right numbers of Cell.
-   */
-  test("Number of cells", () => {
-    const initVal = [
-      "6",
-      "5",
-      "",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-
-    const wrapper = shallow(<Grid initial={initVal} />);
-    expect(wrapper.find("Cell")).toHaveLength(81);
-  });
-
-  /**
-   * This test evaluates that the grid display the right initial value.
-   */
-  test("Cell initialization", () => {
-    const initVal = [
-      "6",
-      "5",
-      "",
-      "3",
-      "8",
-      "7",
-      "9",
-      "1",
-      "4",
-      "7",
-      "1",
-      "9",
-      "4",
-      "5",
-      "2",
-      "3",
-      "6",
-      "8",
-      "3",
-      "4",
-      "8",
-      "1",
-      "9",
-      "6",
-      "2",
-      "5",
-      "7",
-      "8",
-      "2",
-      "1",
-      "9",
-      "3",
-      "5",
-      "4",
-      "7",
-      "6",
-      "5",
-      "9",
-      "6",
-      "2",
-      "7",
-      "4",
-      "8",
-      "3",
-      "1",
-      "4",
-      "7",
-      "3",
-      "8",
-      "6",
-      "1",
-      "5",
-      "2",
-      "9",
-      "1",
-      "8",
-      "7",
-      "5",
-      "2",
-      "9",
-      "",
-      "",
-      "3",
-      "2",
-      "3",
-      "4",
-      "6",
-      "1",
-      "8",
-      "7",
-      "9",
-      "5",
-      "",
-      "6",
-      "5",
-      "7",
-      "4",
-      "3",
-      "1",
-      "8",
-      "2",
-    ];
-
-    const wrapper = mount(<Grid initial={initVal} />);
-    expect(wrapper.find("Cell").first().text()).toBe("6");
+/**
+ * This test evaluates that cellsIndexOfBlock return a list containing index of all cells of the same block.
+ */
+ describe("cellsIndexOfBlock", () => {
+  test("cellsIndexOfBlock", () => {
+    expect(cellsIndexOfBlock(0)).toStrictEqual([0, 1, 2, 9, 10, 11, 18, 19, 20]);
+    expect(cellsIndexOfBlock(1)).toStrictEqual([3, 4, 5, 12, 13, 14, 21, 22, 23]);
+    expect(cellsIndexOfBlock(2)).toStrictEqual([6, 7, 8, 15, 16, 17, 24, 25, 26]);
+    expect(cellsIndexOfBlock(4)).toStrictEqual([30, 31, 32, 39, 40, 41, 48, 49, 50]);
+    expect(cellsIndexOfBlock(8)).toStrictEqual([60, 61, 62, 69, 70, 71, 78, 79, 80]);
   });
 });
diff --git a/collaborative/src/components/Grid.tsx b/collaborative/src/components/Grid.tsx
index 33b97a48a17155f556281e4eafbaf2b0663a5d88..dade3e25969254f6eb48988dd06b9b9220b7282f 100644
--- a/collaborative/src/components/Grid.tsx
+++ b/collaborative/src/components/Grid.tsx
@@ -25,213 +25,22 @@
 import React from "react";
 import assert from "assert";
 import Cell from "./Cell";
-import { validInput, GRIDS } from "../constants";
-import { client } from "@concordant/c-client";
-import Submit1Input from "./Submit1Input";
 
 /**
  * Interface for the properties of the Grid
  */
 interface IGridProps {
-  session: any; // eslint-disable-line @typescript-eslint/no-explicit-any
-  collection: any; // eslint-disable-line @typescript-eslint/no-explicit-any
-}
-
-/**
- * Interface for the state of the Grid
- */
-interface IGridState {
-  gridNum: string;
-  mvmap: any; // eslint-disable-line @typescript-eslint/no-explicit-any
   cells: { value: string; modifiable: boolean; error: boolean }[];
-  isConnected: boolean;
   isFinished: boolean;
+  onChange: ((index: number, value: string) => void);
 }
 
 /**
  * This class represent the grid of the Sudoku
  */
-class Grid extends React.Component<IGridProps, IGridState> {
-  timerID!: NodeJS.Timeout;
-  modifiedCells: string[];
-
-  constructor(props: IGridProps) {
-    super(props);
-    const cells = new Array(81)
-      .fill(null)
-      .map(() => ({ value: "", modifiable: false, error: false }));
-    this.modifiedCells = new Array(81).fill(null);
-    const gridNum = "1";
-    const mvmap = this.props.collection.open(
-      "grid" + gridNum,
-      "MVMap",
-      false,
-      function () {
-        return;
-      }
-    );
-    this.state = {
-      gridNum: gridNum,
-      mvmap: mvmap,
-      cells: cells,
-      isConnected: true,
-      isFinished: false,
-    };
-  }
-
-  /**
-   * Called after the component is rendered.
-   * It set a timer to refresh cells values.
-   */
-  componentDidMount(): void {
-    this.initFrom(generateStaticGrid(this.state.gridNum));
-    this.timerID = setInterval(() => this.updateGrid(), 1000);
-  }
-
-  /**
-   * Called when the compenent is about to be removed from the DOM.
-   * It remove the timer set in componentDidMount().
-   */
-  componentWillUnmount(): void {
-    clearInterval(this.timerID);
-  }
-
-  /**
-   * Update cells values from C-Client.
-   */
-  updateGrid(): void {
-    const cells = this.state.cells;
-    if (!this.state.isConnected) {
-      console.error("updateGrid() called while not connected.");
-      return;
-    }
-    for (let index = 0; index < 81; index++) {
-      if (cells[index].modifiable) {
-        cells[index].value = "";
-      }
-    }
-    this.props.session.transaction(client.utils.ConsistencyLevel.None, () => {
-      const itString = this.state.mvmap.iteratorString();
-      while (itString.hasNext()) {
-        const val = itString.next();
-        cells[val.first].value = hashSetToString(val.second);
-      }
-    });
-    this.updateState(cells);
-  }
-
-  /**
-   * This function is used to simulate the offline mode.
-   */
-  switchConnection(): void {
-    if (this.state.isConnected) {
-      this.modifiedCells = new Array(81).fill(null);
-      clearInterval(this.timerID);
-    } else {
-      for (let index = 0; index < 81; index++) {
-        if (
-          this.state.cells[index].modifiable &&
-          this.modifiedCells[index] !== null
-        ) {
-          this.props.session.transaction(
-            client.utils.ConsistencyLevel.None,
-            () => {
-              this.state.mvmap.setString(index, this.modifiedCells[index]);
-            }
-          );
-        }
-      }
-      this.timerID = setInterval(() => this.updateGrid(), 1000);
-    }
-    this.setState({ isConnected: !this.state.isConnected });
-  }
-
-  /**
-   * Initialize the grid with the given values.
-   * @param values values to be set in the grid.
-   */
-  initFrom(values: string): void {
-    assert.ok(values.length === 81);
-    const cells = this.state.cells;
-    for (let index = 0; index < 81; index++) {
-      cells[index].value = values[index] === "." ? "" : values[index];
-      cells[index].modifiable = values[index] === "." ? true : false;
-    }
-    this.updateState(cells);
-  }
-
-  /**
-   * Reset the value of all modifiable cells.
-   */
-  reset(): void {
-    const cells = this.state.cells;
-    for (let index = 0; index < 81; index++) {
-      if (cells[index].modifiable) {
-        cells[index].value = "";
-        if (this.state.isConnected) {
-          this.props.session.transaction(
-            client.utils.ConsistencyLevel.None,
-            () => {
-              this.state.mvmap.setString(index, cells[index].value);
-            }
-          );
-        } else {
-          this.modifiedCells[index] = "";
-        }
-      }
-    }
-    this.updateState(cells);
-  }
-
-  /**
-   * This handler is called when the value of a cell is changed.
-   * @param index The index of the cell changed.
-   * @param value The new value of the cell.
-   */
+class Grid extends React.Component<IGridProps> {
   handleChange(index: number, value: string): void {
-    assert.ok(value === "" || (Number(value) >= 1 && Number(value) <= 9));
-    assert.ok(index >= 0 && index < 81);
-    if (!this.state.cells[index].modifiable) {
-      console.error(
-        "Trying to change an non modifiable cell. Should not happend"
-      );
-    }
-
-    const cells = this.state.cells;
-    cells[index].value = value;
-    this.updateState(cells);
-
-    if (this.state.isConnected) {
-      this.props.session.transaction(client.utils.ConsistencyLevel.None, () => {
-        this.state.mvmap.setString(index, value);
-      });
-    } else {
-      this.modifiedCells[index] = value;
-    }
-  }
-
-  /**
-   * This handler is called when a new grid number is submit.
-   * @param gridNum Desired grid number.
-   */
-  handleSubmit(gridNum: string): void {
-    if (
-      Number(gridNum) < 1 ||
-      Number(gridNum) > 100 ||
-      gridNum === this.state.gridNum
-    ) {
-      return;
-    }
-    const mvmap = this.props.collection.open(
-      "grid" + gridNum,
-      "MVMap",
-      false,
-      function () {
-        return;
-      }
-    );
-    this.setState({ gridNum: gridNum, mvmap: mvmap });
-    this.initFrom(generateStaticGrid(gridNum));
+    this.props.onChange(index, value);
   }
 
   /**
@@ -243,13 +52,13 @@ class Grid extends React.Component<IGridProps, IGridState> {
     return (
       <Cell
         index={index}
-        value={this.state.cells[index].value}
+        value={this.props.cells[index].value}
         onChange={
-          this.state.cells[index].modifiable
+          this.props.cells[index].modifiable
             ? (index: number, value: string) => this.handleChange(index, value)
             : null
         }
-        error={this.state.cells[index].error}
+        error={this.props.cells[index].error}
       />
     );
   }
@@ -260,7 +69,7 @@ class Grid extends React.Component<IGridProps, IGridState> {
    */
   renderBlock(blockNum: number): JSX.Element {
     assert.ok(blockNum >= 0 && blockNum < 9);
-    const index = blockIndex(blockNum);
+    const index = cellsIndexOfBlock(blockNum);
     return (
       <td>
         {this.renderCell(index[0])}
@@ -283,27 +92,7 @@ class Grid extends React.Component<IGridProps, IGridState> {
    */
   render(): JSX.Element {
     return (
-      <div className="sudoku">
-        <div>Current grid : {this.state.gridNum}</div>
-        <Submit1Input
-          inputName="Grid"
-          onSubmit={this.handleSubmit.bind(this)}
-        />
-        <div>
-          Difficulty levels: easy (1-20), medium (21-40), hard (41-60),
-          very-hard (61-80), insane (81-100)
-        </div>
-        <br />
-        <div>
-          <button onClick={this.reset.bind(this)}>Reset</button>
-        </div>
-        <br />
-        <div>
-          <button onClick={() => this.switchConnection()}>
-            {this.state.isConnected ? "Disconnect" : "Connect"}
-          </button>
-        </div>
-        <br />
+      <div>
         <table className="grid">
           <tbody>
             {[0, 1, 2].map((line) => (
@@ -315,7 +104,7 @@ class Grid extends React.Component<IGridProps, IGridState> {
             ))}
           </tbody>
         </table>
-        {this.state.isFinished && (
+        {this.props.isFinished && (
           <h2 className="status" id="status">
             Sudoku completed
           </h2>
@@ -323,168 +112,13 @@ class Grid extends React.Component<IGridProps, IGridState> {
       </div>
     );
   }
-
-  /**
-   * Check if a line respect Sudoku lines rules.
-   * @param line The line number to be checked.
-   */
-  checkLine(line: number): boolean {
-    assert.ok(line >= 0 && line < 9);
-    const cpt = Array(9).fill(0);
-    for (let column = 0; column < 9; column++) {
-      const index = line * 9 + column;
-      const val = this.state.cells[index].value;
-      if (val.length === 0 || val.length > 1) {
-        continue;
-      }
-      cpt[Number(val) - 1]++;
-    }
-    return cpt.every((c) => c <= 1);
-  }
-
-  /**
-   * Check if a column respect Sudoku columns rules.
-   * @param column The column number to be checked.
-   */
-  checkColumn(column: number): boolean {
-    assert.ok(column >= 0 && column < 9);
-    const cpt = Array(9).fill(0);
-    for (let line = 0; line < 9; line++) {
-      const index = line * 9 + column;
-      const val = this.state.cells[index].value;
-      if (val.length === 0 || val.length > 1) {
-        continue;
-      }
-      cpt[Number(val) - 1]++;
-    }
-    return cpt.every((c) => c <= 1);
-  }
-
-  /**
-   * Check if a block respect Sudoku blocks rules.
-   * @param block The block number to be checked.
-   */
-  checkBlock(block: number): boolean {
-    assert.ok(block >= 0 && block < 9);
-    const cpt = Array(9).fill(0);
-    const indexList = blockIndex(block);
-    for (const index of indexList) {
-      const val = this.state.cells[index].value;
-      if (val.length === 0 || val.length > 1) {
-        continue;
-      }
-      cpt[Number(val) - 1]++;
-    }
-    return cpt.every((c) => c <= 1);
-  }
-
-  /**
-   * This function check if all lines respect Sudoku lines rules.
-   */
-  checkLines(): number[] {
-    const indexList = [];
-    for (let line = 0; line < 9; line++) {
-      if (this.checkLine(line) === false) {
-        for (let column = 0; column < 9; column++) {
-          indexList.push(line * 9 + column);
-        }
-      }
-    }
-    return indexList;
-  }
-
-  /**
-   * This function check if all columns respect Sudoku columns rules.
-   */
-  checkColumns(): number[] {
-    const indexList = [];
-    for (let column = 0; column < 9; column++) {
-      if (this.checkColumn(column) === false) {
-        for (let line = 0; line < 9; line++) {
-          indexList.push(line * 9 + column);
-        }
-      }
-    }
-    return indexList;
-  }
-
-  /**
-   * This function check if all blocks respect Sudoku blocks rules.
-   */
-  checkBlocks(): number[] {
-    let indexList: number[] = [];
-    for (let block = 0; block < 9; block++) {
-      if (this.checkBlock(block) === false) {
-        indexList = indexList.concat(blockIndex(block));
-      }
-    }
-    return indexList;
-  }
-
-  /**
-   * This function check if cells contains multiple values.
-   */
-  checkCells(): number[] {
-    const indexList = [];
-    for (let cell = 0; cell < 81; cell++) {
-      const val = this.state.cells[cell].value;
-      if (val.length > 1) {
-        indexList.push(cell);
-      }
-    }
-    return indexList;
-  }
-
-  /**
-   * Check if all cells respect Sudoku rules and update cells.
-   * @param cells Current cells values.
-   */
-  updateState(
-    cells: { value: string; modifiable: boolean; error: boolean }[]
-  ): void {
-    let errorIndexList = this.checkLines();
-    errorIndexList = errorIndexList.concat(this.checkColumns());
-    errorIndexList = errorIndexList.concat(this.checkBlocks());
-    errorIndexList = errorIndexList.concat(this.checkCells());
-
-    const errorIndexSet = new Set(errorIndexList);
-
-    for (let index = 0; index < 81; index++) {
-      if (errorIndexSet.has(index)) {
-        cells[index].error = true;
-      } else {
-        cells[index].error = false;
-      }
-    }
-
-    if (errorIndexSet.size) {
-      this.setState({ cells: cells, isFinished: false });
-      return;
-    }
-
-    for (let index = 0; index < 81; index++) {
-      if (!validInput.test(this.state.cells[index].value)) {
-        this.setState({ cells: cells, isFinished: false });
-        return;
-      }
-    }
-    this.setState({ cells: cells, isFinished: true });
-  }
-}
-
-/**
- * Return a predefined Sudoku grid as a string.
- * @param gridNum Desired grid number
- */
-function generateStaticGrid(gridNum: string) {
-  return GRIDS[gridNum];
 }
 
 /**
  * Return an array containing all cell index of a block.
  * @param block The block number of which we want the cells index.
  */
-function blockIndex(block: number) {
+export function cellsIndexOfBlock(block: number): number[] {
   assert.ok(block >= 0 && block < 9);
   const line = Math.floor(block / 3) * 3;
   const column = (block % 3) * 3;
@@ -502,21 +136,4 @@ function blockIndex(block: number) {
   return index;
 }
 
-/**
- * Concatenates all values of a HashSet as a String.
- * @param set HashSet to be concatenated.
- */
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function hashSetToString(set: any): string {
-  const res = new Set();
-  const it = set.iterator();
-  while (it.hasNext()) {
-    const val = it.next();
-    if (val !== "") {
-      res.add(val);
-    }
-  }
-  return Array.from(res).sort().join(" ");
-}
-
 export default Grid;