public IASTNode Parse() { // Parse the query string into an HQL AST. var lex = new HqlLexer(new CaseInsensitiveStringStream(_hql)); _tokens = new CommonTokenStream(lex); var parser = new HqlParser(_tokens) { TreeAdaptor = new ASTTreeAdaptor(), Filter = _filter }; if (log.IsDebugEnabled) { log.Debug("parse() - HQL: " + _hql); } try { var ast = (IASTNode)parser.statement().Tree; var walker = new NodeTraverser(new ConstantConverter(_sfi)); walker.TraverseDepthFirst(ast); return(ast); } finally { parser.ParseErrorHandler.ThrowQueryException(); } }
public void TraversesSequenceNodes() { var document = @" lorem: - name: ipsum dolor: 1 - sit: 2 amet: - adipiscing: 3 "; var result = new NodeTraverser().Traverse(Parser.Parse(document)); Assert.Equal(new object[] { }, result.ElementAt(0).Path.Segments); Assert.IsType <YamlMappingNode>(result.ElementAt(0).Node); Assert.Equal(new object[] { "lorem" }, result.ElementAt(1).Path.Segments); Assert.IsType <YamlSequenceNode>(result.ElementAt(1).Node); Assert.Equal(new object[] { "amet" }, result.ElementAt(2).Path.Segments); Assert.IsType <YamlSequenceNode>(result.ElementAt(2).Node); Assert.Equal(new object[] { "lorem", 0 }, result.ElementAt(3).Path.Segments); Assert.IsType <YamlMappingNode>(result.ElementAt(3).Node); Assert.Equal(new object[] { "lorem", 1 }, result.ElementAt(4).Path.Segments); Assert.IsType <YamlMappingNode>(result.ElementAt(4).Node); Assert.Equal(new object[] { "amet", 0 }, result.ElementAt(5).Path.Segments); Assert.IsType <YamlMappingNode>(result.ElementAt(5).Node); }
public Node(int index, T value) { this.Index = index; this.Children = new NodeChildren <T>(); this.Value = value; this.Traverse = new NodeTraverser <T>(this); }
public Node(int index, T value) { Index = index; Children = new NodeChildren <T>(); Value = value; Traverse = new NodeTraverser <T>(this); }
private IList <IASTNode> LocateParameters() { var nodeTraverser = new NodeTraverser(this); nodeTraverser.TraverseDepthFirst(_tree); return(_nodes); }
public IList <IASTNode> LocateQuerySources() { // Find all the polymorphic query sources var nodeTraverser = new NodeTraverser(this); nodeTraverser.TraverseDepthFirst(_tree); return(_nodes); }
public void TraversesMappingNodes() { var document = @" lorem: ipsum "; var result = new NodeTraverser().Traverse(Parser.Parse(document)); Assert.Single(result); Assert.Equal(new object[] { }, result.Single().Path.Segments); Assert.IsType <YamlMappingNode>(result.Single().Node); }
public void TraversesNestedMappingNodes() { var document = @" lorem: ipsum: dolor "; var result = new NodeTraverser().Traverse(Parser.Parse(document)); Assert.Equal(2, result.Count()); Assert.Equal(new object[] { }, result.First().Path.Segments); Assert.IsType <YamlMappingNode>(result.First().Node); Assert.Equal(new object[] { "lorem" }, result.Last().Path.Segments); Assert.IsType <YamlMappingNode>(result.Last().Node); }
public void TestBeatable(string mapId, bool expected) { //Arrange var resourceReader = new System.IO.StreamReader(new System.IO.MemoryStream(Properties.Resources.TestLogic)); var data = JsonConvert.DeserializeObject <Common.SaveData.SaveData>(resourceReader.ReadToEnd()); var randomMap = TestData.Data[mapId]; var traverser = new NodeTraverser(); // Act var result = traverser.VerifyBeatable(data, randomMap); // Assert Assert.Equal(expected, result); }
private static void GenerateXml(NodeGen nodeGen, string xmlFileName, Options options) { if (!options.Silent) { Console.WriteLine("Generating game tree..."); } var rootNode0 = nodeGen.Generate(); XElement xElement = new XElement("Node"); NodeTraverser.TraverseToXml(xElement, rootNode0); XDocument doc = new XDocument(xElement); doc.Save(xmlFileName); }
private void HandleWithFragment(FromElement fromElement, IASTNode hqlWithNode) { try { ITreeNodeStream old = input; input = new CommonTreeNodeStream(adaptor, hqlWithNode); IASTNode hqlSqlWithNode = (IASTNode)withClause().Tree; input = old; if (log.IsDebugEnabled()) { log.Debug("handleWithFragment() : {0}", _printer.ShowAsString(hqlSqlWithNode, "-- with clause --")); } WithClauseVisitor visitor = new WithClauseVisitor(fromElement); NodeTraverser traverser = new NodeTraverser(visitor); traverser.TraverseDepthFirst(hqlSqlWithNode); FromElement referencedFromElement = visitor.GetReferencedFromElement(); if (referencedFromElement != fromElement) { if (!referencedFromElement.IsEntityJoin() && !fromElement.IsEntityJoin()) { throw new InvalidWithClauseException( "with-clause expressions did not reference from-clause element to which the with-clause was associated"); } } SqlGenerator sql = new SqlGenerator(_sessionFactoryHelper.Factory, new CommonTreeNodeStream(adaptor, hqlSqlWithNode.GetChild(0))); sql.whereExpr(); var withClauseFragment = new SqlString("(", sql.GetSQL(), ")"); fromElement.SetWithClauseFragment(visitor.GetJoinAlias(), withClauseFragment); } catch (SemanticException) { throw; } catch (InvalidWithClauseException) { throw; } catch (Exception e) { throw new SemanticException(e.Message, e); } }
public void WriteToDb(int hand, Node rootNode, Action <int> nodesWritten = null) { using (MySqlConnection c = ConnectToDatabase()) { using (MySqlCommand cmd = new MySqlCommand("", c)) { string initialString = $"SET autocommit=0; INSERT INTO {DbName} (`Player`, `Hand`, `Actions`, `Round`, `NextPlayer`, `Pay`, `PossibleActions`, `Cfr`) VALUES "; StringBuilder sb = new StringBuilder(initialString); int i = 0; int total = 0; NodeTraverser.TraverseWithAction(rootNode, (node, actions) => { string nextPlayer = node.Children.Length > 0 ? node.Children[0].Pos.ToString() : "NULL"; string pay = node.IsTerminal() ? node.PayOff.ToString() : "NULL"; float[] avStrategy = node.GetAverageStrategy(hand); string cfr = avStrategy.Any() ? $"'{string.Join(";", avStrategy)}'" : "NULL"; string possibleActions = node.IsTerminal() ? "NULL" : $"'{string.Join(",", node.Children.Select(x => x.Action.ToShortString()))}'"; sb.Append($"({node.Pos}, {hand}, '{actions}', {(int)node.Round}, {nextPlayer}, {pay}, {possibleActions}, {cfr}),"); i++; total++; if (i > MaxInsertsPerQuery) { sb[sb.Length - 1] = ';'; sb.AppendLine("COMMIT;"); cmd.CommandText = sb.ToString(); cmd.ExecuteNonQuery(); sb.Clear(); sb.Append(initialString); i = 0; nodesWritten?.Invoke(total); } }); sb[sb.Length - 1] = ';'; sb.AppendLine("COMMIT;"); cmd.CommandText = sb.ToString(); cmd.ExecuteNonQuery(); nodesWritten?.Invoke(total); } } }
private void HandleWithFragment(FromElement fromElement, IASTNode hqlWithNode) { try { ITreeNodeStream old = input; input = new CommonTreeNodeStream(adaptor, hqlWithNode); IASTNode hqlSqlWithNode = (IASTNode)withClause().Tree; input = old; if (log.IsDebugEnabled()) { log.Debug("handleWithFragment() : {0}", _printer.ShowAsString(hqlSqlWithNode, "-- with clause --")); } WithClauseVisitor visitor = new WithClauseVisitor(fromElement); NodeTraverser traverser = new NodeTraverser(visitor); traverser.TraverseDepthFirst(hqlSqlWithNode); SqlGenerator sql = new SqlGenerator(_sessionFactoryHelper.Factory, new CommonTreeNodeStream(adaptor, hqlSqlWithNode.GetChild(0))); sql.whereExpr(); fromElement.WithClauseFragment = new SqlString("(", sql.GetSQL(), ")"); } catch (SemanticException) { throw; } catch (InvalidWithClauseException) { throw; } catch (Exception e) { throw new SemanticException(e.Message, e); } }
public Dictionary <string, Guid> FillLocations(SaveData someData, FillOptions options, ItemPool pool, Inventory startingInventory, Random random, Dictionary <string, Guid> originalItemMap) { Log = new LogLayer("Item Placement"); var inventory = new Inventory(startingInventory); var nodeCollection = new NodeCollection(); nodeCollection.InitializeNodes(someData); keyNodes = nodeCollection.myNodes.Where(node => node is KeyNode).ToList(); var eventNodes = keyNodes.Where(node => node is EventKeyNode).Select(node => node as EventKeyNode); startNode = eventNodes.FirstOrDefault(node => node.myKeyId == StaticKeys.GameStart); endNode = eventNodes.FirstOrDefault(node => node.myKeyId == StaticKeys.GameFinish); charlieNode = eventNodes.FirstOrDefault(node => node.myKeyId == StaticKeys.CharlieDefeated); // Generate Item map var itemMap = new Dictionary <string, Guid>(originalItemMap); if (options.majorSwap == FillOptions.ItemSwap.Unchanged || options.minorSwap == FillOptions.ItemSwap.Unchanged) { var allRandomKeyNodes = keyNodes.Where(node => node is RandomKeyNode randomNode).Select(node => node as RandomKeyNode).OrderBy(node => node.id); var openRandomKeyNodes = allRandomKeyNodes.Where(node => !itemMap.ContainsKey(node.myRandomKeyIdentifier)); foreach (var keyNode in openRandomKeyNodes) { var item = keyNode.GetOriginalKey(); if (item == null) { continue; } if ((StaticKeys.IsMajorItem(item.Id) && options.majorSwap == FillOptions.ItemSwap.Unchanged) || (StaticKeys.IsMinorItem(item.Id) && options.minorSwap == FillOptions.ItemSwap.Unchanged)) { var pulled = pool.Pull(item.Id); if (pulled) { itemMap.Add(keyNode.myRandomKeyIdentifier, item.Id); } } } } KeyManager.SetRandomKeyMap(itemMap); // Set up location rules itemRequiredLocationRules = ItemRuleUtility.GetRequiredLocationRules(options.itemRules); itemBlockedLocationRules = ItemRuleUtility.GetBlockedLocationRules(options.itemRules); restrictedLocations = new HashSet <string>(); if (itemRequiredLocationRules.Any()) { Log.AddChild("RequiredLocationRules", itemRequiredLocationRules.Select(group => new LogLayer(KeyManager.GetKeyName(group.Key), group.Value))); } if (itemBlockedLocationRules.Any()) { Log.AddChild("BlockedLocationRules", itemBlockedLocationRules.Select(group => new LogLayer(KeyManager.GetKeyName(group.Key), group.Value))); } UpdateLocationRestrictions(inventory, itemMap, pool, random, Log); // Initialize search terms searcher = new FillSearcher(); var reachableKeys = new List <NodeBase>(); var retracableKeys = new List <NodeBase>(); var restrictedItems = new List <Guid>(); var searchDepth = 0; var stepCount = 1; if (options.gameCompletion == FillOptions.GameCompletion.NoLogic) { Log.AddChild("Game Completion has No Logic - Skipping standard steps"); } else { var logSteps = Log.AddChild("Standard Steps"); while (true) { var logCurrentStep = logSteps.AddChild($"Step {stepCount++}, depth {searchDepth}"); logCurrentStep.AddChild(inventory.GetKeyLog()); // Beatable conditional if (options.gameCompletion == FillOptions.GameCompletion.Beatable && inventory.myNodes.Contains(endNode)) { logCurrentStep.AddChild($"EndNode reached"); break; } // Do not place any power bombs until obtaining powered suit restrictedItems.Clear(); if (options.noEarlyPbs && !inventory.ContainsKey(StaticKeys.CharlieDefeated)) { restrictedItems.Add(StaticKeys.PowerBombs); } var itemDepthRestrictions = options.itemRules.Where(rest => rest is ItemRuleRestrictedBeforeDepth depthRest && depthRest.SearchDepth > searchDepth); if (itemDepthRestrictions.Any()) { restrictedItems.AddRange(itemDepthRestrictions.Select(rest => rest.ItemId)); } if (restrictedItems.Any()) { logCurrentStep.AddChild("Restricted Items", restrictedItems.Select(key => KeyManager.GetKeyName(key))); } // Find all nodes that can be reached with current inventory reachableKeys.RemoveAll(node => inventory.myNodes.Contains(node)); reachableKeys.AddRange(searcher.ContinueSearch(startNode, inventory, node => (node is KeyNode) && !inventory.myNodes.Contains(node))); logCurrentStep.AddChild("Reachable keys", reachableKeys.Select(node => node.Name())); // Find all reachable keys that are also possible to get back from // (End node is always considered retracable, since being able to reach it at all is just akin to "being in go mode") retracableKeys.RemoveAll(node => inventory.myNodes.Contains(node)); var notRetracable = reachableKeys.Except(retracableKeys); retracableKeys.AddRange(notRetracable.AsParallel().Where(node => node == endNode || NodeTraverser.PathExists(node, startNode, node is EventKeyNode ? inventory.Expand(node) : inventory)).ToList()); logCurrentStep.AddChild("Retracable keys", retracableKeys.Select(node => node.Name())); if (!retracableKeys.Any()) { break; } // If any events can be reached, add to inventory and update search before continuing var retracableEvents = retracableKeys.Where(node => node is EventKeyNode).ToList(); if (retracableEvents.Any()) { logCurrentStep.AddChild("Retracable events", retracableEvents.Select(node => node.Name())); inventory.myNodes.AddRange(retracableEvents); continue; } var randomizedLocations = retracableKeys.Where(key => key is RandomKeyNode randomNode).Select(key => key as RandomKeyNode).OrderBy(x => x.id).ToList(); // Pick up any items already filled in on the map and update search before placing any items var preFilledLocations = randomizedLocations.Where(loc => itemMap.ContainsKey(loc.myRandomKeyIdentifier)); if (preFilledLocations.Any()) { logCurrentStep.AddChild("Prefilled locations", preFilledLocations.Select(node => $"{node.Name()} - {node.GetKeyName()}")); inventory.myNodes.AddRange(preFilledLocations); continue; } // Get items that are prioritized according to item rules var prioritizedItems = options.itemRules.Where(rest => rest is ItemRulePrioritizedAfterDepth depthRest && depthRest.SearchDepth <= searchDepth) .Select(rest => rest.ItemId) .Where(item => !restrictedItems.Contains(item) && !inventory.ContainsKey(item)) .ToList(); logCurrentStep.AddChild("Prioritized Items", prioritizedItems.Select(key => KeyManager.GetKeyName(key))); var selectedRelevantKey = FindRelevantKey(inventory, searcher, options, randomizedLocations, reachableKeys.Except(retracableKeys), restrictedItems, prioritizedItems, pool, itemMap, random, logCurrentStep); // Special case to handle how chozodia area is built // Specifically can't get out of it without power bombs, which creates awkward dynamics regarding the placements of said power bombs) // Special case triggers on reaching charlie when no early pbs is enabled if (reachableKeys.Any(key => key is EventKeyNode eventKey && eventKey.myKeyId == StaticKeys.CharlieDefeated) && options.noEarlyPbs && (NodeTraverser.PathExists(charlieNode, endNode, inventory.Expand(charlieNode)) || selectedRelevantKey == Guid.Empty)) { FillRandomly(restrictedItems, inventory, options, itemMap, pool, random, logCurrentStep.AddChild("Charlie random fill")); if (!inventory.ContainsKey(StaticKeys.CharlieDefeated)) { // Unless Charlie was for some reason reached during fill, start new search with Charlie as new start node startNode = charlieNode; inventory.myNodes.Add(startNode); searcher = new FillSearcher(); } continue; } if (selectedRelevantKey == Guid.Empty) { break; } // Filter out available locations where selected key cannot be placed var filteredLocations = randomizedLocations.Where(location => KeyAllowedInLocation(selectedRelevantKey, options, itemMap, pool, location)).OrderBy(x => x.id).ToList(); logCurrentStep.AddChild("Filtered Locations", filteredLocations.Select(node => node.Name())); if (!filteredLocations.Any()) { break; } pool.Pull(selectedRelevantKey); // Pick out one random accessible location, place the selected key there and add that item to inventory var selectedLocation = filteredLocations.ElementAt(random.Next(filteredLocations.Count)); randomizedLocations.Remove(selectedLocation); itemMap.Add(selectedLocation.myRandomKeyIdentifier, selectedRelevantKey); inventory.myNodes.Add(selectedLocation); logCurrentStep.AddChild($"Selected Location: {selectedLocation.Name()}"); prioritizedItems.Remove(selectedRelevantKey); // Only increase searchDepth if an actual item is placed (debatable if this is the correct approach) searchDepth++; UpdateLocationRestrictions(inventory, itemMap, pool, random, logCurrentStep); // Fill remaining accessible locations with random items if (options.majorSwap != FillOptions.ItemSwap.LocalPool && options.minorSwap != FillOptions.ItemSwap.LocalPool) { var randomizedLocationLog = logCurrentStep.AddChild("Randomized Locations"); foreach (var node in randomizedLocations) { var locationLog = randomizedLocationLog.AddChild(node.Name()); // This is possible through Required Location Rules if (itemMap.ContainsKey(node.myRandomKeyIdentifier)) { locationLog.AddChild($"Already filled with: {node.GetKeyName()}"); inventory.myNodes.Add(node); continue; } var filteredPrioritizedItems = prioritizedItems.Where(key => KeyAllowedInLocation(key, options, itemMap, pool, node)); if (filteredPrioritizedItems.Any()) { locationLog.AddChild("Filtered Prioritized Items", filteredPrioritizedItems.Select(key => KeyManager.GetKeyName(key))); var randomKey = pool.PullAmong(filteredPrioritizedItems, random); prioritizedItems.Remove(randomKey); itemMap.Add(node.myRandomKeyIdentifier, randomKey); inventory.myNodes.Add(node); locationLog.Message += $" : {KeyManager.GetKeyName(randomKey)}"; locationLog.AddChild($"Prioritized Key placed: {KeyManager.GetKeyName(randomKey)}"); } else { // Add all items that cannot be in this location to restrictedItems var locationRestrictedItems = restrictedItems.Union(pool.AvailableItems().Where(key => !KeyAllowedInLocation(key, options, itemMap, pool, node))); locationLog.AddChild("Location Restricted Items", locationRestrictedItems.Select(key => KeyManager.GetKeyName(key))); var selectedKey = pool.PullExcept(locationRestrictedItems, random); if (selectedKey != Guid.Empty) { itemMap.Add(node.myRandomKeyIdentifier, selectedKey); inventory.myNodes.Add(node); locationLog.Message += $" : {KeyManager.GetKeyName(selectedKey)}"; locationLog.AddChild($"Selected Key placed: {KeyManager.GetKeyName(selectedKey)}"); } } UpdateLocationRestrictions(inventory, itemMap, pool, random, locationLog); } } // Go back to start of loop to continue search with updated inventory } } var postFillLog = Log.AddChild("Post fill"); // POST-FILL: // Reachable if seed is beatable or if it ran out of possible relevant keys // Fill in remaining locations as well as possible without breaking any restrictions // Do not place any power bombs until obtaining powered suit restrictedItems.Clear(); if (options.noEarlyPbs && !inventory.ContainsKey(StaticKeys.CharlieDefeated)) { restrictedItems.Add(StaticKeys.PowerBombs); } postFillLog.AddChild("Restricted Items", restrictedItems.Select(key => KeyManager.GetKeyName(key))); if (options.gameCompletion == FillOptions.GameCompletion.AllItems) { var nonEmptyLog = postFillLog.AddChild("Add non-empty items"); // Prioritize filling in non-empty items var restrictedAndEmpty = new List <Guid>(restrictedItems); restrictedAndEmpty.Add(StaticKeys.Nothing); FillRandomly(restrictedAndEmpty, inventory, options, itemMap, pool, random, nonEmptyLog); } var reachableLog = postFillLog.AddChild("Fill remaining reachable locations"); // Fill remaining reachable nodes randomly FillRandomly(restrictedItems, inventory, options, itemMap, pool, random, reachableLog); restrictedItems.Clear(); // Fill all remaining (unreachable) locations with any remaining items var remainingNodes = keyNodes.Where(node => node is RandomKeyNode randomNode && !itemMap.ContainsKey(randomNode.myRandomKeyIdentifier)).Select(key => key as RandomKeyNode).OrderBy(x => x.id); if (remainingNodes.Any()) { var respectableLog = postFillLog.AddChild("Fill unreachable locations"); FillRandomly(remainingNodes, restrictedItems, inventory, options, itemMap, pool, random, respectableLog); } // Fill final locations with blanks var finalEmptyLocations = keyNodes.Where(node => node is RandomKeyNode randomNode && !itemMap.ContainsKey(randomNode.myRandomKeyIdentifier)).Select(key => key as RandomKeyNode).OrderBy(x => x.id); if (finalEmptyLocations.Any()) { var finalFill = postFillLog.AddChild("Final fill"); foreach (var node in finalEmptyLocations) { if (itemMap.ContainsKey(node.myRandomKeyIdentifier)) { continue; } var locationLog = finalFill.AddChild(node.myRandomKeyIdentifier); var item = StaticKeys.Nothing; locationLog.Message += $" : {KeyManager.GetKeyName(item)}"; locationLog.AddChild($"Selected item: {KeyManager.GetKeyName(item)}"); itemMap.Add(node.myRandomKeyIdentifier, item); UpdateLocationRestrictions(inventory, itemMap, pool, random, locationLog); } } return(itemMap); }
private void FillRandomly(List <Guid> restrictedItems, Inventory inventory, FillOptions options, Dictionary <string, Guid> itemMap, ItemPool pool, Random random, LogLayer log) { var fillLog = log.AddChild("Random Fill"); fillLog.AddChild("Restricted Items", restrictedItems.Select(key => KeyManager.GetKeyName(key))); var reachableNodes = new List <NodeBase>(); var localSearcher = new FillSearcher(); // Fill all still reachable random nodes int stepCount = 1; while (true) { var stepLog = new LogLayer($"Step {stepCount++}"); stepLog.AddChild(inventory.GetKeyLog()); reachableNodes.RemoveAll(node => inventory.myNodes.Contains(node)); reachableNodes.AddRange(localSearcher.ContinueSearch(startNode, inventory, node => (node is KeyNode) && !inventory.myNodes.Contains(node))); stepLog.AddChild(new LogLayer("Reachable Nodes", reachableNodes.Select(node => node.Name()))); var retracableKeys = reachableNodes.AsParallel().Where(node => node == endNode || NodeTraverser.PathExists(node, startNode, node is EventKeyNode ? inventory.Expand(node) : inventory)).ToList(); // Find all reachable events that are also possible to get back from var retracableEvents = retracableKeys.Where(node => node is EventKeyNode); // If any events can be reached, add to inventory and update search before continuing if (retracableEvents.Any()) { stepLog.AddChild("Retracable events", retracableEvents.Select(node => node.Name())); fillLog.AddChild(stepLog); inventory.myNodes.AddRange(retracableEvents); continue; } var fillNodes = retracableKeys.Any() ? retracableKeys : reachableNodes; var fillRandomKeyNodes = fillNodes.Where(node => node is RandomKeyNode).Select(node => node as RandomKeyNode).OrderBy(x => x.id); var addedNodes = FillRandomly(fillRandomKeyNodes, restrictedItems, inventory, options, itemMap, pool, random, stepLog); if (!addedNodes) { break; } fillLog.AddChild(stepLog); } }
public static void DoTest() { var fileNames = new List <string>(Directory.GetFiles(Environment.CurrentDirectory)); var logicFile = ChooseLogic(fileNames.Where(x => Path.GetExtension(x) == ".lgc").ToList()); if (logicFile == null) { // Log issue _logMessage += $"No logic file chosen{Environment.NewLine}"; return; } var itemFile = ChooseItems(fileNames.Where(x => Path.GetExtension(x) == ".txt" || Path.GetExtension(x) == ".log").ToList()); if (itemFile == null) { // Log issue _logMessage += $"No item file chosen{Environment.NewLine}"; return; } var data = JsonConvert.DeserializeObject <SaveData>(File.ReadAllText(logicFile)); KeyManager.Initialize(data); var inventoryKeys = ParseInventory(itemFile); if (inventoryKeys == null) { // Error logged in parser return; } var randomMap = ParseItemMap(data, itemFile); if (randomMap == null) { // Error logged in parser return; } Console.WriteLine(); var traverser = new NodeTraverser(); var inventory = new Inventory(); inventory.myKeys = inventoryKeys; _Timer.Start(); //for (int count = 0; count < 100; count++) { _logMessage += Environment.NewLine; var fullCompleteResult = traverser.VerifyFullCompletable(data, randomMap, new Inventory(inventory)); _logMessage += $"100%: {fullCompleteResult}{Environment.NewLine}{traverser.GetWaveLog()}{Environment.NewLine}{Environment.NewLine}"; var unreachablenodes = traverser.GetUnreachable(); if (unreachablenodes.Any()) { _logMessage += $"Unreachable: {traverser.GetUnreachable().Select(node => Utility.GetNodeName(node) + (node is RandomKeyNode keyNode? $"({(keyNode.GetKey() is BaseKey key ? key.Name : "empty")})" : string.Empty)).Aggregate((i, j) => i + ", " + j)}{Environment.NewLine}{Environment.NewLine}"; } var beatableResult = traverser.VerifyBeatable(data, randomMap, new Inventory(inventory)); _logMessage += $"Beatable: {beatableResult}{Environment.NewLine}{traverser.GetWaveLog()}"; } _Timer.Stop(); }
public static void Randomize() { var fileNames = new List <string>(Directory.GetFiles(Environment.CurrentDirectory)); var logicFile = ChooseLogic(fileNames.Where(x => Path.GetExtension(x) == ".lgc").ToList()); if (logicFile == null) { // Log issue _logMessage += $"No logic file chosen{Environment.NewLine}"; } var data = JsonConvert.DeserializeObject <SaveData>(File.ReadAllText(logicFile)); KeyManager.Initialize(data); var traverser = new NodeTraverser(); var settingsFile = ChooseSettings(fileNames.Where(x => Path.GetExtension(x) == ".txt" || Path.GetExtension(x) == ".log").ToList()); if (settingsFile == null) { // Log issue _logMessage += $"No settings chosen{Environment.NewLine}"; } if (!TryParseSettingsFile(startingInventory, settingsFile)) { // Log issue _logMessage += "Failed to parse settings"; } var randomizationType = ChooseRandomization(); var gameCompletion = ChooseGameCompletion(); var random = new Random(); var seed = random.Next(); // var seed = 1083686163; var count = 0; _Timer.Start(); while (true) { if (randomizationType == 1) { var placer = new ItemPlacer(); var options = new FillOptions(); options.gameCompletion = gameCompletion; options.majorSwap = FillOptions.ItemSwap.GlobalPool; options.minorSwap = FillOptions.ItemSwap.LocalPool; // options.noEarlyPbs = true; var result = false; var itemMap = new Dictionary <string, Guid>(); ItemPool pool = new ItemPool(); pool.CreatePool(); foreach (var item in itemMap.Values) { pool.Pull(item); } while (true) { random = new Random(seed); //pool.RemoveRandomItemsExcept(90, random, new List<Guid>() { StaticKeys.Morph, StaticKeys.Missile, StaticKeys.Bombs, StaticKeys.IceBeam, StaticKeys.PlasmaBeam }); var testInventory = new Inventory(startingInventory); testInventory.myKeys.AddRange(pool.AvailableItems().Where(key => key != StaticKeys.Nothing && (!options.noEarlyPbs || key != StaticKeys.PowerBombs)).Select(id => KeyManager.GetKey(id))); if (traverser.VerifyBeatable(data, itemMap, testInventory)) { break; } seed = random.Next(); pool.CreatePool(); foreach (var item in itemMap.Values) { pool.Pull(item); } } random = new Random(seed); var randomMap = placer.FillLocations(data, options, pool, startingInventory, random, itemMap); if (gameCompletion == FillOptions.GameCompletion.Beatable) { result = traverser.VerifyBeatable(data, randomMap, new Inventory(startingInventory)); } else if (gameCompletion == FillOptions.GameCompletion.AllItems) { result = traverser.VerifyFullCompletable(data, randomMap, new Inventory(startingInventory)); } if (result) { Console.WriteLine($"{Environment.NewLine}Randomization complete after {count} attempts - Successful seed: {seed}"); Console.WriteLine(traverser.GetWaveLog()); _Timer.Stop(); resultItemMap = randomMap; return; } seed = random.Next(); Console.WriteLine($"Attempts {count}"); } else if (randomizationType == 2) { var pool = new ItemPool(); pool.CreatePool(); random = new Random(seed); var randomMap = StaticData.Locations.ToDictionary(location => location, location => pool.Pull(random)); var morphItem = randomMap.FirstOrDefault(x => x.Value.Equals(StaticKeys.Morph)); if (string.IsNullOrWhiteSpace(morphItem.Key)) { seed = random.Next(); continue; } var morphLocation = randomMap.FirstOrDefault(x => x.Key.Equals("BrinstarMorph")); randomMap[morphItem.Key] = morphLocation.Value; randomMap[morphLocation.Key] = StaticKeys.Morph; var result = false; if (gameCompletion == FillOptions.GameCompletion.Beatable) { result = traverser.VerifyBeatable(data, randomMap, new Inventory(startingInventory)); } else if (gameCompletion == FillOptions.GameCompletion.AllItems) { result = traverser.VerifyFullCompletable(data, randomMap, new Inventory(startingInventory)); } if (result) { Console.WriteLine($"Randomization complete after {count} attempts - Successful seed: {seed}"); _Timer.Stop(); resultItemMap = randomMap; return; } if (count % 50 == 0) { Console.WriteLine($"Attempts {count}"); } } count++; seed = random.Next(); } }
private Guid FindRelevantKey(Inventory inventory, FillSearcher aSearcher, FillOptions options, IEnumerable <RandomKeyNode> availableLocations, IEnumerable <NodeBase> unRetracableKeys, IEnumerable <Guid> restrictedItems, IEnumerable <Guid> prioritizedItems, ItemPool pool, Dictionary <string, Guid> itemMap, Random random, LogLayer log) { var relevantKeyLog = log.AddChild("Relevant Key"); var relevantKeys = new Dictionary <Guid, List <NodeBase> >(); foreach (var item in pool.AvailableItems().Distinct().Where(key => !restrictedItems.Contains(key))) { var testInventory = inventory.Expand(KeyManager.GetKey(item)); var tempSearcher = new FillSearcher(aSearcher); var currentKeyLog = relevantKeyLog.AddChild(KeyManager.GetKeyName(item)); var reachableKeys = new List <NodeBase>(); bool searchAgain; do { // Find all nodes that can be reached with current inventory reachableKeys.RemoveAll(node => testInventory.myNodes.Contains(node)); reachableKeys.AddRange(tempSearcher.ContinueSearch(testInventory, node => (node is KeyNode) && !testInventory.myNodes.Contains(node))); var combinedReachableKeys = unRetracableKeys.Where(key => !testInventory.myNodes.Contains(key)).Union(reachableKeys); searchAgain = false; var retracableKeys = combinedReachableKeys.AsParallel().Where(node => node == endNode || NodeTraverser.PathExists(node, startNode, node is EventKeyNode ? testInventory.Expand(node) : testInventory)).ToList(); if (retracableKeys.Any()) { // If any events can be reached, add to inventory and update search before continuing var retracableEvents = retracableKeys.Where(node => node is EventKeyNode).ToList(); if (retracableEvents.Any()) { currentKeyLog.AddChild("Retracable events", retracableEvents.Select(node => node.Name())); testInventory.myNodes.AddRange(retracableEvents); // Prioritize item that will let you beat the game if (retracableEvents.Any(node => node == endNode)) { relevantKeyLog.Message += $" : {KeyManager.GetKeyName(item)}"; return(item); } searchAgain = true; continue; } var randomizedLocations = retracableKeys.Where(key => key is RandomKeyNode randomNode).Select(key => key as RandomKeyNode).OrderBy(x => x.id).ToList(); // Pick up any items already filled in on the map and update search before placing any items var preFilledLocations = randomizedLocations.Where(loc => itemMap.ContainsKey(loc.myRandomKeyIdentifier)); if (preFilledLocations.Any()) { currentKeyLog.AddChild("Prefilled locations", preFilledLocations.Select(node => $"{node.Name()} - {node.GetKeyName()}")); testInventory.myNodes.AddRange(preFilledLocations); searchAgain = true; continue; } currentKeyLog.AddChild($"Locations", retracableKeys.Select(key => key.Name())); relevantKeys.Add(item, retracableKeys); } } while (searchAgain); } // Filter out any keys that by rules cannot be placed in any available location var filteredKeys = relevantKeys.Where(key => availableLocations.Any(location => KeyAllowedInLocation(key.Key, options, itemMap, pool, location))).ToDictionary(key => key.Key, key => key.Value); relevantKeyLog.AddChild("Filtered Keys", filteredKeys.Select(key => $"{KeyManager.GetKeyName(key.Key)}")); if (!filteredKeys.Any()) { return(Guid.Empty); } // Correlate prioritized and relevant keys var prioritizedRelevantKeys = filteredKeys.Where(key => prioritizedItems.Contains(key.Key)); if (prioritizedRelevantKeys.Any()) { filteredKeys = prioritizedRelevantKeys.ToDictionary(key => key.Key, key => key.Value); } relevantKeyLog.AddChild("Prioritized Relevant Keys", filteredKeys.Select(key => $"{KeyManager.GetKeyName(key.Key)}")); // Prioritize items that open up major location for local swaps if (options.majorSwap == FillOptions.ItemSwap.LocalPool || options.minorSwap == FillOptions.ItemSwap.LocalPool) { var keysWithMajorLocation = filteredKeys.Where(key => key.Value.Any(location => StaticKeys.IsMajorLocation(location))); if (keysWithMajorLocation.Any()) { filteredKeys = keysWithMajorLocation.ToDictionary(key => key.Key, key => key.Value); } } // Avoid sprawl calculation bias if value is not set or there is only one item to choose from if (options.SprawlFactor == 0 || filteredKeys.Count < 2) { var item = pool.PeekAmong(filteredKeys.Keys, random); relevantKeyLog.Message += $" : {KeyManager.GetKeyName(item)}"; relevantKeyLog.AddChild($"Item pulled from pool: {KeyManager.GetKeyName(item)}"); return(item); } relevantKeyLog.AddChild($"Sprawl factor: {options.SprawlFactor}"); // Translate sprawl factor to a decimal var sprawl = ((double)options.SprawlFactor) / 10; // Weight is numberOfLocationsUnlocked ^ sprawl var keysGroupedByWeight = filteredKeys.ToLookup(key => key.Value.Count, key => key.Key).Select(group => new KeyValuePair <double, List <Guid> >(Math.Pow(group.Key, sprawl), group.ToList())).OrderBy(pair => pair.Key); relevantKeyLog.AddChild("Keys with weights", keysGroupedByWeight.SelectMany(group => group.Value.Select(key => $"{KeyManager.GetKeyName(key)} - {group.Key}"))); // Sum of all weights var weightSum = keysGroupedByWeight.Select(pair => pair.Key).Sum(); relevantKeyLog.AddChild($"Sum of Weights: {weightSum}"); // Pick random number between 0 and weightSum var weightRandom = random.NextDouble() * weightSum; relevantKeyLog.AddChild($"Weight Random: {weightRandom}"); // Remove weight from random value until it goes below zero then pick that key foreach (var key in keysGroupedByWeight) { weightRandom -= key.Key; if (weightRandom < 0) { relevantKeyLog.AddChild($"Chosen weight: {key.Key}"); var item = pool.PeekAmong(key.Value, random); relevantKeyLog.Message += $" : {KeyManager.GetKeyName(item)}"; relevantKeyLog.AddChild($"Selected Key: {KeyManager.GetKeyName(item)}"); return(item); } } relevantKeyLog.AddChild($"No Key Selected"); return(Guid.Empty); }