public override void Act(Queue <Message> messages)
        {
            while (messages.Count > 0 && running)
            {
                Message message = messages.Dequeue();
                Console.WriteLine("\t[{1} -> {0}]: {2}", this.Name, message.Sender, message.Content);

                FloorPlanMessage receivedMessage = JsonSerializer.Deserialize <FloorPlanMessage>(message.Content);
                if (message.Sender == MonitorAgent.Monitor)
                {
                    HandleMessageFromMonitor(receivedMessage);
                }
                else
                {
                    HandleMessageFromPeer(receivedMessage, message);
                }


                blockList = blockList.Select(kvp => new KeyValuePair <int, int>(kvp.Key, kvp.Value - 1))
                            .Where(kvp => kvp.Value > 0)
                            .ToDictionary(
                    kvp => kvp.Key,
                    kvp => kvp.Value
                    );

                // if (state == State.WaitingForPeerResponses)
                // {
                //     --waitTurns;
                //     if (wa)
                // }
            }
        }
        public override void Act(Queue <Message> messages)
        {
            while (messages.Count > 0)
            {
                Message message = messages.Dequeue();
                Console.WriteLine("\t[{1} -> {0}]: {2}", this.Name, message.Sender, message.Content);

                FloorPlanMessage floorPlanMessage = JsonSerializer.Deserialize <FloorPlanMessage>(message.Content);

                switch (floorPlanMessage.type)
                {
                case Start:
                    HandleStart(message.Sender, floorPlanMessage);
                    break;

                case MessageType.Move:
                    HandleChangePosition(message.Sender, floorPlanMessage);
                    break;

                default:
                    break;
                }

                guiForm.UpdatePlanetGUI();
            }
        }
        private Point PickCandidate(FloorPlanMessage receivedMessageFromMonitor)
        {
            Point candidate = null;

            if (state == State.MovingRandomly)
            {
                candidate = MoveRandomly();
            }
            else
            {
                if (receivedMessageFromMonitor.exitsInFieldOfViewPositions.Count > 0)
                {
                    state     = State.MovingTowardsExit;
                    candidate = MoveNear(Utils.closestPoint(receivedMessageFromMonitor.exitsInFieldOfViewPositions,
                                                            this.position));
                }
                else if (receivedMessageFromMonitor.agentsInFieldOfViewPositions.Count > 0)
                {
                    receivedMessageFromMonitor.agentsInFieldOfViewPositions.ForEach(peerAgent =>
                    {
                        var peerQuestionMessage = new FloorPlanMessage(MessageType.PeerQuestion, peerAgent.Position);
                        if (!blockList.ContainsKey(peerAgent.Id) ||
                            (blockList.ContainsKey(peerAgent.Id) && blockList[peerAgent.Id] <= 0))
                        {
                            Send("Worker " + peerAgent.Id, JsonSerializer.Serialize(peerQuestionMessage));
                        }
                    });

                    // move in a direction until you get a response

                    // todo: our strategy might not be the best because then we have to handle inconsistencies by getting blocked by the monitor,
                    //  but otherwise we need other stateful solution to let time pass (we focused on turns which are linked to messages received, but if we do not
                    //  send message to monitor, we don't progress)
                    if (receivedMessageFromMonitor.type == MessageType.Block)
                    {
                        candidate = MoveInOtherDirection();
                    }
                    else
                    {
                        candidate = MoveInDirection();
                    }

                    state = State.WaitingForPeerResponses;
                }
                else
                {
                    if (receivedMessageFromMonitor.type == MessageType.Block)
                    {
                        candidate = MoveInOtherDirection();
                    }
                    else
                    {
                        candidate = MoveInDirection();
                    }
                }
            }

            return(candidate);
        }
        public override void Setup()
        {
            Console.WriteLine("Starting worker " + Id);

            FloorPlanMessage positionMessage = new FloorPlanMessage();

            positionMessage.type     = MessageType.Start;
            positionMessage.position = this.position;
            Send(MonitorAgent.Monitor, JsonSerializer.Serialize(positionMessage));
        }
        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 HandleMessageFromPeer(FloorPlanMessage receivedMessage, Message message)
        {
            switch (receivedMessage.type)
            {
            case MessageType.PeerQuestion:
            {
                string messageType = lastReceivedMessageFromMonitor.exitsInFieldOfViewPositions.Count > 0
                        ? MessageType.PeerAffirmative
                        : MessageType.PeerNegative;
                // string messageType = PeerNegative;
                FloorPlanMessage response =
                    new FloorPlanMessage(messageType, lastReceivedMessageFromMonitor.position);
                Send(message.Sender, JsonSerializer.Serialize(response));
                break;
            }

            case MessageType.PeerAffirmative:
            {
                // todo: following not working right, but deadlock cooldown
                // is implemented by not asking that agent again for a number of turns
                if (state == State.WaitingForPeerResponses)
                {
                    state = State.FollowingOther;
                    var candidate = MoveNear(receivedMessage.position);
                    FloorPlanMessage changePositionMessage =
                        new FloorPlanMessage(MessageType.Move, candidate);
                    Send(MonitorAgent.Monitor, JsonSerializer.Serialize(changePositionMessage));
                }

                break;
            }

            case MessageType.PeerNegative:
            {
                blockList[Utils.ParsePeer(message.Sender)] = cooldownForTalking;
                break;
            }

            default:
                throw new NotImplementedException();
            }
        }
        private void HandleMessageFromMonitor(FloorPlanMessage receivedMessage)
        {
            this.position = receivedMessage.position;
            switch (receivedMessage.type)
            {
            case MessageType.Acknowledge:
            {
                var candidate = PickCandidate(receivedMessage);
                FloorPlanMessage changePositionMessage = new FloorPlanMessage(MessageType.Move, candidate);
                Send(MonitorAgent.Monitor, JsonSerializer.Serialize(changePositionMessage));
                break;
            }

            case MessageType.Emergency:
            {
                state = State.MovingInConstantDirection;
                var candidate = PickCandidate(receivedMessage);
                FloorPlanMessage changePositionMessage = new FloorPlanMessage(MessageType.Move, candidate);
                Send(MonitorAgent.Monitor, JsonSerializer.Serialize(changePositionMessage));
                break;
            }

            case MessageType.Block:
            {
                Point            candidate             = PickCandidate(receivedMessage);
                FloorPlanMessage changePositionMessage = new FloorPlanMessage(MessageType.Move, candidate);
                Send(MonitorAgent.Monitor, JsonSerializer.Serialize(changePositionMessage));
                break;
            }

            case Exit:
            {
                running = false;
                break;
            }

            default:
                throw new NotImplementedException();
            }

            lastReceivedMessageFromMonitor = receivedMessage;
        }
        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));
        }