stsdb 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- stsdb-0.1.1/PKG-INFO +102 -0
- stsdb-0.1.1/README.md +88 -0
- stsdb-0.1.1/pyproject.toml +34 -0
- stsdb-0.1.1/setup.cfg +4 -0
- stsdb-0.1.1/stsdb/__init__.py +3 -0
- stsdb-0.1.1/stsdb/__main__.py +5 -0
- stsdb-0.1.1/stsdb/cli.py +35 -0
- stsdb-0.1.1/stsdb/core.py +137 -0
- stsdb-0.1.1/stsdb/data/card.csv +372 -0
- stsdb-0.1.1/stsdb/data/card_upgrade.csv +372 -0
- stsdb-0.1.1/stsdb/data/hero.csv +5 -0
- stsdb-0.1.1/stsdb/data/play.csv +372 -0
- stsdb-0.1.1/stsdb/data/relic.csv +178 -0
- stsdb-0.1.1/stsdb/data/relic_availability.csv +178 -0
- stsdb-0.1.1/stsdb.egg-info/PKG-INFO +102 -0
- stsdb-0.1.1/stsdb.egg-info/SOURCES.txt +18 -0
- stsdb-0.1.1/stsdb.egg-info/dependency_links.txt +1 -0
- stsdb-0.1.1/stsdb.egg-info/entry_points.txt +2 -0
- stsdb-0.1.1/stsdb.egg-info/top_level.txt +1 -0
- stsdb-0.1.1/tests/test_stsdb.py +67 -0
stsdb-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: stsdb
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Deterministic Slay the Spire card and relic query toolset
|
|
5
|
+
Author: Taardisaa
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: slay-the-spire,database,cards,relics
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.9
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# Slay the Spire Database (stsdb)
|
|
16
|
+
|
|
17
|
+
A card/relic query toolset for [Slay the Spire](https://www.megacrit.com/).
|
|
18
|
+
|
|
19
|
+
It exposes two main commands:
|
|
20
|
+
|
|
21
|
+
- `query_card`: query card metadata, with optional upgrade level.
|
|
22
|
+
- `query_relic`: query relic metadata.
|
|
23
|
+
|
|
24
|
+
Both commands use exact name matching only (no fuzzy match, no partial match, no fallback).
|
|
25
|
+
|
|
26
|
+
`query_card` also supports `upgrade_times`:
|
|
27
|
+
|
|
28
|
+
- Most cards: capped at one applied upgrade.
|
|
29
|
+
- `Searing Blow`: supports unbounded upgrades using the in-game scaling rule.
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install stsdb
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Dev installation:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install -e .
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Usage
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
stsdb query_card "Bash"
|
|
47
|
+
stsdb query_card "Searing Blow" --upgrade-times 3
|
|
48
|
+
stsdb query_relic "Burning Blood"
|
|
49
|
+
python -m stsdb query_card "Bash"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Python API
|
|
53
|
+
|
|
54
|
+
```python
|
|
55
|
+
import stsdb
|
|
56
|
+
from stsdb import query_card, query_relic
|
|
57
|
+
|
|
58
|
+
stsdb.query_card("Bash")
|
|
59
|
+
query_card("Bash")
|
|
60
|
+
query_card("Searing Blow", upgrade_times=3)
|
|
61
|
+
query_relic("Burning Blood")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Local development
|
|
65
|
+
|
|
66
|
+
Install in development mode:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install -e .
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Run tests:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
python -m unittest discover -s tests -v
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Output
|
|
79
|
+
|
|
80
|
+
- Success: `{"found": true, "entry": {...}}`
|
|
81
|
+
- Card miss: `{"found": false, "error": "CARD_NOT_FOUND"}`
|
|
82
|
+
- Invalid upgrade input: `{"found": false, "error": "INVALID_UPGRADE_TIMES"}`
|
|
83
|
+
- Relic miss: `{"found": false, "error": "RELIC_NOT_FOUND"}`
|
|
84
|
+
|
|
85
|
+
## Other Notes
|
|
86
|
+
|
|
87
|
+
Data files are shipped inside the package under `stsdb/data/`:
|
|
88
|
+
|
|
89
|
+
- `card.csv`
|
|
90
|
+
- `relic.csv`
|
|
91
|
+
- `hero.csv`
|
|
92
|
+
- `play.csv`
|
|
93
|
+
- `relic_availability.csv`
|
|
94
|
+
- `card_upgrade.csv`
|
|
95
|
+
|
|
96
|
+
Upgrade metadata format (`card_upgrade.csv`):
|
|
97
|
+
|
|
98
|
+
- `nameCard;hasUpgrade;costUpgraded;descriptionUpgraded`
|
|
99
|
+
|
|
100
|
+
## Credits
|
|
101
|
+
|
|
102
|
+
This repository is adapted from the original project by [Ferdomgar97](https://github.com/ferdomgar97/Slay-the-Spire)
|
stsdb-0.1.1/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# Slay the Spire Database (stsdb)
|
|
2
|
+
|
|
3
|
+
A card/relic query toolset for [Slay the Spire](https://www.megacrit.com/).
|
|
4
|
+
|
|
5
|
+
It exposes two main commands:
|
|
6
|
+
|
|
7
|
+
- `query_card`: query card metadata, with optional upgrade level.
|
|
8
|
+
- `query_relic`: query relic metadata.
|
|
9
|
+
|
|
10
|
+
Both commands use exact name matching only (no fuzzy match, no partial match, no fallback).
|
|
11
|
+
|
|
12
|
+
`query_card` also supports `upgrade_times`:
|
|
13
|
+
|
|
14
|
+
- Most cards: capped at one applied upgrade.
|
|
15
|
+
- `Searing Blow`: supports unbounded upgrades using the in-game scaling rule.
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
pip install stsdb
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Dev installation:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install -e .
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Usage
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
stsdb query_card "Bash"
|
|
33
|
+
stsdb query_card "Searing Blow" --upgrade-times 3
|
|
34
|
+
stsdb query_relic "Burning Blood"
|
|
35
|
+
python -m stsdb query_card "Bash"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Python API
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
import stsdb
|
|
42
|
+
from stsdb import query_card, query_relic
|
|
43
|
+
|
|
44
|
+
stsdb.query_card("Bash")
|
|
45
|
+
query_card("Bash")
|
|
46
|
+
query_card("Searing Blow", upgrade_times=3)
|
|
47
|
+
query_relic("Burning Blood")
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Local development
|
|
51
|
+
|
|
52
|
+
Install in development mode:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install -e .
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Run tests:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
python -m unittest discover -s tests -v
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Output
|
|
65
|
+
|
|
66
|
+
- Success: `{"found": true, "entry": {...}}`
|
|
67
|
+
- Card miss: `{"found": false, "error": "CARD_NOT_FOUND"}`
|
|
68
|
+
- Invalid upgrade input: `{"found": false, "error": "INVALID_UPGRADE_TIMES"}`
|
|
69
|
+
- Relic miss: `{"found": false, "error": "RELIC_NOT_FOUND"}`
|
|
70
|
+
|
|
71
|
+
## Other Notes
|
|
72
|
+
|
|
73
|
+
Data files are shipped inside the package under `stsdb/data/`:
|
|
74
|
+
|
|
75
|
+
- `card.csv`
|
|
76
|
+
- `relic.csv`
|
|
77
|
+
- `hero.csv`
|
|
78
|
+
- `play.csv`
|
|
79
|
+
- `relic_availability.csv`
|
|
80
|
+
- `card_upgrade.csv`
|
|
81
|
+
|
|
82
|
+
Upgrade metadata format (`card_upgrade.csv`):
|
|
83
|
+
|
|
84
|
+
- `nameCard;hasUpgrade;costUpgraded;descriptionUpgraded`
|
|
85
|
+
|
|
86
|
+
## Credits
|
|
87
|
+
|
|
88
|
+
This repository is adapted from the original project by [Ferdomgar97](https://github.com/ferdomgar97/Slay-the-Spire)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "stsdb"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Deterministic Slay the Spire card and relic query toolset"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.9"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Taardisaa" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["slay-the-spire", "database", "cards", "relics"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent"
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
[project.scripts]
|
|
24
|
+
stsdb = "stsdb.cli:main"
|
|
25
|
+
|
|
26
|
+
[tool.setuptools]
|
|
27
|
+
include-package-data = true
|
|
28
|
+
|
|
29
|
+
[tool.setuptools.packages.find]
|
|
30
|
+
where = ["."]
|
|
31
|
+
include = ["stsdb*"]
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.package-data]
|
|
34
|
+
stsdb = ["data/*.csv"]
|
stsdb-0.1.1/setup.cfg
ADDED
stsdb-0.1.1/stsdb/cli.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from .core import query_card, query_relic
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _build_parser():
|
|
8
|
+
parser = argparse.ArgumentParser(description="Deterministic exact-match query toolset")
|
|
9
|
+
subparsers = parser.add_subparsers(dest="tool", required=True)
|
|
10
|
+
|
|
11
|
+
card_parser = subparsers.add_parser("query_card", help="Query a card by exact name")
|
|
12
|
+
card_parser.add_argument("name", help="Exact card name")
|
|
13
|
+
card_parser.add_argument(
|
|
14
|
+
"--upgrade-times",
|
|
15
|
+
type=int,
|
|
16
|
+
default=0,
|
|
17
|
+
help="Requested upgrade count (default: 0)",
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
relic_parser = subparsers.add_parser("query_relic", help="Query a relic by exact name")
|
|
21
|
+
relic_parser.add_argument("name", help="Exact relic name")
|
|
22
|
+
|
|
23
|
+
return parser
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main():
|
|
27
|
+
parser = _build_parser()
|
|
28
|
+
args = parser.parse_args()
|
|
29
|
+
|
|
30
|
+
if args.tool == "query_card":
|
|
31
|
+
result = query_card(args.name, args.upgrade_times)
|
|
32
|
+
else:
|
|
33
|
+
result = query_relic(args.name)
|
|
34
|
+
|
|
35
|
+
print(json.dumps(result, ensure_ascii=True))
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import csv
|
|
2
|
+
from functools import lru_cache
|
|
3
|
+
from importlib.resources import files
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _normalize_cost(raw_cost: str):
|
|
7
|
+
if raw_cost == "NULL":
|
|
8
|
+
return None
|
|
9
|
+
return int(raw_cost)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _data_path(filename: str):
|
|
13
|
+
return files("stsdb").joinpath("data", filename)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@lru_cache(maxsize=1)
|
|
17
|
+
def _cards_by_name():
|
|
18
|
+
cards = {}
|
|
19
|
+
with _data_path("card.csv").open("r", encoding="utf-8", newline="") as f:
|
|
20
|
+
reader = csv.reader(f, delimiter=";")
|
|
21
|
+
for row in reader:
|
|
22
|
+
name, rarity, card_type, cost, description = row
|
|
23
|
+
cards[name] = {
|
|
24
|
+
"name": name,
|
|
25
|
+
"rarity": None if rarity == "NULL" else rarity,
|
|
26
|
+
"type": card_type,
|
|
27
|
+
"cost": _normalize_cost(cost),
|
|
28
|
+
"description": description,
|
|
29
|
+
}
|
|
30
|
+
return cards
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@lru_cache(maxsize=1)
|
|
34
|
+
def _relics_by_name():
|
|
35
|
+
relics = {}
|
|
36
|
+
with _data_path("relic.csv").open("r", encoding="utf-8", newline="") as f:
|
|
37
|
+
reader = csv.reader(f, delimiter=";")
|
|
38
|
+
for row in reader:
|
|
39
|
+
name, rarity, description = row
|
|
40
|
+
relics[name] = {
|
|
41
|
+
"name": name,
|
|
42
|
+
"rarity": rarity,
|
|
43
|
+
"description": description,
|
|
44
|
+
}
|
|
45
|
+
return relics
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@lru_cache(maxsize=1)
|
|
49
|
+
def _card_playable_by():
|
|
50
|
+
card_map = {}
|
|
51
|
+
with _data_path("play.csv").open("r", encoding="utf-8", newline="") as f:
|
|
52
|
+
reader = csv.reader(f, delimiter=";")
|
|
53
|
+
for row in reader:
|
|
54
|
+
card_name, hero_name = row
|
|
55
|
+
card_map.setdefault(card_name, []).append(hero_name)
|
|
56
|
+
return card_map
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@lru_cache(maxsize=1)
|
|
60
|
+
def _card_upgrade_by_name():
|
|
61
|
+
upgrades = {}
|
|
62
|
+
with _data_path("card_upgrade.csv").open("r", encoding="utf-8", newline="") as f:
|
|
63
|
+
reader = csv.reader(f, delimiter=";")
|
|
64
|
+
for row in reader:
|
|
65
|
+
card_name, has_upgrade, cost_upgraded, description_upgraded = row
|
|
66
|
+
upgrades[card_name] = {
|
|
67
|
+
"has_upgrade": has_upgrade == "true",
|
|
68
|
+
"cost_upgraded": _normalize_cost(cost_upgraded),
|
|
69
|
+
"description_upgraded": description_upgraded,
|
|
70
|
+
}
|
|
71
|
+
return upgrades
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@lru_cache(maxsize=1)
|
|
75
|
+
def _relic_available_to():
|
|
76
|
+
relic_map = {}
|
|
77
|
+
with _data_path("relic_availability.csv").open("r", encoding="utf-8", newline="") as f:
|
|
78
|
+
reader = csv.reader(f, delimiter=";")
|
|
79
|
+
for row in reader:
|
|
80
|
+
relic_name, hero_name = row
|
|
81
|
+
relic_map.setdefault(relic_name, []).append(hero_name)
|
|
82
|
+
return relic_map
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _apply_searing_blow_upgrades(base_card, upgrade_times: int):
|
|
86
|
+
if upgrade_times <= 0:
|
|
87
|
+
return base_card
|
|
88
|
+
|
|
89
|
+
base_damage = 12
|
|
90
|
+
upgraded_damage = (upgrade_times * (upgrade_times + 7)) // 2 + base_damage
|
|
91
|
+
upgraded_description = f"Deal {upgraded_damage} damage. Can be Upgraded any number of times."
|
|
92
|
+
|
|
93
|
+
upgraded_card = dict(base_card)
|
|
94
|
+
upgraded_card["description"] = upgraded_description
|
|
95
|
+
return upgraded_card
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def query_card(name: str, upgrade_times: int = 0):
|
|
99
|
+
if upgrade_times < 0:
|
|
100
|
+
return {"found": False, "error": "INVALID_UPGRADE_TIMES"}
|
|
101
|
+
|
|
102
|
+
card = _cards_by_name().get(name)
|
|
103
|
+
if card is None:
|
|
104
|
+
return {"found": False, "error": "CARD_NOT_FOUND"}
|
|
105
|
+
|
|
106
|
+
entry = dict(card)
|
|
107
|
+
upgrade_info = _card_upgrade_by_name().get(name)
|
|
108
|
+
|
|
109
|
+
applied_upgrade_times = 0
|
|
110
|
+
max_upgrade_times = 0
|
|
111
|
+
|
|
112
|
+
if name == "Searing Blow":
|
|
113
|
+
entry = _apply_searing_blow_upgrades(entry, upgrade_times)
|
|
114
|
+
applied_upgrade_times = upgrade_times
|
|
115
|
+
max_upgrade_times = -1
|
|
116
|
+
elif upgrade_info and upgrade_info["has_upgrade"]:
|
|
117
|
+
max_upgrade_times = 1
|
|
118
|
+
if upgrade_times > 0:
|
|
119
|
+
applied_upgrade_times = 1
|
|
120
|
+
entry["cost"] = upgrade_info["cost_upgraded"]
|
|
121
|
+
entry["description"] = upgrade_info["description_upgraded"]
|
|
122
|
+
|
|
123
|
+
entry["playable_by"] = _card_playable_by().get(name, [])
|
|
124
|
+
entry["requested_upgrade_times"] = upgrade_times
|
|
125
|
+
entry["applied_upgrade_times"] = applied_upgrade_times
|
|
126
|
+
entry["max_upgrade_times"] = max_upgrade_times
|
|
127
|
+
return {"found": True, "entry": entry}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def query_relic(name: str):
|
|
131
|
+
relic = _relics_by_name().get(name)
|
|
132
|
+
if relic is None:
|
|
133
|
+
return {"found": False, "error": "RELIC_NOT_FOUND"}
|
|
134
|
+
|
|
135
|
+
entry = dict(relic)
|
|
136
|
+
entry["available_to"] = _relic_available_to().get(name, [])
|
|
137
|
+
return {"found": True, "entry": entry}
|