EZTIME2025 commited on
Commit
d89bbf7
·
1 Parent(s): 2249362

adding win

Browse files
game_viz.log CHANGED
@@ -2402,3 +2402,15 @@ Current Player: ► c
2402
  -----
2403
  Board Tiles: 19 tiles configured
2404
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2402
  -----
2403
  Board Tiles: 19 tiles configured
2404
 
2405
+
2406
+ ============================================================
2407
+ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ 
2408
+
2409
+ 🎉 GAME OVER - WE HAVE A WINNER! 🎉
2410
+
2411
+ 🏆 C (Player 2) 🏆
2412
+ with 5 victory points!
2413
+
2414
+ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ ✨ 
2415
+ ============================================================
2416
+
pycatan/console_visualization.py CHANGED
@@ -700,4 +700,26 @@ class ConsoleVisualization(Visualization):
700
  return
701
 
702
  # Display structured log string
703
- self._print(log_entry.to_log_string())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
700
  return
701
 
702
  # Display structured log string
703
+ self._print(log_entry.to_log_string())
704
+
705
+ def display_winner(self, player_name: str, player_id: int, victory_points: int) -> None:
706
+ """Display game winner announcement."""
707
+ if not self.enabled:
708
+ return
709
+
710
+ # Create a celebratory banner
711
+ banner_line = "=" * 60
712
+ stars_line = "✨ " * 30
713
+
714
+ self._print()
715
+ self._print(f"{self.colors['bold']}{self.colors['yellow']}{banner_line}{self.colors['reset']}")
716
+ self._print(f"{self.colors['bold']}{self.colors['yellow']}{stars_line}{self.colors['reset']}")
717
+ self._print()
718
+ self._print(f"{self.colors['bold']}{self.colors['green']}🎉 GAME OVER - WE HAVE A WINNER! 🎉{self.colors['reset']}".center(80))
719
+ self._print()
720
+ self._print(f"{self.colors['bold']}{self.colors['cyan']}🏆 {player_name.upper()} (Player {player_id}) 🏆{self.colors['reset']}".center(80))
721
+ self._print(f"{self.colors['bold']}{self.colors['white']}with {victory_points} victory points!{self.colors['reset']}".center(80))
722
+ self._print()
723
+ self._print(f"{self.colors['bold']}{self.colors['yellow']}{stars_line}{self.colors['reset']}")
724
+ self._print(f"{self.colors['bold']}{self.colors['yellow']}{banner_line}{self.colors['reset']}")
725
+ self._print()
pycatan/game_manager.py CHANGED
@@ -1716,7 +1716,7 @@ class GameManager:
1716
  victory_points = player.get_VP(include_dev=True)
1717
 
1718
  # Check if this player has won (10+ victory points)
1719
- if victory_points >= 5:
1720
  self._announce_winner(player_id, victory_points)
1721
  return True
1722
 
@@ -1738,6 +1738,10 @@ class GameManager:
1738
  f"🎉 {winner_name} has won the game with {victory_points} victory points! 🎉"
1739
  )
1740
 
 
 
 
 
1741
  # Log the victory for debugging/statistics
1742
  print(f"[GAME END] Player {player_id} ({winner_name}) won with {victory_points} victory points")
1743
 
 
1716
  victory_points = player.get_VP(include_dev=True)
1717
 
1718
  # Check if this player has won (10+ victory points)
1719
+ if victory_points >= 10:
1720
  self._announce_winner(player_id, victory_points)
1721
  return True
1722
 
 
1738
  f"🎉 {winner_name} has won the game with {victory_points} victory points! 🎉"
1739
  )
1740
 
1741
+ # Notify all visualizations
1742
+ if self.visualization_manager:
1743
+ self.visualization_manager.display_winner(winner_name, player_id, victory_points)
1744
+
1745
  # Log the victory for debugging/statistics
1746
  print(f"[GAME END] Player {player_id} ({winner_name}) won with {victory_points} victory points")
1747
 
pycatan/static/js/main.js CHANGED
@@ -161,6 +161,8 @@ function connectToSSE() {
161
  logEvent(data.payload, 'info');
162
  } else if (data.type === 'error') {
163
  logEvent(data.payload, 'error');
 
 
164
  }
165
  };
166
 
@@ -394,6 +396,131 @@ function appendToLog(container, element) {
394
  container.scrollTop = container.scrollHeight;
395
  }
396
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
397
  // Game initialization
