Created
June 29, 2017 16:12
Reddit Daily Programmer 320 Hard
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Net; | |
using System.Xml; | |
using System.Xml.Linq; | |
using System.Xml.XPath; | |
namespace Reddit | |
{ | |
internal static class Hard | |
{ | |
internal static void Run() | |
{ | |
Run("Molecule"); | |
} | |
internal static void Run(string input) | |
{ | |
var visited = new HashSet<string>(); | |
visited.Add("Philosophy"); | |
string value = input; | |
while (value != null) | |
{ | |
Console.WriteLine(value); | |
if (visited.Contains(value)) | |
{ | |
value = null; | |
} | |
else | |
{ | |
visited.Add(value); | |
value = Next(value); | |
} | |
} | |
} | |
internal static string Next(string input) | |
{ | |
string content = Download(input); | |
if (content != null) | |
{ | |
var parentheses = new Parentheses(); | |
parentheses.Load(content); | |
var root = XElement.Parse(content, LoadOptions.SetLineInfo); | |
var items = root.Descendants("a").ToList(); | |
if (items.Count > 0) | |
{ | |
foreach (var item in items.Where(e => | |
e.Attribute("title") != null && | |
e.Attribute("href") != null)) | |
{ | |
int position = ((IXmlLineInfo)item).LinePosition; | |
if (parentheses.Surround(position) == false) | |
{ | |
return item.Attribute("title").Value; | |
} | |
} | |
} | |
} | |
return null; | |
} | |
internal static string Download(string input) | |
{ | |
var uri = new Uri("https://en.wikipedia.org/wiki/" + input); | |
using (var client = new WebClient()) | |
{ | |
string value = client.DownloadString(uri); | |
var root = XElement.Parse(value); | |
var content = root.XPathSelectElement( | |
"/body/div[@id='content']/div[@id='bodyContent']" + | |
"/descendant::p[1]"); | |
if (content != null) | |
{ | |
return content.ToString(SaveOptions.DisableFormatting); | |
} | |
} | |
return null; | |
} | |
} | |
internal class Parentheses | |
{ | |
internal List<Node> Nodes; | |
internal void Load(string input) | |
{ | |
const char start = '(', end = ')'; | |
var root = new Node(); | |
root.Index = -1; | |
root.Length = -1; | |
var child = root; | |
for (int i = 0; i < input.Length; i++) | |
{ | |
if (input[i] == start) | |
{ | |
var node = new Node(); | |
node.Index = i; | |
node.Length = -1; | |
node.Parent = child; | |
child.Add(node); | |
child = node; | |
} | |
else | |
{ | |
if (input[i] == end) | |
{ | |
if (child.Index != -1) | |
{ | |
child.Length = (i - child.Index) + 1; | |
child = child.Parent; | |
} | |
} | |
} | |
} | |
Nodes = new List<Node>(root.Flatten()); | |
} | |
internal bool Surround(int position) | |
{ | |
foreach (var node in Nodes) | |
{ | |
if (position >= node.Index && | |
position <= node.Index + node.Length) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
internal class Node | |
{ | |
internal int Index; | |
internal int Length; | |
internal Node Parent; | |
internal List<Node> Children = new List<Node>(); | |
internal void Add(Node node) | |
{ | |
Children.Add(node); | |
} | |
internal IEnumerable<Node> Flatten() | |
{ | |
if (Length != -1) | |
{ | |
yield return this; | |
} | |
else | |
{ | |
foreach (var child in Children) | |
{ | |
foreach (var node in child.Flatten()) | |
{ | |
yield return node; | |
} | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment