File size: 16,264 Bytes
29b445b |
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 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 |
#!/usr/bin/env python3
"""
Modified scan handler for Tag Collector Game with Enkephalin rewards for rare tags
"""
import streamlit as st
import torch
import time
import math
from tag_categories import (
get_unlocked_categories,
get_collection_power_level
)
from game_constants import TAG_CURRENCY_NAME, ENKEPHALIN_CURRENCY_NAME, ENKEPHALIN_ICON, RARITY_LEVELS, TAG_POWER_BONUSES
from state_manager import update_game_state
def enhanced_scan_button_handler(image_path):
"""
Enhanced scan button handler with Enkephalin rewards for rare tag discoveries
"""
try:
# Run inference
results = st.session_state.model.predict(
image_path=image_path,
threshold=st.session_state.threshold
)
# Get probabilities
probs = results['refined_probabilities'][0] # Remove batch dimension
# All categories are now unlocked
unlocked_categories = get_unlocked_categories(st.session_state)
# No limit on tags
max_tags = float('inf') # Unlimited
# Get collection power bonus
power_info = get_collection_power_level(st.session_state)
coin_multiplier = power_info['current_level']['coin_bonus']
# Store all detected tags for display
all_tags = {} # Format: {category: [(tag, probability, rarity), ...]}
found_tags = [] # Tags that pass the threshold
total_currency_earned = 0
total_enkephalin_earned = 0
new_tag_count = 0
# Minimum probability to display (can be lower than threshold)
min_display_prob = 0.1
# Track any newly completed combinations
previously_unlocked = set(st.session_state.unlocked_combinations) if hasattr(st.session_state, 'unlocked_combinations') else set()
# Collect all tags that are above threshold
candidates = []
for idx in range(len(probs)):
prob_value = probs[idx].item()
# Only process tags above threshold
if prob_value >= st.session_state.threshold:
tag, category = st.session_state.model.dataset.get_tag_info(idx)
candidates.append({
"idx": idx,
"tag": tag,
"probability": prob_value,
"category": category
})
# Sort by probability (highest first)
candidates.sort(key=lambda x: x["probability"], reverse=True)
# Add all tags to appropriate categories (for display purposes)
for idx in range(len(probs)):
prob_value = probs[idx].item()
# Skip if below display threshold
if prob_value < min_display_prob:
continue
# Get tag information
tag, category = st.session_state.model.dataset.get_tag_info(idx)
# Determine rarity
rarity = determine_tag_rarity(tag, prob_value, category)
# Add to category in all_tags
if category not in all_tags:
all_tags[category] = []
# Check if this tag is above threshold (collected)
is_collected = prob_value >= st.session_state.threshold
# Add to all_tags with appropriate status
if is_collected:
all_tags[category].append((tag, prob_value, rarity, "collected"))
else:
all_tags[category].append((tag, prob_value, rarity, "displayed"))
# Process all candidates for collection and currency
for candidate in candidates:
tag = candidate["tag"]
prob_value = candidate["probability"]
category = candidate["category"]
# Determine rarity
rarity = determine_tag_rarity(tag, prob_value, category)
# Add tag to collection and get currency
currency_earned, enkephalin_earned, is_new_tag = add_tag_to_collection(tag, prob_value, category, coin_multiplier)
# Count new tags
if is_new_tag:
new_tag_count += 1
# Add to total currency earned
if currency_earned > 0:
total_currency_earned += currency_earned
# Add to total enkephalin earned
if enkephalin_earned > 0:
total_enkephalin_earned += enkephalin_earned
# Add to found tags list
found_tags.append({
"tag": tag,
"probability": prob_value,
"category": category,
"currency": currency_earned,
"enkephalin": enkephalin_earned,
"rarity": rarity,
"is_new": is_new_tag
})
# Sort each category by probability
for category in all_tags:
all_tags[category].sort(key=lambda x: x[1], reverse=True)
# Update game stats - IMPORTANT: Direct modification to ensure updates
# are properly tracked by Streamlit's session state mechanism
st.session_state.game_stats["images_processed"] += 1
st.session_state.game_stats["total_tags_found"] += len(found_tags)
# Update enkephalin stats if we earned any
if total_enkephalin_earned > 0:
if "enkephalin_generated" not in st.session_state.game_stats:
st.session_state.game_stats["enkephalin_generated"] = 0
st.session_state.game_stats["enkephalin_generated"] += total_enkephalin_earned
# Update tag power ONCE
threshold_bonus, coin_bonus = calculate_tag_power()
st.session_state.tag_power_bonus = threshold_bonus
st.session_state.coin_multiplier = coin_bonus
# Force update of state_version to trigger UI refresh
if 'state_version' not in st.session_state:
st.session_state.state_version = 0
st.session_state.state_version += 1
# Store results in session state
st.session_state.current_scan = {
"all_tags": all_tags,
"found_tags": found_tags,
"threshold": st.session_state.threshold,
"total_currency_earned": total_currency_earned,
"total_enkephalin_earned": total_enkephalin_earned,
"new_tag_count": new_tag_count,
}
# # Save game state explicitly
# save_game_state()
return True
except Exception as e:
st.error(f"Error scanning image: {str(e)}")
import traceback
st.code(traceback.format_exc())
return False
def determine_tag_rarity(tag, probability, category):
"""
Determine the rarity of a tag based on the metadata if available,
otherwise use a simplified probability-based approach.
Always returns a valid rarity level.
"""
# Set a default rarity (safeguard against returning None)
default_rarity = "Canard"
try:
# If we have the rarity metadata loaded, use it
if hasattr(st.session_state, 'tag_rarity_metadata') and st.session_state.tag_rarity_metadata:
# Check if this tag exists in our metadata
if tag in st.session_state.tag_rarity_metadata:
tag_info = st.session_state.tag_rarity_metadata[tag]
# Handle both new and old format
if isinstance(tag_info, dict) and "rarity" in tag_info:
# New format with rarity and sample_count
rarity = tag_info["rarity"]
else:
# Old format where tag_info is the rarity string directly
rarity = tag_info
# Verify the rarity is valid
if rarity in RARITY_LEVELS:
return rarity
# Special handling for rating_* and year_* tags
if tag.startswith("rating_") or tag.startswith("year_"):
for metadata_tag in st.session_state.tag_rarity_metadata:
if metadata_tag == tag:
tag_info = st.session_state.tag_rarity_metadata[metadata_tag]
if isinstance(tag_info, dict) and "rarity" in tag_info:
rarity = tag_info["rarity"]
else:
rarity = tag_info
if rarity in RARITY_LEVELS:
return rarity
except Exception as e:
# Log the error but don't crash
print(f"Error determining rarity for tag {tag}: {str(e)}")
# Return the default rarity as a fallback
return default_rarity
def get_enkephalin_reward(rarity):
"""
Determine the Enkephalin reward based on tag rarity
Args:
rarity (str): The tag rarity level
Returns:
int: Amount of Enkephalin to award
"""
# Get enkephalin reward from TAG_POWER_BONUSES
if rarity in TAG_POWER_BONUSES:
return TAG_POWER_BONUSES[rarity]["enkephalin_reward"]
return 0
def add_tag_to_collection(tag, probability, category, coin_multiplier=1.0):
"""
Add a tag to the user's collection and award currency and enkephalin for new discoveries.
"""
try:
# Get the tag's rarity
rarity = determine_tag_rarity(tag, probability, category)
# Check if this is a new tag discovery
is_new_tag = tag not in st.session_state.collected_tags
# Check if tag was previously sacrificed
was_sacrificed = hasattr(st.session_state, 'sacrificed_tags') and tag in st.session_state.sacrificed_tags
# Get base currency value for this rarity
base_currency_value = RARITY_LEVELS[rarity]["value"]
# Basic debug info - always print this
print(f"Processing tag: {tag}, rarity: {rarity}, is_new: {is_new_tag}, base_value: {base_currency_value}")
# Initialize currency earned
currency_earned = 0
enkephalin_earned = 0
# Record the tag acquisition
timestamp = time.strftime("%H:%M:%S")
# Update tag collection
if tag in st.session_state.collected_tags:
# If already collected, just increment the count, no new currency
st.session_state.collected_tags[tag]["count"] += 1
else:
# New tag discovery - create entry in collection
st.session_state.collected_tags[tag] = {
"count": 1,
"rarity": rarity,
"category": category,
"discovery_time": timestamp
}
# Award currency and enkephalin only if not previously sacrificed and is a new tag
if not was_sacrificed and is_new_tag:
# Calculate tag power bonuses
tag_power_bonus, base_coin_multiplier = calculate_tag_power()
# Now print the debug info AFTER calculating base_coin_multiplier
print(f" Base multiplier: {base_coin_multiplier}, Collection multiplier: {coin_multiplier}")
# Apply collection power multiplier
total_multiplier = base_coin_multiplier * coin_multiplier
# Check if category is mastered for additional bonus
if hasattr(st.session_state, 'mastered_categories') and category in st.session_state.mastered_categories:
from tag_categories import CATEGORY_MASTERY_BONUS
total_multiplier += CATEGORY_MASTERY_BONUS.get('coin_multiplier', 0)
# Award currency with multiplier for new discoveries
currency_earned = int(base_currency_value * total_multiplier)
# Award enkephalin for new tag discoveries based on rarity
enkephalin_earned = get_enkephalin_reward(rarity)
# Apply any enkephalin bonus from achievements if it exists
if hasattr(st.session_state, 'enkephalin_bonus') and st.session_state.enkephalin_bonus > 0:
enkephalin_earned = int(enkephalin_earned * (1 + st.session_state.enkephalin_bonus))
print(f" Final multiplier: {total_multiplier}, Final award: {currency_earned} {TAG_CURRENCY_NAME}, {enkephalin_earned} {ENKEPHALIN_CURRENCY_NAME}")
# Add to player's currency
st.session_state.tag_currency += currency_earned
# Add to player's enkephalin if earned
if enkephalin_earned > 0:
st.session_state.enkephalin += enkephalin_earned
# Track in stats
st.session_state.game_stats["total_currency_earned"] += currency_earned
# Add to history for new discoveries
if not hasattr(st.session_state, 'tag_history'):
st.session_state.tag_history = []
st.session_state.tag_history.append({
"tag": tag,
"rarity": rarity,
"value": currency_earned,
"enkephalin": enkephalin_earned,
"time": timestamp,
"is_new": True
})
# Always increment total tags found count
st.session_state.game_stats["total_tags_found"] += 1
# Update tag power calculations with the new tag
threshold_bonus, coin_bonus = calculate_tag_power()
st.session_state.tag_power_bonus = threshold_bonus
st.session_state.coin_multiplier = coin_bonus
update_game_state(tag_currency=st.session_state.tag_currency, enkephalin=st.session_state.enkephalin)
# Return the earned currency, enkephalin, and new tag status
return currency_earned, enkephalin_earned, is_new_tag
except Exception as e:
# Log the error
print(f"Error adding tag '{tag}' to collection: {str(e)}")
import traceback
traceback.print_exc()
# Return safe defaults to prevent crashing
return 0, 0, False
def calculate_tag_power():
"""
Calculate tag power bonuses based on collected tags (not sacrificed ones).
Tags that are sacrificed no longer contribute to tag power until recollected.
Returns:
(threshold_reduction, coin_multiplier)
"""
if not hasattr(st.session_state, 'collected_tags'):
return 0, 1.0
total_threshold_reduction = 0
total_coin_multiplier = 1.0
# Calculate bonuses from individual tags
for tag, info in st.session_state.collected_tags.items():
rarity = info["rarity"]
if rarity in TAG_POWER_BONUSES:
# Add threshold reduction (scales with tag count, but with diminishing returns)
count = info["count"]
# Use logarithmic scaling to prevent excessive bonuses from farming
scaling_factor = 1 + (math.log(count) / 2) if count > 1 else 1
# Apply the bonus
total_coin_multiplier += TAG_POWER_BONUSES[rarity]["coin_multiplier"] * scaling_factor
# Apply collection power coin bonus
if hasattr(st.session_state, 'collection_power_coin_bonus'):
total_coin_multiplier *= st.session_state.collection_power_coin_bonus
return total_threshold_reduction, total_coin_multiplier |