/// <summary> /// Set start and get its neighbours to the queue. /// </summary> /// <param name="queue">An empty queue which has to be initialized.</param> /// <param name="start">Coordinates of an entrance of an amusement entrance.</param> /// <param name="paths">An auxilary array which represents "copy" of pathMap</param> /// <returns>true if the initialization was done successful, otherwise false.</returns> private bool InitializeQueue(Queue<DirectionItem> queue, Coordinates start, DirectionItem[][] paths) { // dont use pathRWLock (or change it to recursive mode) if (paths[start.x][start.y] == null) { return false; // it can happen if the entrance is demolished } paths[start.x][start.y].dir = Direction.here; DirectionItem aux; if ((start.x - 1 >= 0) && (aux = paths[start.x - 1][start.y]) != null) { aux.dir = Direction.E; // if(!aux.isEnterExit) queue.Enqueue(aux); //cannot go over these paths (without stop in an amusement) } if ((aux = paths[start.x][start.y - 1]) != null) { aux.dir = Direction.S; //if (!aux.isEnterExit) queue.Enqueue(aux); } if ((aux = paths[start.x][start.y + 1]) != null) { aux.dir = Direction.N; //if (!aux.isEnterExit) queue.Enqueue(aux); } if ((aux = paths[start.x + 1][start.y]) != null) { aux.dir = Direction.W; // if (!aux.isEnterExit) queue.Enqueue(aux); } return true; }
/// <summary> /// analyse item's neighbours, eventually enque them and set them right direction /// </summary> /// <param name="item">coordinates of the queue item which is analysed</param> /// <param name="queue">queue which realise BFS</param> /// <param name="paths">An auxilary array which represents a "copy" of pathMap </param> private void ProcessQueueItem(DirectionItem item, Queue<DirectionItem> queue, DirectionItem[][] paths) { // dont use pathRWLock (or change it to recursive mode)!! // border fields (except the gate) don't matter because there is a fence (i.e. null) around the playing map // direction is set the other way around because it is correct from a person perspective. byte x = item.x, y = item.y; DirectionItem aux; if ((x - 1 >= 0) && (aux = paths[x - 1][y]) != null && aux.dir == Direction.no) // item.x - 1 >= 0 due to the gate { aux.dir = Direction.E; if (!aux.isEnterExit) queue.Enqueue(aux); // cannot go over these paths (without stop in an amusement) } if ((aux = paths[x][y - 1]) != null && aux.dir == Direction.no) { aux.dir = Direction.S; if (!aux.isEnterExit) queue.Enqueue(aux); } if ((aux = paths[x][y + 1]) != null && aux.dir == Direction.no) { aux.dir = Direction.N; if (!aux.isEnterExit) queue.Enqueue(aux); } if ((aux = paths[x + 1][y]) != null && aux.dir == Direction.no) { aux.dir = Direction.W; if (!aux.isEnterExit) queue.Enqueue(aux); } }
/// <summary> /// Updates directions to all amusements. Useful when paths changed. /// </summary> private void UpdateDirections() { for (int i = 0; i < internalWidthMap; i++) { for (int j = 0; j < internalHeightMap; j++) { // here isnt a Lock, auxPathMap is not always actual -> lock here=nonsence if (pathMap[i][j] == null) auxPathMap[i][j] = null; else auxPathMap[i][j] = new DirectionItem((byte)i, (byte)j, (pathMap[i][j]).GetType()); } } Queue<DirectionItem> queue = new Queue<DirectionItem>(); Amusements[] amusA = gameRec.amusList.GetCopyArray(); foreach (var a in amusA) { UpdateDirectionToAmusement(a, queue, auxPathMap); queue.Clear(); for (int i = 0; i < internalWidthMap; i++) for (int j = 0; j < internalHeightMap; j++) { if (auxPathMap[i][j] != null) auxPathMap[i][j].dir = Direction.no; } } }
/// <summary> /// Set to paths in pathMap calculated directions to the amusement. It should be used only for a particular update (for updating all amusements use UpdateDirectionToAmusement()). /// </summary> /// <param name="a">An Amusements item</param> private void UpdateDirectionToOnlyOneAmusement(Amusements a) { Queue<DirectionItem> queue = new Queue<DirectionItem>(internalWidthMap * internalHeightMap + 5); for (int i = 0; i < internalWidthMap; i++) { for (int j = 0; j < internalHeightMap; j++) { // here isnt a Lock, auxPathMap is not always actual -> lock here=nonsence if (pathMap[i][j] == null) auxPathMap[i][j] = null; else auxPathMap[i][j] = new DirectionItem((byte)i, (byte)j, (pathMap[i][j]).GetType()); } } UpdateDirectionToAmusement(a, queue, auxPathMap); }
/// <summary> /// Set to paths in pathMap calculated directions to the amusement. /// </summary> /// <param name="a">an amusement to which directions are updated</param> /// <param name="queue">an empty instance of Queue</param> /// <param name="paths">a new auxilary array of builded paths</param> private void UpdateDirectionToAmusement(Amusements a, Queue<DirectionItem> queue, DirectionItem[][] paths) { DirectionItem item; AmusementPath entrance = a.entrance; if (entrance == null) return; if (!InitializeQueue(queue, entrance.coord, paths)) return; while (queue.Count != 0) { item = queue.Dequeue(); ProcessQueueItem(item, queue, paths); } // ---set calculated directions pathRWLock.EnterReadLock(); try { for (int i = 0; i < internalWidthMap; i++) { for (int j = 0; j < internalHeightMap; j++) { if ((item = paths[i][j]) != null && pathMap[i][j] != null) { pathMap[i][j].signpostAmus[a.Id] = item.dir; } } } } finally { pathRWLock.ExitReadLock(); } }
public Map(SerializationInfo si, StreamingContext sc) { gameRec = (GameRecords)si.GetValue("gameRec", typeof(GameRecords)); amusementMap = (Amusements[][])si.GetValue("amusementMap", typeof(Amusements[][])); pathMap = (Path[][])si.GetValue("pathMap", typeof(Path[][])); //todo: Bylo by rychlejsi, kdybych si vytvorila seznam a teprve ten pak prochazela? internalWidthMap = gameRec.internalWidth; internalHeightMap = gameRec.internalHeight; auxPathMap = new DirectionItem[internalWidthMap][]; for (int i = 0; i < internalWidthMap; i++) { auxPathMap[i] = new DirectionItem[internalHeightMap]; } lastAddedAmusLock = new object(); pathRWLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); amusRWLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion); pathChanged = true; // due to calling UpdateDirection() lastAddedAmus = new ConcurrentQueue<Amusements>(); }
/// <summary> /// Represents the current playing map, includes maps of paths and amusements, provides algorithms for navigation. /// </summary> /// <param name="width">The internal width of the map.</param> /// <param name="height">The internal height of the map.</param> /// <param name="m"></param> public Map(byte width, byte height, GameRecords m) { this.internalWidthMap = width; this.internalHeightMap = height; this.gameRec = m; //---initialize helpPath auxPathMap = new DirectionItem[width][]; for (int i = 0; i < width; i++) { auxPathMap[i] = new DirectionItem[height]; } //---initialize pathMap pathMap = new Path[width][]; for (int i = 0; i < width; i++) pathMap[i] = new Path[height]; //---initialize amusementMap amusementMap = new Amusements[width][]; for (int i = 0; i < width; i++) amusementMap[i] = new Amusements[height]; }