示例#1
0
        private void _handleUseActionEvent(IActor source, ITarget target, Action action)
        {
            // Queue next actor availability.
            long t = source.BeginCast(action, Time);

            EventQueue.Add(new BattleEvent(BattleEventType.ACTOR_READY, t, source));

            // Resolves later if it has a cast time, else resolves now.
            if (action.BaseAction.CastTime > 0)
            {
                EventQueue.Add(new BattleEvent(
                                   BattleEventType.RESOLVE_ACTION,
                                   t,
                                   source,
                                   target,
                                   action: action));
            }
            else
            {
                EventQueue.Add(new BattleEvent(
                                   BattleEventType.RESOLVE_ACTION,
                                   Time,
                                   source,
                                   target,
                                   action: action));
            }
        }
示例#2
0
        private void _handleResolveActionEvent(IActor source, ITarget target, Action action)
        {
            var a = action.BaseAction;

            ITarget[] targets = getTargetsInRadius(target, a.Radius);
            //EventLog.Add(new CombatLogEvent(CombatLogEventType.CAST, Time, source, action: a));

            foreach (ITarget tar in targets)
            {
                // Calculate and apply damage.
                if (a.Potency > 0)
                {
                    //CombatLogEvent damage = calculateActionDamage(a, source, tar);
                    //EventLog.Add(damage);
                }

                // Apply auras.
                if (a.AurasApplied != null)
                {
                    foreach (BaseAura aura in a.AurasApplied)
                    {
                        if (aura.Targets == AuraTarget.TARGET)
                        {
                            EventQueue.Add(new BattleEvent(
                                               BattleEventType.APPLY_AURA,
                                               Time,
                                               source,
                                               tar,
                                               baseAura: aura));
                        }
                    }
                }
            }

            // Apply self-auras.
            if (a.AurasApplied != null)
            {
                foreach (BaseAura aura in a.AurasApplied)
                {
                    if (aura.Targets == AuraTarget.SOURCE)
                    {
                        EventQueue.Add(new BattleEvent(
                                           BattleEventType.APPLY_AURA,
                                           Time,
                                           source,
                                           source,
                                           baseAura: aura));
                    }
                }
            }

            // Resolve action effects on the source actor, and add any
            // resulting events to the queue.
            var newEvents = source.ExecuteAction(action, Time);

            foreach (BattleEvent ev in newEvents)
            {
                EventQueue.Add(ev);
            }
        }
示例#3
0
        private void SendCommand(FrameFormat realTimeCmd)
        {
            string data = realTimeCmd.AsString;
            // Create two different encodings.
            Encoding ascii   = Encoding.ASCII;
            Encoding unicode = Encoding.Unicode;

            // Convert the string into a byte array.
            byte[] unicodeBytes = unicode.GetBytes(data);

            // Perform the conversion from one encoding to the other.
            byte[] asciiBytes = Encoding.Convert(unicode, ascii, unicodeBytes);

            // Convert the new byte[] into a char[] and then into a string.
            char[] asciiChars = new char[ascii.GetCharCount(asciiBytes, 0, asciiBytes.Length)];
            ascii.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0);
            string asciiString = new string(asciiChars);

            Debug.WriteLine(string.Format("{0} Sending {1}", DateTime.Now, asciiString));
            logger.Trace("Sending {0}", asciiString);

            //serialPort.Write(asciiChars, 0, asciiChars.Length);

            var response = commPort.SendReceive(asciiString);

            Debug.WriteLine(string.Format("{0} Received {1}", DateTime.Now, response));
            logger.Trace("Received {0}", response);

            incommingQueue.Add(response);
        }
示例#4
0
        private void _handleActorReadyEvent(IActor source)
        {
            // Decision should be either ACTOR_READY or RESOLVE_ACTION.
            BattleEvent decision = source.DecideAction(Time, Actors, Enemies);

            EventQueue.Add(decision);
        }
