Create app.py
Browse files
app.py
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import numpy as np
|
| 3 |
+
import matplotlib.pyplot as plt
|
| 4 |
+
import random
|
| 5 |
+
|
| 6 |
+
# ============================================
|
| 7 |
+
# র্যান্ডম ডাটা জেনারেটর
|
| 8 |
+
# ============================================
|
| 9 |
+
|
| 10 |
+
def generate_random_multipliers(num_rounds=30, house_edge=0.03):
|
| 11 |
+
"""
|
| 12 |
+
র্যান্ডম মাল্টিপ্লায়ার জেনারেট করে
|
| 13 |
+
house_edge: 0.01 = 1%, 0.05 = 5% ইত্যাদি
|
| 14 |
+
"""
|
| 15 |
+
multipliers = []
|
| 16 |
+
|
| 17 |
+
for _ in range(num_rounds):
|
| 18 |
+
# 2-3% ইন্সট্যান্ট ক্র্যাশ
|
| 19 |
+
if random.random() < 0.025:
|
| 20 |
+
multipliers.append(1.00)
|
| 21 |
+
continue
|
| 22 |
+
|
| 23 |
+
# র্যান্ডম r (0 থেকে 1)
|
| 24 |
+
r = random.random()
|
| 25 |
+
|
| 26 |
+
# ডিভাইড বাই জিরো এড়াতে
|
| 27 |
+
if r >= 0.999999:
|
| 28 |
+
r = 0.999999
|
| 29 |
+
|
| 30 |
+
# মাল্টিপ্লায়ার ফর্মুলা
|
| 31 |
+
m = (1 - house_edge) / (1 - r)
|
| 32 |
+
|
| 33 |
+
# ২ দশমিকে রাউন্ড
|
| 34 |
+
multipliers.append(round(m, 2))
|
| 35 |
+
|
| 36 |
+
return multipliers
|
| 37 |
+
|
| 38 |
+
# ============================================
|
| 39 |
+
# অ্যানালাইসিস ফাংশন
|
| 40 |
+
# ============================================
|
| 41 |
+
|
| 42 |
+
def parse_multipliers(multiplier_text):
|
| 43 |
+
"""টেক্সট থেকে মাল্টিপ্লায়ার লিস্ট বানায়"""
|
| 44 |
+
try:
|
| 45 |
+
# x থাকলে সরিয়ে ফেলা
|
| 46 |
+
text = multiplier_text.replace('x', '').replace('X', '')
|
| 47 |
+
# কমা বা স্পেস দিয়ে আলাদা
|
| 48 |
+
parts = text.replace(',', ' ').split()
|
| 49 |
+
multipliers = [float(p.strip()) for p in parts if p.strip()]
|
| 50 |
+
return multipliers
|
| 51 |
+
except:
|
| 52 |
+
return []
|
| 53 |
+
|
| 54 |
+
def format_multipliers_text(multipliers):
|
| 55 |
+
"""লিস্টকে টেক্সটে কনভার্ট করে"""
|
| 56 |
+
return ', '.join([f"{m:.2f}x" for m in multipliers])
|
| 57 |
+
|
| 58 |
+
def analyze_multipliers(multiplier_text, rounds_limit=10000):
|
| 59 |
+
"""
|
| 60 |
+
মাল্টিপ্লায়ার ডাটা অ্যানালাইসিস করে
|
| 61 |
+
"""
|
| 62 |
+
multipliers = parse_multipliers(multiplier_text)
|
| 63 |
+
|
| 64 |
+
if not multipliers:
|
| 65 |
+
return "❌ ইনপুট সঠিক নয়। উদাহরণ: 1.02, 1.15, 2.34", None, None
|
| 66 |
+
|
| 67 |
+
if len(multipliers) > rounds_limit:
|
| 68 |
+
return f"⚠️ সর্বোচ্চ {rounds_limit} রাউন্ড পর্যন্ত সাপোর্ট করে। আপনি {len(multipliers)} দিয়েছেন।", None, None
|
| 69 |
+
|
| 70 |
+
if len(multipliers) < 3:
|
| 71 |
+
return "⚠️ কমপক্ষে ৩টি মাল্টিপ্লায়ার দরকার।", None, None
|
| 72 |
+
|
| 73 |
+
rounds = len(multipliers)
|
| 74 |
+
|
| 75 |
+
# ডিস্ট্রিবিউশন ক্যালকুলেশন
|
| 76 |
+
buckets = {
|
| 77 |
+
"1x - 2x": 0,
|
| 78 |
+
"2x - 5x": 0,
|
| 79 |
+
"5x - 10x": 0,
|
| 80 |
+
"10x - 50x": 0,
|
| 81 |
+
"50x +": 0
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
for m in multipliers:
|
| 85 |
+
if m < 2:
|
| 86 |
+
buckets["1x - 2x"] += 1
|
| 87 |
+
elif m < 5:
|
| 88 |
+
buckets["2x - 5x"] += 1
|
| 89 |
+
elif m < 10:
|
| 90 |
+
buckets["5x - 10x"] += 1
|
| 91 |
+
elif m < 50:
|
| 92 |
+
buckets["10x - 50x"] += 1
|
| 93 |
+
else:
|
| 94 |
+
buckets["50x +"] += 1
|
| 95 |
+
|
| 96 |
+
# পরিসংখ্যান
|
| 97 |
+
avg_multiplier = np.mean(multipliers)
|
| 98 |
+
median_multiplier = np.median(multipliers)
|
| 99 |
+
max_multiplier = max(multipliers)
|
| 100 |
+
min_multiplier = min(multipliers)
|
| 101 |
+
std_multiplier = np.std(multipliers)
|
| 102 |
+
|
| 103 |
+
# আনুমানিক হাউস এজ
|
| 104 |
+
if avg_multiplier > 1:
|
| 105 |
+
estimated_house_edge = (1 - (1 / avg_multiplier)) * 100
|
| 106 |
+
estimated_rtp = 100 - estimated_house_edge
|
| 107 |
+
else:
|
| 108 |
+
estimated_house_edge = 0
|
| 109 |
+
estimated_rtp = 100
|
| 110 |
+
|
| 111 |
+
# ইন্সট্যান্ট ক্র্যাশ
|
| 112 |
+
instant_crash = len([m for m in multipliers if m == 1.00])
|
| 113 |
+
instant_crash_pct = (instant_crash / rounds) * 100
|
| 114 |
+
|
| 115 |
+
# টেক্সট রিপোর্ট
|
| 116 |
+
report = f"""
|
| 117 |
+
## 📊 অ্যানালাইসিস রিপোর্ট
|
| 118 |
+
|
| 119 |
+
| মেট্রিক | মান |
|
| 120 |
+
|---------|-----|
|
| 121 |
+
| **মোট রাউন্ড** | {rounds} |
|
| 122 |
+
| **গড় মাল্টিপ্লায়ার** | {avg_multiplier:.4f}x |
|
| 123 |
+
| **মধ্যমান (মিডিয়ান)** | {median_multiplier:.4f}x |
|
| 124 |
+
| **সর্বোচ্চ** | {max_multiplier:.2f}x |
|
| 125 |
+
| **সর্বনিম্ন** | {min_multiplier:.2f}x |
|
| 126 |
+
| **স্ট্যান্ডার্ড ডেভিয়েশন** | {std_multiplier:.4f} |
|
| 127 |
+
|
| 128 |
+
---
|
| 129 |
+
|
| 130 |
+
### 🎲 হাউস এজ অনুমান
|
| 131 |
+
- **হাউস এজ:** {estimated_house_edge:.2f}%
|
| 132 |
+
- **RTP:** {estimated_rtp:.2f}%
|
| 133 |
+
|
| 134 |
+
---
|
| 135 |
+
|
| 136 |
+
### ⚡ ইন্সট্যান্ট ক্র্যা��
|
| 137 |
+
- **1.00x এসেছে:** {instant_crash} বার ({instant_crash_pct:.2f}%)
|
| 138 |
+
|
| 139 |
+
---
|
| 140 |
+
|
| 141 |
+
### 📈 রেঞ্জ ভিত্তিক ডিস্ট্রিবিউশন
|
| 142 |
+
"""
|
| 143 |
+
|
| 144 |
+
for key, value in buckets.items():
|
| 145 |
+
pct = (value / rounds) * 100
|
| 146 |
+
bar = "█" * int(pct / 2)
|
| 147 |
+
report += f"\n- **{key}:** {value} বার ({pct:.2f}%) {bar}"
|
| 148 |
+
|
| 149 |
+
# বড় হিট কয়টা
|
| 150 |
+
big_hits = len([m for m in multipliers if m >= 10])
|
| 151 |
+
report += f"""
|
| 152 |
+
|
| 153 |
+
---
|
| 154 |
+
|
| 155 |
+
### 🔥 বড় হিট (10x+)
|
| 156 |
+
- **মোট:** {big_hits} বার ({big_hits/rounds*100:.2f}%)
|
| 157 |
+
|
| 158 |
+
---
|
| 159 |
+
|
| 160 |
+
### 🧠 বিশ্লেষণ
|
| 161 |
+
"""
|
| 162 |
+
|
| 163 |
+
if estimated_house_edge < 3:
|
| 164 |
+
report += "✅ হাউস এজ খুব কম — গেমটি প্লেয়ার-ফ্রেন্ডলি মনে হচ্ছে।"
|
| 165 |
+
elif estimated_house_edge < 8:
|
| 166 |
+
report += "📊 হাউস এজ স্বাভাবিক সীমার মধ্যে (2-8%)।"
|
| 167 |
+
else:
|
| 168 |
+
report += "⚠️ হাউস এজ অনেক বেশি! ডাটা কম হলে এটা হতে পারে। 1000+ রাউন্ড দিয়ে আবার চেক করুন।"
|
| 169 |
+
|
| 170 |
+
if instant_crash_pct > 5:
|
| 171 |
+
report += f"\n⚠️ ইন্সট্যান্ট ক্র্যাশ ({instant_crash_pct:.1f}%) স্বাভাবিকের চেয়ে বেশি। সাধারণত 2-3% হয়।"
|
| 172 |
+
elif instant_crash_pct < 1:
|
| 173 |
+
report += f"\n📊 ইন্সট্যান্ট ক্র্যাশ ({instant_crash_pct:.1f}%) স্বাভাবিকের চেয়ে কম।"
|
| 174 |
+
else:
|
| 175 |
+
report += f"\n✅ ইন্সট্যান্ট ক্র্যাশ ({instant_crash_pct:.1f}%) স্বাভাবিক সীমার মধ্যে।"
|
| 176 |
+
|
| 177 |
+
report += f"""
|
| 178 |
+
|
| 179 |
+
---
|
| 180 |
+
|
| 181 |
+
### 💡 টিপস
|
| 182 |
+
- যত বেশি রাউন্ডের ডাটা দেবেন, অনুমান তত সঠিক হবে
|
| 183 |
+
- 500+ রাউন্ড দিলে হাউস এজ প্রায় নির্ভুল হয়
|
| 184 |
+
- 1x-2x রেঞ্জে 60-80% রাউন্ড হওয়া স্বাভাবিক
|
| 185 |
+
"""
|
| 186 |
+
|
| 187 |
+
# গ্রাফ বানানো
|
| 188 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
|
| 189 |
+
|
| 190 |
+
# হিস্টোগ্রাম
|
| 191 |
+
ax1.hist(multipliers, bins=min(30, rounds//2), edgecolor='black', alpha=0.7, color='skyblue')
|
| 192 |
+
ax1.axvline(avg_multiplier, color='red', linestyle='--', linewidth=2, label=f'গড়: {avg_multiplier:.2f}x')
|
| 193 |
+
ax1.axvline(median_multiplier, color='green', linestyle='--', linewidth=2, label=f'মিডিয়ান: {median_multiplier:.2f}x')
|
| 194 |
+
ax1.set_xlabel('মাল্টিপ্লায়ার')
|
| 195 |
+
ax1.set_ylabel('কতবার এসেছে')
|
| 196 |
+
ax1.set_title('মাল্টিপ্লায়ার ডিস্ট্রিবিউশন')
|
| 197 |
+
ax1.legend()
|
| 198 |
+
ax1.grid(True, alpha=0.3)
|
| 199 |
+
|
| 200 |
+
# বার চার্ট
|
| 201 |
+
categories = list(buckets.keys())
|
| 202 |
+
values = list(buckets.values())
|
| 203 |
+
colors = ['#2ecc71', '#3498db', '#f39c12', '#e74c3c', '#9b59b6']
|
| 204 |
+
bars = ax2.bar(categories, values, color=colors[:len(categories)], edgecolor='black')
|
| 205 |
+
ax2.set_xlabel('রেঞ্জ')
|
| 206 |
+
ax2.set_ylabel('রাউন্ড সংখ্যা')
|
| 207 |
+
ax2.set_title('রেঞ্জ ভিত্তিক ডিস্ট্রিবিউশন')
|
| 208 |
+
ax2.tick_params(axis='x', rotation=45)
|
| 209 |
+
|
| 210 |
+
for bar, val in zip(bars, values):
|
| 211 |
+
if val > 0:
|
| 212 |
+
ax2.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.2,
|
| 213 |
+
str(val), ha='center', va='bottom', fontsize=10)
|
| 214 |
+
|
| 215 |
+
plt.tight_layout()
|
| 216 |
+
|
| 217 |
+
return report, fig, format_multipliers_text(multipliers[:20])
|
| 218 |
+
|
| 219 |
+
# ============================================
|
| 220 |
+
# রিজেনারেট ফাংশন
|
| 221 |
+
# ============================================
|
| 222 |
+
|
| 223 |
+
def regenerate_data(num_rounds, house_edge):
|
| 224 |
+
"""নতুন র্যান্ডম ডাটা জেনারেট করে"""
|
| 225 |
+
multipliers = generate_random_multipliers(int(num_rounds), house_edge/100)
|
| 226 |
+
text = format_multipliers_text(multipliers)
|
| 227 |
+
return text
|
| 228 |
+
|
| 229 |
+
# ============================================
|
| 230 |
+
# গ্র্যাডিও UI
|
| 231 |
+
# ============================================
|
| 232 |
+
|
| 233 |
+
with gr.Blocks(title="মাল্টিপ্লায়ার অ্যানালাইসার", theme=gr.themes.Soft()) as demo:
|
| 234 |
+
gr.Markdown("""
|
| 235 |
+
# 🎲 মাল্টিপ্লায়ার অ্যানালাইসার
|
| 236 |
+
|
| 237 |
+
ক্র্যাশ/এভিয়েটর টাইপ গেমের মাল্টিপ্লায়ার ডাটা বিশ্লেষণ করুন।
|
| 238 |
+
""")
|
| 239 |
+
|
| 240 |
+
with gr.Tabs():
|
| 241 |
+
with gr.TabItem("📝 ম্যানুয়াল ইনপুট"):
|
| 242 |
+
with gr.Row():
|
| 243 |
+
with gr.Column(scale=3):
|
| 244 |
+
multiplier_input = gr.Textbox(
|
| 245 |
+
label="মাল্টিপ্লায়ার ইনপুট",
|
| 246 |
+
placeholder="যেমন: 1.02, 1.15, 2.34, 1.05",
|
| 247 |
+
lines=6,
|
| 248 |
+
value="1.00, 17.11, 1.17, 1.00, 1.35, 1.98, 4.26, 1.72, 1.66, 2.33, 1.45, 2.02, 1.27, 2.47, 2.06, 2.46, 1.07, 1.12, 2.17, 13.19, 1.38, 2.35, 2.02, 3.80, 1.64, 1.43, 1.94, 2.00"
|
| 249 |
+
)
|
| 250 |
+
|
| 251 |
+
with gr.Row():
|
| 252 |
+
rounds_limit = gr.Slider(
|
| 253 |
+
minimum=100,
|
| 254 |
+
maximum=10000,
|
| 255 |
+
value=5000,
|
| 256 |
+
step=100,
|
| 257 |
+
label="সর্বোচ্চ রাউন্ড সংখ্যা"
|
| 258 |
+
)
|
| 259 |
+
analyze_btn = gr.Button("🔍 অ্যানালাইসিস করুন", variant="primary")
|
| 260 |
+
|
| 261 |
+
with gr.Column(scale=2):
|
| 262 |
+
report_output = gr.Markdown(label="📊 রিপোর্ট")
|
| 263 |
+
|
| 264 |
+
with gr.Row():
|
| 265 |
+
plot_output = gr.Plot(label="📈 গ্রাফ")
|
| 266 |
+
|
| 267 |
+
with gr.TabItem("🎲 র্যান্ডম জেনারেটর"):
|
| 268 |
+
gr.Markdown("""
|
| 269 |
+
### র্যান্ডম ডাটা জেনারেট করুন
|
| 270 |
+
|
| 271 |
+
এখান থেকে নতুন র্যান্ডম মাল্টিপ্লায়ার জেনারেট করে অ্যানালাইসিস করতে পারেন।
|
| 272 |
+
""")
|
| 273 |
+
|
| 274 |
+
with gr.Row():
|
| 275 |
+
with gr.Column():
|
| 276 |
+
num_rounds = gr.Slider(
|
| 277 |
+
minimum=10,
|
| 278 |
+
maximum=500,
|
| 279 |
+
value=30,
|
| 280 |
+
step=10,
|
| 281 |
+
label="রাউন্ড সংখ্যা"
|
| 282 |
+
)
|
| 283 |
+
house_edge_input = gr.Slider(
|
| 284 |
+
minimum=0,
|
| 285 |
+
maximum=10,
|
| 286 |
+
value=3,
|
| 287 |
+
step=0.5,
|
| 288 |
+
label="হাউস এজ (%)",
|
| 289 |
+
info="সাধারণত 1-5% এর মধ্যে"
|
| 290 |
+
)
|
| 291 |
+
regenerate_btn = gr.Button("🔄 রিজেনারেট ডাটা", variant="secondary", size="lg")
|
| 292 |
+
|
| 293 |
+
with gr.Column():
|
| 294 |
+
random_data_output = gr.Textbox(
|
| 295 |
+
label="জেনারেটেড ডাটা",
|
| 296 |
+
lines=6,
|
| 297 |
+
interactive=False
|
| 298 |
+
)
|
| 299 |
+
|
| 300 |
+
with gr.Row():
|
| 301 |
+
random_analyze_btn = gr.Button("📊 এই ডাটা অ্যানালাইসিস করুন", variant="primary")
|
| 302 |
+
|
| 303 |
+
with gr.TabItem("📖 গাইড"):
|
| 304 |
+
gr.Markdown("""
|
| 305 |
+
## কিভাবে ব্যবহার করবেন?
|
| 306 |
+
|
| 307 |
+
### ম্যানুয়াল ইনপুট
|
| 308 |
+
1. প্রথম ট্যাবে মাল্টিপ্লায়ার লিখুন
|
| 309 |
+
2. কমা (,) বা স্পেস দিয়ে আলাদা করুন
|
| 310 |
+
3. "x" ব্যবহার করলেও সমস্যা নেই
|
| 311 |
+
4. "অ্যানালাইসিস করুন" ক্লিক করুন
|
| 312 |
+
|
| 313 |
+
### র্যান্ডম জেনারেটর
|
| 314 |
+
1. দ্বিতীয় ট্যাবে যান
|
| 315 |
+
2. রাউন্ড সংখ্যা সেট করুন
|
| 316 |
+
3. হাউস এজ সেট করুন (সাধারণত 1-5%)
|
| 317 |
+
4. "রিজেনারেট ডাটা" ক্লিক করুন
|
| 318 |
+
5. "এই ডাটা অ্যানালাইসিস করুন" ক্লিক করুন
|
| 319 |
+
|
| 320 |
+
### উদাহরণ ইনপুট
|