mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 12:11:33 -06:00

This PR adds a new, optional aspect to the Ancient Cave experience: During their run, players can have the opportunity to purchase some additional items or spells to improve their party. If enabled, a shop will appear everytime a certain (configurable) number of floors in the dungeon has been completed. The shop inventories are generated randomly (taking into account player preference as well as a system to ensure that more expensive items can only become available deeper into the run). For customization, 3 new options are introduced: - `shop_interval`: Determines by how many floors the shops are separated (or keeps them turned off entirely) - `shop_inventory`: Determines what's possible to be for sale. (Players can specify weights for general categories of things such as "weapon" or "spell" or even adjust the probabilities of individual items) - `gold_modifier`: Determines how much gold is dropped by enemies. This is the player's only source of income and thus controls how much money they will have available to spend in shops
31 lines
1.4 KiB
Python
31 lines
1.4 KiB
Python
import itertools
|
|
from operator import itemgetter
|
|
from random import Random
|
|
from typing import Dict, Iterable, List, MutableSequence, Sequence, Set, Tuple
|
|
|
|
|
|
def constrained_choices(population: Sequence[int], d: int, *, k: int, random: Random) -> List[int]:
|
|
n: int = len(population)
|
|
constraints: Dict[int, Tuple[int, ...]] = {
|
|
i: tuple(dict.fromkeys(population[j] for j in range(max(0, i - d), min(i + d + 1, n)))) for i in range(n)
|
|
}
|
|
|
|
return [random.choice(constraints[i]) for i in range(k)]
|
|
|
|
|
|
def constrained_shuffle(x: MutableSequence[int], d: int, random: Random) -> None:
|
|
n: int = len(x)
|
|
constraints: Dict[int, Set[int]] = {i: set(x[j] for j in range(max(0, i - d), min(i + d + 1, n))) for i in range(n)}
|
|
|
|
for _ in range(d * n * n):
|
|
i, j = random.randrange(n), random.randrange(n)
|
|
if x[i] in constraints[j] and x[j] in constraints[i]:
|
|
x[i], x[j] = x[j], x[i]
|
|
|
|
|
|
def weighted_sample(population: Iterable[int], weights: Iterable[float], k: int, *, random: Random) -> List[int]:
|
|
population, keys = zip(*((item, pow(random.random(), 1 / group_weight))
|
|
for item, group in itertools.groupby(sorted(zip(population, weights)), key=itemgetter(0))
|
|
if (group_weight := sum(weight for _, weight in group))))
|
|
return sorted(population, key=dict(zip(population, keys)).__getitem__)[-k:]
|