示例#5
0
        public void Start()
        {
            EventQueue.Add(new TrafficEvent(SystemTime, Stages[0].Duration[0], Stages[0], stage => stage.Activate(SystemTime)));

            /**
             * Pop event from Queue.
             * Process the event.
             * Add event span to SystemTime.
             */
        }
        /// <inheritdoc />
        public void RegisterEvent(double scheduledDispatchBeatTime, Action eventToDispatch)
        {
            if (scheduledDispatchBeatTime < CurrentBeatsTimeFunction())
            {
                throw new InvalidOperationException($"Cannot register event with scheduled Time: {scheduledDispatchBeatTime} because that time has already passed.");
            }

            IBeatEvent beatsEvent = new ScheduledBeatsEvent(scheduledDispatchBeatTime, eventToDispatch);

            //Just register the beats event
            lock (syncObj)
                EventQueue.Add(beatsEvent);
        }
示例#7
0
        private void ReceiveId()
        {
            Packet       packet = DequeueProcessQueue();
            EventCapsule idCapsule;

            if (!IsValidPacket(packet))
            {
                idCapsule = new IdCapsule(UserToken.UserId, Pid);
                idCapsule.NetworkEvent = NetworkEvent.IdRequestFailed;
                idCapsule.ErrorType    = ErrorType.InvalidPacket;
                EventQueue.Add(idCapsule);
                TerminateProcess(this);
                return;
            }

            if (packet.RequestType == (byte)PacketType.Id)
            {
                UserToken.UserId = BitConverter.ToUInt32(packet.Data, 0);//Sets the ID received
                idCapsule        = new IdCapsule(UserToken.UserId, Pid)
                {
                    NetworkEvent = NetworkEvent.IdRequestDone,
                    ErrorType    = ErrorType.Success
                };
                EventQueue.Add(idCapsule);
                TerminateProcess(this);
            }

            if (packet.RequestType == (byte)PacketType.Error)
            {
                idCapsule = new IdCapsule(UserToken.UserId, Pid)
                {
                    NetworkEvent = NetworkEvent.IdRequestFailed,
                    ErrorType    = (ErrorType)packet.Data[1]
                };
                EventQueue.Add(idCapsule);
                TerminateProcess(this);
            }

            if (packet.RequestType == (byte)PacketType.Suspend)
            {
                idCapsule = new IdCapsule(UserToken.UserId, Pid)
                {
                    NetworkEvent = NetworkEvent.IdRequestFailed,
                    ErrorType    = ErrorType.SocketClosed
                };
                EventQueue.Add(idCapsule);
                TerminateProcess(this);
            }
        }
示例#8
0
        public void TestCaseRandom()
        {
            Random     randomGenerator = new Random();
            EventQueue eventQueue      = new EventQueue();

            for (int i = 0; i < 1000; i++)
            {
                eventQueue.Add(new Event((ulong)randomGenerator.Next(0, 100), null));
            }

            ulong time = 0;

            while (eventQueue.IsNotEmpty())
            {
                Event e = eventQueue.GetNextEvent();
                Assert.GreaterOrEqual(e.Time, time);
                time = e.Time;
            }
            Assert.False(eventQueue.IsNotEmpty());
        }
示例#9
0
        protected override void Append(LoggingEvent evt)
        {
            SetupThread();
            string webUserName = GlobalContext.Properties["user"].ToString();
            string pageUrl     = GlobalContext.Properties["pageUrl"].ToString();
            string referUrl    = GlobalContext.Properties["referUrl"].ToString();
            string requestId   = GlobalContext.Properties["requestId"].ToString();
            var    evtw        = new LoggingEventWrap {
                Evt = evt, webUser = webUserName, pageUrl = pageUrl, referUrl = referUrl, requestId = requestId
            };

            if (!_lossy)
            {
                EventQueue.Add(getEntity(evtw));
            }
            else
            {
                EventQueue.TryAdd(getEntity(evtw));
            }
        }
示例#10
0
        /// <summary>
        /// Generates a queue of unpublished domain events
        /// </summary>
        /// <param name="preTransaction">True, if pre-transaction events are required</param>
        /// <returns>A collection of domain events</returns>
        private IEventQueue GenerateEventQueue
        (
            bool preTransaction = false
        )
        {
            var aggregates = GetPendingAggregates();
            var queue      = new EventQueue();

            foreach (var aggregate in aggregates)
            {
                var aggregateKey  = aggregate.GetKeyValue();
                var aggregateType = aggregate.GetType();
                var nextEvents    = default(IList <IDomainEvent>);

                if (preTransaction)
                {
                    nextEvents = aggregate.GetPreTransactionEvents();
                }
                else
                {
                    nextEvents = aggregate.GetPostTransactionEvents();
                }

                if (nextEvents != null && nextEvents.Any())
                {
                    foreach (var @event in nextEvents)
                    {
                        queue.Add
                        (
                            aggregateKey,
                            aggregateType,
                            @event
                        );
                    }
                }
            }

            return(queue);
        }
