import json import sys from typing import Dict, List, Tuple, Optional from artifact_optimizer import ArtifactOptimizer class InteractiveArtifactOptimizer: def __init__(self): self.optimizer = ArtifactOptimizer() self.available_characters = [] def load_data(self): """Load artifact and character data""" try: self.optimizer.load_data('data.json', 'characters.json') self.available_characters = list(self.optimizer.character_data.keys()) print("āœ… Data loaded successfully!") print(f"šŸ“¦ Total artifacts: {len(self.optimizer.artifacts)}") print(f"šŸ‘„ Available characters: {len(self.available_characters)}") return True except FileNotFoundError as e: print(f"āŒ Error loading data: {e}") print("Make sure 'data.json' and 'characters.json' are in the current directory.") return False except Exception as e: print(f"āŒ Unexpected error: {e}") return False def display_character_info(self, character: str): """Display detailed character information""" char_data = self.optimizer.character_data.get(character, {}) print(f"\n{'='*50}") print(f"CHARACTER INFO: {character}") print(f"{'='*50}") # ER Requirements er_req = char_data.get('er_requirement', {}) print("šŸ”‹ Energy Recharge Requirements:") if isinstance(er_req, dict) and 'min' in er_req: print(f" {er_req['min']}-{er_req.get('max', er_req['min'])}%") elif isinstance(er_req, dict): for scenario, req in er_req.items(): print(f" {scenario}: {req['min']}-{req['max']}%") else: print(" No specific requirement") # Ideal Main Stats ideal_stats = char_data.get('ideal_main_stats', {}) if ideal_stats: print("\nšŸŽÆ Ideal Main Stats:") for slot, stats in ideal_stats.items(): print(f" {slot.capitalize()}: {', '.join(stats)}") # Substat Priority substats = char_data.get('substat_priority', []) if substats: print(f"\nšŸ“Š Substat Priority: {' > '.join(substats)}") # Notes notes = char_data.get('notes', []) if notes: print(f"\nšŸ“ Notes:") for note in notes: print(f" • {note}") def select_characters(self) -> List[str]: """Interactive character selection""" print(f"\n{'='*60}") print("CHARACTER SELECTION") print(f"{'='*60}") print("Available characters:") for i, char in enumerate(self.available_characters, 1): print(f" {i}. {char}") selected_chars = [] while True: print(f"\nšŸ“‹ Current priority order: {' -> '.join(selected_chars) if selected_chars else '(none)'}") print(f"šŸŽÆ Remaining characters: {len(self.available_characters) - len(selected_chars)}") print("\nOptions:") print(" • Enter character number to add to priority list") print(" • Type character name directly") print(" • 'info [character]' to view character details") print(" • 'remove [position]' to remove from priority list") print(" • 'done' to finish selection") print(" • 'quit' to exit") choice = input("\nāž¤ Your choice: ").strip() if choice.lower() == 'quit': sys.exit(0) elif choice.lower() == 'done': if selected_chars: break else: print("āŒ Please select at least one character!") continue elif choice.startswith('info '): char_name = choice[5:].strip() if char_name in self.available_characters: self.display_character_info(char_name) else: print(f"āŒ Character '{char_name}' not found!") elif choice.startswith('remove '): try: pos = int(choice[7:].strip()) - 1 if 0 <= pos < len(selected_chars): removed = selected_chars.pop(pos) print(f"āœ… Removed {removed} from position {pos + 1}") else: print("āŒ Invalid position!") except ValueError: print("āŒ Invalid position number!") elif choice.isdigit(): try: char_index = int(choice) - 1 if 0 <= char_index < len(self.available_characters): char = self.available_characters[char_index] if char not in selected_chars: selected_chars.append(char) print(f"āœ… Added {char} to priority position {len(selected_chars)}") else: print(f"āš ļø {char} is already in the priority list!") else: print("āŒ Invalid character number!") except ValueError: print("āŒ Invalid input!") elif choice in self.available_characters: if choice not in selected_chars: selected_chars.append(choice) print(f"āœ… Added {choice} to priority position {len(selected_chars)}") else: print(f"āš ļø {choice} is already in the priority list!") else: print("āŒ Invalid choice! Try again.") return selected_chars def get_optimization_settings(self) -> Dict: """Get optimization settings from user""" print(f"\n{'='*60}") print("OPTIMIZATION SETTINGS") print(f"{'='*60}") settings = {} # Ask about 4-star fallback while True: use_4star = input("Allow 4-star artifacts as fallback? (y/n) [default: y]: ").strip().lower() if use_4star in ['', 'y', 'yes']: settings['allow_4star_fallback'] = True break elif use_4star in ['n', 'no']: settings['allow_4star_fallback'] = False break else: print("āŒ Please enter 'y' or 'n'") # Ask about ER flexibility while True: try: er_flexibility = input("ER requirement flexibility (%) [default: 20]: ").strip() if er_flexibility == '': settings['er_flexibility'] = 20 break else: settings['er_flexibility'] = float(er_flexibility) break except ValueError: print("āŒ Please enter a valid number") return settings def run_optimization(self, character_priority: List[str], settings: Dict): """Run the optimization process""" print(f"\n{'='*60}") print("RUNNING OPTIMIZATION") print(f"{'='*60}") print(f"šŸŽÆ Character priority: {' -> '.join(character_priority)}") print(f"āš™ļø Settings: {settings}") print("\nOptimizing...") # Run optimization results = self.optimizer.optimize_builds(character_priority) # Display results formatted_output = self.optimizer.format_results(results) print(formatted_output) # Save results filename = 'interactive_optimization_results.txt' with open(filename, 'w') as f: f.write("INTERACTIVE ARTIFACT OPTIMIZATION RESULTS\n") f.write("="*60 + "\n") f.write(f"Character Priority: {' -> '.join(character_priority)}\n") f.write(f"Settings: {settings}\n") f.write("="*60 + "\n\n") f.write(formatted_output) print(f"\nšŸ’¾ Results saved to '{filename}'") return results def show_summary_stats(self, results: Dict): """Show summary statistics""" print(f"\n{'='*60}") print("SUMMARY STATISTICS") print(f"{'='*60}") successful_builds = [data for data in results.values() if data['build'] is not None] if successful_builds: scores = [data['average_score'] for data in successful_builds] print(f"šŸ“Š Build Quality Distribution:") print(f" Best build: {max(scores):.1f}/100") print(f" Worst build: {min(scores):.1f}/100") print(f" Average: {sum(scores)/len(scores):.1f}/100") # Quality tiers tiers = { 'God-like (88+)': len([s for s in scores if s >= 88]), 'Insane (77+)': len([s for s in scores if 77 <= s < 88]), 'Amazing (66+)': len([s for s in scores if 66 <= s < 77]), 'Great (55+)': len([s for s in scores if 55 <= s < 66]), 'Good (44+)': len([s for s in scores if 44 <= s < 55]), 'Below 44': len([s for s in scores if s < 44]) } print(f"\nšŸ† Quality Tiers:") for tier, count in tiers.items(): if count > 0: print(f" {tier}: {count} build(s)") # ER compliance er_compliant = sum(1 for data in results.values() if data['build'] and data['er_info']['meets_requirement']) print(f"\n⚔ Energy Recharge Compliance:") print(f" Builds meeting ER requirements: {er_compliant}/{len(results)}") def main_menu(self): """Main interactive menu""" print("="*60) print("šŸŽ® INTERACTIVE GENSHIN ARTIFACT OPTIMIZER") print("="*60) print("Based on the artifact scoring system by Sevy") print("Automates the optimization process for multiple characters") if not self.load_data(): return while True: print(f"\n{'='*40}") print("MAIN MENU") print(f"{'='*40}") print("1. Start Optimization") print("2. View Character Info") print("3. View Available Characters") print("4. Exit") choice = input("\nāž¤ Select option (1-4): ").strip() if choice == '1': # Start optimization process character_priority = self.select_characters() if character_priority: settings = self.get_optimization_settings() results = self.run_optimization(character_priority, settings) self.show_summary_stats(results) # Ask if user wants to try again while True: again = input("\nšŸ”„ Run another optimization? (y/n): ").strip().lower() if again in ['y', 'yes']: break elif again in ['n', 'no']: continue else: print("āŒ Please enter 'y' or 'n'") if again in ['n', 'no']: break elif choice == '2': # View character info print("\nAvailable characters:") for i, char in enumerate(self.available_characters, 1): print(f" {i}. {char}") char_choice = input("\nEnter character name or number: ").strip() if char_choice.isdigit(): try: char_index = int(char_choice) - 1 if 0 <= char_index < len(self.available_characters): self.display_character_info(self.available_characters[char_index]) else: print("āŒ Invalid character number!") except ValueError: print("āŒ Invalid input!") elif char_choice in self.available_characters: self.display_character_info(char_choice) else: print(f"āŒ Character '{char_choice}' not found!") elif choice == '3': # View available characters print(f"\nšŸ“‹ Available Characters ({len(self.available_characters)}):") for char in sorted(self.available_characters): print(f" • {char}") elif choice == '4': print("\nšŸ‘‹ Thanks for using the Artifact Optimizer!") break else: print("āŒ Invalid choice! Please select 1-4.") def main(): """Main entry point""" optimizer = InteractiveArtifactOptimizer() try: optimizer.main_menu() except KeyboardInterrupt: print("\n\nšŸ‘‹ Optimization interrupted. Goodbye!") except Exception as e: print(f"\nāŒ An error occurred: {e}") print("Please check your data files and try again.") if __name__ == "__main__": main()