Files
Stock-Game/mainweb.py
2025-12-12 16:12:13 -05:00

322 lines
10 KiB
Python

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)