示例#11
0
        private void _handleApplyAuraEvent(IActor source, ITarget target, BaseAura aura)
        {
            // Apply the aura.
            var appliedAura = _applyAura(aura, source, target);

            // Log event.
            CombatLogEventType type;

            if (appliedAura.isBuff)
            {
                type = CombatLogEventType.APPLYBUFF;
            }
            else
            {
                type = CombatLogEventType.APPLYDEBUFF;
            }
            //EventLog.Add(new CombatLogEvent(type, appliedAura.Expires, appliedAura.Source, target, appliedAura.BaseAura));

            // Add aura expiration event in the future.
            EventQueue.Add(new BattleEvent(BattleEventType.EXPIRE_AURA,
                                           appliedAura.Expires, appliedAura.Source,
                                           target, aura: appliedAura));
        }
示例#12
0
        public void TestCase()
        {
            EventQueue eventQueue = new EventQueue();

            eventQueue.Add(new Event(0, null));
            eventQueue.Add(new Event(1, null));
            eventQueue.Add(new Event(1, null));
            eventQueue.Add(new Event(5, null));
            eventQueue.Add(new Event(1, null));
            eventQueue.Add(new Event(2, null));
            eventQueue.Add(new Event(5, null));

            ulong time = 0;

            while (eventQueue.IsNotEmpty())
            {
                Event e = eventQueue.GetNextEvent();
                Assert.GreaterOrEqual(e.Time, time);
                time = e.Time;
            }
            Assert.False(eventQueue.IsNotEmpty());
        }
        /// <summary>
        /// Computes the intersection of one or more line strings.
        /// </summary>
        public void Compute()
        {
            // source: http://geomalgorithms.com/a09-_intersect-3.html

            _intersections = new List <Coordinate>();
            _edgeIndices   = new List <Tuple <Int32, Int32> >();
            Event              currentEvent = _eventQueue.Next();
            SweepLineSegment   segment;
            IList <Coordinate> intersections;

            while (currentEvent != null)
            {
                if (currentEvent is EndPointEvent)
                {
                    EndPointEvent endPointEvent = (EndPointEvent)currentEvent;
                    switch (endPointEvent.Type)
                    {
                    // Left endpoint event: check for possible intersection with below and / or above segments.
                    case EventType.Left:
                        segment = _sweepLine.Add(endPointEvent);
                        if (segment.Above != null)
                        {
                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segment.Above.LeftCoordinate, segment.Above.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0)
                            {
                                IntersectionEvent intersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segment,
                                    Above  = segment.Above
                                };
                                _eventQueue.Add(intersectionEvent);
                            }
                        }
                        if (segment.Below != null)
                        {
                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segment.Below.LeftCoordinate, segment.Below.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0)
                            {
                                IntersectionEvent intersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segment.Below,
                                    Above  = segment
                                };
                                _eventQueue.Add(intersectionEvent);
                            }
                        }
                        break;

                    // Right endpoint event: check for possible intersection of the below and above segments.
                    case EventType.Right:
                        segment = _sweepLine.Search(endPointEvent);
                        if (segment != null)
                        {
                            if (segment.Above != null && segment.Below != null)
                            {
                                intersections = LineAlgorithms.Intersection(segment.Above.LeftCoordinate,
                                                                            segment.Above.RightCoordinate,
                                                                            segment.Below.LeftCoordinate,
                                                                            segment.Below.RightCoordinate,
                                                                            PrecisionModel);

                                if (intersections.Count > 0)
                                {
                                    IntersectionEvent intersectionEvent = new IntersectionEvent
                                    {
                                        Vertex = intersections[0],
                                        Below  = segment.Below,
                                        Above  = segment.Above
                                    };
                                    if (!_eventQueue.Contains(intersectionEvent))
                                    {
                                        _eventQueue.Add(intersectionEvent);
                                    }
                                }
                            }
                            _sweepLine.Remove(segment);
                        }
                        break;
                    }
                }

                // Intersection point event: switch the two concerned segments and check for possible intersection with their below and above segments.
                else if (currentEvent is IntersectionEvent)
                {
                    IntersectionEvent intersectionEvent = (IntersectionEvent)currentEvent;

                    /*
                     * Segment order before intersection: segmentBelow <-> segmentAbove <-> segment <-> segmentAboveAbove
                     * Segment order after intersection:  segmentBelow <-> segment <-> segmentAbove <-> segmentAboveAbove
                     */
                    segment = intersectionEvent.Above;
                    SweepLineSegment segmentAbove = intersectionEvent.Below;

                    // Handle closing intersection points when segments (partially) overlap each other.
                    if (intersectionEvent.IsClose)
                    {
                        if (!_sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                        {
                            _intersections.Add(currentEvent.Vertex);
                            _edgeIndices.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                          Math.Max(segment.Edge, segmentAbove.Edge)));
                        }
                    }

                    // It is possible that the previously detected intersection point is not a real intersection, because a new segment started between them,
                    // therefore a repeated check is necessary to carry out.
                    else if (_sweepLine.Add(intersectionEvent))
                    {
                        if (!_sweepLine.IsAdjacent(segment.Edge, segmentAbove.Edge))
                        {
                            _intersections.Add(currentEvent.Vertex);
                            _edgeIndices.Add(Tuple.Create(Math.Min(segment.Edge, segmentAbove.Edge),
                                                          Math.Max(segment.Edge, segmentAbove.Edge)));

                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 1 && !intersections[1].Equals(intersections[0]))
                            {
                                IntersectionEvent newIntersectionEvent = new IntersectionEvent
                                {
                                    Vertex  = intersections[1],
                                    Below   = segment,
                                    Above   = segmentAbove,
                                    IsClose = true,
                                };
                                _eventQueue.Add(newIntersectionEvent);
                            }
                        }

                        if (segmentAbove.Above != null)
                        {
                            intersections = LineAlgorithms.Intersection(segmentAbove.LeftCoordinate, segmentAbove.RightCoordinate,
                                                                        segmentAbove.Above.LeftCoordinate, segmentAbove.Above.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0 && intersections[0].X >= intersectionEvent.Vertex.X)
                            {
                                IntersectionEvent newIntersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segmentAbove,
                                    Above  = segmentAbove.Above
                                };
                                if (!_eventQueue.Contains(newIntersectionEvent))
                                {
                                    _eventQueue.Add(newIntersectionEvent);
                                }
                            }
                        }

                        if (segment.Below != null)
                        {
                            intersections = LineAlgorithms.Intersection(segment.LeftCoordinate, segment.RightCoordinate,
                                                                        segment.Below.LeftCoordinate, segment.Below.RightCoordinate,
                                                                        PrecisionModel);

                            if (intersections.Count > 0 && intersections[0].X >= intersectionEvent.Vertex.X)
                            {
                                IntersectionEvent newIntersectionEvent = new IntersectionEvent
                                {
                                    Vertex = intersections[0],
                                    Below  = segment.Below,
                                    Above  = segment
                                };
                                if (!_eventQueue.Contains(newIntersectionEvent))
                                {
                                    _eventQueue.Add(newIntersectionEvent);
                                }
                            }
                        }
                    }
                }

                currentEvent = _eventQueue.Next();
            }
            _hasResult = true;
        }