398
  document.addEventListener('DOMContentLoaded', async function() {
399
  console.log('🎲 Starting Catan board with server connection...');
 
161
  logEvent(data.payload, 'info');
162
  } else if (data.type === 'error') {
163
  logEvent(data.payload, 'error');
164
+ } else if (data.type === 'game_winner') {
165
+ showWinnerAnnouncement(data.payload);
166
  }
167
  };
168
 
 
396
  container.scrollTop = container.scrollHeight;
397
  }
398
 
399
+ // Show winner announcement overlay
400
+ function showWinnerAnnouncement(winnerData) {
401
+ console.log('🎉 GAME WINNER:', winnerData);
402
+
403
+ // Log to action log
404
+ const logDiv = document.getElementById('action-log');
405
+ if (logDiv) {
406
+ const winnerEntry = document.createElement('div');
407
+ winnerEntry.className = 'log-winner';
408
+ winnerEntry.innerHTML = `
409
+ <strong>${winnerData.timestamp}</strong> -
410
+ 🎉 <strong>${winnerData.player_name}</strong> won with ${winnerData.victory_points} victory points! 🎉
411
+ `;
412
+ logDiv.insertBefore(winnerEntry, logDiv.firstChild);
413
+ }
414
+
415
+ // Create fullscreen overlay
416
+ const overlay = document.createElement('div');
417
+ overlay.id = 'winner-overlay';
418
+ overlay.style.cssText = `
419
+ position: fixed;
420
+ top: 0;
421
+ left: 0;
422
+ width: 100%;
423
+ height: 100%;
424
+ background: rgba(0, 0, 0, 0.85);
425
+ display: flex;
426
+ justify-content: center;
427
+ align-items: center;
428
+ z-index: 9999;
429
+ animation: fadeIn 0.5s ease-in;
430
+ `;
431
+
432
+ overlay.innerHTML = `
433
+ <div style="
434
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
435
+ padding: 60px;
436
+ border-radius: 20px;
437
+ text-align: center;
438
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
439
+ animation: bounceIn 0.8s ease-out;
440
+ max-width: 600px;
441
+ ">
442
+ <div style="font-size: 80px; margin-bottom: 20px;">🎉</div>
443
+ <h1 style="
444
+ color: white;
445
+ font-size: 48px;
446
+ margin: 20px 0;
447
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
448
+ ">GAME OVER!</h1>
449
+ <div style="
450
+ background: rgba(255, 255, 255, 0.2);
451
+ padding: 30px;
452
+ border-radius: 15px;
453
+ margin: 30px 0;
454
+ ">
455
+ <div style="font-size: 60px; margin-bottom: 15px;">🏆</div>
456
+ <h2 style="
457
+ color: #ffd700;
458
+ font-size: 42px;
459
+ margin: 10px 0;
460
+ text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5);
461
+ ">${winnerData.player_name.toUpperCase()}</h2>
462
+ <p style="
463
+ color: white;
464
+ font-size: 24px;
465
+ margin-top: 15px;
466
+ ">Victory Points: ${winnerData.victory_points}</p>
467
+ </div>
468
+ <button onclick="document.getElementById('winner-overlay').remove()" style="
469
+ background: white;
470
+ color: #667eea;
471
+ border: none;
472
+ padding: 15px 40px;
473
+ font-size: 20px;
474
+ font-weight: bold;
475
+ border-radius: 10px;
476
+ cursor: pointer;
477
+ margin-top: 20px;
478
+ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
479
+ transition: transform 0.2s;
480
+ " onmouseover="this.style.transform='scale(1.05)'"
481
+ onmouseout="this.style.transform='scale(1)'">
482
+ Close
483
+ </button>
484
+ </div>
485
+ `;
486
+
487
+ // Add CSS animations
488
+ if (!document.getElementById('winner-animations')) {
489
+ const style = document.createElement('style');
490
+ style.id = 'winner-animations';
491
+ style.textContent = `
492
+ @keyframes fadeIn {
493
+ from { opacity: 0; }
494
+ to { opacity: 1; }
495
+ }
496
+ @keyframes bounceIn {
497
+ 0% { transform: scale(0.3); opacity: 0; }
498
+ 50% { transform: scale(1.05); }
499
+ 70% { transform: scale(0.9); }
500
+ 100% { transform: scale(1); opacity: 1; }
501
+ }
502
+ .log-winner {
503
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
504
+ color: white;
505
+ padding: 15px;
506
+ border-radius: 8px;
507
+ margin: 10px 0;
508
+ font-size: 16px;
509
+ font-weight: bold;
510
+ text-align: center;
511
+ animation: slideIn 0.5s ease-out;
512
+ }
513
+ @keyframes slideIn {
514
+ from { transform: translateX(-100%); opacity: 0; }
515
+ to { transform: translateX(0); opacity: 1; }
516
+ }
517
+ `;
518
+ document.head.appendChild(style);
519
+ }
520
+
521
+ document.body.appendChild(overlay);
522
+ }
523
+
524
  // Game initialization
525
  document.addEventListener('DOMContentLoaded', async function() {
526
  console.log('🎲 Starting Catan board with server connection...');
pycatan/visualization.py CHANGED
@@ -114,6 +114,18 @@ class Visualization(ABC):
114
  """
115
  pass
116
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  def enable(self) -> None:
118
  """Enable this visualization."""
119
  self.enabled = True
@@ -201,6 +213,12 @@ class VisualizationManager:
201
  if viz.is_enabled():
202
  viz.display_message(message)
203
 
 
 
 
 
 
 
204
  def log_event(self, log_entry: LogEntry) -> None:
205
  """Log a structured event to all enabled visualizations."""
206
  for viz in self.visualizations:
 
114
  """
115
  pass
116
 
117
+ @abstractmethod
118
+ def display_winner(self, player_name: str, player_id: int, victory_points: int) -> None:
119
+ """
120
+ Display game winner announcement.
121
+
122
+ Args:
123
+ player_name: Name of the winning player
124
+ player_id: ID of the winning player
125
+ victory_points: Number of victory points the winner achieved
126
+ """
127
+ pass
128
+
129
  def enable(self) -> None:
130
  """Enable this visualization."""
131
  self.enabled = True
 
213
  if viz.is_enabled():
214
  viz.display_message(message)
215
 
216
+ def display_winner(self, player_name: str, player_id: int, victory_points: int) -> None:
217
+ """Update all enabled visualizations with winner announcement."""
218
+ for viz in self.visualizations:
219
+ if viz.is_enabled():
220
+ viz.display_winner(player_name, player_id, victory_points)
221
+
222
  def log_event(self, log_entry: LogEntry) -> None:
223
  """Log a structured event to all enabled visualizations."""
224
  for viz in self.visualizations:
pycatan/web_visualization.py CHANGED
@@ -862,6 +862,53 @@ class WebVisualization(Visualization):
862
  'payload': message_data
863
  })
864
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
865
  def _convert_dict_to_web_format(self, game_state: Dict[str, Any]) -> Dict[str, Any]:
866
  """Convert dict game state to web format."""
867
  web_format = {
 
862
  'payload': message_data
863
  })
864
 
865
+ def display_winner(self, player_name: str, player_id: int, victory_points: int) -> None:
866
+ """Display game winner announcement."""
867
+ timestamp = datetime.now().strftime("%H:%M:%S")
868
+
869
+ winner_data = {
870
+ 'timestamp': timestamp,
871
+ 'player_name': player_name,
872
+ 'player_id': player_id,
873
+ 'victory_points': victory_points,
874
+ 'message': f"🎉 {player_name} has won with {victory_points} victory points! 🎉"
875
+ }
876
+
877
+ # Get turn number safely (handle both dict and GameState object)
878
+ turn_number = 0
879
+ if self.current_game_state:
880
+ if isinstance(self.current_game_state, dict):
881
+ turn_number = self.current_game_state.get('turn_number', 0)
882
+ else:
883
+ turn_number = getattr(self.current_game_state, 'turn_number', 0)
884
+
885
+ # Create structured log entry
886
+ log_entry = create_log_entry(
887
+ event_type=EventType.GAME_END,
888
+ turn=turn_number,
889
+ player_id=player_id,
890
+ player_name=player_name,
891
+ data={
892
+ 'victory_points': victory_points,
893
+ 'winner': player_name
894
+ },
895
+ status="SUCCESS"
896
+ )
897
+ self.log_entries.append(log_entry)
898
+
899
+ # Add to event history
900
+ self.event_history.append({
901
+ 'type': 'game_end',
902
+ 'timestamp': timestamp,
903
+ 'data': winner_data
904
+ })
905
+
906
+ # Broadcast to web clients
907
+ self._broadcast_to_clients({
908
+ 'type': 'game_winner',
909
+ 'payload': winner_data
910
+ })
911
+
912
  def _convert_dict_to_web_format(self, game_state: Dict[str, Any]) -> Dict[str, Any]:
913
  """Convert dict game state to web format."""
914
  web_format = {