روبیکا من : https://rubika.ir/artinkarimian3 سایت من : https://sites.google.com/view/artin-karimian
پروژه چهارم : همستر کامبت (ساده)

خب برای این پروژه وسایلی که نیاز دارید :
برنامه پایتون
کتابخانه tkinter
کتابخانه json
کتابخانه datetime
کتابخانه random
کتابخانه os
کتابخانه math

کتابخانه های لازم را نصب کنید و کد زیر را دخل آن وارد کنید.
import tkinter as tk
from tkinter import ttk # For themed widgets like Notebook (tabs)
import json
import datetime
import random
import os
import math # For ceiling function
SETTINGS_FILE = "hamster_combat_settings.json"
# --- Initial Data ---
INITIAL_UPGRADES = {
"tap_boost": {"name": "Tap Boost", "description": "Increases balance per tap", "base_cost": 100, "cost_multiplier": 1.15, "tap_increase": 1, "level": 0, "icon": "⚡"},
"hourly_profit_boost": {"name": "Hourly Profit Boost", "description": "Increases profit per hour", "base_cost": 500, "cost_multiplier": 1.2, "hourly_profit": 10, "level": 0, "icon": "💰"},
"cost_reduction": {"name": "Cost Reduction", "description": "Reduces upgrade costs", "base_cost": 1000, "cost_multiplier": 1.3, "cost_reduction_percent": 0.05, "level": 0, "icon": "📉"}, # 5% reduction
"special_card_chance": {"name": "Special Card Chance", "description": "Increases chance of special cards", "base_cost": 2000, "cost_multiplier": 1.25, "special_card_chance_boost": 0.02, "level": 0, "icon": "❓"} # 2% boost
}
SPECIAL_CARDS = {
"double_tap": {"name": "Double Tap", "duration": 60, "effect": lambda balance, tap_value: (balance + tap_value * 2, tap_value * 2), "description": "Tap value doubled", "icon": "💥"},
"hourly_boost_x5": {"name": "Hourly Boost x5", "duration": 120, "effect": lambda profit: profit * 5, "description": "Hourly profit x5", "icon": "🚀"},
"free_upgrade": {"name": "Free Upgrade", "duration": 10, "effect": lambda: True, "description": "Next upgrade is free", "icon": "🎁"}
}
# --- Colors and Fonts ---
BG_COLOR = '#f0e6d2'
FRAME_COLOR = '#e8dcc2'
BUTTON_COLOR = '#a08a7a'
BUTTON_HOVER_COLOR = '#8a7a6a'
TEXT_COLOR_DARK = '#3a2a1a'
TEXT_COLOR_MEDIUM = '#5a4a3a'
FONT_LARGE_BOLD = ('Arial', 24, 'bold')
FONT_MEDIUM_BOLD = ('Arial', 18, 'bold')
FONT_MEDIUM = ('Arial', 16)
FONT_SMALL_BOLD = ('Arial', 14, 'bold')
FONT_SMALL = ('Arial', 12)
FONT_TINY_ITALIC = ('Arial', 10, 'italic')
# --- Game Class ---
class HamsterCombatGame:
def __init__(self, master):
self.master = master
self.master.title("Hamster Combat Sim")
self.master.geometry("900x700") # Adjusted size for better layout
self.master.configure(bg=BG_COLOR)
# --- Game State Variables ---
self.balance = tk.IntVar(value=0)
self.hourly_profit = tk.IntVar(value=0)
self.tap_value = tk.IntVar(value=1)
self.current_cost_multiplier = tk.DoubleVar(value=1.0)
self.special_card_chance_boost = tk.DoubleVar(value=0.0)
self.active_special_card = None
self.special_card_end_time = None
self.last_hourly_profit_time = datetime.datetime.now()
self.original_hourly_profit_for_boost = 0 # To store profit before x5 boost
self.upgrades = self.load_settings()
self.save_settings_on_exit()
self.create_main_layout()
self.update_display()
self.add_hourly_profit_periodically()
self.check_special_cards()
self.trigger_random_special_card() # Start checking for special cards
self.auto_save()
def create_main_layout(self):
# --- Main Notebook (Tabbed Interface) ---
self.notebook = ttk.Notebook(self.master)
self.notebook.pack(pady=10, padx=10, expand=True, fill='both')
# --- Frame Colors for Notebook ---
style = ttk.Style()
style.configure("TNotebook", background=BG_COLOR, borderwidth=0)
style.map("TNotebook", background=[("selected", BG_COLOR)]) # Make selected tab background match
style.configure("TNotebook.Tab", padding=[10, 5], font=FONT_SMALL_BOLD, background=FRAME_COLOR, foreground=TEXT_COLOR_MEDIUM)
style.map("TNotebook.Tab", background=[("selected", BG_COLOR)], foreground=[("selected", TEXT_COLOR_DARK)])
# --- Create individual tabs ---
self.home_tab = ttk.Frame(self.notebook, padding=15, style="TFrame")
self.upgrades_tab = ttk.Frame(self.notebook, padding=15, style="TFrame")
self.mines_tab = ttk.Frame(self.notebook, padding=15, style="TFrame") # Placeholder for future expansion
self.notebook.add(self.home_tab, text=' 🏠 Home ')
self.notebook.add(self.upgrades_tab, text=' 🛠️ Upgrades ')
self.notebook.add(self.mines_tab, text=' ⛏️ Mines ')
# --- Populate Tabs ---
self.create_home_tab_widgets()
self.create_upgrades_tab_widgets()
# self.create_mines_tab_widgets() # Call if mines tab is implemented
# --- Home Tab ---
def create_home_tab_widgets(self):
home_frame = self.home_tab
# Top Panel: Balance and Profit Display
top_panel = tk.Frame(home_frame, bg=FRAME_COLOR, pady=15, relief=tk.RIDGE, borderwidth=2)
top_panel.pack(fill=tk.X, pady=(0, 20))
tk.Label(top_panel, text="Hamster Coin:", font=FONT_LARGE_BOLD, bg=FRAME_COLOR, fg=TEXT_COLOR_DARK).pack(pady=(0, 5))
self.balance_label = tk.Label(top_panel, textvariable=self.balance, font=('Arial', 48, 'bold'), bg=FRAME_COLOR, fg=TEXT_COLOR_DARK)
self.balance_label.pack(pady=5)
self.profit_label = tk.Label(home_frame, text="", font=FONT_MEDIUM, bg=BG_COLOR, fg=TEXT_COLOR_MEDIUM)
self.profit_label.pack(pady=5)
# Central Area: Click Button
click_area = tk.Frame(home_frame, bg=BG_COLOR)
click_area.pack(pady=30, expand=True)
self.click_button = tk.Button(click_area, text="Click Me!", font=('Impact', 40), bg=BUTTON_COLOR, fg='white',
activebackground=BUTTON_HOVER_COLOR, activeforeground='white',
command=self.increase_balance_by_tap, relief=tk.FLAT, borderwidth=0, # Flat button style
padx=30, pady=20, width=10) # Increased padding for button size
self.click_button.pack(pady=20)
# Add a subtle visual effect on hover (optional, requires more advanced binding)
# Special Card Info Display
self.special_card_label = tk.Label(home_frame, text="", font=FONT_MEDIUM_BOLD, bg=BG_COLOR, fg='#d85000')
self.special_card_label.pack(pady=10)
# --- Upgrades Tab ---
def create_upgrades_tab_widgets(self):
upgrade_frame = self.upgrades_tab
# Canvas for scrollable upgrades
self.upgrade_canvas = tk.Canvas(upgrade_frame, bg=BG_COLOR, highlightthickness=0)
self.upgrade_scrollbar = ttk.Scrollbar(upgrade_frame, orient="vertical", command=self.upgrade_canvas.yview)
self.scrollable_upgrade_frame = tk.Frame(self.upgrade_canvas, bg=BG_COLOR)
self.upgrade_scrollbar.pack(side="right", fill="y")
self.upgrade_canvas.pack(side="left", fill="both", expand=True)
self.upgrade_canvas.configure(yscrollcommand=self.upgrade_scrollbar.set)
self.upgrade_canvas.create_window((0, 0), window=self.scrollable_upgrade_frame, anchor="nw")
self.scrollable_upgrade_frame.bind("<Configure>", lambda e: self.upgrade_canvas.configure(scrollregion=self.upgrade_canvas.bbox("all")))
self.load_upgrade_buttons()
def load_upgrade_buttons(self):
# Clear previous buttons if any
for widget in self.scrollable_upgrade_frame.winfo_children():
widget.destroy()
row_num = 0
for key, upgrade_data in sorted(self.upgrades.items()): # Sort for consistent order
frame = tk.Frame(self.scrollable_upgrade_frame, bg=FRAME_COLOR, relief=tk.RAISED, borderwidth=2, padx=10, pady=8)
frame.grid(row=row_num, column=0, sticky="ew", padx=5, pady=5)
# Icon and Name
icon = upgrade_data.get("icon", "")
tk.Label(frame, text=f"{icon} {upgrade_data['name']} (Lv. {upgrade_data['level']})", font=FONT_SMALL_BOLD, bg=FRAME_COLOR, fg=TEXT_COLOR_DARK, anchor='w').grid(row=0, column=0, sticky="w", padx=(5, 0))
# Description
desc = upgrade_data.get('description', '')
tk.Label(frame, text=desc, font=FONT_TINY_ITALIC, bg=FRAME_COLOR, fg=TEXT_COLOR_MEDIUM, anchor='w').grid(row=1, column=0, sticky="w", padx=(5, 0))
# Cost and Buy Button
cost = self.calculate_upgrade_cost(key)
cost_str = f"{cost:,}" # Formatted cost
button_text = "خرید"
button_color = BUTTON_COLOR
button_hover_color = BUTTON_HOVER_COLOR
# Check if enough balance
if self.balance.get() < cost:
button_text = "موجودی کافی نیست"
button_color = '#cccccc' # Greyed out
button_hover_color = '#cccccc'
buy_button = tk.Button(frame, text=f"{button_text} ({cost_str})", font=FONT_SMALL, command=lambda k=key: self.buy_upgrade(k), bg=button_color, fg='white',
activebackground=button_hover_color, activeforeground='white', relief=tk.FLAT, borderwidth=0, padx=10, pady=5)
buy_button.grid(row=0, column=1, rowspan=2, sticky="e", padx=5)
row_num += 1
# Configure grid weights for responsiveness
self.scrollable_upgrade_frame.grid_columnconfigure(0, weight=1) # Upgrade info takes available space
self.scrollable_upgrade_frame.grid_columnconfigure(1, weight=0) # Button takes minimum space
# --- Core Game Logic (mostly unchanged, minor tweaks for UI) ---
def load_settings(self):
if os.path.exists(SETTINGS_FILE):
try:
with open(SETTINGS_FILE, 'r', encoding='utf-8') as f:
data = json.load(f)
loaded_upgrades = {}
# Load upgrades ensuring all fields exist
for key, initial_data in INITIAL_UPGRADES.items():
upgrade_data = data.get("upgrades", {}).get(key, initial_data.copy())
for field, default_value in initial_data.items():
if field not in upgrade_data:
upgrade_data[field] = default_value
loaded_upgrades[key] = upgrade_data
# Ensure upgrades dictionary always contains keys from INITIAL_UPGRADES
for key, initial_data in INITIAL_UPGRADES.items():
if key not in loaded_upgrades:
loaded_upgrades[key] = initial_data.copy()
else:
# Ensure all fields are present in loaded upgrades
for field, default_val in initial_data.items():
if field not in loaded_upgrades[key]:
loaded_upgrades[key][field] = default_val
self.balance.set(data.get("balance", 0))
self.hourly_profit.set(data.get("hourly_profit", 0))
self.tap_value.set(data.get("tap_value", 1))
self.active_special_card = data.get("active_special_card", None)
if self.active_special_card:
try:
end_time_str = data.get("special_card_end_time")
if end_time_str:
self.special_card_end_time = datetime.datetime.fromisoformat(end_time_str)
else: self.special_card_end_time = None
except ValueError:
self.active_special_card, self.special_card_end_time = None, None
else: self.special_card_end_time = None
self.last_hourly_profit_time = datetime.datetime.fromisoformat(data.get("last_hourly_profit_time", datetime.datetime.now().isoformat()))
self.current_cost_multiplier.set(data.get("current_cost_multiplier", 1.0))
self.special_card_chance_boost.set(data.get("special_card_chance_boost", 0.0))
self.original_hourly_profit_for_boost = data.get("original_hourly_profit_for_boost", 0) # Load boost value too
return loaded_upgrades
except (json.JSONDecodeError, FileNotFoundError, ValueError, KeyError) as e:
print(f"Error loading settings: {e}. Creating default settings.")
return self.create_default_settings()
else:
return self.create_default_settings()
def create_default_settings(self):
default_upgrades = {}
for key, value in INITIAL_UPGRADES.items():
default_upgrades[key] = value.copy()
return default_upgrades
def save_settings_on_exit(self):
self.master.protocol("WM_DELETE_WINDOW", self.on_exit)
def on_exit(self):
self.save_settings()
self.master.destroy()
def save_settings(self):
settings = {
"balance": self.balance.get(),
"hourly_profit": self.hourly_profit.get(),
"tap_value": self.tap_value.get(),
"upgrades": self.upgrades,
"active_special_card": self.active_special_card,
"special_card_end_time": self.special_card_end_time.isoformat() if self.special_card_end_time else None,
"last_hourly_profit_time": self.last_hourly_profit_time.isoformat(),
"current_cost_multiplier": self.current_cost_multiplier.get(),
"special_card_chance_boost": self.special_card_chance_boost.get(),
"original_hourly_profit_for_boost": self.original_hourly_profit_for_boost # Save boost value
}
try:
with open(SETTINGS_FILE, 'w', encoding='utf-8') as f:
json.dump(settings, f, indent=4, ensure_ascii=False)
except IOError as e:
print(f"Error saving settings: {e}")
def recalculate_profits(self):
base_tap = 1
base_hourly = 0
cost_reduction_percent = 0.0
# Recalculate based on current upgrade levels
for key, upgrade_data in self.upgrades.items():
level = upgrade_data.get('level', 0)
if level > 0:
if key == "tap_boost":
base_tap += upgrade_data.get("tap_increase", 0) * level
elif key == "hourly_profit_boost":
base_hourly += upgrade_data.get("hourly_profit", 0) * level
elif key == "cost_reduction":
cost_reduction_percent += upgrade_data.get("cost_reduction_percent", 0.0) * level
elif key == "special_card_chance":
self.special_card_chance_boost.set(upgrade_data.get("special_card_chance_boost", 0.0) * level)
self.tap_value.set(base_tap)
# Apply hourly boost multiplier ONLY IF the card is active and it's the x5 boost
current_hourly_profit = base_hourly
if self.active_special_card == "hourly_boost_x5":
# Ensure original_hourly_profit_for_boost is set correctly before applying multiplier
self.original_hourly_profit_for_boost = base_hourly # Store the base hourly profit
current_hourly_profit = self.original_hourly_profit_for_boost * SPECIAL_CARDS["hourly_boost_x5"]["effect"](1) # Apply the multiplier
else:
self.original_hourly_profit_for_boost = 0 # Reset if not x5 boost card
current_hourly_profit = base_hourly # Use the base hourly profit
self.hourly_profit.set(current_hourly_profit)
self.current_cost_multiplier.set(max(0.1, 1.0 - cost_reduction_percent))
def calculate_upgrade_cost(self, upgrade_key):
upgrade_data = self.upgrades[upgrade_key]
base_cost = upgrade_data["base_cost"]
level = upgrade_data["level"]
cost_multiplier = upgrade_data["cost_multiplier"]
effective_cost_multiplier = self.current_cost_multiplier.get()
# Calculate cost: base * (multiplier^level) * reduction_multiplier
cost = base_cost * (cost_multiplier ** level) * effective_cost_multiplier
return math.ceil(cost) # Use ceiling to ensure cost is always rounded up
def increase_balance_by_tap(self):
tap = self.tap_value.get()
current_tap_value = tap
# Apply special card effect if active
if self.active_special_card == "double_tap":
current_tap_value *= 2
self.balance.set(self.balance.get() + current_tap_value)
self.update_display()
# Optionally, consume the double tap card after one use if it's meant to be single-use per activation
# self.deactivate_special_card() # Uncomment if double tap should only apply once per activation
else:
self.balance.set(self.balance.get() + current_tap_value)
self.update_display()
def buy_upgrade(self, upgrade_key):
upgrade_data = self.upgrades[upgrade_key]
cost = self.calculate_upgrade_cost(upgrade_key)
is_free_upgrade_card = (self.active_special_card == "free_upgrade")
if is_free_upgrade_card:
# If free upgrade card is active, the cost is effectively zero for this purchase
# But we still need to consume the card
pass # Cost is ignored, card will be consumed later
elif self.balance.get() < cost:
print("Not enough balance!") # Show message to user
return # Do not proceed if balance is insufficient and not a free card
# If we reach here, either balance is sufficient OR it's a free upgrade card
# Deduct cost only if it's not a free upgrade card purchase
if not is_free_upgrade_card:
self.balance.set(self.balance.get() - cost)
# Increase level and update data
upgrade_data["level"] += 1
self.upgrades[upgrade_key] = upgrade_data
# Recalculate profits/tap value AFTER the upgrade level is updated
self.recalculate_profits()
# Consume the free upgrade card if it was used
if is_free_upgrade_card:
self.deactivate_special_card()
self.update_display()
self.load_upgrade_buttons() # Refresh the upgrade buttons to show new costs/levels
def add_hourly_profit_periodically(self):
now = datetime.datetime.now()
time_elapsed = (now - self.last_hourly_profit_time).total_seconds()
# Calculate profit based on current hourly_profit value
# Ensure hourly_profit reflects any active multipliers (like x5 boost)
profit_per_second = self.hourly_profit.get() / 3600.0
earned_profit = int(profit_per_second * time_elapsed)
if earned_profit > 0:
self.balance.set(self.balance.get() + earned_profit)
self.last_hourly_profit_time = now # Reset timer only when profit is earned
self.update_display()
# Schedule next check
self.master.after(60000, self.add_hourly_profit_periodically) # Check every minute
def check_special_cards(self):
if self.active_special_card and self.special_card_end_time:
if datetime.datetime.now() >= self.special_card_end_time:
self.deactivate_special_card()
else:
self.update_special_card_label()
self.master.after(1000, self.check_special_cards) # Check every second
def update_special_card_label(self):
if self.active_special_card:
card_info = SPECIAL_CARDS.get(self.active_special_card)
if card_info and self.special_card_end_time:
remaining_time = int((self.special_card_end_time - datetime.datetime.now()).total_seconds())
icon = card_info.get("icon", "")
self.special_card_label.config(text=f"{icon} {card_info['name']} ({remaining_time}s)")
else: # Card info missing or time ended but not caught?
self.special_card_label.config(text="")
self.active_special_card = None
self.special_card_end_time = None
else:
self.special_card_label.config(text="")
def deactivate_special_card(self):
if self.active_special_card:
card_info = SPECIAL_CARDS.get(self.active_special_card)
print(f"Special card '{card_info['name']}' ended.") # Log message
# Revert effects if necessary
if self.active_special_card == "hourly_boost_x5":
# Restore hourly profit to its base value before the boost
self.hourly_profit.set(self.original_hourly_profit_for_boost)
self.original_hourly_profit_for_boost = 0 # Clear stored value
elif self.active_special_card == "double_tap":
# Tap value is read dynamically, so no explicit revert needed here
pass
elif self.active_special_card == "free_upgrade":
# No ongoing effect to revert
pass
self.active_special_card = None
self.special_card_end_time = None
self.update_special_card_label()
self.update_display() # Update display to reflect changes if any
def trigger_random_special_card(self):
base_chance = 0.01 # 1% base chance
total_chance = base_chance + self.special_card_chance_boost.get()
if not self.active_special_card and random.random() < total_chance:
card_key = random.choice(list(SPECIAL_CARDS.keys()))
self.activate_special_card(card_key)
self.master.after(5000, self.trigger_random_special_card) # Check every 5 seconds
def activate_special_card(self, card_key):
if card_key in SPECIAL_CARDS:
card_info = SPECIAL_CARDS[card_key]
duration = card_info["duration"]
self.active_special_card = card_key
self.special_card_end_time = datetime.datetime.now() + datetime.timedelta(seconds=duration)
# Apply immediate effect if any
if card_key == "hourly_boost_x5":
self.original_hourly_profit_for_boost = self.hourly_profit.get() # Store current profit BEFORE applying boost
self.hourly_profit.set(self.original_hourly_profit_for_boost * card_info['effect'](1)) # Apply the multiplier
elif card_key == "free_upgrade":
# Effect is applied during purchase, just mark it active
pass
elif card_key == "double_tap":
# Effect applied during tap
pass
print(f"Special card activated: {card_info['name']} for {duration} seconds.")
self.update_special_card_label()
self.update_display() # Update display to reflect changes immediately (e.g., hourly profit)
else:
print(f"Special card with key '{card_key}' not found.")
def update_display(self):
# Update balance label (formatted)
self.balance_label.config(text=f"{self.balance.get():,}")
# Update profit label with current tap value and hourly profit
tap_val = self.tap_value.get()
hourly_prof = self.hourly_profit.get()
profit_text = f"Tap: {tap_val:,} | Hourly: {hourly_prof:,}"
# Add indicators for active special cards
if self.active_special_card == "double_tap":
profit_text += " (Tap x2)"
elif self.active_special_card == "hourly_boost_x5":
profit_text += f" (Hourly x{SPECIAL_CARDS['hourly_boost_x5']['effect'](1)})"
self.profit_label.config(text=profit_text)
# Update costs on upgrade buttons (this is called after purchase or when needed)
self.load_upgrade_buttons()
def auto_save(self):
self.save_settings()
self.master.after(300000, self.auto_save) # Save every 5 minutes
# --- Main Execution ---
if __name__ == "__main__":
root = tk.Tk()
game = HamsterCombatGame(root)
root.mainloop()
خب کد را اجرا کنید ، صفحه پایین را می بینید.

اینم از این ، نسخه سادش هست و خودتون این را ارتقا بدهید .
برای دانلود همین پایتون یا فایل تبدیل شده به برنامه روی نوشته لینک بزنید و 15ثانیه صبر کنید و فایل را دریافت کنید .
اگر ایده یا پروژه ای دیگری میخواهید در نظر ها بنویسید .
مطلبی دیگر از این انتشارات
پروژه هشتم پایتون : استخراج لینک از وب
مطلبی دیگر از این انتشارات
ساخت بازی مار در NOTEPAD در ۲ دقیقه
مطلبی دیگر از این انتشارات
آموزش ساخت یک سرور با پایتون (سرور فایل)