private void HandleStart(string sender, FloorPlanMessage startMessage)
        {
            int senderId = Utils.ParsePeer(sender);

            WorkerPositions.Add(senderId, startMessage.position);
            numberOfPositionChanges[senderId] = 0;

            FloorPlanMessage ackMessage = BuildFloorPlanMessage(MessageType.Acknowledge, WorkerPositions[senderId]);

            Send(sender, JsonSerializer.Serialize(ackMessage));
        }
        private FloorPlanMessage BuildFloorPlanMessage(string type, Point position)
        {
            var planMessage = new FloorPlanMessage();

            planMessage.type     = type;
            planMessage.position = position;
            planMessage.exitsInFieldOfViewPositions = ExitPositions.Values
                                                      .Where(exitPosition => InFieldOfView(exitPosition, position))
                                                      .ToList();
            planMessage.agentsInFieldOfViewPositions = WorkerPositions
                                                       .Where(agentKvp => InFieldOfView(agentKvp.Value, position) && !agentKvp.Value.Equals(position))
                                                       .Select(agentKvp => new AgentSummary(agentKvp.Key, agentKvp.Value))
                                                       .ToList();
            return(planMessage);
        }
        private void HandleChangePosition(string sender, FloorPlanMessage receivedMessage)
        {
            int senderId = Utils.ParsePeer(sender);

            // Block is handled regardless if in emergency or not
            foreach (int workerId in WorkerPositions.Keys)
            {
                if (workerId == senderId)
                {
                    continue;
                }
                if (WorkerPositions[workerId].Equals(receivedMessage.position))
                {
                    var blockMessage = BuildFloorPlanMessage(MessageType.Block, WorkerPositions[senderId]);
                    Send(sender, JsonSerializer.Serialize(blockMessage));
                    return;
                }
            }

            // todo: block if server is congested
            if (WorkerPositions.ContainsKey(senderId) && Utils.Distance(WorkerPositions[senderId], receivedMessage.position) > 1)
            {
                var blockMessage = BuildFloorPlanMessage(MessageType.Block, WorkerPositions[senderId]);
                Send(sender, JsonSerializer.Serialize(blockMessage));
                return;
            }

            // Allow the requested move
            if (!WorkerPositions.ContainsKey(senderId))
            {
                return;
            }
            else
            {
                WorkerPositions[senderId] = receivedMessage.position;
            }

            // Should declare emergency
            if (++numberOfPositionChanges[senderId] == turnsUntilEmergency)
            {
                var emergencyMessage = BuildFloorPlanMessage(MessageType.Emergency, WorkerPositions[senderId]);
                Send(sender, JsonSerializer.Serialize(emergencyMessage));
                return;
            }

            // Exit if emergency is declared
            if (isEmergencyDeclared(senderId) && ExitPositions.Values.Contains(WorkerPositions[senderId]))
            {
                var exitMessage = BuildFloorPlanMessage(MessageType.Exit, WorkerPositions[senderId]);
                Send(sender, JsonSerializer.Serialize(exitMessage));

                WorkerPositions.Remove(senderId);
                this.Environment.Remove(sender);
                if (WorkerPositions.Count == 0)
                {
                    this.Stop();
                }
                return;
            }

            // Only thing remaining to do is acknowledge the move
            var moveMessage = BuildFloorPlanMessage(MessageType.Acknowledge, WorkerPositions[senderId]);

            Send(sender, JsonSerializer.Serialize(moveMessage));
        }