Initial commit: Plants turn-based battle game
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from collections import Counter
|
||||
|
||||
from .plants import POOL, plant_rarity
|
||||
from .types import ALL_TYPES
|
||||
|
||||
PACK_TYPES = ("lesser", "tower", "general") + ALL_TYPES # lesser, tower, general + one per type
|
||||
REWARD_PACK_TYPES = ("general",) + ALL_TYPES # good packs only (win rewards)
|
||||
RARITY_WEIGHTS = {"common": 50, "rare": 35, "super_rare": 5, "super_super_rare": 2, "ultra_rare": 1}
|
||||
LESSER_RARITY_WEIGHTS = {"common": 70, "rare": 25, "super_rare": 2, "super_super_rare": 0, "ultra_rare": 0}
|
||||
TOWER_RARITY_WEIGHTS = {"common": 2, "rare": 15, "super_rare": 25, "super_super_rare": 15, "ultra_rare": 5}
|
||||
|
||||
|
||||
def _weighted(names, weights_map=None) -> str:
|
||||
weights_map = weights_map or RARITY_WEIGHTS
|
||||
weights = [weights_map.get(plant_rarity(n), 20) for n in names]
|
||||
return random.choices(names, weights=weights, k=1)[0]
|
||||
|
||||
|
||||
def open_pack(pack_type: str) -> str:
|
||||
"""Return a random plant name for the given pack type."""
|
||||
if pack_type == "lesser":
|
||||
return _weighted(list(POOL.keys()), LESSER_RARITY_WEIGHTS)
|
||||
if pack_type == "tower":
|
||||
return _weighted(list(POOL.keys()), TOWER_RARITY_WEIGHTS)
|
||||
if pack_type == "general":
|
||||
return _weighted(list(POOL.keys()))
|
||||
if pack_type in ALL_TYPES:
|
||||
# type pack: roll the rarity first (with the general ladder), then pick a
|
||||
# plant of that rarity from the type; fall back to the whole pool only if
|
||||
# that rarity isn't present in the type.
|
||||
dist = _rarity_odds(list(POOL.keys()), RARITY_WEIGHTS)
|
||||
rarity = random.choices(list(dist.keys()),
|
||||
weights=[dist[r] for r in dist], k=1)[0]
|
||||
candidates = [n for n in POOL
|
||||
if POOL[n]["type"] == pack_type and plant_rarity(n) == rarity]
|
||||
if not candidates:
|
||||
candidates = [n for n in POOL if plant_rarity(n) == rarity]
|
||||
return random.choice(candidates)
|
||||
return _weighted(list(POOL.keys()))
|
||||
|
||||
|
||||
def _rarity_odds(pool, weights_map) -> dict:
|
||||
"""Chance (0..1) of each rarity when rolling from `pool` with `weights_map`."""
|
||||
counts = Counter(plant_rarity(n) for n in pool)
|
||||
total = sum(counts.get(r, 0) * w for r, w in weights_map.items())
|
||||
if total <= 0:
|
||||
return {r: 0.0 for r in weights_map}
|
||||
return {r: counts.get(r, 0) * weights_map[r] / total for r in weights_map}
|
||||
|
||||
|
||||
def pack_odds(pack_type: str) -> dict:
|
||||
"""Chance (0..1) of each rarity for the given pack type."""
|
||||
whole = list(POOL.keys())
|
||||
if pack_type == "lesser":
|
||||
return _rarity_odds(whole, LESSER_RARITY_WEIGHTS)
|
||||
if pack_type == "tower":
|
||||
return _rarity_odds(whole, TOWER_RARITY_WEIGHTS)
|
||||
if pack_type == "general":
|
||||
return _rarity_odds(whole, RARITY_WEIGHTS)
|
||||
# type packs roll the rarity first with the general ladder, so their rarity
|
||||
# odds match the general pack (the plant then comes from the type when possible).
|
||||
return _rarity_odds(whole, RARITY_WEIGHTS)
|
||||
Reference in New Issue
Block a user