示例#14
0
        internal override void StartFileSend(string fileName, FileType fileType, byte[] fileData)
        {
            int    fileSize       = fileData.Length;
            int    sourceOffset   = 0;
            Packet fileInfoPacket = new Packet
            {
                PacketNumber = 0,
                RequestType  = (byte)PacketType.FileInfo,
                FileType     = (byte)fileType,
                MorePackets  = true,
                ProcessId    = Pid
            };

            fileInfoPacket.DataSize =
                (uint)MakeFileDataInfo(fileInfoPacket, (uint)fileSize, fileName, UserToken.UserId);
            MakePacketHeader(fileInfoPacket);
            UserToken.EnqueueSend(fileInfoPacket);
            ushort packetNum = 1;

            while (sourceOffset < fileSize)
            {
                int    copySize = PacketConsts.ReceiverBufferSize;
                Packet packet   = new Packet
                {
                    PacketNumber = packetNum,
                    RequestType  = (byte)PacketType.File,
                    FileType     = (byte)fileType,
                    MorePackets  = true,
                    ProcessId    = Pid
                };
                packetNum += 1;
                if (copySize > fileSize - sourceOffset)
                {
                    copySize           = fileSize - sourceOffset;
                    packet.MorePackets = false;
                }

                packet.DataSize = (uint)copySize;
                MakePacketHeader(packet);
                packet.Data = new byte[copySize];
                Array.Copy(fileData, sourceOffset, packet.Data, 0, copySize);
                UserToken.EnqueueSend(packet);
                sourceOffset += copySize;
            }

            Packet replyPacket = DequeueProcessQueue();

            if (replyPacket.RequestType == (byte)PacketType.Suspend)
            {
                EventCapsule terminateCapsule = new FileSaveCapsule(UserToken.UserId, Pid, NetworkEvent.FileSaveFailed,
                                                                    ErrorType.SocketClosed);
                EventQueue.Add(terminateCapsule);
            }

            if (replyPacket.RequestType == (byte)PacketType.FileSaveDone)
            {
                EventCapsule capsule =
                    new FileSaveCapsule(UserToken.UserId, Pid, NetworkEvent.FileSaveDone, ErrorType.Success);
                EventQueue.Add(capsule);
            }

            if (replyPacket.RequestType == (byte)PacketType.Error)
            {
                EventCapsule capsule = new FileSaveCapsule(UserToken.UserId, Pid, NetworkEvent.FileSaveFailed,
                                                           (ErrorType)replyPacket.Data[0]);
                EventQueue.Add(capsule);
            }

            TerminateProcess(this);
        }
