Advertisement
Guest User

shoukaku_deps.py

a guest
Sep 19th, 2019
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.34 KB | None | 0 0
  1. #!/usr/bin/python3
  2. """
  3. Goes through the quests.html file pulled from http://kancolle.wikia.com/wiki/Quests and builds
  4. a dependency graph based off of A23, the earliest quest that requires Shoukaku. Could be adapted
  5. to make a more complete quest dependency graph but not having Shoukaku has made me mad enough to
  6. the point to have this script directly target that dumb crane.
  7. """
  8. import bs4
  9. import pprint
  10. import re
  11.  
  12. questIdentifier = re.compile("\w\d{1,3}")
  13. thatFuckingQuest = "A23"
  14. unlockText = "Unlock"
  15. requiresText = "Requires:"
  16. quests = {}
  17.  
  18. class Quest():
  19.     """
  20.    Basic building blocks of Kancolle quests
  21.    """
  22.     def __init__(self, num):
  23.         self.id = num
  24.         self.requires = []
  25.         self.unlocks = []
  26.  
  27.     def __str__(self):
  28.         reqs = ",".join(self.requires)
  29.         unlocks = ",".join(self.unlocks)
  30.         return "\n".join(["id: " + self.id, "requires: " + reqs, "unlocks: " + unlocks, ""])
  31.  
  32.  
  33. def traverse():
  34.     """
  35.    Go through and build the dependency graph for the shoukaku quest
  36.    """
  37.     init = [quests[thatFuckingQuest].unlocks]
  38.     layers = []
  39.     while len(init) > 0:
  40.         layer = init.pop(0)
  41.         layers.append(layer)
  42.         newLayer = []
  43.         for quest in layer:
  44.             newLayer.extend(quests[quest].unlocks)
  45.         if len(newLayer) == 0:
  46.             break
  47.         init.append(newLayer)
  48.     return layers
  49.  
  50.  
  51. def quests_only(x):
  52.     """
  53.    Filters out any nested tags and strings that are not quest strings
  54.    """
  55.     flattenedElements = []
  56.     elements = x
  57.     testString = lambda x: questIdentifier.search(x) is not None
  58.     # Flatten out any non String elements
  59.     while len(elements) > 0:
  60.         ele = elements.pop()
  61.         if not isinstance(ele, bs4.element.NavigableString):
  62.             elements.extend(ele.contents)
  63.         else:
  64.             flattenedElements.append(ele)
  65.     return filter(testString, flattenedElements)
  66.  
  67.  
  68. def populate_quests():
  69.     """
  70.    Goes through the quests.html file and pulls out all quests. Includes requirements and unlocks.
  71.    """
  72.     with open("quests.html", "r") as f:
  73.         soup = bs4.BeautifulSoup(f, "lxml")
  74.     rows = soup.find_all("tr")
  75.     currentQuest = None
  76.     for r in rows:
  77.         if "class" in r.attrs:
  78.             rowClass = r.attrs["class"]
  79.             assert(len(rowClass) == 1)
  80.             rowClass = rowClass[0]
  81.             if "details" in rowClass:
  82.                 # Quest itself. Find the Requirements and Unlocks.
  83.                 for c in r.contents:
  84.                     if isinstance(c, bs4.element.NavigableString):
  85.                         # Ignore quest descriptions
  86.                         continue
  87.                     insertUnlocks = 0
  88.                     for sc in c.contents:
  89.                         if isinstance(sc, bs4.element.NavigableString):
  90.                             # Check for "Unlock" or "Requires" strings
  91.                             if unlockText in sc:
  92.                                 insertUnlocks = 1
  93.                             elif requiresText in sc:
  94.                                 insertUnlocks = -1
  95.                         if isinstance(sc, bs4.element.Tag):
  96.                             # Pull out all the identifiers for other quests
  97.                             if insertUnlocks > 0:
  98.                                 currentQuest.unlocks.extend(quests_only(sc.contents))
  99.                             elif insertUnlocks < 0:
  100.                                 currentQuest.requires.extend(quests_only(sc.contents))
  101.                             else:
  102.                                 continue
  103.                 # Entire quest has been assembled. Stick it in the map and reset
  104.                 quests[currentQuest.id] = currentQuest
  105.                 currentQuest = None
  106.             elif "id" in r.attrs and rowClass.startswith("quest_"):
  107.                 # ID of the quest is here. Begin quest generation
  108.                 currentQuest = Quest(r.attrs["id"])
  109.             else:
  110.                 # No useful information. Reset just in case
  111.                 continue
  112.         else:
  113.             continue
  114.  
  115.  
  116. if __name__ == "__main__":
  117.     populate_quests()
  118.     damage = traverse()
  119.     tabs = 0
  120.     totalQuests = 0
  121.     for d in damage:
  122.         totalQuests += len(d)
  123.         print("  "*tabs + " ".join(d))
  124.         tabs += 1
  125.     print("Total quests that depend on Shoukaku: ", totalQuests)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement