prophetdiceskills 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: prophetdiceskills
3
+ Version: 1.0.0
4
+ Summary: A library converting RNG cracking algorithms into callable functions with bot emulation.
5
+ Author: Prophet Dice Skills
6
+ Author-email: prophet@example.com
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Operating System :: OS Independent
9
+ Requires-Python: >=3.6
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: numba
12
+ Requires-Dist: numpy
13
+ Requires-Dist: scipy
14
+ Requires-Dist: scikit-learn
15
+ Requires-Dist: PyWavelets
16
+ Requires-Dist: matplotlib
17
+ Requires-Dist: seaborn
18
+ Requires-Dist: river
19
+ Requires-Dist: torch
20
+ Dynamic: author
21
+ Dynamic: author-email
22
+ Dynamic: classifier
23
+ Dynamic: description
24
+ Dynamic: description-content-type
25
+ Dynamic: requires-dist
26
+ Dynamic: requires-python
27
+ Dynamic: summary
28
+
29
+ # Prophet Dice Skills
30
+
31
+ This library provides all the fundamental RNG cracking functions converted into callable API methods.
32
+ It also brings a full object-oriented dice bot simulation suite, letting you retrieve balances, place conditions, and wager effectively using standard interfaces.
33
+
34
+ ## Usage
35
+
36
+ ```python
37
+ from prophetdiceskills import ProphetBot, aggressive_time_crack
38
+
39
+ bot = ProphetBot(initial_balance=5000.0)
40
+ bot.setwager(10)
41
+ bot.setcondition("<")
42
+ bot.settarget(49.5)
43
+
44
+ result = 45.12
45
+ bot.simulate_roll(result)
46
+
47
+ print(bot.getbalance())
48
+ print(bot.getprofit())
49
+ ```
50
+
51
+ ## Functions Included
52
+ - `getbalance()`
53
+ - `setcondition()`
54
+ - `setwager()`
55
+ - `getresult()`
56
+ - ... and more, along with all `beatstake` / `stakeenhanced` capabilities!
57
+ - `GroundbreakingPredictor` for Deep Learning (Transformer/MLP/RF) time-series forecasting.
58
+ - `AdvancedBettingSystem` with Anti-Human Burst Strategies.
59
+ - `RegimeDetector` and `SimpleKalmanFilter` for signal processing and anomaly detection.
@@ -0,0 +1,31 @@
1
+ # Prophet Dice Skills
2
+
3
+ This library provides all the fundamental RNG cracking functions converted into callable API methods.
4
+ It also brings a full object-oriented dice bot simulation suite, letting you retrieve balances, place conditions, and wager effectively using standard interfaces.
5
+
6
+ ## Usage
7
+
8
+ ```python
9
+ from prophetdiceskills import ProphetBot, aggressive_time_crack
10
+
11
+ bot = ProphetBot(initial_balance=5000.0)
12
+ bot.setwager(10)
13
+ bot.setcondition("<")
14
+ bot.settarget(49.5)
15
+
16
+ result = 45.12
17
+ bot.simulate_roll(result)
18
+
19
+ print(bot.getbalance())
20
+ print(bot.getprofit())
21
+ ```
22
+
23
+ ## Functions Included
24
+ - `getbalance()`
25
+ - `setcondition()`
26
+ - `setwager()`
27
+ - `getresult()`
28
+ - ... and more, along with all `beatstake` / `stakeenhanced` capabilities!
29
+ - `GroundbreakingPredictor` for Deep Learning (Transformer/MLP/RF) time-series forecasting.
30
+ - `AdvancedBettingSystem` with Anti-Human Burst Strategies.
31
+ - `RegimeDetector` and `SimpleKalmanFilter` for signal processing and anomaly detection.
@@ -0,0 +1,29 @@
1
+ from .core import StakeRNG, aggressive_time_crack, aggressive_collision_farm, analyze_n_gram_transitions, verify_server_seed
2
+ from .bot import ProphetBot
3
+ from .ml import GroundbreakingPredictor, AdvancedFeatureEngineer, RegimeDetector, SimpleKalmanFilter
4
+ from .advanced_bot import AdvancedBettingSystem, ConfigManager
5
+ from .charting import RealTimePlotter
6
+ from .online_learning import OnlineLearningTracker
7
+ from .advanced_dl import TransformerPredictor
8
+ from .anomaly import RNGAnomalyDetector
9
+ from .quantum import QuantumInspiredOptimizer
10
+
11
+ __all__ = [
12
+ "StakeRNG",
13
+ "aggressive_time_crack",
14
+ "aggressive_collision_farm",
15
+ "analyze_n_gram_transitions",
16
+ "verify_server_seed",
17
+ "ProphetBot",
18
+ "GroundbreakingPredictor",
19
+ "AdvancedFeatureEngineer",
20
+ "RegimeDetector",
21
+ "SimpleKalmanFilter",
22
+ "AdvancedBettingSystem",
23
+ "ConfigManager",
24
+ "RealTimePlotter",
25
+ "OnlineLearningTracker",
26
+ "TransformerPredictor",
27
+ "RNGAnomalyDetector",
28
+ "QuantumInspiredOptimizer"
29
+ ]
@@ -0,0 +1,198 @@
1
+ import json
2
+ import os
3
+ import random
4
+ from collections import deque
5
+ import numpy as np
6
+
7
+ CONFIG_FILE = "auditor_config.json"
8
+
9
+ class ConfigManager:
10
+ """Manages persistent settings"""
11
+ def __init__(self, filename=CONFIG_FILE):
12
+ self.filename = filename
13
+ self.config = {
14
+ "base_bet": 0.0000001,
15
+ "risk_level": "balanced", # conservative, balanced, aggressive
16
+ "stop_loss_pct": 0.15,
17
+ "take_profit_pct": 0.50,
18
+ "auto_retrain": True
19
+ }
20
+ self.load()
21
+
22
+ def load(self):
23
+ if os.path.exists(self.filename):
24
+ try:
25
+ with open(self.filename, 'r') as f:
26
+ loaded = json.load(f)
27
+ self.config.update(loaded)
28
+ except:
29
+ pass
30
+
31
+ def save(self):
32
+ try:
33
+ with open(self.filename, 'w') as f:
34
+ json.dump(self.config, f, indent=4)
35
+ except:
36
+ pass
37
+
38
+ def get(self, key):
39
+ return self.config.get(key)
40
+
41
+ def set(self, key, value):
42
+ self.config[key] = value
43
+ self.save()
44
+
45
+ class AdvancedBettingSystem:
46
+ """
47
+ Short Burst Reset Anti-Human Non-Standard Strategy
48
+ Focuses on short, aggressive profit taking sequences with frequent resets
49
+ to avoid pattern detection and long-term negative variance.
50
+ """
51
+
52
+ def __init__(self, config_manager=None):
53
+ self.config = config_manager or ConfigManager()
54
+ self.base_bet = self.config.get("base_bet")
55
+ self.bankroll = 1.0
56
+ self.peak_bankroll = 1.0
57
+ self.drawdown = 0.0
58
+
59
+ # Performance tracking
60
+ self.trade_history = deque(maxlen=100)
61
+ self.short_term_memory = deque(maxlen=10) # For circuit breaker
62
+ self.win_rate = 0.5
63
+ self.sharpe_ratio = 0.0
64
+
65
+ # Burst Strategy State
66
+ self.burst_active = False
67
+ self.burst_step = 0
68
+ self.burst_history = []
69
+ self.cooldown_steps = 0
70
+ self.circuit_breaker_active = False
71
+ self.circuit_breaker_steps = 0
72
+ self.retrain_requested = False # Request model retraining
73
+
74
+ # Configuration
75
+ self.max_burst_length = 4
76
+ self.burst_multiplier = 2.5 # Aggressive start
77
+ self.compound_rate = 1.5 # Reinvest 50% of winnings in burst
78
+ self.reset_on_loss = True # Anti-Martingale (Reset immediately on loss)
79
+
80
+ # Anti-Human Parameters
81
+ self.jitter_factor = 0.13 # Add randomness to bet size
82
+ self.random_reset_prob = 0.05 # Randomly reset burst
83
+
84
+ # Flaw Detection / Risk Management
85
+ self.min_confidence_threshold = 0.55
86
+ self.max_drawdown_pct = 0.15 # Tightened stop loss
87
+
88
+ self.apply_risk_profile()
89
+
90
+ def apply_risk_profile(self):
91
+ """Adjust parameters based on risk profile"""
92
+ profile = self.config.get("risk_level")
93
+ if profile == "conservative":
94
+ self.burst_multiplier = 1.5
95
+ self.compound_rate = 1.1
96
+ self.min_confidence_threshold = 0.65
97
+ self.max_drawdown_pct = 0.10
98
+ elif profile == "aggressive":
99
+ self.burst_multiplier = 3.0
100
+ self.compound_rate = 1.8
101
+ self.min_confidence_threshold = 0.50
102
+ self.max_drawdown_pct = 0.25
103
+ else: # balanced
104
+ self.burst_multiplier = 2.5
105
+ self.compound_rate = 1.5
106
+ self.min_confidence_threshold = 0.55
107
+ self.max_drawdown_pct = 0.15
108
+
109
+ def get_bet_size(self, prediction_data):
110
+ """Calculate bet size based on Short Burst Reset Strategy"""
111
+ # Refresh base bet from config in case it changed
112
+ self.base_bet = self.config.get("base_bet")
113
+
114
+ if not prediction_data:
115
+ return self.base_bet
116
+
117
+ confidence = prediction_data['confidence']
118
+ model_health = prediction_data.get('model_health', 100.0)
119
+ micro_regime = prediction_data.get('micro_regime', 'NORMAL')
120
+
121
+ if self.circuit_breaker_active:
122
+ self.circuit_breaker_steps -= 1
123
+ if self.circuit_breaker_steps <= 0:
124
+ self.circuit_breaker_active = False
125
+ return self.base_bet
126
+
127
+ if self.cooldown_steps > 0:
128
+ self.cooldown_steps -= 1
129
+ return self.base_bet
130
+
131
+ if not self.burst_active:
132
+ threshold = self.min_confidence_threshold
133
+ if model_health < 70:
134
+ threshold += 0.1
135
+ if micro_regime == "CHAOS":
136
+ threshold += 0.15
137
+
138
+ if confidence > threshold or (random.random() < 0.10 and model_health > 80):
139
+ self.burst_active = True
140
+ self.burst_step = 1
141
+ bet = self.base_bet * self.burst_multiplier
142
+ else:
143
+ return self.base_bet
144
+ else:
145
+ if self.burst_step == 1:
146
+ bet = self.base_bet * self.burst_multiplier
147
+ else:
148
+ bet = self.base_bet * (self.burst_multiplier * (self.compound_rate ** (self.burst_step - 1)))
149
+
150
+ bet = min(bet, self.base_bet * 100.0)
151
+
152
+ jitter = bet * (random.uniform(-self.jitter_factor, self.jitter_factor))
153
+ final_bet = bet + jitter
154
+ final_bet = max(self.base_bet, final_bet)
155
+
156
+ if self.drawdown > self.max_drawdown_pct:
157
+ final_bet = self.base_bet
158
+ self.burst_active = False
159
+
160
+ return final_bet
161
+
162
+ def update(self, bet_size, won, profit):
163
+ """Update state based on result"""
164
+ self.bankroll += profit
165
+ self.peak_bankroll = max(self.peak_bankroll, self.bankroll)
166
+ self.drawdown = (self.peak_bankroll - self.bankroll) / self.peak_bankroll
167
+
168
+ self.trade_history.append({'profit': profit, 'bet': bet_size})
169
+ self.short_term_memory.append(1 if won else 0)
170
+
171
+ if len(self.short_term_memory) >= 5:
172
+ recent_wins = sum(list(self.short_term_memory)[-5:])
173
+ if recent_wins <= 1:
174
+ self.circuit_breaker_active = True
175
+ self.circuit_breaker_steps = 10
176
+ self.burst_active = False
177
+ self.retrain_requested = True
178
+
179
+ if self.burst_active:
180
+ if won:
181
+ self.burst_step += 1
182
+ if self.burst_step > self.max_burst_length:
183
+ self.burst_active = False
184
+ self.cooldown_steps = random.randint(2, 5)
185
+ else:
186
+ self.burst_active = False
187
+ self.cooldown_steps = random.randint(1, 3)
188
+
189
+ if self.burst_active and random.random() < self.random_reset_prob:
190
+ self.burst_active = False
191
+ self.cooldown_steps = 1
192
+
193
+ wins = [t for t in self.trade_history if t['profit'] > 0]
194
+ self.win_rate = len(wins) / len(self.trade_history) if self.trade_history else 0
195
+
196
+ if len(self.trade_history) > 10:
197
+ profits = [t['profit'] for t in self.trade_history]
198
+ self.sharpe_ratio = np.mean(profits) / (np.std(profits) + 1e-9)
@@ -0,0 +1,146 @@
1
+ import numpy as np
2
+
3
+ try:
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.optim as optim
7
+ from torch.utils.data import DataLoader, TensorDataset
8
+ HAS_TORCH = True
9
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
10
+ except ImportError:
11
+ HAS_TORCH = False
12
+ DEVICE = None
13
+
14
+ class TimeSeriesTransformer(nn.Module if HAS_TORCH else object):
15
+ """
16
+ Advanced Multi-Head Attention Transformer for Deep Sequence Forecasting.
17
+ Designed to catch non-linear microscopic patterns in RNG outputs.
18
+ """
19
+ def __init__(self, input_dim=1, d_model=64, nhead=4, num_layers=3, dropout=0.1):
20
+ if not HAS_TORCH:
21
+ raise ImportError("PyTorch is required for the Transformer module.")
22
+ super().__init__()
23
+ self.input_projection = nn.Linear(input_dim, d_model)
24
+
25
+ # Positional Encoding
26
+ self.pos_encoder = PositionalEncoding(d_model, dropout)
27
+
28
+ encoder_layers = nn.TransformerEncoderLayer(d_model, nhead, d_model*4, dropout, batch_first=True)
29
+ self.transformer_encoder = nn.TransformerEncoder(encoder_layers, num_layers)
30
+
31
+ self.decoder = nn.Sequential(
32
+ nn.Linear(d_model, d_model // 2),
33
+ nn.ReLU(),
34
+ nn.Dropout(dropout),
35
+ nn.Linear(d_model // 2, 1)
36
+ )
37
+
38
+ def forward(self, src):
39
+ # src shape: [batch_size, sequence_length, input_dim]
40
+ src = self.input_projection(src)
41
+ src = self.pos_encoder(src)
42
+ output = self.transformer_encoder(src)
43
+ # Take the last sequence output to predict the next step
44
+ last_out = output[:, -1, :]
45
+ return self.decoder(last_out)
46
+
47
+ class PositionalEncoding(nn.Module if HAS_TORCH else object):
48
+ def __init__(self, d_model, dropout=0.1, max_len=5000):
49
+ if not HAS_TORCH: return
50
+ super().__init__()
51
+ self.dropout = nn.Dropout(p=dropout)
52
+
53
+ position = torch.arange(max_len).unsqueeze(1)
54
+ div_term = torch.exp(torch.arange(0, d_model, 2) * (-np.log(10000.0) / d_model))
55
+ pe = torch.zeros(max_len, 1, d_model)
56
+ pe[:, 0, 0::2] = torch.sin(position * div_term)
57
+ pe[:, 0, 1::2] = torch.cos(position * div_term)
58
+ self.register_buffer('pe', pe)
59
+
60
+ def forward(self, x):
61
+ """
62
+ Arguments:
63
+ x: Tensor, shape ``[batch_size, seq_len, embedding_dim]``
64
+ """
65
+ x = x + self.pe[:x.size(1)].transpose(0, 1)
66
+ return self.dropout(x)
67
+
68
+ class TransformerPredictor:
69
+ """Wrapper to easily train and infer using the Transformer."""
70
+ def __init__(self, sequence_length=20, epochs=50, lr=0.001):
71
+ self.sequence_length = sequence_length
72
+ self.epochs = epochs
73
+ self.lr = lr
74
+ self.model = None
75
+ self.is_trained = False
76
+
77
+ if HAS_TORCH:
78
+ self.model = TimeSeriesTransformer(input_dim=1).to(DEVICE)
79
+ self.optimizer = optim.Adam(self.model.parameters(), lr=self.lr)
80
+ self.criterion = nn.MSELoss()
81
+
82
+ def _prepare_data(self, history):
83
+ if len(history) <= self.sequence_length:
84
+ return None, None
85
+
86
+ X, y = [], []
87
+ for i in range(len(history) - self.sequence_length):
88
+ raw_x = history[i:i+self.sequence_length]
89
+ raw_y = history[i+self.sequence_length]
90
+
91
+ flat_x = [float(np.ravel(val)[0]) for val in raw_x]
92
+ flat_y = float(np.ravel(raw_y)[0])
93
+
94
+ X.append(flat_x)
95
+ y.append(flat_y)
96
+
97
+ # Normalize to 0-1 for better gradients
98
+ X = np.array(X, dtype=np.float32) / 100.0
99
+ y = np.array(y, dtype=np.float32) / 100.0
100
+
101
+ X = torch.tensor(X).unsqueeze(-1).to(DEVICE) # [Batch, Seq, 1]
102
+ y = torch.tensor(y).unsqueeze(-1).to(DEVICE) # [Batch, 1]
103
+ return X, y
104
+
105
+ def train(self, history):
106
+ if not HAS_TORCH or len(history) < self.sequence_length * 2:
107
+ return False
108
+
109
+ X, y = self._prepare_data(history)
110
+ if X is None: return False
111
+
112
+ dataset = TensorDataset(X, y)
113
+ loader = DataLoader(dataset, batch_size=32, shuffle=True)
114
+
115
+ self.model.train()
116
+ for epoch in range(self.epochs):
117
+ total_loss = 0
118
+ for batch_x, batch_y in loader:
119
+ self.optimizer.zero_grad()
120
+ output = self.model(batch_x)
121
+ loss = self.criterion(output, batch_y)
122
+ loss.backward()
123
+ self.optimizer.step()
124
+ total_loss += loss.item()
125
+
126
+ self.is_trained = True
127
+ return True
128
+
129
+ def predict(self, recent_history):
130
+ if not self.is_trained or not HAS_TORCH:
131
+ return None
132
+ if len(recent_history) < self.sequence_length:
133
+ return None
134
+
135
+ # Take the most recent sequences and flatten them in case they are nested
136
+ raw_seq = recent_history[-self.sequence_length:]
137
+ flat_seq = [float(np.ravel(x)[0]) for x in raw_seq]
138
+ seq = np.array(flat_seq, dtype=np.float32) / 100.0
139
+ seq = torch.tensor(seq).unsqueeze(0).unsqueeze(-1).to(DEVICE) # [1, Seq, 1]
140
+
141
+ self.model.eval()
142
+ with torch.no_grad():
143
+ pred = self.model(seq)
144
+
145
+ # Denormalize
146
+ return float(pred.item() * 100.0)
@@ -0,0 +1,81 @@
1
+ import numpy as np
2
+ from collections import deque
3
+
4
+ try:
5
+ from sklearn.ensemble import IsolationForest
6
+ HAS_IFOREST = True
7
+ except ImportError:
8
+ HAS_IFOREST = False
9
+
10
+ class RNGAnomalyDetector:
11
+ """
12
+ Monitors the stream of RNG values to detect statistically bizarre
13
+ sequences that indicate the Casino might have altered the seed
14
+ or logic server-side.
15
+ """
16
+ def __init__(self, window_size=50, contamination=0.05):
17
+ self.window_size = window_size
18
+ self.contamination = contamination
19
+ self.history = deque(maxlen=2000)
20
+ self.model = None
21
+ self.is_fitted = False
22
+
23
+ if HAS_IFOREST:
24
+ self.model = IsolationForest(
25
+ n_estimators=100,
26
+ contamination=self.contamination,
27
+ random_state=42
28
+ )
29
+
30
+ def _extract_window_features(self, sequence):
31
+ """Extracts spatial/temporal properties of a sequence window."""
32
+ seq = np.array(sequence)
33
+ return [
34
+ np.mean(seq),
35
+ np.std(seq),
36
+ np.max(seq) - np.min(seq),
37
+ np.mean(np.abs(np.diff(seq))), # Average jump size
38
+ np.sum(seq > 50) / len(seq), # Ratio over 50
39
+ np.median(seq)
40
+ ]
41
+
42
+ def add(self, roll):
43
+ self.history.append(roll)
44
+
45
+ # Fit the anomaly baseline when we have enough data
46
+ if HAS_IFOREST and not self.is_fitted and len(self.history) >= 500:
47
+ self.fit_baseline()
48
+
49
+ def fit_baseline(self):
50
+ """Trains what a 'Normal' RNG sequence looks like for this seed."""
51
+ if not HAS_IFOREST or len(self.history) < self.window_size * 2:
52
+ return
53
+
54
+ data = list(self.history)
55
+ features = []
56
+ for i in range(len(data) - self.window_size):
57
+ window = data[i:i+self.window_size]
58
+ features.append(self._extract_window_features(window))
59
+
60
+ if len(features) > 100:
61
+ self.model.fit(features)
62
+ self.is_fitted = True
63
+
64
+ def check_anomaly(self):
65
+ """
66
+ Checks if the most recent window is anomalous compared to the baseline.
67
+ Returns: ExceptionScore (-1 for Anomaly, 1 for Normal), and Raw Distance.
68
+ """
69
+ if not self.is_fitted or not HAS_IFOREST:
70
+ return 1, 0.0
71
+
72
+ if len(self.history) < self.window_size:
73
+ return 1, 0.0
74
+
75
+ recent_window = list(self.history)[-self.window_size:]
76
+ feat = np.array([self._extract_window_features(recent_window)])
77
+
78
+ prediction = self.model.predict(feat)[0]
79
+ score = self.model.decision_function(feat)[0]
80
+
81
+ return prediction, score
@@ -0,0 +1,62 @@
1
+ class ProphetBot:
2
+ """A standard bot framework with typical dice bot functions."""
3
+ def __init__(self, initial_balance=1000.0):
4
+ self._balance = initial_balance
5
+ self._wager = 0.0
6
+ self._condition = "<"
7
+ self._target = 50.0
8
+ self._win = False
9
+ self._current_streak = 0
10
+ self._last_result = 0.0
11
+ self._profit = 0.0
12
+
13
+ def getbalance(self):
14
+ """Returns the current balance."""
15
+ return self._balance
16
+
17
+ def setwager(self, amount):
18
+ """Sets the current wager."""
19
+ self._wager = amount
20
+
21
+ def setcondition(self, condition):
22
+ """Sets the win condition ('<' or '>')."""
23
+ self._condition = condition
24
+
25
+ def settarget(self, target):
26
+ """Sets the target outcome (multiplier or chance)."""
27
+ self._target = target
28
+
29
+ def getresult(self):
30
+ """Returns the result of the last roll."""
31
+ return self._last_result
32
+
33
+ def simulate_roll(self, result):
34
+ """Simulates an incoming roll result from the casino."""
35
+ self._last_result = result
36
+ if self._condition == "<":
37
+ self._win = result < self._target
38
+ elif self._condition == ">":
39
+ self._win = result > self._target
40
+
41
+ if self._win:
42
+ # Simple assumption: 99% RTP
43
+ multiplier = 99.0 / self._target if self._target > 0 else 2.0
44
+ payout = self._wager * multiplier
45
+ self._profit += (payout - self._wager)
46
+ self._balance += (payout - self._wager)
47
+ self._current_streak = self._current_streak + 1 if self._current_streak > 0 else 1
48
+ else:
49
+ self._profit -= self._wager
50
+ self._balance -= self._wager
51
+ self._current_streak = self._current_streak - 1 if self._current_streak < 0 else -1
52
+
53
+ return self._win
54
+
55
+ def getprofit(self):
56
+ return self._profit
57
+
58
+ def is_win(self):
59
+ return self._win
60
+
61
+ def getstreak(self):
62
+ return self._current_streak
@@ -0,0 +1,81 @@
1
+ import numpy as np
2
+ import collections
3
+
4
+ try:
5
+ import matplotlib.pyplot as plt
6
+ import seaborn as sns
7
+ from IPython.display import clear_output
8
+ HAS_PLOTTING = True
9
+ except ImportError:
10
+ HAS_PLOTTING = False
11
+
12
+ class RealTimePlotter:
13
+ """Provides real-time matplotlib/seaborn charts tracking predictions, accuracy, and bankroll."""
14
+ def __init__(self, max_points=200):
15
+ self.max_points = max_points
16
+ self.rolls = collections.deque(maxlen=max_points)
17
+ self.predictions = collections.deque(maxlen=max_points)
18
+ self.accuracy = collections.deque(maxlen=max_points)
19
+ self.bankroll = collections.deque(maxlen=max_points)
20
+ self.win_loss = collections.deque(maxlen=max_points)
21
+
22
+ if HAS_PLOTTING:
23
+ sns.set_theme(style="darkgrid")
24
+ plt.ion() # Interactive mode
25
+ self.fig, self.axs = plt.subplots(3, 1, figsize=(10, 12))
26
+ self.fig.canvas.manager.set_window_title('Prophet ML Auditor Dashboard')
27
+ plt.tight_layout(pad=3.0)
28
+
29
+ def update(self, roll_result, prediction, current_accuracy, current_bankroll, won):
30
+ """Update tracker with new data from the latest roll step."""
31
+ self.rolls.append(roll_result)
32
+ self.predictions.append(prediction)
33
+ self.accuracy.append(current_accuracy)
34
+ self.bankroll.append(current_bankroll)
35
+ self.win_loss.append(1 if won else 0)
36
+
37
+ if HAS_PLOTTING and len(self.rolls) > 5:
38
+ self._draw()
39
+
40
+ def _draw(self):
41
+ """Redraws the matplot canvas."""
42
+ for ax in self.axs:
43
+ ax.clear()
44
+
45
+ x_data = range(len(self.rolls))
46
+
47
+ # Plot 1: Rolls vs Predictions
48
+ self.axs[0].plot(x_data, self.rolls, label="Actual Roll", color="blue", alpha=0.6)
49
+ pred_array = np.array(self.predictions)
50
+
51
+ # Color correct predictions green, incorrect red
52
+ colors = ['green' if w else 'red' for w in self.win_loss]
53
+ self.axs[0].scatter(x_data, pred_array, c=colors, label="Prediction (G=Win, R=Loss)", s=15, zorder=5)
54
+ self.axs[0].axhline(y=50, color='gray', linestyle='--', alpha=0.5)
55
+ self.axs[0].set_title("Actual Rolls vs Predictions")
56
+ self.axs[0].set_ylabel("Outcome")
57
+ self.axs[0].legend(loc="upper left")
58
+
59
+ # Plot 2: Model Accuracy (Moving Average)
60
+ self.axs[1].plot(x_data, [a * 100 for a in self.accuracy], label="Overall Accuracy %", color="purple")
61
+ self.axs[1].axhline(y=50, color='red', linestyle='--', alpha=0.5, label="Baseline (50%)")
62
+ self.axs[1].set_title("Prediction Accuracy")
63
+ self.axs[1].set_ylabel("Accuracy (%)")
64
+ self.axs[1].set_ylim([0, 100])
65
+ self.axs[1].legend(loc="upper left")
66
+
67
+ # Plot 3: Bankroll
68
+ self.axs[2].plot(x_data, self.bankroll, label="Bankroll", color="gold")
69
+ self.axs[2].set_title("Bankroll Evolution")
70
+ self.axs[2].set_ylabel("Balance")
71
+ self.axs[2].set_xlabel("Roll Number")
72
+ self.axs[2].legend(loc="upper left")
73
+
74
+ plt.draw()
75
+ plt.pause(0.01)
76
+
77
+ def show_final(self):
78
+ """Blocking call to show final charts."""
79
+ if HAS_PLOTTING:
80
+ plt.ioff()
81
+ plt.show()