private Door PlaceDoorAndUpdateDependencyGraph(DoorRequirements doorReq) { //Check the edge is in the reduced map (will throw an exception if can't find) var edgeForDoor = doorReq.Location; var foundEdge = mapNoCycles.GetEdgeBetweenRoomsNoCycles(edgeForDoor.Source, edgeForDoor.Target); //Add locked door on this edge Door thisDoor = BuildDoorAndAddToMap(doorReq); int thisDoorIndex = thisDoor.LockIndex; //Find all clues now locked by this door, these clues depend on new door var newlyLockedClues = GetCluesBehindLockedEdge(foundEdge); var lockedCluesDoorIndices = newlyLockedClues.Select(clue => clue.OpenLockIndex); //Find all objectives now locked by this door, these objectives depend on new door var newlyLockedObj = GetObjectivesBehindLockedEdge(foundEdge); var lockedObjDoorIndices = newlyLockedObj.SelectMany(o => o.OpenLockIndex); var allLockedIndices = lockedCluesDoorIndices.Union(lockedObjDoorIndices); AddLockDependencyToExistingLocks(thisDoorIndex, allLockedIndices); return thisDoor; }
/// <summary> /// Lock an edge with an id, no checks, no dependency updates. /// Returns the door id /// </summary> /// <param name="edgeForDoorSource"></param> /// <param name="edgeForDoorTarget"></param> /// <param name="doorId"></param> private Door BuildDoorAndAddToMap(DoorRequirements doorReqs) { var edgeForDoor = doorReqs.Location; var foundEdge = mapNoCycles.GetEdgeBetweenRoomsNoCycles(edgeForDoor.Source, edgeForDoor.Target); int thisDoorIndex = nextLockIndex; nextLockIndex++; var doorEdgeInFullMap = mapNoCycles.edgeMappingNoCycleToFullMap[new Connection(edgeForDoor.Source, edgeForDoor.Target).Ordered]; Door newDoor = new Door(foundEdge, edgeForDoor, doorEdgeInFullMap, doorReqs.Id, thisDoorIndex, doorReqs.NumberOfCluesRequired); doorMap.Add(thisDoorIndex, newDoor); lockDependencyGraph.AddVertex(thisDoorIndex); return newDoor; }
/// <summary> /// Place a door and multiple clues for the door. /// Ensures that dependency graph is correctly updated (dependencies for new door and changes to dependencies for /// existing doors) /// Does no checking at all, so impossible situations can be created /// Only really public for tests /// </summary> public IEnumerable<Clue> PlaceDoorAndCluesNoChecks(DoorRequirements doorReq, IEnumerable<int> clueVertices) { Door thisDoor = PlaceDoorAndUpdateDependencyGraph(doorReq); var clues = PlaceCluesAndUpdateDependencyGraph(clueVertices, thisDoor, null); return clues; }
/// <summary> /// Place a door and multiple clues. /// Ensures that dependency graph is correctly updated (dependencies for new door and changes to dependencies for /// existing doors) /// Does a (slow) check that all clues are being placed in valid areas. If GetValidRoomsToPlaceClue() has been used /// outside the function, then use the NoChecks version. /// Doesn't check that sufficient clues are being placed for the door, but this should be ensured /// </summary> /// <param name="edge"></param> /// <param name="doorId"></param> /// <param name="clueVertex"></param> public IEnumerable<Clue> PlaceDoorAndClues(DoorRequirements doorReq, IEnumerable<int> clueVertices) { //Check all clues are in the valid placement area if (clueVertices.Except(GetValidRoomsToPlaceClueForDoor(doorReq.Location)).Any()) throw new ApplicationException(String.Format("Can't put clues: {0}, behind door at {1}:{2}", GetValidRoomsToPlaceClueForDoor(doorReq.Location).Except(clueVertices).ToString(), doorReq.Location.Source, doorReq.Location.Target)); return PlaceDoorAndCluesNoChecks(doorReq, clueVertices); }
/// <summary> /// See PlaceDoorAndClues /// </summary> public Clue PlaceDoorAndClue(DoorRequirements doorReq, int clueVertex) { return PlaceDoorAndClues(doorReq, new List<int> { clueVertex }).First(); }
/// <summary> /// See PlaceDoorAndClues /// </summary> public void PlaceDoor(DoorRequirements doorReq) { PlaceDoorAndClues(doorReq, new List<int>()); }