示例#15
0
        /*
         * ReadFilePackets
         * This method will Read packet until MorePackets ==false, and Create fileCapsule storing file Data
         * This method assumes Analyzer works Correct. will be terminated if invalid packet arrives
         * -Receivable Packets-
         * FileInfo, File, Suspend, Error
         * FileInfo packet must arrive before File packet arrives
         */
        protected void ReadFilePackets()
        {
            FileCapsule fileCapsule  = new FileCapsule(UserToken.UserId, Pid);
            List <byte> fileDataList = new List <byte>();
            Packet      filePacket   = DequeueProcessQueue();

            if (!IsValidPacket(filePacket))
            {
                fileCapsule.NetworkEvent = NetworkEvent.FileRequestFailed;
                fileCapsule.ErrorType    = ErrorType.InvalidPacket;
                EventQueue.Add(fileCapsule);
                TerminateProcess(this);
                return;
            }

            if (filePacket.RequestType == (byte)PacketType.Suspend)
            {
                fileCapsule.NetworkEvent = NetworkEvent.FileRequestFailed;
                fileCapsule.ErrorType    = ErrorType.SocketClosed;
                EventQueue.Add(fileCapsule);
                TerminateProcess(this);
                return;
            } //Handles suspend signal

            if (filePacket.RequestType == (byte)PacketType.Error)
            {
                fileCapsule.NetworkEvent = NetworkEvent.FileRequestFailed;
                fileCapsule.ErrorType    = (ErrorType)filePacket.Data[1];
                EventQueue.Add(fileCapsule);
                TerminateProcess(this);
                return;
            } //Handles error signal

            if (filePacket.RequestType == (byte)PacketType.FileInfo) //First Packet must be FileInfo
            {
                fileCapsule.FileSize = BitConverter.ToUInt32(filePacket.Data, 0);// brings file size
                fileCapsule.UserId   = BitConverter.ToUInt32(filePacket.Data, 4);
                fileCapsule.FileName = Encoding.ASCII.GetString(filePacket.Data, 9, filePacket.Data[8]);
                fileCapsule.FileType = (FileType)filePacket.FileType;
                ReceivedPacketCount  = 0;
            }
            while (filePacket.MorePackets)
            {
                if (filePacket.RequestType == (byte)PacketType.File)
                {
                    fileDataList.AddRange(filePacket.Data.ToList());
                    ReceivedPacketCount++;
                }

                filePacket = DequeueProcessQueue();
                if (!IsValidPacket(filePacket))
                {
                    fileCapsule.NetworkEvent = NetworkEvent.FileRequestFailed;
                    fileCapsule.ErrorType    = ErrorType.InvalidPacket;
                    EventQueue.Add(fileCapsule);
                    TerminateProcess(this);
                    return;
                }

                if (filePacket.RequestType == (byte)PacketType.Suspend)
                {
                    fileCapsule.NetworkEvent = NetworkEvent.FileRequestFailed;
                    fileCapsule.ErrorType    = ErrorType.SocketClosed;
                    EventQueue.Add(fileCapsule);
                    TerminateProcess(this);
                    return;
                } //Handles suspend signal

                if (filePacket.RequestType == (byte)PacketType.Error)
                {
                    fileCapsule.NetworkEvent = NetworkEvent.FileRequestFailed;
                    fileCapsule.ErrorType    = (ErrorType)filePacket.Data[1];
                    EventQueue.Add(fileCapsule);
                    TerminateProcess(this);
                    return;
                } //Handles error signal
            }

            if (filePacket.MorePackets == false && filePacket.RequestType == (byte)PacketType.File)
            {
                fileDataList.AddRange(filePacket.Data.ToList());
                ReceivedPacketCount++;
                fileCapsule.Data         = fileDataList.ToArray();
                fileCapsule.NetworkEvent = NetworkEvent.FileRequestDone;
                fileCapsule.ErrorType    = ErrorType.Success;
                EventQueue.Add(fileCapsule);
                TerminateProcess(this); // remove itself from processList
            }
        }
        public Simulation(SimulationParameters simulationParameters, ProtocolParameters protocolParameters)
        {
            this.simulationParameters = simulationParameters;
            this.protocolParameters   = protocolParameters;

            // init sim state
            clock      = 0;
            eventQueue = new EventQueue();

            var initialCycleDuration = protocolParameters.t_sleep + protocolParameters.t_listen;

            eventQueue.Add(new StartEvent()
            {
                time     = initialCycleDuration + protocolParameters.t_delta,             // must start AFTER first duty cycle events
                sim      = this,
                previous = null
            });
            eventQueue.Add(new EndEvent()
            {
                time     = simulationParameters.max_time,
                sim      = this,
                previous = null
            });

            if (simulationParameters.debugType == DebugType.Interval)
            {
                eventQueue.Add(new DebugEvent()
                {
                    time     = simulationParameters.debug_interval,
                    sim      = this,
                    previous = null
                });
            }

            // init relays as asleep and schedule random awake
            relays    = new List <Relay>();
            relayById = new Dictionary <int, Relay>();
            for (int i = 0; i < simulationParameters.n_nodes; i++)
            {
                var relay = new Relay {
                    id     = i,
                    range  = simulationParameters.range,
                    status = RelayStatus.Asleep,
                    sim    = this
                };
                relays.Add(relay);
                relayById[relay.id] = relay;
                eventQueue.Add(new AwakeEvent()
                {
                    relay = relay,
                    // could be at any point of its duty cycle
                    time     = RNG.rand() * initialCycleDuration,
                    sim      = this,
                    previous = null
                });
            }

            // create distance matrix
            distances = new float[relays.Count, relays.Count];

            // move disconnected
            //Console.WriteLine("Placing relays");
            var connected = false;
            int n_slots   = simulationParameters.binsCount;

            while (!connected)
            {
                // check wether the grid slot is available
                var slotBusy = new bool[n_slots, n_slots];
                foreach (var relay in relays)
                {
                    var X_slot      = 0;
                    var Y_slot      = 0;
                    var validRegion = false;
                    do
                    {
                        X_slot = RNG.rand_int(0, n_slots);
                        Y_slot = RNG.rand_int(0, n_slots);

                        // assign actual position
                        relay.position.X = slotToX(X_slot);
                        relay.position.Y = slotToX(Y_slot);

                        // calculate if in region
                        var X  = relay.position.X;
                        var Y  = relay.position.Y;
                        var c  = simulationParameters.area_side / 2;
                        var dx = X - c;
                        var dy = Y - c;
                        switch (simulationParameters.emptyRegionType)
                        {
                        case EmptyRegionType.None:
                            validRegion = true;
                            break;

                        case EmptyRegionType.Cross:
                            var w  = simulationParameters.emptyRegionSize / Math.Sqrt(2);
                            var h  = Math.Max(relay.range + 2, simulationParameters.emptyRegionSize / 10) / Math.Sqrt(2);
                            var l  = simulationParameters.area_side;
                            var w1 = (l - w) > (X + Y);
                            var w2 = (l + w) < (X + Y);
                            var w3 = (w) < (X - Y);
                            var w4 = -(w) > (X - Y);
                            var h1 = (h) < (X - Y);
                            var h2 = -(h) > (X - Y);
                            var h3 = (l - h) > (X + Y);
                            var h4 = (l + h) < (X + Y);
                            validRegion = (w1 || w2 || h1 || h2) && (w3 || w4 || h3 || h4);
                            break;

                        case EmptyRegionType.Square:
                            var side = simulationParameters.emptyRegionSize;
                            validRegion = (Math.Abs(dx) >= side / 2) || (Math.Abs(dy) >= side / 2);
                            break;

                        case EmptyRegionType.Lines:
                            var side_w          = simulationParameters.emptyRegionSize;
                            var side_h          = Math.Max(relay.range + 2, side_w / 6);
                            var validFirstLine  = (X <= c - side_w / 2) || (X >= c + side_w / 2) || (Y <= c * 3 / 2 - side_h / 2) || (Y >= c * 3 / 2 + side_h / 2);
                            var validSecondLine = (X <= c - side_w / 2) || (X >= c + side_w / 2) || (Y <= c * 1 / 2 - side_h / 2) || (Y >= c * 1 / 2 + side_h / 2);
                            validRegion = validFirstLine && validSecondLine;
                            break;

                        case EmptyRegionType.Holes:
                            var radius = simulationParameters.emptyRegionSize;
                            var d1     = GraphUtils.Distance(X, Y, 0.5 * c, 0.5 * c);
                            var d2     = GraphUtils.Distance(X, Y, 0.5 * c, 1.5 * c);
                            var d3     = GraphUtils.Distance(X, Y, 1.5 * c, 0.5 * c);
                            var d4     = GraphUtils.Distance(X, Y, 1.5 * c, 1.5 * c);
                            validRegion = d1 >= radius && d2 >= radius && d3 >= radius && d4 >= radius;
                            break;
                        }
                    }while (slotBusy[X_slot, Y_slot] || !validRegion);

                    // take slot
                    slotBusy[X_slot, Y_slot] = true;
                }

                //Console.WriteLine("Checking connected relays");

                // calculate new neighbours
                GraphUtils.Distances(relays, distances);
                GraphUtils.SetNeighbours(relays, distances);
                connected = GraphUtils.Connected(relays);
            }
            if (protocolParameters.protocolVersion == ProtocolVersion.BFS || protocolParameters.protocolVersion == ProtocolVersion.BFS_half)
            {
                GraphUtils.RepeatedBFS(relays, distances, protocolParameters.protocolVersion);
            }
            //Console.WriteLine("Placed relays");

            // init debug state
            if (simulationParameters.debugType != DebugType.Never)
            {
                debugWriter = new StreamWriter(simulationParameters.debug_file);
                debugWriter.Write("debug_data=`");
                debugWriter.WriteLine($"{JsonConvert.SerializeObject(simulationParameters)}");
                debugWriter.WriteLine("#");
                debugWriter.WriteLine($"{JsonConvert.SerializeObject(protocolParameters)}");
                debugWriter.WriteLine("#");
                foreach (var r in relays)
                {
                    debugWriter.WriteLine($"{r.id};{r.position.X};{r.position.Y};{r.range}");
                }
                debugWriter.WriteLine("#");
                debugWriter.WriteLine($"{JsonConvert.SerializeObject(distances)}");
                debugWriter.WriteLine("#");
            }
        }