from flask import Flask, render_template, request, jsonify, session import random import json import os from datetime import datetime app = Flask(__name__) # Leaderboard file path LEADERBOARD_FILE = 'leaderboard.json' # List of all companies - EASY TO ADD/REMOVE COMPANIES HERE COMPANIES = [ {'id': 1, 'name': 'Kwik trip', 'key': 'kwiktrip'}, {'id': 2, 'name': 'Apple computers', 'key': 'apple'}, {'id': 3, 'name': 'Microsoft', 'key': 'microsoft'}, {'id': 4, 'name': 'Walmart Super Store', 'key': 'walmart'}, {'id': 5, 'name': 'Car company', 'key': 'car'}, {'id': 6, 'name': 'Tesla', 'key': 'tesla'}, {'id': 7, 'name': 'Amazon', 'key': 'amazon'}, {'id': 8, 'name': 'Google', 'key': 'google'}, {'id': 9, 'name': 'Netflix', 'key': 'netflix'}, {'id': 10, 'name': 'Steam', 'key': 'steam',}, {'id': 11, 'name': 'Nvidia', 'key': 'nvidia'} ] # Game state management game_state = {} leaderboard = [] def load_leaderboard(): """Load leaderboard from file""" global leaderboard if os.path.exists(LEADERBOARD_FILE): try: with open(LEADERBOARD_FILE, 'r') as f: leaderboard = json.load(f) except (json.JSONDecodeError, IOError): leaderboard = [] else: leaderboard = [] def save_leaderboard(): """Save leaderboard to file""" try: with open(LEADERBOARD_FILE, 'w') as f: json.dump(leaderboard, f, indent=4) except IOError as e: print(f"Error saving leaderboard: {e}") def init_game(days): """Initialize a new game session""" # Generate random offsets for initial prices for each company price_offsets = {company['key']: random.randint(-100, 100) for company in COMPANIES} # Build state with dynamic company prices and history state = { 'balance': 1000, 'day': 1, 'daysleft': days, 'leaderboardDays': days, 'message': '', 'priceHistory': {}, } # Add stock prices and holdings for each company for company in COMPANIES: key = company['key'] offset = price_offsets[key] # Ensure initial price is at least $1 initial_price = max(1, 100 + offset) state[f'{key}StockPrice'] = initial_price state[key] = 0 state['priceHistory'][key] = [initial_price] return state def calculate_index(state): """Calculate market index""" prices = [state[f"{company['key']}StockPrice"] for company in COMPANIES] return sum(prices) / len(prices) if prices else 0 def get_stock_list(state): """Return list of stocks with prices""" return [ {'id': company['id'], 'name': company['name'], 'price': state[f"{company['key']}StockPrice"]} for company in COMPANIES ] def get_holdings(state): """Return user's stock holdings""" return [ {'id': company['id'], 'name': company['name'], 'amount': state[company['key']]} for company in COMPANIES ] def get_game_state_data(): """Get current game state data as dictionary""" if 'current' not in game_state: return None state = game_state['current'] stocks = get_stock_list(state) holdings = get_holdings(state) return { 'balance': state['balance'], 'day': state['day'], 'daysleft': state['daysleft'], 'index': round(calculate_index(state), 2), 'stocks': stocks, 'holdings': holdings, 'message': state.get('message', ''), 'priceHistory': state.get('priceHistory', {}) } @app.route('/') def home(): """Home page - ask for number of days""" return render_template('index.html') @app.route('/api/start', methods=['POST']) def start_game(): """Initialize a new game""" data = request.json days = int(data.get('days', 5)) state = init_game(days) game_state['current'] = state return jsonify(get_game_state_data()) @app.route('/api/game-state', methods=['GET']) def get_game_state(): """Get current game state""" state_data = get_game_state_data() if state_data is None: return jsonify({'error': 'Game not started'}), 400 return jsonify(state_data) @app.route('/api/buy', methods=['POST']) def buy_stock(): """Buy stocks""" if 'current' not in game_state: return jsonify({'error': 'Game not started'}), 400 state = game_state['current'] data = request.json try: stock_id = int(data['stock_id']) amount = int(data['amount']) stocks = get_stock_list(state) stock_price = stocks[stock_id - 1]['price'] total_cost = amount * stock_price if state['balance'] < total_cost: state['message'] = f"Insufficient funds. Cost: ${total_cost}, Balance: ${state['balance']}" return jsonify({'error': state['message']}), 400 state['balance'] -= total_cost # Use dynamic COMPANIES list instead of hardcoded array stock_key = COMPANIES[stock_id - 1]['key'] state[stock_key] += amount state['message'] = f"Successfully bought {amount} shares of {stocks[stock_id - 1]['name']} for ${total_cost}" return jsonify(get_game_state_data()) except (ValueError, IndexError, KeyError) as e: return jsonify({'error': str(e)}), 400 @app.route('/api/sell', methods=['POST']) def sell_stock(): """Sell stocks""" if 'current' not in game_state: return jsonify({'error': 'Game not started'}), 400 state = game_state['current'] data = request.json try: stock_id = int(data['stock_id']) amount = int(data['amount']) stocks = get_stock_list(state) holdings = get_holdings(state) user_holdings = holdings[stock_id - 1]['amount'] if user_holdings < amount: state['message'] = f"You don't own enough shares. You own: {user_holdings}" return jsonify({'error': state['message']}), 400 stock_price = stocks[stock_id - 1]['price'] total_payout = amount * stock_price state['balance'] += total_payout # Use dynamic COMPANIES list instead of hardcoded array stock_key = COMPANIES[stock_id - 1]['key'] state[stock_key] -= amount state['message'] = f"Successfully sold {amount} shares of {stocks[stock_id - 1]['name']} for ${total_payout}" return jsonify(get_game_state_data()) except (ValueError, IndexError, KeyError) as e: return jsonify({'error': str(e)}), 400 @app.route('/api/next-day', methods=['POST']) def next_day(): """Progress to next day""" if 'current' not in game_state: return jsonify({'error': 'Game not started'}), 400 state = game_state['current'] if state['daysleft'] <= 0: return jsonify({'error': 'Game over!', 'game_over': True}), 400 state['day'] += 1 state['daysleft'] -= 1 # Update stock prices dynamically for all companies for company in COMPANIES: key = company['key'] price_key = f"{key}StockPrice" new_price = state[price_key] + random.randint(-100, 100) # Ensure price is at least $1 state[price_key] = max(1, new_price) state['priceHistory'][key].append(state[price_key]) # Market crash chance if random.randint(0, 1000) == 555: # Market crash - set all prices to $1 minimum for company in COMPANIES: key = company['key'] crash_price = max(1, int(state[f"{key}StockPrice"] * 0.2)) # Drop to 20% of current price, but no lower than $1 state[f"{key}StockPrice"] = crash_price state['priceHistory'][key][-1] = crash_price state['message'] = "Market crash! All stocks dropped significantly!" else: state['message'] = f"Moved to day {state['day']}" return jsonify(get_game_state_data()) @app.route('/api/end-game', methods=['GET']) def end_game(): """Get end game statistics""" if 'current' not in game_state: return jsonify({'error': 'Game not started'}), 400 state = game_state['current'] stocks = get_stock_list(state) total_net_worth = state['balance'] holdings = get_holdings(state) for i, holding in enumerate(holdings): total_net_worth += holding['amount'] * stocks[i]['price'] profit = state['balance'] - 1000 return jsonify({ 'starting_balance': 1000, 'ending_balance': state['balance'], 'total_net_worth': round(total_net_worth, 2), 'profit': profit, 'holdings': holdings, 'stocks': stocks }) @app.route('/api/save-score', methods=['POST']) def save_score(): """Save game score to leaderboard""" if 'current' not in game_state: return jsonify({'error': 'Game not started'}), 400 data = request.json player_name = data.get('name', 'Anonymous') state = game_state['current'] stocks = get_stock_list(state) total_net_worth = state['balance'] holdings = get_holdings(state) for i, holding in enumerate(holdings): total_net_worth += holding['amount'] * stocks[i]['price'] profit = state['balance'] - 1000 score_entry = { 'name': player_name, 'profit': profit, 'net_worth': round(total_net_worth, 2), 'final_balance': state['balance'], 'leaderboardDays': state['leaderboardDays'], 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S') } leaderboard.append(score_entry) leaderboard.sort(key=lambda x: x['profit'], reverse=True) # Save leaderboard to file save_leaderboard() return jsonify({'success': True, 'rank': leaderboard.index(score_entry) + 1}) @app.route('/api/leaderboard', methods=['GET']) def get_leaderboard(): """Get leaderboard scores""" return jsonify({'scores': leaderboard[:10]}) # Load leaderboard from file at startup load_leaderboard() if __name__ == '__main__': app.run(debug=False)