Skip to content

Instantly share code, notes, and snippets.

@szarroug3
Last active April 16, 2019 02:24
Show Gist options
  • Save szarroug3/7b9b7a3d0b42970864f1465119ac9120 to your computer and use it in GitHub Desktop.
Save szarroug3/7b9b7a3d0b42970864f1465119ac9120 to your computer and use it in GitHub Desktop.
FFXIV Craft Leveling Calculator
import json
import math
import os
from collections import defaultdict
xp_chart = [300, 600, 1100, 1700, 2300, 4200, 6000, 7350, 9930, 11800,
15600, 19600, 23700, 26400, 30500, 35400, 40500, 45700, 51000, 56600,
63900, 71400, 79100, 87100, 95200, 109800, 124800, 140200, 155900, 162500,
175900, 189600, 203500, 217900, 232320, 249900, 267800, 286200, 304900, 324000,
340200, 356800, 373700, 390800, 408200, 437600, 467500, 498000, 529000, 864000,
1058400, 1267200, 1555200, 1872000, 2217600, 2592000, 2995200, 3427200, 3888000, 4470000,
4873000, 5316000, 5809000, 6364000, 6995000, 7722000, 8575000, 9593000, 10826000]
config_file = 'ffxiv.json'
if os.path.exists(config_file):
with open(config_file) as f:
config = json.load(f)
else:
config = {}
with open(config_file, 'w') as f:
json.dump(config, f, indent=4)
def get_xp_needed():
start_level = int(input('Starting Level: '))
end_level = int(input('Ending Level: '))
total_xp_needed = 0 - int(input('Starting XP: ') or 0)
for i in range(start_level, end_level):
total_xp_needed += xp_chart[i-1]
return total_xp_needed
def get_quest_data():
name = input('Quest Recipe Name: ')
if not name:
return
if name not in config:
add_recipe(name)
count = int(input('Recipe Count: '))
xp = int(input('Quest XP: '))
allowances = int(input('Allowances: ') or 1)
return name, count, xp, allowances
def add_recipe(name):
print('Ingredients for {}: '.format(name))
recipe = {}
config[name] = {'recipe': recipe}
while True:
data = input()
if not data:
break
quantity, ing_name = data.split(' ', 1)
config[name]['recipe'][ing_name] = int(quantity)
yields = input('Yields: ')
if not yields:
yields = 1
else:
yields = int(yields)
config[name]['yield'] = yields
for sub_name in config[name]['recipe'].keys():
if sub_name not in config:
add_recipe(sub_name)
with open(config_file, 'w') as f:
json.dump(config, f, indent=4)
def calculate(xp_needed, quests):
if xp_needed <= 0:
return
base = defaultdict(int)
crafted = {}
leftovers = defaultdict(int)
order = 0
for name, count, xp, allowances in quests:
xp_needed, needed = calculate_repeat(xp_needed, xp, allowances)
print('\nCompleting {} quest {} times will get you to {} XP needed'.format(name, needed, xp_needed))
base, crafted, leftovers, order = get_recipe_data(name, base, crafted, leftovers, needed * count, order)
return base, crafted, order
def calculate_repeat(total_xp_needed, xp, allowances):
total_needed = math.ceil(total_xp_needed / xp)
if total_needed > allowances:
total_needed = allowances
total_xp_needed -= (total_needed * xp)
return total_xp_needed, total_needed
def get_recipe_data(name, base, crafted, leftovers, count, order=0):
if len(config[name]['recipe']) > 0:
if leftovers.get(name, 0) > 0:
leftovers[name] -= count
if leftovers.get(name) >= count:
leftovers[name] -= count
count = 0
else:
count -= leftovers[name]
leftovers[name] = 0
if count <= 0:
return base, crafted, leftovers, order
if name not in leftovers:
have = int(input('How much {} do you have? '.format(name)) or 0)
left = have - count
if left < 0:
left = 0
leftovers[name] += left
count -= have
if count <= 0:
return base, crafted, leftovers, order
need = int(math.ceil(count / config[name]['yield']))
leftovers[name] += config[name]['yield'] * count
for sub_name, sub_count in config[name]['recipe'].items():
total_sub_count = need * sub_count
base, crafted, leftovers, order = get_recipe_data(sub_name, base, crafted, leftovers, total_sub_count, order=order)
if name not in crafted:
order += 1
crafted[name] = {'count': need, 'order': order}
else:
crafted[name]['count'] += need
else:
if name not in leftovers:
have = int(input('How much {} do you have? '.format(name)) or 0)
leftovers[name] += have - count
count -= have
if count < 0:
count = 0
base[name] += count
return base, crafted, leftovers, order
if __name__ == '__main__':
total_xp_needed = get_xp_needed()
print('Total XP Needed:', total_xp_needed)
quests = []
while True:
data = get_quest_data()
if not data:
break
quests.append(data)
base, crafted, order = calculate(total_xp_needed, quests)
if base:
print('\nBase Ingredients:')
for name, count in base.items():
if count > 0:
print('{} {}'.format(count, name))
if crafted:
print()
if crafted:
print('Crafted Recipes:')
for name, data in sorted(list(crafted.items()), key=lambda x:x[1]['order']):
if data['count'] > 0:
print('{} {}'.format(data['count'], name))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment