private static void VerifyConverterDecksAreEqual(ConverterDeck converterDeck, ConverterDeck otherConverterDeck) { for (int cs = 0; cs < converterDeck.ConverterSections.Count; cs++) { VerifyConverterSectionsAreIdentical(converterDeck.ConverterSections[cs], otherConverterDeck.ConverterSections[cs]); } }
/// <summary> /// Converts a LoTR URL from cardgamedb.com into a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="url">The URL of the Deck</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck which is populated with all cards and deck name</returns> private static ConverterDeck ConvertURL_cardgamedb_com_LoTR(string url, IEnumerable<string> deckSectionNames) { object htmlWebInstance = HtmlAgilityPackWrapper.HtmlWeb_CreateInstance(); object htmlDocumentInstance = HtmlAgilityPackWrapper.HtmlWeb_InvokeMethod_Load(htmlWebInstance, url); object htmlDocument_DocumentNode = HtmlAgilityPackWrapper.HtmlDocument_GetProperty_DocumentNode(htmlDocumentInstance); // Find the div with class name 'category_block block_wrap clear' object deckDivHtmlNode = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(htmlDocument_DocumentNode, "//div[@class='category_block block_wrap clear']"); // Find the table inside deckDiv, because one of the rows contains all of the cards object deckTableHtmlNode = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(deckDivHtmlNode, "table"); ////Find all 'tr' nodes, because one of them contains all of the cards System.Collections.IEnumerable deckTRHtmlNodes = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectNodes(deckTableHtmlNode, "tr"); foreach (object tableRowHtmlNode in deckTRHtmlNodes) { // Get the second td node object secondTDHtmlNode = HtmlAgilityPackWrapper.HtmlNode_InvokeMethod_SelectSingleNode(tableRowHtmlNode, @"td[2]"); // Check if the TD contains 'Total Cards (' string innerText = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(secondTDHtmlNode); if (innerText.Contains("Total Cards (")) { Dictionary<string, IEnumerable<Tuple<string, string>>> deckSectionLinesAndSets = new Dictionary<string, IEnumerable<Tuple<string, string>>>(); List<Tuple<string, string>> currentSectionLinesAndSets = null; string currentLineCardName = null; string currentSetName = null; foreach (object childNode in HtmlAgilityPackWrapper.HtmlNode_GetProperty_ChildNodes(secondTDHtmlNode)) { string nodeName = HtmlAgilityPackWrapper.HtmlNode_GetProperty_Name(childNode); if (nodeName.Equals("strong")) { string sectionText = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(childNode); string deckSectionName = deckSectionNames.FirstOrDefault(dsn => sectionText.ToLowerInvariant().Contains(dsn.ToLowerInvariant())); if (deckSectionName != null) { currentSectionLinesAndSets = new List<Tuple<string, string>>(); deckSectionLinesAndSets.Add(deckSectionName, currentSectionLinesAndSets); } } else if (nodeName.Equals("a")) { currentLineCardName = HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(childNode); var htmlAttributeList = HtmlAgilityPackWrapper.HtmlNode_GetProperty_Attributes(childNode); var hrefAttribute = htmlAttributeList.Cast<object>().First(attr => HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Name(attr).Equals(@"href", StringComparison.InvariantCultureIgnoreCase)); // This is the entire string inside the href attribute of the 'a' link for this card string hrefValue = HtmlAgilityPackWrapper.HtmlAttribute_GetProperty_Value(hrefAttribute); string[] hrefValuesSplit = hrefValue.Split(new char[] { '/' }); // The set name should be the second to last group after splitting on '/' string rawSetName = hrefValuesSplit[hrefValuesSplit.Length - 2]; // Special case - Sets for The Hobbit have "the-hobbit" in the parent directory if (hrefValuesSplit[hrefValuesSplit.Length - 3].Equals("the-hobbit")) { rawSetName = hrefValuesSplit[hrefValuesSplit.Length - 3] + " " + rawSetName; } // Special case - 'core' should be renamed to 'core-set' if (rawSetName.Equals("core")) { rawSetName = "core-set"; } currentSetName = rawSetName.Replace('-', ' '); } else if (nodeName.Equals("#text")) { currentSectionLinesAndSets.Add(new Tuple<string, string> ( currentLineCardName + " " + HtmlAgilityPackWrapper.HtmlNode_GetProperty_InnerText(childNode), currentSetName )); currentLineCardName = null; currentSetName = null; } } ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); foreach (KeyValuePair<string, IEnumerable<Tuple<string, string>>> section in deckSectionLinesAndSets) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals(section.Key, StringComparison.InvariantCultureIgnoreCase)); foreach (Tuple<string, string> lineAndSection in section.Value) { ConverterMapping converterMapping = RegexMatch_RegularCardQuantityAfterName(lineAndSection.Item1); converterMapping.CardSet = lineAndSection.Item2; converterSection.AddConverterMapping(converterMapping); } } return converterDeck; } } throw new NotImplementedException(); }
/// <summary> /// Reads each line in each section, and returns a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="sectionLines">A collection of deck sections with Item1 as Name, and Item2 as a collection of lines of text which are cards</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> private static ConverterDeck ConvertDeckWithSeparateSections(Dictionary<string, IEnumerable<string>> sectionLines, IEnumerable<string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); foreach (KeyValuePair<string, IEnumerable<string>> section in sectionLines) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals(section.Key, StringComparison.InvariantCultureIgnoreCase)); foreach (string line in section.Value) { // The line is the Deck Name? Record it. string potentialDeckName = ConvertEngine.RegexMatch_DeckName(line); if (potentialDeckName != null) { converterDeck.DeckName = potentialDeckName; } else { // The line is not a Comment? if (ConvertEngine.RegexMatch_Comment(line) == null) { // The line is a regular main deck Card/Quantity entry, without any Set info? Record it ConverterMapping potentialRegularCard = RegexMatch_RegularCard(line); ConverterMapping potentialRegularCardQuantityAfterName = RegexMatch_RegularCardQuantityAfterName(line); if (potentialRegularCard != null) { converterSection.AddConverterMapping(potentialRegularCard); } else if (potentialRegularCardQuantityAfterName != null) { converterSection.AddConverterMapping(potentialRegularCardQuantityAfterName); } else { // The line is a MWS main deck Card/Quantity entry with Set info? Record it ConverterMapping potentialMWSMainDeckCard = RegexMatch_MWSMainDeckCard(line); if (potentialMWSMainDeckCard != null) { converterSection.AddConverterMapping(potentialMWSMainDeckCard); } else { // The line is not a valid card entry } } } } } } converterDeck.ConversionSuccessful = true; return converterDeck; }
/// <summary> /// Reads the file which has Sideboard cards denoted on each line, and returns a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="lines">An array of all the lines of text from a Deck file</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> private static ConverterDeck ConvertMTGDeckWithSideBoardCardsListedEachLine(IEnumerable<string> lines, IEnumerable<string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); ConverterSection mtgMainDeckConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Main", StringComparison.InvariantCultureIgnoreCase)); ConverterSection mtgSideboardConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Sideboard", StringComparison.InvariantCultureIgnoreCase)); foreach (string line in lines) { // The line is the Deck Name? Record it. string potentialDeckName = ConvertEngine.RegexMatch_DeckName(line); if (potentialDeckName != null) { converterDeck.DeckName = potentialDeckName; } else { // The line is not a Comment? if (ConvertEngine.RegexMatch_Comment(line) == null) { // Ordering: The most specific pattern is listed first, and each more generalized pattern follows if (RegexMatch_MWSSideBoardCard(line) != null) { // The line is a MWS sideboard "SB: Quantity [SET] Card" entry mtgSideboardConverterSection.AddConverterMapping(RegexMatch_MWSSideBoardCard(line)); } else if (RegexMatch_MWSMainDeckCard(line) != null) { // The line is a MWS main deck "Quantity [SET] Card" entry mtgMainDeckConverterSection.AddConverterMapping(RegexMatch_MWSMainDeckCard(line)); } else if (RegexMatch_RegularMTGSideBoardCard(line) != null) { // The line is a regular sideboard "Quantity Card" entry, without any Set info mtgSideboardConverterSection.AddConverterMapping(RegexMatch_RegularMTGSideBoardCard(line)); } else if (RegexMatch_RegularCard(line) != null) { // The line is a regular main deck "Quantity Card" entry, without any Set info mtgMainDeckConverterSection.AddConverterMapping(RegexMatch_RegularCard(line)); } else if (RegexMatch_RegularCardQuantityAfterName(line) != null) { // The line is a regular main deck "Card Quantity" entry, without any Set info mtgMainDeckConverterSection.AddConverterMapping(RegexMatch_RegularCardQuantityAfterName(line)); } else { // The line is not a valid card entry } } } } converterDeck.ConversionSuccessful = true; return converterDeck; }
/// <summary> /// Reads the OCTGN format file, and returns a ConverterDeck which is populated with all cards. /// </summary> /// <param name="fullPathName">The full path name of the OCTGN Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> /// <remarks>This will purposely ignore the Guids, which may help importing from OCTGN2 or other unofficial sets</remarks> private static ConverterDeck ConvertOctgn(string fullPathName, IEnumerable<string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); XmlTextReader reader = new XmlTextReader(fullPathName); reader.WhitespaceHandling = WhitespaceHandling.None; XmlDocument xd = new XmlDocument(); xd.Load(reader); XmlNode xnodDE = xd.DocumentElement; if (xnodDE.Name != "deck") { throw new InvalidOperationException("File is not a Octgn Deck"); } foreach (XmlNode child in xnodDE.ChildNodes) { if (child.Name.Equals("section", StringComparison.InvariantCultureIgnoreCase)) { ConverterSection converterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals(child.Attributes.GetNamedItem("name").Value, StringComparison.InvariantCultureIgnoreCase)); foreach (XmlNode cardXmlNode in child.ChildNodes) { converterSection.AddConverterMapping ( new ConverterMapping ( cardXmlNode.InnerText, string.Empty, int.Parse(cardXmlNode.Attributes.GetNamedItem("qty").Value) ) ); } } } converterDeck.ConversionSuccessful = true; return converterDeck; }
/// <summary> /// Reads the Cockatrice format file, and returns a ConverterDeck which is populated with all cards and deck name. /// </summary> /// <param name="fullPathName">The full path name of the Cockatrice Deck file to convert</param> /// <param name="deckSectionNames">List of the name of each section for the deck being converted.</param> /// <returns>A ConverterDeck object populated with all cards and deck name</returns> private static ConverterDeck ConvertCockatrice(string fullPathName, IEnumerable<string> deckSectionNames) { ConverterDeck converterDeck = new ConverterDeck(deckSectionNames); XmlTextReader reader = new XmlTextReader(fullPathName); reader.WhitespaceHandling = WhitespaceHandling.None; XmlDocument xd = new XmlDocument(); xd.Load(reader); XmlNode xnodDE = xd.DocumentElement; if (xnodDE.Name != "cockatrice_deck") { throw new InvalidOperationException("File is not a Cockatrice Deck"); } ConverterSection mtgMainDeckConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Main", StringComparison.InvariantCultureIgnoreCase)); ConverterSection mtgSideboardConverterSection = converterDeck.ConverterSections.First(cs => cs.SectionName.Equals("Sideboard", StringComparison.InvariantCultureIgnoreCase)); foreach (XmlNode child in xnodDE.ChildNodes) { if (child.Name.Equals("deckname", StringComparison.InvariantCultureIgnoreCase)) { converterDeck.DeckName = child.InnerText; } else if (child.Name.Equals("zone", StringComparison.InvariantCultureIgnoreCase)) { if (child.Attributes.GetNamedItem("name").Value.Equals("main", StringComparison.InvariantCultureIgnoreCase)) { foreach (XmlNode cardXmlNode in child.ChildNodes) { mtgMainDeckConverterSection.AddConverterMapping ( new ConverterMapping ( cardXmlNode.Attributes.GetNamedItem("name").Value, string.Empty, int.Parse(cardXmlNode.Attributes.GetNamedItem("number").Value) ) ); } } else if (child.Attributes.GetNamedItem("name").Value.Equals("side", StringComparison.InvariantCultureIgnoreCase)) { foreach (XmlNode cardXmlNode in child.ChildNodes) { mtgSideboardConverterSection.AddConverterMapping ( new ConverterMapping ( cardXmlNode.Attributes.GetNamedItem("name").Value, string.Empty, int.Parse(cardXmlNode.Attributes.GetNamedItem("number").Value) ) ); } } } } converterDeck.ConversionSuccessful = true; return converterDeck; }