diff --git a/game-of-life/CMakeLists.txt b/game-of-life/CMakeLists.txt
index ba5d195..cd8b3f7 100644
--- a/game-of-life/CMakeLists.txt
+++ b/game-of-life/CMakeLists.txt
@@ -1,18 +1,18 @@
 project(GOL)
 cmake_minimum_required(VERSION 2.8)
 
 find_package(MPI REQUIRED)
 
 set(CMAKE_CXX_FLAGS "-Wall -Werror -Wextra -pedantic")
 
 set(CMAKE_INCLUDE_CURRENT_DIR ON)
 set(CMAKE_AUTOMOC ON)
 set(CMAKE_CXX_STANDARD 14)
 
 find_package(Qt5Network)
 
-add_executable(gol game-of-life.cc client.cc client.hh grid.hh)
+add_executable(gol game-of-life.cc client.cc client.hh grid.hh grid.cc simu.hh simu_gol.hh)
 target_include_directories(gol PRIVATE ${MPI_CXX_INCLUDE_PATH})
 target_link_libraries(gol ${MPI_CXX_LIBRARIES} Qt5::Network)
 
 add_subdirectory(gol_gui)
diff --git a/game-of-life/client.cc b/game-of-life/client.cc
index 8e0765a..4bc3018 100644
--- a/game-of-life/client.cc
+++ b/game-of-life/client.cc
@@ -1,123 +1,87 @@
 #include "client.hh"
 
 #include <QByteArray>
 #include <QDataStream>
 #include <QTcpSocket>
 #include <iostream>
 
-// static auto error_handler = [](auto var, const std::string &message) -> void
-// {
-//   if (var < 0) {
-//     std::cerr << message << " -- " << std::strerror(errno) << std::endl;
-//     std::exit(1);
-//   }
-// };
 enum {
   READ_IMAGE = -1,
   READ_IMAGE_WAIT = -2,
   WAIT = -3,
   CONFIGURE = -4,
 };
 
 /* -------------------------------------------------------------------------- */
