aboutsummaryrefslogtreecommitdiff
path: root/most-valuable-materia.ipynb
blob: 13ba22349b50133a2cedddf69408903cb14bc37e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "c8e634f8-f5b1-4a93-ac99-2124a21183d2",
   "metadata": {},
   "source": [
    "# Most Valuable Materia\n",
    "\n",
    "I have a lot of Sacks of Nuts and Cracked Whateverclusters and I'd like to know which materia will give me the most money on the market board.\n",
    "I don't have any Cracked Whatevercrystals, so I don't care about non-combat materia.\n",
    "\n",
    "Powered by [Universalis](https://universalis.app/).\n",
    "\n",
    "Set the world and materia tiers you care about:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bbc35fe7-615a-44ac-81bd-3eb394e10365",
   "metadata": {},
   "outputs": [],
   "source": [
    "world = 'Jenova'\n",
    "tiers = [\"VII\", \"VIII\", \"IX\", \"X\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5a49afe-1a0e-4370-9610-30b975ec6f5b",
   "metadata": {},
   "source": [
    "Then hit Run > Run All Cells, and the two most valuable materia at each tier should show up after all the code.\n",
    "If you're curious, you can click the hidden code cell below to see how it works."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d87b9ff9-eb2c-403f-9432-20b22112ba93",
   "metadata": {
    "jupyter": {
     "source_hidden": true
    }
   },
   "outputs": [],
   "source": [
    "# useful constants\n",
    "ROMAN_NUMERALS = [\"I\", \"II\", \"III\", \"IV\", \"V\", \"VI\", \"VII\", \"VIII\", \"IX\", \"X\"]\n",
    "HUNT_CURRENCIES = {\"VI\": (400, \"seal\"), \"VII\": (150, \"nut\"), \"VIII\": (400, \"nut\"), \"IX\": (150, \"nut\"), \"X\": (400, \"nut\")}\n",
    "\n",
    "# grabbed by hand from XIVAPI\n",
    "MATERIA = {\n",
    "    \"Piety\": [5629, 5630, 5631, 5632, 5633, 18011, 25186, 26727, 33917, 33930],\n",
    "    \"Heavens' Eye\": [5664, 5665, 5666, 5667, 5668, 18018, 25187, 26728, 33918, 33931],\n",
    "    \"Savage Aim\": [5669, 5670, 5671, 5672, 5673, 18019, 25188, 26729, 33919, 33932],\n",
    "    \"Savage Might\": [5674, 5675, 5676, 5677, 5678, 18020, 25189, 26730, 33920, 33933],\n",
    "    \"Battledance\": [5679, 5680, 5681, 5682, 5683, 18021, 25190, 26731, 33921, 33934],\n",
    "    \"Quickarm\": [5714, 5715, 5716, 5717, 5718, 18028, 25197, 26738, 33928, 33941],\n",
    "    \"Quicktongue\": [5719, 5720, 5721, 5722, 5723, 18029, 25198, 26739, 33929, 33942],\n",
    "}\n",
    "\n",
    "# 1. sort out the items to search for\n",
    "target_materia = dict()\n",
    "all_ids = []\n",
    "for tier in tiers:\n",
    "    target_materia[tier] = dict()\n",
    "    index = ROMAN_NUMERALS.index(tier)\n",
    "    for materia_type in MATERIA:\n",
    "        item_name = f\"{materia_type} Materia {tier}\"\n",
    "        item_id = MATERIA[materia_type][index]\n",
    "        target_materia[tier][item_id] = item_name\n",
    "        all_ids.append(item_id)\n",
    "\n",
    "# 2. get prices\n",
    "import requests\n",
    "\n",
    "if len(target_materia) > 100:\n",
    "    raise ValueError(\"Can't load market data for more than 100 items at a time\")\n",
    "\n",
    "universalis_url = f'https://universalis.app/api/v2/{world}/{\",\".join(str(x) for x in all_ids)}?listings=0&entries=0&noGst=1'\n",
    "\n",
    "response = requests.get(universalis_url)\n",
    "\n",
    "response.raise_for_status()\n",
    "\n",
    "response = response.json()\n",
    "\n",
    "if len(response[\"itemIDs\"]) != len(tiers) * len(MATERIA):\n",
    "    print(\"Got back the wrong number of items for some reason\")\n",
    "\n",
    "prices = {item[\"itemID\"]: item[\"minPrice\"] for item in response[\"items\"].values()}\n",
    "\n",
    "# 3. sort prices\n",
    "from IPython.display import Markdown\n",
    "\n",
    "for tier in tiers:\n",
    "    display(Markdown(f\"## Materia {tier}\"))\n",
    "    targets = target_materia[tier]\n",
    "    target_ids = list(targets.keys())\n",
    "    best_ids = sorted(target_ids, key=lambda id: prices[id], reverse=True)\n",
    "    for this_id in best_ids[:2]:\n",
    "        name = targets[this_id]\n",
    "        price = prices[this_id]\n",
    "        if tier in HUNT_CURRENCIES:\n",
    "            qty, currency = HUNT_CURRENCIES[tier]\n",
    "            hunt_price = f\" - {round(price/qty, 2)} g/{currency}\"\n",
    "        else:\n",
    "            hunt_price = \"\"\n",
    "        display(Markdown(f\"- {name} - {price}g{hunt_price}\"))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}