private void Socket_OnMessage(object sender, MessageEventArgs e)
        {
            if (!ShouldExit)
            {
                var watch    = System.Diagnostics.Stopwatch.StartNew();
                var response = e.Data;

                if (!response.StartsWith(ResponsePrefix))
                {
                    Console.WriteLine("Something strange is happening on the server... Response:\n{0}", response);
                    ShouldExit = true;
                }
                else
                {
                    var boardString = response.Substring(ResponsePrefix.Length);
                    var board       = new Board(boardString);
                    Board = board;
                    if (FullBoard.CurrentLevel == 0)
                    {
                        FullBoard.CurrentLevel = board.CurrentLevel;
                    }

                    if (FullBoard.CurrentLevel != board.CurrentLevel)
                    {
                        FullBoard = new Board(Constants.FullBoardSize);
                        if (Directory.Exists(Constants.CacheFolder))
                        {
                            var levelCacheFile = $"{Constants.CacheFolder}/{board.CurrentLevel}.dat";
                            if (File.Exists(levelCacheFile))
                            {
                                using (FileStream fs = new FileStream(levelCacheFile, FileMode.OpenOrCreate))
                                {
                                    FullBoard = (Board)formatter.Deserialize(fs);
                                }
                            }
                        }
                        FullBoard.CurrentLevel = board.CurrentLevel;
                    }
                    for (int layer = 0; layer < FullBoard.Field.GetLength(0); layer++)
                    {
                        for (int x = 0; x < FullBoard.Size; x++)
                        {
                            for (int y = 0; y < FullBoard.Size; y++)
                            {
                                if (FullBoard.IsAt(layer, x, y,
                                                   Element.ROBO_OTHER, Element.ROBO_OTHER_FLYING, Element.ROBO_OTHER_LASER, Element.ROBO_OTHER_FALLING,
                                                   Element.LASER_DOWN, Element.LASER_UP, Element.LASER_LEFT, Element.LASER_RIGHT, Element.ZOMBIE_DIE, Element.FEMALE_ZOMBIE, Element.MALE_ZOMBIE,
                                                   Element.AIM, Element.PATH, Element.GOLD))
                                {
                                    FullBoard.Field[layer, x, y] = (char)Element.EMPTY;
                                }
                            }
                        }
                    }
                    for (int layer = 0; layer < board.Field.GetLength(0); layer++)
                    {
                        for (int x = 0; x < board.Size; x++)
                        {
                            for (int y = 0; y < board.Size; y++)
                            {
                                var absolutePoint = new Point(x, y).RelativeToAbsolute(board.Size, board.Offset);
                                FullBoard.Field[layer, absolutePoint.X, absolutePoint.Y] = board.Field[layer, x, y];
                            }
                        }
                    }

                    if (board.HeroPosition.Y <= 1)
                    {
                        for (int x = 0; x < board.Size; x++)
                        {
                            var absolutePoint = new Point(x, -1).RelativeToAbsolute(board.Size, board.Offset);
                            FullBoard.Field[0, absolutePoint.X, absolutePoint.Y] = (char)Element.WALL_FRONT;
                        }
                    }

                    if (board.HeroPosition.X >= board.Size - 2)
                    {
                        for (int y = 0; y < board.Size; y++)
                        {
                            var absolutePoint = new Point(board.Size, y).RelativeToAbsolute(board.Size, board.Offset);
                            FullBoard.Field[0, absolutePoint.X, absolutePoint.Y] = (char)Element.WALL_FRONT;
                        }
                    }
                    FullBoard.HeroPosition = board.HeroPosition.RelativeToAbsolute(board.Size, board.Offset);

                    if (!Directory.Exists(Constants.CacheFolder))
                    {
                        Directory.CreateDirectory(Constants.CacheFolder);
                    }

                    using (FileStream fs = new FileStream($"Cache/{FullBoard.CurrentLevel}.dat", FileMode.OpenOrCreate))
                    {
                        formatter.Serialize(fs, FullBoard);
                    }
                    //Just print current state (gameBoard) to console

                    /*Console.Clear();
                     * Console.SetCursorPosition(0, 0);*/
                    var action = "";
                    var time   = "";
                    try
                    {
                        turnCounter++;
                        action = WhatToDo(board).ToString();
                        time   = $"Execution Time: {watch.ElapsedMilliseconds} ms";
                    }
                    catch { }
                    if (action.Contains("ACT(3)"))
                    {
                        Static.TurnsWithoutFire            = 0;
                        Static.PerkCooldownDeathRay        = 0;
                        Static.PerkCooldownUnstopableLaser = 0;
                    }
                    else
                    {
                        Static.TurnsWithoutFire++;
                    }
                    var str = new StringBuilder();

                    str.AppendLine(time);
                    str.AppendLine("Answer: " + action);
                    str.AppendLine("Gold collected: " + goldCollected);
                    str.AppendLine("Turns without fire: " + Static.TurnsWithoutFire);
                    str.AppendLine("DeathRay Perk Cooldown: " + Static.PerkCooldownDeathRay);
                    str.AppendLine("Unlimited Fire Perk Cooldown: " + Static.PerkCooldownUnlimitedFire);
                    str.AppendLine("Unstopable Laser Perk Cooldown: " + Static.PerkCooldownUnstopableLaser);
                    str.AppendLine(board.ToString());
                    str.AppendLine(FullBoard.ToString());
                    if (PrevBoard != null)
                    {
                        str.AppendLine(PrevFullBoard.ToString());
                    }
                    if (!action.IsNullOrEmpty())
                    {
                        prevState = str.ToString();
                    }

                    for (int layer = 0; layer < board.Field.GetLength(0); layer++)
                    {
                        for (int x = 0; x < board.Size; x++)
                        {
                            for (int y = 0; y < board.Size; y++)
                            {
                                PrevBoard.Field[layer, x, y] = board.Field[layer, x, y];
                            }
                        }
                    }

                    for (int layer = 0; layer < FullBoard.Field.GetLength(0); layer++)
                    {
                        for (int x = 0; x < FullBoard.Size; x++)
                        {
                            for (int y = 0; y < FullBoard.Size; y++)
                            {
                                PrevFullBoard.Field[layer, x, y] = FullBoard.Field[layer, x, y];
                            }
                        }
                    }

                    /*Console.WriteLine(str.ToString());
                     * Console.SetCursorPosition(0, 0);*/
                    ((WebSocket)sender).Send(action);
                    BoardUpdated?.Invoke(board, str.ToString());
                }
            }
        }
 public abstract Command WhatToDo(Board board);