-GridSender::GridSender(const Grid & grid, int prank, int psize,
-                       const std::string & server_name, int port)
-    : _grid(grid), prank(prank) {
-  // std::stringstream sstr;
-  // sstr << port;
-  // struct addrinfo hints;
-  // struct addrinfo *servinfo;
-  // memset(&hints, 0, sizeof hints);
-  // hints.ai_family = AF_UNSPEC;     // don't care IPv4 or IPv6
-  // hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
+GridSender::GridSender(const Grid & grid) : _grid(grid), prank(0), psize(0) {}
 
-  // error_handler(
-  //     getaddrinfo(server_name.c_str(), sstr.str().c_str(), &hints,
-  //     &servinfo),
-  //     "Could not retrieve server info");
-
-  // error_handler(sockfd = socket(servinfo->ai_family, servinfo->ai_socktype,
-  //                               servinfo->ai_protocol),
-  //               "Could not open a socket");
-
-  // error_handler(connect(sockfd, servinfo->ai_addr, servinfo->ai_addrlen),
-  //               "Could not connect to server");
-  // freeaddrinfo(servinfo);
+void GridSender::setParallelContext(int prank, int psize) {
+  this->prank = prank;
+  this->psize = psize;
+}
 
+void GridSender::connect(const std::string & server_name, int port) {
   socket = new QTcpSocket();
   qDebug() << prank << "Connecting to" << server_name.c_str();
   socket->connectToHost(QString(server_name.c_str()), port);
   socket->waitForConnected();
   qDebug() << prank << "Connected";
 
   char command = CONFIGURE;
   socket->putChar(command);
   QByteArray data;
   QDataStream buffer(&data, QIODevice::WriteOnly);
 
   buffer << prank;
   buffer << psize;
-  buffer << int(grid.size(0));
-  buffer << int(grid.size(1));
-  buffer << int(grid.offset(0));
-  buffer << int(grid.offset(1));
-  buffer << int(grid.ghost());
+  buffer << int(_grid.size(0));
+  buffer << int(_grid.size(1));
+  buffer << int(_grid.globalSize(0));
+  buffer << int(_grid.globalSize(1));
+  buffer << int(_grid.offset(0));
+  buffer << int(_grid.offset(1));
+  buffer << int(_grid.ghost());
 
   socket->write(data);
 
   qDebug() << prank << "Waiting for connection confirmation...";
   socket->waitForReadyRead();
   socket->getChar(&command);
   qDebug() << prank << "command" << int(command) << "ok!";
-
-  // error_handler(::send(sockfd, reinterpret_cast<char *>(buffer), 7 *
-  // sizeof(int), 0),
-  //               "Could not send the grid");
-
-  // delete [] buffer;
 }
 
 /* -------------------------------------------------------------------------- */
 GridSender::~GridSender() {
   socket->disconnectFromHost();
   socket->waitForDisconnected();
 }
 
 /* -------------------------------------------------------------------------- */
 void GridSender::send(bool wait) {
   char command = wait ? READ_IMAGE_WAIT : READ_IMAGE;
   socket->putChar(command);
-  // error_handler(::send(sockfd, &command, 1, 0),
-  //               "Could not send the grid");
+
   qDebug() << prank << "Sending" << _grid.fullSize() << "chars";
   socket->write(_grid.data(), _grid.fullSize());
-  // error_handler(::send(sockfd, _grid.data(), _grid.fullSize(), 0),
-  //               "Could not send the grid");
+  socket->waitForBytesWritten();
 
   if (wait) {
     qDebug() << prank << "Waiting...";
-    if(socket->waitForReadyRead()) {
+    if (socket->waitForReadyRead()) {
       socket->getChar(&command);
-      // error_handler(::recv(sockfd, &command, 1, MSG_WAITALL),
-      //               "Could not recv wait message");
       qDebug() << prank << "command" << int(command) << "ok!";
     } else {
-      qFatal("Confirmation timeouted!!!");
+      qFatal("Confirmation timeout!!!");
     }
   }
 }
 
 void GridSender::wait() {
   char command = WAIT;
 
   socket->putChar(command);
-  qDebug() << prank << "Sending wait" << command;
+  qDebug() << prank << "Sending wait" << int(command);
   socket->waitForReadyRead();
   socket->getChar(&command);
   qDebug() << prank << "command" << int(command) << "ok!";
-  // error_handler(::send(sockfd, &command, 1, MSG_WAITALL),
-  //               "Could not recv wait message");
-
-  // error_handler(::recv(sockfd, &command, 1, MSG_WAITALL),
-  //               "Could not recv wait message");
 }
diff --git a/game-of-life/client.hh b/game-of-life/client.hh
index 071fe38..7ba3250 100644
--- a/game-of-life/client.hh
+++ b/game-of-life/client.hh
@@ -1,20 +1,21 @@
 #include "grid.hh"
 #include <string>
 
 class QTcpSocket;
 
 class GridSender {
 public:
-  GridSender(const Grid &grid, int prank, int psize, const std::string &server,
-             int port);
+  GridSender(const Grid & grid);
 
   ~GridSender();
 
+  void setParallelContext(int prank, int psize);
+  void connect(const std::string & server, int port);
   void send(bool wait = true);
   void wait();
 
 private:
-  const Grid &_grid;
-  int prank;
+  const Grid & _grid;
+  int prank, psize;
   QTcpSocket * socket;
 };
diff --git a/game-of-life/game-of-life.cc b/game-of-life/game-of-life.cc
index 6ca31e4..ef38adc 100644
--- a/game-of-life/game-of-life.cc
+++ b/game-of-life/game-of-life.cc
@@ -1,77 +1,25 @@
-#include "grid.hh"
-#include "client.hh"
+#include "simu_gol.hh"
 
 #include <mpi.h>
 #include <iostream>
 
 int main(int argc, char **argv) {
   MPI_Init(&argc, &argv);
 
-  int nproc, rank;
-  MPI_Comm_size(MPI_COMM_WORLD, &nproc);
-  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+  long int dims[2] = {216, 384};
 
-  int nprocs[2] = {0, 0};
-  MPI_Dims_create(nproc, 2, nprocs);
+  GOL simu(dims, 1, true, MPI_COMM_WORLD, "127.0.0.1");
 
-  int periods[2] = {true, true};
-  MPI_Comm cart_comm;
-  MPI_Cart_create(MPI_COMM_WORLD, 2, nprocs, periods, true, &cart_comm);
-
-  std::size_t dims[2] = {120, 160};
-  std::size_t local_dims[2];
-  std::size_t offsets[2] = {0, 0};
-
-  for (std::size_t i = 0; i < 2; ++i) {
-    int mod = dims[i] % nprocs[i];
-
-    local_dims[i] = dims[i] / nprocs[i];
-    offsets[i] = local_dims[i] * rank + (rank < mod ? rank : mod);
-
-    local_dims[i] += (rank < mod ? 1 : 0);
+  simu.initialState();
+  while(true) {
+    simu.send();
+    simu.determineCells();
+    simu.swap();
   }
-
-  Grid grid(local_dims[0], local_dims[1], 1);
-  grid.setOffsets(offsets);
-
-  Grid old_grid(grid);
-
-  GridSender sender(old_grid, rank, nproc, "127.0.0.1", 4321);
-
-  for (std::size_t i = 0; i < grid.size(0); i++) {
-    old_grid(i, grid.size(1)/2) = 1;
-  }
-  sender.send();
-
-  std::cout << "Grid " <<old_grid.size() << " -- [" << old_grid.size(0) << ", "
-            << old_grid.size(1) << "]" << std::endl;
-
-  for (std::size_t k = 0; k < 100; k++) {
-    // for (std::size_t i = 0; i < grid.size(0); i++) {
-    //   for (std::size_t j = 0; j < grid.size(1); j++) {
-    //     double neighbours = -old_grid(i, j);
-    //     for (char v = -1; v < 1; ++v)
-    //       for (char w = -1; w < 1; ++w)
-    //         neighbours += old_grid(i + v, j + w);
-
-    //     if (neighbours < 2)
-    //       grid(i, j) = 0;
-    //     if (neighbours == 2)
-    //       grid(i, j) = old_grid(i, j);
-    //     if (neighbours == 3)
-    //       grid(i, j) = 1;
-    //     if (neighbours > 3)
-    //       grid(i, j) = 0;
-    //   }
-    // }
-
-    // grid.swap(old_grid);
-    sender.send();
-  }
-
-  sender.wait();
+  simu.send();
+  simu.getSender().wait();
 
   MPI_Finalize();
 
   return 0;
 }
diff --git a/game-of-life/gol_gui/data_thread.cc b/game-of-life/gol_gui/data_thread.cc
index 15c4983..604a343 100644
--- a/game-of-life/gol_gui/data_thread.cc
+++ b/game-of-life/gol_gui/data_thread.cc
@@ -1,139 +1,154 @@
 #include "data_thread.hh"
 #include "grid.hh"
 
 #include <QDataStream>
 #include <QHostAddress>
+#include <QTcpSocket>
 #include <QThread>
 #include <iostream>
 
 DataThread::DataThread(int socket_desc, Grid & grid, QObject * parent)
-    : QThread(parent), socket(parent), socket_desc(socket_desc), grid(grid), partial_read(0), i(0), j(0) {
-  connect(&socket, SIGNAL(readyRead()), this, SLOT(readFrame()));
-  connect(&socket, SIGNAL(disconnected()), this, SLOT(quit()));
-
-  if (!socket.setSocketDescriptor(socket_desc)) {
-    emit error(socket.error());
-    return;
-  }
-}
+    : QThread(parent), socket(nullptr), socket_desc(socket_desc), grid(grid),
+      partial_read(0), i(0), j(0) {}
 
 DataThread::~DataThread() {
   qDebug() << "DataThread " << prank << ": sayonara";
-  socket.abort();
 }
 
 void DataThread::run() {
+  socket = new QTcpSocket;
+
+  if (!socket->setSocketDescriptor(socket_desc)) {
+    emit error(socket->error());
+    return;
+  }
+
+  connect(socket, SIGNAL(readyRead()), currentThread(), SLOT(readFrame()),
+          Qt::DirectConnection);
+  connect(socket, SIGNAL(disconnected()), currentThread(), SLOT(quit()),
+          Qt::DirectConnection);
+
   qDebug() << "Ready to roll" << currentThreadId();
   exec();
+
+  socket->disconnectFromHost();
+  grid.unconnectPiece();
 }
 
 enum {
   READ_IMAGE = -1,
   READ_IMAGE_WAIT = -2,
   WAIT = -3,
   CONFIGURE = -4,
 };
 
 void DataThread::readFrame() {
-  qDebug() << "Readable data" << socket.bytesAvailable();
+  qDebug() << "DataThread" << currentThreadId() << "Readable data"
+           << socket->bytesAvailable();
 
-  if(partial_read == 0) {
-    QByteArray data = socket.read(1);
+  if (partial_read == 0) {
+    QByteArray data = socket->read(1);
     command = data[0];
 
     qDebug() << "DataThread" << currentThreadId() << "Got command"
              << int(command);
   }
 
   switch (command) {
   case READ_IMAGE:
   case READ_IMAGE_WAIT: {
-    int max_size = (size[0] + 2 * ghost) * (size[1] + 2 * ghost);
+    int max_size = (lsize[0] + 2 * ghost) * (lsize[1] + 2 * ghost);
     int buffer_size = max_size - partial_read;
     qDebug() << "DataThread" << currentThreadId() << "Receiving" << buffer_size
              << "chars";
-    QByteArray data = socket.read(buffer_size);
+    QByteArray data = socket->read(buffer_size);
 
     qDebug() << "DataThread" << currentThreadId() << "Received" << data.size()
              << "chars";
     QDataStream buffer(&data, QIODevice::ReadOnly);
     // buffer.setByteOrder(QDataStream::LittleEndian);
 
     if (partial_read == 0) {
       qDebug() << "DataThread" << currentThreadId() << ": getting a piece...";
       grid.getPiece();
       i = 0;
       j = 0;
       qDebug() << "DataThread" << currentThreadId() << ": got a piece";
     }
 
-    for(int d = partial_read; d < partial_read + data.size(); ++d) {
+    for (int d = 0; d < data.size(); ++d) {
       quint8 val;
       buffer >> val;
-      bool is_ghost = i < ghost || j < ghost || i >= (size[0] + ghost) ||
-                          j >= (size[1] + ghost);
-      if (!is_ghost)
-        grid(i - ghost, j - ghost) = val * (prank + 1);
-
+      bool is_ghost = i < ghost || j < ghost || i >= (lsize[0] + ghost) ||
+                      j >= (lsize[1] + ghost);
+      if (!is_ghost) {
+        grid(i - ghost + offset[0], j - ghost + offset[1]) = val * (prank + 1);
+      }
       j += 1;
-      if (j == (size[1] + 2*ghost)) {
+      if (j == (lsize[1] + 2 * ghost)) {
         i += 1;
         j = 0;
       }
     }
 
     partial_read += data.size();
-    if(partial_read == max_size) {
+    if (partial_read == max_size) {
       qDebug() << "DataThread" << currentThreadId() << prank << ": data ready";
       partial_read = 0;
+      i = 0;
+      j = 0;
 
       emit dataReady();
 
-      if(command == READ_IMAGE_WAIT) {
-        qDebug() << "DataThread" << currentThreadId() << "Unlock client" << int(command);
-        socket.putChar(command);
+      if (command == READ_IMAGE_WAIT) {
+        qDebug() << "DataThread" << currentThreadId() << "Unlock client"
+                 << int(command);
+        socket->putChar(command);
       }
     }
     break;
   }
-  case WAIT : {
+  case WAIT: {
     qDebug() << "DataThread" << currentThreadId() << "Unlock client";
-    socket.putChar(command);
+    socket->putChar(command);
     break;
   }
   case CONFIGURE: {
-    QByteArray data = socket.read(7 * sizeof(int));
+    QByteArray data = socket->read(9 * sizeof(int));
     QDataStream stream(&data, QIODevice::ReadOnly);
     //  stream.setByteOrder(QDataStream::LittleEndian);
     stream >> prank;
     stream >> psize;
-    stream >> size[0];
-    stream >> size[1];
+    stream >> lsize[0];
+    stream >> lsize[1];
+    stream >> gsize[0];
+    stream >> gsize[1];
     stream >> offset[0];
     stream >> offset[1];
     stream >> ghost;
 
     if (prank == 0) {
-      grid.resize(size[0], size[1]);
+      grid.resize(gsize[0], gsize[1]);
       grid.setPiece(psize);
       grid.releasePieces();
-      qDebug() << "DataThread" << currentThreadId() << "Grid has"
-               << grid.getNbPieces() << "piece(s)";
+      qDebug() << "DataThread" << currentThreadId() << "Grid (" << gsize[0]
+               << "x" << gsize[1] << ") has" << grid.getNbPieces()
+               << "piece(s)";
     }
 
     qDebug() << "DataThread" << currentThreadId() << ":" << prank << "/"
-             << psize << "-" << socket.peerAddress().toString()
-             << "- local grid size" << size[0] << "x" << size[1] << "+"
+             << psize << "-" << socket->peerAddress().toString()
+             << "- local grid size" << lsize[0] << "x" << lsize[1] << "+"
              << offset[0] << "-" << offset[1];
 
     qDebug() << "DataThread" << currentThreadId() << "Unlock client";
-    socket.putChar(command);
+    socket->putChar(command);
 
     break;
   }
   default:
     qDebug() << "DataThread" << currentThreadId() << "Unknown command"
              << int(command);
     return;
   }
 }
diff --git a/game-of-life/gol_gui/data_thread.hh b/game-of-life/gol_gui/data_thread.hh
index 7d5c69c..bce2499 100644
--- a/game-of-life/gol_gui/data_thread.hh
+++ b/game-of-life/gol_gui/data_thread.hh
@@ -1,41 +1,42 @@
 #ifndef DATA_THREAD_H
 #define DATA_THREAD_H
 
 #include <QThread>
 #include <QTcpSocket>
 
 class Grid;
 
 class DataThread : public QThread {
   Q_OBJECT
 public:
   DataThread(int socket_desc, Grid & grid, QObject *parent);
   ~DataThread();
   void run() Q_DECL_OVERRIDE;
 
 signals:
   void error(QTcpSocket::SocketError socketError);
   void dataReady();
 
 protected slots:
   void readFrame();
 
 private:
-  QTcpSocket socket;
+  QTcpSocket * socket;
   int socket_desc;
   Grid & grid;
 
   int prank, psize;
-  int size[2];
+  int lsize[2];
+  int gsize[2];
   int offset[2];
   int ghost;
 
   bool lock_write;
 
   int partial_read;
   int i;
   int j;
   char command;
 };
 
 #endif /* DATA_THREAD_H */
diff --git a/game-of-life/gol_gui/grid.hh b/game-of-life/gol_gui/grid.hh
index c1ffd4b..bbe4d5d 100644
--- a/game-of-life/gol_gui/grid.hh
+++ b/game-of-life/gol_gui/grid.hh
@@ -1,59 +1,54 @@
 #ifndef GRID_HH
 #define GRID_HH
 
 #include <QImage>
 #include <QSemaphore>
+#include <QMutex>
+#include <QMutexLocker>
 #include <cstddef>
 #include <vector>
 
-// class Pixel {
-// public:
-//   Pixel(QImage & data, int x, int y) : data(data), x(x), y(y) {}
-
-//   operator uint32_t () { return data.pixelIndex(x, y); }
-
-//   Pixel & operator=(uint32_t i) { data.setPixel(x, y, i); return *this; }
-
-// private:
-//   QImage & data;
-//   int x, y;
-// };
-
 class Grid {
   typedef uint32_t T;
 
 public:
   Grid(size_t m = 0, size_t n = 0)
-      : pieces(0), nb_pieces(0), data(n*m),
-        _size{m, n} {
+      : pieces(0), nb_pieces(0), data(n * m), _size{m, n} {
     for (size_t i = 0; i < n; ++i) {
-      data[(m / 2)*n + i] = 1;
+      data[(m / 2) * n + i] = 1;
     }
   }
 
   void resize(size_t m, size_t n) {
     _size[0] = m;
     _size[1] = n;
-    data.resize(n*m);
+    data.resize(n * m);
   }
 
   T & operator()(size_t i, size_t j) { return data[j + i * _size[1]]; }
   const T & operator()(size_t i, size_t j) const {
     return data[j + i * _size[1]];
   }
 
   size_t getNbPieces() const { return nb_pieces; }
   size_t size(int i) const { return _size[i]; }
   void getPiece() { return pieces.acquire(1); }
   void setPiece(size_t nb_pieces) { this->nb_pieces = nb_pieces; }
   void releasePieces() { pieces.release(nb_pieces); }
 
+  void unconnectPiece() {
+    QMutexLocker locker(&_nb_pieces_lock);
+    --nb_pieces;
+    if(nb_pieces == 0) releasePieces();
+  }
 
 private:
   QSemaphore pieces;
   size_t nb_pieces;
   std::vector<T> data;
   size_t _size[2];
+
+  QMutex _nb_pieces_lock;
 };
 
 #endif /* GRID_HH */
diff --git a/game-of-life/gol_gui/helper.cpp b/game-of-life/gol_gui/helper.cpp
index 0a8a2b0..9451c86 100644
--- a/game-of-life/gol_gui/helper.cpp
+++ b/game-of-life/gol_gui/helper.cpp
@@ -1,73 +1,73 @@
 #include "helper.hh"
 
-#include <QImage>
 #include <QBrush>
+#include <QColor>
 #include <QDebug>
+#include <QImage>
 #include <QPaintEvent>
 #include <QPainter>
 #include <QWidget>
 
+#include <chrono>
+
+#include <unistd.h>
+
+//#define DELAY 50000us
+
 Helper::Helper() {
-  // QLinearGradient gradient(QPointF(50, -20), QPointF(80, 20));
-  // gradient.setColorAt(0.0, Qt::white);
-  // gradient.setColorAt(1.0, QColor(0xa6, 0xce, 0x39));
-  borderPen = QPen(Qt::black);
-  borderPen.setWidth(1);
-  deadBrush = QBrush(QColor(64, 32, 64));
-  cellBrush = QBrush(Qt::white);
+  border_pen = QPen(Qt::black);
+  border_pen.setWidth(1);
+
+  cell_brushes.push_back(QBrush(QColor("darkslateblue")));
+  cell_brushes.push_back(QBrush(Qt::white  ));
+  cell_brushes.push_back(QBrush(Qt::cyan   ));
+  cell_brushes.push_back(QBrush(Qt::green  ));
+  cell_brushes.push_back(QBrush(Qt::red    ));
+  cell_brushes.push_back(QBrush(Qt::yellow ));
+  cell_brushes.push_back(QBrush(Qt::blue   ));
+  cell_brushes.push_back(QBrush(Qt::magenta));
+  cell_brushes.push_back(QBrush(QColor("orange")));
 }
 
 void Helper::paint(QPainter * painter, QPaintEvent * event,
                    __attribute__((unused)) int elapsed) {
+#if defined(DELAY)
+  static auto last_call = std::chrono::high_resolution_clock::now();
+
+  auto now = std::chrono::high_resolution_clock::now();
+  using namespace std::chrono_literals;
+  std::chrono::duration<double, std::micro> diff = now - last_call;
+  if(diff < DELAY) {
+      qDebug() << "wait" << (100ms - diff).count() << "us";
+      usleep((DELAY - diff).count());
+  }
+#endif
+
   qDebug() << "Drawing image" << grid.size(1) << "x" << grid.size(0);
-  painter->fillRect(event->rect(), deadBrush);
+  painter->fillRect(event->rect(), cell_brushes[0]);
   if (grid.size(1) != 0 && grid.size(0) != 0) {
-    QImage bitmap(5 * grid.size(1), 5 * grid.size(0), QImage::Format_RGB32);
-    QPainter painting(&bitmap);
-    bitmap.fill(deadBrush.color());
+    // QImage bitmap(5 * grid.size(1) + 1, 5 * grid.size(0) + 1,
+    //               QImage::Format_RGB32);
+    QImage bitmap(5 * grid.size(1), 5 * grid.size(0),
+                  QImage::Format_RGB32);
 
-    painting.setPen(borderPen);
-
-    for (size_t i = 0; i < grid.size(0); ++i) {
-      painting.drawLine(0, i * 5, bitmap.width(), i * 5);
-    }
-    for (size_t j = 0; j < grid.size(1); ++j) {
-      painting.drawLine(j * 5, 0, j * 5, bitmap.height());
-    }
+    QPainter painting(&bitmap);
+    //painting.setPen(border_pen);
 
-    painting.setBrush(cellBrush);
     for (size_t i = 0; i < grid.size(0); ++i) {
       for (size_t j = 0; j < grid.size(1); ++j) {
-        if (grid(i, j) != 0) {
+          painting.setBrush(cell_brushes[grid(i, j)]);
           painting.drawRect(5 * j, 5 * i, 5, 5);
-        }
       }
     }
 
-    // painter->translate(100, 100);
-    // painter->save();
-    // painter->setBrush(circleBrush);
-    // painter->setPen(circlePen);
-    // painter->rotate(elapsed * 0.030);
-
-    // qreal r = elapsed / 1000.0;
-    // int n = 30;
-    // for (int i = 0; i < n; ++i) {
-    //   painter->rotate(30);
-    //   qreal factor = (i + r) / n;
-    //   qreal radius = 0 + 120.0 * factor;
-    //   qreal circleRadius = 1 + factor * 20;
-    //   painter->drawEllipse(
-    //       QRectF(radius, -circleRadius, circleRadius * 2, circleRadius * 2));
-    // }
-    // painter->restore();
-
-    // painter->setPen(textPen);
-    // painter->setFont(textFont);
-    // painter->drawText(QRect(-50, -50, 100, 100), Qt::AlignCenter,
-    //                   QStringLiteral("Qt"));
     painter->drawImage(event->rect(), bitmap, bitmap.rect());
   }
+
+#if defined(DELAY)
+  last_call = std::chrono::system_clock::now();
+#endif
+
   grid.releasePieces();
   qDebug() << "Image drawn";
 }
diff --git a/game-of-life/gol_gui/helper.hh b/game-of-life/gol_gui/helper.hh
index 910e7e9..95c4996 100644
--- a/game-of-life/gol_gui/helper.hh
+++ b/game-of-life/gol_gui/helper.hh
@@ -1,27 +1,27 @@
 #ifndef HELPER_H
 #define HELPER_H
 
 #include "grid.hh"
 
 #include <QBrush>
 #include <QFont>
 #include <QPen>
 #include <QWidget>
 
 class Helper
 {
 public:
     Helper();
 
 public:
     void paint(QPainter *painter, QPaintEvent *event, int elapsed);
 
     Grid & getGrid() { return grid; }
 private:
     QBrush background;
-    QBrush deadBrush, cellBrush;
-    QPen borderPen;
+    std::vector<QBrush> cell_brushes;
+    QPen border_pen;
     Grid grid;
 };
 
 #endif
diff --git a/game-of-life/gol_gui/window.cpp b/game-of-life/gol_gui/window.cpp
index f27023d..a6b7d70 100644
--- a/game-of-life/gol_gui/window.cpp
+++ b/game-of-life/gol_gui/window.cpp
@@ -1,58 +1,58 @@
 #include "window.hh"
 #include "gl_widget.hh"
 
 #include <QGridLayout>
 #include <QHostAddress>
 #include <QLabel>
 #include <QMessageBox>
 #include <QSocketNotifier>
 #include <iostream>
 #include <sys/socket.h>
 #include <unistd.h>
 
 int Window::sigabort_fd[2];
 
 Window::Window() : server(helper.getGrid(), this) {
   setWindowTitle(tr("Game of Life"));
-  //  setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
+  setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
   GLWidget * openGL = new GLWidget(&helper, this);
   QGridLayout * layout = new QGridLayout;
   layout->addWidget(openGL, 0, 0);
 
   setLayout(layout);
 
   if (!server.listen(QHostAddress::Any, 4321)) {
     QMessageBox::critical(
         this, tr("GOL Server"),
         tr("Unable to start the server: %1.").arg(server.errorString()));
     close();
     return;
   }
 
   qInfo() << "Server listening on " << server.serverAddress().toString() << ":"
           << server.serverPort();
 
   connect(&server, SIGNAL(dataReady()), openGL, SLOT(animate()));
 
   if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigabort_fd))
     qFatal("Couldn't create ABORT socketpair");
   sn_abort = new QSocketNotifier(sigabort_fd[1], QSocketNotifier::Read, this);
   connect(sn_abort, SIGNAL(activated(int)), this, SLOT(handleSigAbort()));
 }
 
 void Window::abortSignalHandler(int) {
   qCritical() << "Aborting";
   char a = 1;
   ::write(sigabort_fd[0], &a, sizeof(a));
 }
 
 void Window::handleSigAbort() {
   sn_abort->setEnabled(false);
   char tmp;
   ::read(sigabort_fd[1], &tmp, sizeof(tmp));
 
   qDebug() << "Window: Abort the mission";
   server.stop();
 
   sn_abort->setEnabled(true);
 }
diff --git a/game-of-life/grid.cc b/game-of-life/grid.cc
new file mode 100644
index 0000000..d45997f
--- /dev/null
+++ b/game-of-life/grid.cc
@@ -0,0 +1,137 @@
+#include "grid.hh"
+
+#include <mpi.h>
+
+typedef enum {
+  _north,
+  _south,
+  _east,
+  _west,
+  _north_east,
+  _north_west,
+  _south_east,
+  _south_west
+} comm_tag_t;
+
+Grid::~Grid() {
+  delete[] _grid;
+  MPI_Type_free(&_column_t);
+  MPI_Type_free(&_line_t);
+
+  MPI_Request * req = _requests;
+  for (int i = 0; i < 8 * 2; ++i, ++req) {
+    MPI_Request_free(req);
+  }
+
+  delete [] _requests;
+}
+
+void Grid::initalizeCommunicationRequests(MPI_Comm & comm, int coords[2]) {
+  _requests = new MPI_Request[8 * 2];
+
+  MPI_Type_vector(_dims[0], 1, _dims[1] + 2 * _ghosts, MPI_CHAR, &_column_t);
+  MPI_Type_vector(_dims[1], 1, 1, MPI_CHAR, &_line_t);
+  MPI_Type_commit(&_column_t);
+  MPI_Type_commit(&_line_t);
+
+  MPI_Request * srequests = _requests;
+  MPI_Request * rrequests = _requests + 8;
+  { /* south east -> north west */
+    int nrank;
+    int rcoords[2] = {coords[0] - 1, coords[1] - 1};
+    MPI_Cart_rank(comm, rcoords, &nrank);
+
+    char & send = operator()(0, 0);
+    char & recv = operator()(-_ghosts, -_ghosts);
+    MPI_Send_init(&send, 1, MPI_CHAR, nrank, _south_east, comm, srequests);
+    MPI_Recv_init(&recv, 1, MPI_CHAR, nrank, _north_west, comm, rrequests);
+    ++srequests;
+    ++rrequests;
+  }
+
+  { /* south west -> north east */
+    int nrank;
+    int rcoords[2] = {coords[0] - 1, coords[1] + 1};
+    MPI_Cart_rank(comm, rcoords, &nrank);
+    char & send = operator()(0, _dims[1] - 1);
+    char & recv = operator()(-_ghosts, _dims[1] - 1 + _ghosts);
+    MPI_Send_init(&send, 1, MPI_CHAR, nrank, _south_west, comm, srequests);
+    MPI_Recv_init(&recv, 1, MPI_CHAR, nrank, _north_east, comm, rrequests);
+    ++srequests;
+    ++rrequests;
+  }
+
+  { /* north west ->  south east */
+    int nrank;
+    int rcoords[2] = {coords[0] + 1, coords[1] + 1};
+    MPI_Cart_rank(comm, rcoords, &nrank);
+    char & send = operator()(_dims[1] - 1          , _dims[1] - 1);
+    char & recv = operator()(_dims[1] - 1 + _ghosts, _dims[1] - 1 + _ghosts);
+    MPI_Send_init(&send, 1, MPI_CHAR, nrank, _north_west, comm, srequests);
+    MPI_Recv_init(&recv, 1, MPI_CHAR, nrank, _south_east, comm, rrequests);
+    ++srequests;
+    ++rrequests;
+  }
+
+  { /* north_east -> south_west */
+    int nrank;
+    int rcoords[2] = {coords[0] + 1, coords[1] - 1};
+    MPI_Cart_rank(comm, rcoords, &nrank);
+    char & send = operator()(_dims[1] - 1          , 0);
+    char & recv = operator()(_dims[1] - 1 + _ghosts, -_ghosts);
+    MPI_Send_init(&send, 1, MPI_CHAR, nrank, _north_east, comm, srequests);
+    MPI_Recv_init(&recv, 1, MPI_CHAR, nrank, _south_west, comm, rrequests);
+    ++srequests;
+    ++rrequests;
+  }
+
+  /* Sides */
+  { /* south -> north */
+    int nrank;
+    int rcoords[2] = {coords[0] - 1, coords[1]};
+    MPI_Cart_rank(comm, rcoords, &nrank);
+    char & send = operator()(       0, 0);
+    char & recv = operator()(-_ghosts, 0);
+    MPI_Send_init(&send, 1, _line_t, nrank, _north, comm, srequests);
+    MPI_Recv_init(&recv, 1, _line_t, nrank, _south, comm, rrequests);
+    ++srequests;
+    ++rrequests;
+  }
+
+  { /* west -> east */
+    int nrank;
+    int rcoords[2] = {coords[0], coords[1] + 1};
+    MPI_Cart_rank(comm, rcoords, &nrank);
+    char & send = operator()(0, _dims[1] - 1);
+    char & recv = operator()(0, _dims[1] - 1 + _ghosts);
+    MPI_Send_init(&send, 1, _column_t, nrank, _west, comm, srequests);
+    MPI_Recv_init(&recv, 1, _column_t, nrank, _east, comm, rrequests);
+    ++srequests;
+    ++rrequests;
+  }
+
+  { /* north -> south */
+    int nrank;
+    int rcoords[2] = {coords[0] + 1, coords[1]};
+    MPI_Cart_rank(comm, rcoords, &nrank);
+    char & send = operator()(_dims[0] - 1          , 0);
+    char & recv = operator()(_dims[0] - 1 + _ghosts, 0);
+    MPI_Send_init(&send, 1, _column_t, nrank, _north, comm, srequests);
+    MPI_Recv_init(&recv, 1, _column_t, nrank, _south, comm, rrequests);
+    ++srequests;
+    ++rrequests;
+  }
+
+  /* east -> west */
+  {
+    int nrank;
+    int rcoords[2] = {coords[0], coords[1] - 1};
+    MPI_Cart_rank(comm, rcoords, &nrank);
+    char & send = operator()(0, 0);
+    char & recv = operator()(0, -_ghosts);
+    MPI_Send_init(&send, 1, _column_t, nrank, _east, comm, srequests);
+    MPI_Recv_init(&recv, 1, _column_t, nrank, _west, comm, rrequests);
+    ++srequests;
+    ++rrequests;
+  }
+}
diff --git a/game-of-life/grid.hh b/game-of-life/grid.hh
index f3c4a98..1cf4967 100644
--- a/game-of-life/grid.hh
+++ b/game-of-life/grid.hh
@@ -1,55 +1,81 @@
+#include <algorithm>
 #include <cstddef>
+#include <iostream>
+#include <memory>
+#include <mpi.h>
+#include <vector>
 
 #ifndef GRID_H
 #define GRID_H
 
 class Grid {
   typedef char T;
 
 public:
-  Grid(std::size_t m, std::size_t n, std::size_t ghosts)
-      : _dims{m, n}, _offsets{0, 0}, _ghosts(ghosts),
-        _grid(new T[(m + 2 * _ghosts) * (n + 2 * _ghosts)]) {}
+  Grid(const long int ldims[2], const long int gdims[2],
+       const long int offsets[2], int ghost)
+      : _dims{ldims[0], ldims[1]}, _gdims{gdims[0], gdims[1]},
+        _offsets{offsets[0], offsets[1]}, _ghosts(ghost),
+        _grid(new T[(ldims[0] + 2 * _ghosts) * (ldims[1] + 2 * _ghosts)]),
+        _requests(NULL) {
+    std::uninitialized_fill_n(_grid, fullSize() * sizeof(T), T());
+  }
 
-  Grid(const Grid &other)
-      : _dims{other._dims[0], other._dims[1]},
-        _offsets{other._offsets[0], other._offsets[1]}, _ghosts(other._ghosts),
-        _grid(new T[(_dims[0] + 2 * _ghosts) * (_dims[1] + 2 * _ghosts)]) {}
+  Grid(const Grid & other)
+      : Grid(other._dims, other._gdims, other._offsets, other._ghosts) {
+    std::copy_n(other._grid, fullSize(), _grid);
+  }
 
-  ~Grid() { delete[] _grid; }
+  ~Grid();
 
-  T &operator()(std::size_t i, std::size_t j) {
-    return *(_grid + (i + _ghosts) * _dims[1] + (j + _ghosts));
+  T & operator()(long int i, long int j) {
+    return *(_grid + (i + _ghosts) * (_dims[1] + 2 * _ghosts) + (j + _ghosts));
   }
 
-  void swap(Grid &other) {
-    T *tmp = _grid;
+  void swap(Grid & other) {
+    T * tmp = _grid;
     _grid = other._grid;
     other._grid = tmp;
+
+    MPI_Request * tmp_reqs = _requests;
+    _requests = other._requests;
+    other._requests = tmp_reqs;
   }
 
-  void setOffsets(std::size_t offsets[2]) {
+  void setOffsets(long int offsets[2]) {
     _offsets[0] = offsets[0];
     _offsets[1] = offsets[1];
   }
 
-  std::size_t size(std::size_t i) const { return _dims[i]; }
-  std::size_t size() const { return _dims[0] * _dims[1]; }
+  void initalizeCommunicationRequests(MPI_Comm & comm, int coords[2]);
 
-  std::size_t fullSize(std::size_t i) const { return (_dims[i]+2*_ghosts); }
-  std::size_t fullSize() const { return (_dims[0]+2*_ghosts) * (_dims[1]+2*_ghosts); }
+  void commAll() { MPI_Startall(16, _requests); }
+  void waitRecv() { MPI_Waitall(8, _requests + 8, MPI_STATUS_IGNORE); }
+  void waitSend() { MPI_Waitall(8, _requests, MPI_STATUS_IGNORE); }
 
-  std::size_t offset(std::size_t i) const { return _offsets[i]; }
+  long int size(long int i) const { return _dims[i]; }
+  long int size() const { return _dims[0] * _dims[1]; }
 
-  std::size_t ghost() const { return _ghosts; }
+  long int globalSize(long int i) const { return _gdims[i]; }
+  long int globalSize() const { return _gdims[0] * _gdims[1]; }
+
+  long int fullSize(long int i) const { return (_dims[i] + 2 * _ghosts); }
+  long int fullSize() const {
+    return (_dims[0] + 2 * _ghosts) * (_dims[1] + 2 * _ghosts);
+  }
 
+  long int offset(long int i) const { return _offsets[i]; }
+  long int ghost() const { return _ghosts; }
   const T * data() const { return _grid; }
 
 private:
-  std::size_t _dims[2];
-  std::size_t _offsets[2];
-  std::size_t _ghosts;
-  T *_grid;
+  long int _dims[2];
+  long int _gdims[2];
+  long int _offsets[2];
+  long int _ghosts;
+  T * _grid;
+  MPI_Request * _requests;
+  MPI_Datatype _column_t, _line_t;
 };
 
 #endif /* GRID_H */
diff --git a/game-of-life/simu.hh b/game-of-life/simu.hh
new file mode 100644
index 0000000..6c26e74
--- /dev/null
+++ b/game-of-life/simu.hh
@@ -0,0 +1,114 @@
+#ifndef SIMU_HH
+#define SIMU_HH
+
+#include "client.hh"
+#include "grid.hh"
+
+#include <iostream>
+#include <mpi.h>
+#include <random>
+
+/* -------------------------------------------------------------------------- */
+class Simu {
+public:
+  Simu(long int dims[2], int ghost, bool periodic = true,
+       MPI_Comm global_comm = MPI_COMM_WORLD,
+       const std::string & server = "127.0.0.1")
+      : _ghost(ghost), _world(global_comm), periodic(periodic) {
+
+    int psize, prank;
+    MPI_Comm_size(_world, &psize);
+    MPI_Comm_rank(_world, &prank);
+
+    int nprocs[2] = {0, 0};
+    int periods[2] = {periodic, periodic};
+
+    MPI_Dims_create(psize, 2, nprocs);
+    MPI_Cart_create(MPI_COMM_WORLD, 2, nprocs, periods, true, &_neigbours);
+    MPI_Cart_coords(_neigbours, prank, 2, _coords);
+
+    long int local_dims[2];
+    long int offsets[2] = {0, 0};
+
+    for (int i = 0; i < 2; ++i) {
+      int mod = dims[i] % nprocs[i];
+
+      local_dims[i] = dims[i] / nprocs[i];
+      offsets[i] = local_dims[i] * _coords[i] + (_coords[i] < mod ? _coords[i] : mod);
+
+      local_dims[i] += (_coords[i] < mod ? 1 : 0);
+    }
+
+    _grid = new Grid(local_dims, dims, offsets, ghost);
+    _old_grid = new Grid(*_grid);
+
+    _grid->initalizeCommunicationRequests(_neigbours, _coords);
+    _old_grid->initalizeCommunicationRequests(_neigbours, _coords);
+
+    if (prank == 0) {
+      std::cout << "Grid " << _old_grid->globalSize() << " -- ["
+                << _old_grid->globalSize(0) << ", " << _old_grid->globalSize(1)
+                << "]" << std::endl;
+    }
+
+    for (int p = 0; p < psize; ++p) {
+      if (p == prank)
+        std::cout << "Local grid " << prank << " - " << _old_grid->size()
+                  << " -- [" << _old_grid->size(0) << ", " << _old_grid->size(1)
+                  << "]"
+                  << "+ [" << _old_grid->offset(0) << ", " << _old_grid->offset(1)
+                  << "]" << std::endl;
+      MPI_Barrier(_world);
+    }
+
+    sender = new GridSender(*_old_grid);
+    sender->setParallelContext(prank, psize);
+    sender->connect(server, 4321);
+  }
+
+
+  virtual void determineCells() {
+    _old_grid->commAll();
+    for (long int i = _ghost; i < _grid->size(0) - _ghost; i++) {
+      for (long int j = _ghost; j < _grid->size(1) - _ghost; j++) {
+        this->determineCell(i, j);
+      }
+    }
+    _old_grid->waitRecv();
+
+
+    for (long int i = 0; i < _grid->size(0); i++) {
+        this->determineCell(i, 0);
+        this->determineCell(i, _grid->size(1) - 1);
+    }
+
+    for (long int j = 0; j < _grid->size(1); j++) {
+      this->determineCell(0, j);
+      this->determineCell(_grid->size(0) - 1, j);
+    }
+
+    _old_grid->waitSend();
+  }
+
+  virtual void determineCell(long int i, long int j) = 0;
+  virtual void initialState() = 0;
+
+  void swap() { _grid->swap(*_old_grid); }
+  void send() { sender->send(); }
+
+  GridSender & getSender() { return *sender; }
+
+protected:
+  long int _ghost;
+  Grid * _grid;
+  Grid * _old_grid;
+  GridSender * sender;
+
+  MPI_Comm _world;
+  MPI_Comm _neigbours;
+  int _coords[2];
+
+  bool periodic;
+};
+
+#endif /* SIMU_HH */
diff --git a/game-of-life/simu_gol.hh b/game-of-life/simu_gol.hh
new file mode 100644
index 0000000..aaca568
--- /dev/null
+++ b/game-of-life/simu_gol.hh
@@ -0,0 +1,44 @@
+#ifndef SIMU_GOL_HH
+#define SIMU_GOL_HH
+
+#include "simu.hh"
+
+/* -------------------------------------------------------------------------- */
+class GOL : public Simu {
+public:
+  GOL(long int dims[2], int ghost, bool periodic = true,
+      MPI_Comm global_comm = MPI_COMM_WORLD,
+      const std::string & server = "127.0.0.1")
+      : Simu(dims, ghost, periodic, global_comm, server) {}
+
+  void determineCell(long int i, long int j) {
+    long int _i = i;
+    long int _j = j;
+    char neighbours = -(*_old_grid)(_i, _j);
+    for (char v = -1; v < 2; ++v)
+      for (char w = -1; w < 2; ++w)
+        neighbours += (*_old_grid)(_i + v, _j + w);
+
+    char res = 0;
+    if (neighbours == 2) {
+      res = (*_old_grid)(i, j);
+    } else if (neighbours == 3) {
+      res = 1;
+    }
+
+    (*_grid)(_i, _j) = res;
+  }
+
+  void initialState() {
+    std::random_device rd;
+    std::mt19937 gen(rd());
+    std::uniform_int_distribution<> dis(0, 4);
+    for (long int i = 0; i < _old_grid->size(0); i++) {
+      for (long int j = 0; j < _old_grid->size(1); j++) {
+        (*_old_grid)(i, j) = dis(gen) > 3 ? 1 : 0;
+      }
+    }
+  }
+};
+
+#endif /* SIMU_GOL_HH */