public void ApplyState(IDungeonState state) { SetSmallKeyDoorState(state.UnlockedDoors); bool bigKeyCollected = state.BigKeyCollected || GetAvailableBigKeys() > 0; SetBigKeyDoorState(bigKeyCollected); }
/// <summary> /// Returns whether the specified number of collected keys and big key can occur, /// based on key logic. /// </summary> /// <param name="keysCollected"> /// A 32-bit integer representing the number of small keys collected. /// </param> /// <param name="bigKeyCollected"> /// A boolean representing whether the big key is collected. /// </param> /// <returns> /// A boolean representing whether the result can occur. /// </returns> public bool ValidateKeyLayout(IDungeonState state) { foreach (var keyLayout in _dungeon.KeyLayouts) { if (keyLayout.CanBeTrue(this, state)) { return(true); } } return(false); }
/// <summary> /// Process the dungeon state permutation. /// </summary> /// <param name="state"> /// The permutation to be processed. /// </param> /// <param name="finalQueue"> /// The final queue. /// </param> /// <param name="nextQueue"> /// The next queue to which this permutation will be added. /// </param> private void ProcessDungeonState( IMutableDungeon dungeonData, IDungeonState state, BlockingCollection <IDungeonState> finalQueue, BlockingCollection <IDungeonState>?nextQueue) { dungeonData.ApplyState(state); int availableKeys = dungeonData.GetAvailableSmallKeys(state.SequenceBreak) + state.KeysCollected - state.UnlockedDoors.Count; if (availableKeys == 0) { finalQueue.Add(state); return; } var accessibleKeyDoors = dungeonData.GetAccessibleKeyDoors(state.SequenceBreak); if (accessibleKeyDoors.Count == 0) { finalQueue.Add(state); return; } foreach (var keyDoor in accessibleKeyDoors) { var newPermutation = state.UnlockedDoors.GetRange(0, state.UnlockedDoors.Count); newPermutation.Add(keyDoor); if (nextQueue == null) { return; } nextQueue.Add( _stateFactory( newPermutation, state.KeysCollected, state.BigKeyCollected, state.SequenceBreak)); } }
/// <summary> /// Process the final dungeon state permutation. /// </summary> /// <param name="state"> /// The permutation to be processed. /// </param> private static void ProcessFinalDungeonState( IMutableDungeon dungeonData, IDungeonState state, BlockingCollection <IDungeonResult> inLogicQueue, BlockingCollection <IDungeonResult> outOfLogicQueue) { dungeonData.ApplyState(state); if (!dungeonData.ValidateKeyLayout(state)) { return; } var result = dungeonData.GetDungeonResult(state); if (state.SequenceBreak) { outOfLogicQueue.Add(result); } else { inLogicQueue.Add(result); } }
/// <summary> /// Returns the current accessibility and accessible item count based on the specified /// number of small keys collected and whether the big key is collected. /// </summary> /// <param name="smallKeyValue"> /// A 32-bit integer representing the number of small keys collected. /// </param> /// <param name="bigKeyValue"> /// A boolean representing whether the big key is collected. /// </param> /// <param name="validationState"> /// A boolean representing whether the order of key doors opened requires a sequence break. /// </param> /// <returns> /// A tuple of the accessibility of items in the dungeon and a 32-bit integer representing /// the number of accessible items in the dungeon. /// </returns> public IDungeonResult GetDungeonResult(IDungeonState state) { int inaccessibleBosses = 0; int inaccessibleItems = 0; bool visible = false; foreach (var item in Items.Keys) { switch (Items[item].Accessibility) { case AccessibilityLevel.None: { if (_dungeon.Bosses.Contains(item)) { inaccessibleBosses++; } inaccessibleItems++; } break; case AccessibilityLevel.Inspect: { inaccessibleItems++; visible = true; } break; case AccessibilityLevel.SequenceBreak: { if (!state.SequenceBreak) { inaccessibleItems++; } } break; } } if (_mode.KeyDropShuffle) { foreach (var item in SmallKeyDrops.Values) { switch (item.Accessibility) { case AccessibilityLevel.None: { inaccessibleItems++; } break; case AccessibilityLevel.SequenceBreak: { if (!state.SequenceBreak) { inaccessibleItems++; } } break; } } foreach (var item in BigKeyDrops.Values) { switch (item.Accessibility) { case AccessibilityLevel.None: { inaccessibleItems++; } break; case AccessibilityLevel.SequenceBreak: { if (!state.SequenceBreak) { inaccessibleItems++; } } break; } } } int minimumInaccessible = _mode.GuaranteedBossItems ? inaccessibleBosses : 0; var bossAccessibility = GetBossAccessibility(); if (inaccessibleItems <= minimumInaccessible) { if (minimumInaccessible == 0) { return(_resultFactory( bossAccessibility, state.SequenceBreak ? AccessibilityLevel.SequenceBreak : AccessibilityLevel.Normal, _dungeon.Sections[0].Available)); } if (minimumInaccessible >= _dungeon.Sections[0].Available) { if (visible) { return(_resultFactory(bossAccessibility, AccessibilityLevel.Inspect, 0)); } return(_resultFactory(bossAccessibility, AccessibilityLevel.None, 0)); } else { return(_resultFactory( bossAccessibility, AccessibilityLevel.Partial, _dungeon.Sections[0].Available - minimumInaccessible)); } } if (!_mode.BigKeyShuffle && !state.BigKeyCollected) { int bigKey = _mode.KeyDropShuffle ? _dungeon.BigKey + _dungeon.BigKeyDrops.Count : _dungeon.BigKey; inaccessibleItems -= bigKey; } if (inaccessibleItems <= minimumInaccessible) { if (minimumInaccessible == 0) { return(_resultFactory( bossAccessibility, state.SequenceBreak ? AccessibilityLevel.SequenceBreak : AccessibilityLevel.Normal, _dungeon.Sections[0].Available)); } if (minimumInaccessible >= _dungeon.Sections[0].Available) { if (visible) { return(_resultFactory(bossAccessibility, AccessibilityLevel.Inspect, 0)); } return(_resultFactory(bossAccessibility, AccessibilityLevel.None, 0)); } else { return(_resultFactory( bossAccessibility, AccessibilityLevel.Partial, _dungeon.Sections[0].Available - minimumInaccessible)); } } if (!_mode.SmallKeyShuffle) { int smallKeys = _mode.KeyDropShuffle ? _dungeon.SmallKeys + _dungeon.SmallKeyDrops.Count : _dungeon.SmallKeys; inaccessibleItems -= smallKeys - state.KeysCollected; } if (inaccessibleItems <= minimumInaccessible) { if (minimumInaccessible == 0) { return(_resultFactory( bossAccessibility, state.SequenceBreak ? AccessibilityLevel.SequenceBreak : AccessibilityLevel.Normal, _dungeon.Sections[0].Available)); } if (minimumInaccessible >= _dungeon.Sections[0].Available) { if (visible) { return(_resultFactory(bossAccessibility, AccessibilityLevel.Inspect, 0)); } return(_resultFactory(bossAccessibility, AccessibilityLevel.None, 0)); } else { return(_resultFactory( bossAccessibility, AccessibilityLevel.Partial, _dungeon.Sections[0].Available - minimumInaccessible)); } } if (!_mode.MapShuffle) { inaccessibleItems -= _dungeon.Map; } if (!_mode.CompassShuffle) { inaccessibleItems -= _dungeon.Compass; } inaccessibleItems = Math.Max(inaccessibleItems, minimumInaccessible); if (inaccessibleItems <= 0) { return(_resultFactory( bossAccessibility, AccessibilityLevel.SequenceBreak, _dungeon.Sections[0].Available)); } if (inaccessibleItems >= _dungeon.Sections[0].Available) { if (visible) { return(_resultFactory(bossAccessibility, AccessibilityLevel.Inspect, 0)); } return(_resultFactory(bossAccessibility, AccessibilityLevel.None, 0)); } return(_resultFactory( bossAccessibility, AccessibilityLevel.Partial, _dungeon.Sections[0].Available - inaccessibleItems)); }
/// <summary> /// Returns whether the key layout is possible in the current game state. /// </summary> /// <param name="dungeonData"> /// The dungeon mutable data. /// </param> /// <param name="smallKeys"> /// A 32-bit signed integer representing the number of small keys collected. /// </param> /// <param name="bigKey"> /// A boolean representing whether the big key was collected. /// </param> /// <returns> /// A boolean representing whether the key layout is possible. /// </returns> public bool CanBeTrue(IMutableDungeon dungeonData, IDungeonState state) { return(_requirement.Met); }
/// <summary> /// Returns whether the key layout is possible in the current game state. /// </summary> /// <param name="dungeonData"> /// The dungeon mutable data. /// </param> /// <param name="state"> /// The dungeon state data. /// </param> /// <returns> /// A boolean representing whether the key layout is possible. /// </returns> public bool CanBeTrue(IMutableDungeon dungeonData, IDungeonState state) { if (dungeonData == null) { throw new ArgumentNullException(nameof(dungeonData)); } if (!_requirement.Met) { return(false); } int inaccessible = 0; foreach (var item in _smallKeyLocations) { switch (dungeonData.DungeonItems[item].Accessibility) { case AccessibilityLevel.SequenceBreak: { if (!state.SequenceBreak) { inaccessible++; } } break; case AccessibilityLevel.Normal: break; default: { inaccessible++; } break; } } if (_bigKeyInLocations && !state.BigKeyCollected) { inaccessible--; } if (!ValidateMinimumKeyCount(state.KeysCollected, inaccessible)) { return(false); } int dungeonSmallKeys = _mode.KeyDropShuffle ? _dungeon.SmallKeys + _dungeon.SmallKeyDrops.Count : _dungeon.SmallKeys; if (!ValidateMaximumKeyCount(dungeonSmallKeys, state.KeysCollected, inaccessible)) { return(false); } foreach (var child in _children) { if (child.CanBeTrue(dungeonData, state)) { return(true); } } return(false); }
/// <summary> /// Returns whether the key layout is possible in the current game state. /// </summary> /// <param name="dungeonData"> /// The dungeon mutable data. /// </param> /// <param name="smallKeys"> /// A 32-bit signed integer representing the number of small keys collected. /// </param> /// <param name="bigKey"> /// A boolean representing whether the big key was collected. /// </param> /// <returns> /// A boolean representing whether the key layout is possible. /// </returns> public bool CanBeTrue(IMutableDungeon dungeonData, IDungeonState state) { if (dungeonData == null) { throw new ArgumentNullException(nameof(dungeonData)); } if (!_requirement.Met) { return(false); } int accessible = 0; int inaccessible = 0; foreach (var item in _bigKeyLocations) { switch (dungeonData.DungeonItems[item].Accessibility) { case AccessibilityLevel.SequenceBreak: { if (state.SequenceBreak) { accessible++; } else { inaccessible++; } } break; case AccessibilityLevel.Normal: { accessible++; } break; default: { inaccessible++; } break; } } if (state.BigKeyCollected && accessible == 0) { return(false); } if (!state.BigKeyCollected && inaccessible == 0) { return(false); } foreach (var child in _children) { if (child.CanBeTrue(dungeonData, state)) { return(true); } } return(false); }