From 404b980e6cf46bcaeb21a9dccdceb4f6951da0f2 Mon Sep 17 00:00:00 2001 From: Ram Dafale Date: Wed, 16 Jul 2025 11:40:17 +0530 Subject: [PATCH] Revert "Develop tennis match prediction service" --- README.md | 253 +--------- pom.xml | 105 ---- .../tennis/TennisPredictionApplication.java | 27 - .../TennisPredictionController.java | 467 ------------------ .../java/com/tennis/entity/HeadToHead.java | 125 ----- src/main/java/com/tennis/entity/Match.java | 201 -------- .../com/tennis/entity/MatchPrediction.java | 141 ------ src/main/java/com/tennis/entity/Player.java | 145 ------ .../repository/HeadToHeadRepository.java | 96 ---- .../repository/MatchPredictionRepository.java | 144 ------ .../tennis/repository/MatchRepository.java | 118 ----- .../tennis/repository/PlayerRepository.java | 93 ---- .../service/DataInitializationService.java | 265 ---------- .../com/tennis/service/PredictionService.java | 454 ----------------- src/main/resources/application.properties | 36 -- src/main/resources/templates/dashboard.html | 435 ---------------- target/classes/application.properties | 36 -- .../tennis/TennisPredictionApplication.class | Bin 1222 -> 0 bytes .../TennisPredictionController.class | Bin 18553 -> 0 bytes .../com/tennis/entity/HeadToHead.class | Bin 14102 -> 0 bytes target/classes/com/tennis/entity/Match.class | Bin 27930 -> 0 bytes .../com/tennis/entity/MatchPrediction.class | Bin 14611 -> 0 bytes target/classes/com/tennis/entity/Player.class | Bin 21563 -> 0 bytes .../repository/HeadToHeadRepository.class | Bin 3677 -> 0 bytes .../MatchPredictionRepository.class | Bin 4080 -> 0 bytes .../tennis/repository/MatchRepository.class | Bin 3264 -> 0 bytes .../tennis/repository/PlayerRepository.class | Bin 2392 -> 0 bytes .../service/DataInitializationService.class | Bin 13670 -> 0 bytes .../tennis/service/PredictionService.class | Bin 13951 -> 0 bytes target/classes/templates/dashboard.html | 435 ---------------- .../compile/default-compile/createdFiles.lst | 12 - .../compile/default-compile/inputFiles.lst | 12 - 32 files changed, 3 insertions(+), 3597 deletions(-) delete mode 100644 pom.xml delete mode 100644 src/main/java/com/tennis/TennisPredictionApplication.java delete mode 100644 src/main/java/com/tennis/controller/TennisPredictionController.java delete mode 100644 src/main/java/com/tennis/entity/HeadToHead.java delete mode 100644 src/main/java/com/tennis/entity/Match.java delete mode 100644 src/main/java/com/tennis/entity/MatchPrediction.java delete mode 100644 src/main/java/com/tennis/entity/Player.java delete mode 100644 src/main/java/com/tennis/repository/HeadToHeadRepository.java delete mode 100644 src/main/java/com/tennis/repository/MatchPredictionRepository.java delete mode 100644 src/main/java/com/tennis/repository/MatchRepository.java delete mode 100644 src/main/java/com/tennis/repository/PlayerRepository.java delete mode 100644 src/main/java/com/tennis/service/DataInitializationService.java delete mode 100644 src/main/java/com/tennis/service/PredictionService.java delete mode 100644 src/main/resources/application.properties delete mode 100644 src/main/resources/templates/dashboard.html delete mode 100644 target/classes/application.properties delete mode 100644 target/classes/com/tennis/TennisPredictionApplication.class delete mode 100644 target/classes/com/tennis/controller/TennisPredictionController.class delete mode 100644 target/classes/com/tennis/entity/HeadToHead.class delete mode 100644 target/classes/com/tennis/entity/Match.class delete mode 100644 target/classes/com/tennis/entity/MatchPrediction.class delete mode 100644 target/classes/com/tennis/entity/Player.class delete mode 100644 target/classes/com/tennis/repository/HeadToHeadRepository.class delete mode 100644 target/classes/com/tennis/repository/MatchPredictionRepository.class delete mode 100644 target/classes/com/tennis/repository/MatchRepository.class delete mode 100644 target/classes/com/tennis/repository/PlayerRepository.class delete mode 100644 target/classes/com/tennis/service/DataInitializationService.class delete mode 100644 target/classes/com/tennis/service/PredictionService.class delete mode 100644 target/classes/templates/dashboard.html delete mode 100644 target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst delete mode 100644 target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst diff --git a/README.md b/README.md index 8c2ae1bf..97d4b2fb 100644 --- a/README.md +++ b/README.md @@ -1,251 +1,4 @@ -# 🎾 Tennis Match Prediction Application +# JavaTraining-Capg -A comprehensive Spring Boot application that provides real-time tennis match predictions using AI algorithms. The application analyzes player statistics, head-to-head records, surface performance, and live match data to predict match winners, current game winners, and current set winners. - -## 🚀 Features - -### Core Prediction Capabilities -- **Match Winner Prediction**: Predicts the overall winner of a tennis match -- **Current Game Winner Prediction**: Predicts who will win the current game -- **Current Set Winner Prediction**: Predicts who will win the current set - -### Advanced Analytics -- **Player Statistics**: Comprehensive player profiles including rankings, surface performance, and recent form -- **Head-to-Head Records**: Historical match data between players -- **Live Match Data**: Real-time statistics and score tracking -- **Surface Analysis**: Performance analysis on different court surfaces (Hard, Clay, Grass) - -### Technical Features -- **RESTful API**: Complete API for all prediction and data operations -- **Real-time Updates**: Auto-refreshing dashboard with live match data -- **Modern UI**: Beautiful, responsive web interface -- **H2 Database**: In-memory database with sample data -- **Prediction Accuracy Tracking**: Monitor prediction success rates - -## 🛠️ Technology Stack - -- **Backend**: Spring Boot 3.2.0 -- **Database**: H2 (In-memory) -- **Frontend**: Thymeleaf, Bootstrap 5, JavaScript -- **Build Tool**: Maven -- **Java Version**: 17 - -## 📋 Prerequisites - -- Java 17 or higher -- Maven 3.6 or higher -- Modern web browser - -## 🚀 Quick Start - -### 1. Clone and Navigate -```bash -cd tennis-prediction-app -``` - -### 2. Build the Application -```bash -mvn clean install -``` - -### 3. Run the Application -```bash -mvn spring-boot:run -``` - -### 4. Access the Application -Open your browser and navigate to: -- **Main Dashboard**: http://localhost:8080/tennis-prediction/ -- **H2 Database Console**: http://localhost:8080/tennis-prediction/h2-console - - JDBC URL: `jdbc:h2:mem:tennisdb` - - Username: `sa` - - Password: `password` - -## 📊 Sample Data - -The application comes pre-loaded with: - -### Top 10 ATP Players (2024 Rankings) -1. Novak Djokovic (Serbia) -2. Carlos Alcaraz (Spain) -3. Daniil Medvedev (Russia) -4. Jannik Sinner (Italy) -5. Andrey Rublev (Russia) -6. Stefanos Tsitsipas (Greece) -7. Alexander Zverev (Germany) -8. Holger Rune (Denmark) -9. Hubert Hurkacz (Poland) -10. Taylor Fritz (USA) - -### Sample Matches -- Live matches with real-time statistics -- Completed matches with full results -- Scheduled matches for future predictions - -### Head-to-Head Records -- Historical match data between all players -- Surface-specific performance records -- Recent match outcomes - -## 🔧 API Endpoints - -### Predictions -- `POST /api/predictions/match-winner/{matchId}` - Predict match winner -- `POST /api/predictions/game-winner/{matchId}` - Predict current game winner -- `POST /api/predictions/set-winner/{matchId}` - Predict current set winner -- `GET /api/predictions/match/{matchId}` - Get all predictions for a match -- `GET /api/predictions/latest/{matchId}/{predictionType}` - Get latest prediction -- `GET /api/predictions/accuracy` - Get prediction accuracy statistics - -### Matches -- `GET /api/matches` - Get all matches -- `GET /api/matches/live` - Get live matches -- `GET /api/matches/{matchId}` - Get match by ID -- `GET /api/matches/tournament/{tournamentName}` - Get matches by tournament -- `GET /api/matches/surface/{surface}` - Get matches by surface -- `POST /api/matches` - Create new match -- `PUT /api/matches/{matchId}` - Update match - -### Players -- `GET /api/players` - Get all players -- `GET /api/players/{playerId}` - Get player by ID -- `GET /api/players/name/{playerName}` - Get player by name -- `GET /api/players/top` - Get top ranked players -- `GET /api/players/country/{country}` - Get players by country -- `GET /api/players/surface/{surface}` - Get players by surface performance -- `GET /api/players/search/{namePattern}` - Search players by name -- `POST /api/players` - Create new player -- `PUT /api/players/{playerId}` - Update player - -### Head-to-Head -- `GET /api/head-to-head/{player1Id}/{player2Id}` - Get head-to-head record -- `GET /api/head-to-head/player/{playerId}` - Get player's head-to-head records - -### Statistics -- `GET /api/statistics` - Get application statistics - -## 🎯 Prediction Algorithm - -The prediction system uses a weighted algorithm that considers: - -### Factors and Weights -- **Player Rankings** (15%): Current ATP rankings -- **Head-to-Head Records** (20%): Historical performance against opponent -- **Surface Performance** (15%): Win rates on specific surfaces -- **Recent Form** (15%): Recent match performance -- **Live Statistics** (25%): Current match statistics -- **Match Momentum** (10%): Current match flow and score - -### Prediction Types -1. **Match Winner**: Overall match outcome prediction -2. **Game Winner**: Current game prediction (focuses on serving and immediate momentum) -3. **Set Winner**: Current set prediction (considers set score and match momentum) - -## 🎨 User Interface - -### Dashboard Features -- **Real-time Statistics**: Live match count, prediction accuracy, player rankings -- **Live Matches**: Current matches with real-time scores and statistics -- **Top Players**: Ranked list of top players with performance metrics -- **Recent Predictions**: Latest predictions with confidence scores and reasoning -- **Auto-refresh**: Dashboard updates every 30 seconds - -### Interactive Elements -- **Prediction Buttons**: One-click predictions for match, game, and set winners -- **Confidence Indicators**: Visual confidence levels for predictions -- **Detailed Reasoning**: Explanation of prediction factors -- **Responsive Design**: Works on desktop, tablet, and mobile devices - -## 🔍 Database Schema - -### Entities -- **Player**: Comprehensive player profiles with statistics -- **Match**: Live match data and scores -- **HeadToHead**: Historical match records between players -- **MatchPrediction**: Prediction results with confidence scores - -### Key Relationships -- Players have multiple matches (as player1 or player2) -- Matches have multiple predictions (different types) -- Players have head-to-head records with other players - -## 🚀 Deployment - -### Local Development -```bash -# Run with Maven -mvn spring-boot:run - -# Or build and run JAR -mvn clean package -java -jar target/tennis-prediction-app-1.0.0.jar -``` - -### Production Deployment -1. Build the application: `mvn clean package` -2. Deploy the JAR file to your server -3. Configure database connection (switch from H2 to production database) -4. Set up external API keys for live data feeds - -## 🔧 Configuration - -### Application Properties -```properties -# Server Configuration -server.port=8080 -server.servlet.context-path=/tennis-prediction - -# Database Configuration -spring.datasource.url=jdbc:h2:mem:tennisdb -spring.datasource.username=sa -spring.datasource.password=password - -# Prediction Settings -tennis.prediction.model.threshold=0.6 -tennis.prediction.update-interval=30000 -``` - -## 📈 Future Enhancements - -### Planned Features -- **Machine Learning Integration**: Advanced ML models for better predictions -- **External API Integration**: Real-time data from FlashScore, ATP, etc. -- **User Authentication**: User accounts and personalized predictions -- **Mobile App**: Native mobile application -- **Advanced Analytics**: Detailed statistical analysis and visualizations -- **Tournament Brackets**: Tournament prediction and bracket management - -### Technical Improvements -- **Microservices Architecture**: Split into separate services -- **Real-time WebSocket**: Live updates via WebSocket -- **Caching Layer**: Redis for improved performance -- **Containerization**: Docker support for easy deployment - -## 🤝 Contributing - -1. Fork the repository -2. Create a feature branch -3. Make your changes -4. Add tests for new functionality -5. Submit a pull request - -## 📝 License - -This project is licensed under the MIT License - see the LICENSE file for details. - -## 🆘 Support - -For support and questions: -- Create an issue in the repository -- Check the API documentation -- Review the sample data and configurations - -## 🎯 Quick Test - -1. Start the application -2. Navigate to http://localhost:8080/tennis-prediction/ -3. View the live matches -4. Click "Predict Winner" on any live match -5. See the prediction with confidence score and reasoning - -The application is ready to use immediately with sample data and working predictions! +this repo contains all practices related to basic java and advanced java. +covering spring , servlet , junit , logger,PMD etc diff --git a/pom.xml b/pom.xml deleted file mode 100644 index ff5d616c..00000000 --- a/pom.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - 4.0.0 - - - org.springframework.boot - spring-boot-starter-parent - 3.2.0 - - - - com.tennis - tennis-prediction-app - 1.0.0 - tennis-prediction-app - Tennis Match Prediction Application - - - 17 - - - - - - org.springframework.boot - spring-boot-starter-web - - - - org.springframework.boot - spring-boot-starter-data-jpa - - - - org.springframework.boot - spring-boot-starter-thymeleaf - - - - org.springframework.boot - spring-boot-starter-validation - - - - - com.h2database - h2 - runtime - - - - - com.fasterxml.jackson.core - jackson-databind - - - - - org.springframework.boot - spring-boot-starter-webflux - - - - - org.projectlombok - lombok - true - - - - - org.springframework.boot - spring-boot-devtools - runtime - true - - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - \ No newline at end of file diff --git a/src/main/java/com/tennis/TennisPredictionApplication.java b/src/main/java/com/tennis/TennisPredictionApplication.java deleted file mode 100644 index e59bcfb4..00000000 --- a/src/main/java/com/tennis/TennisPredictionApplication.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.tennis; - -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.scheduling.annotation.EnableScheduling; - -/** - * Main Spring Boot Application class for Tennis Match Prediction - * This application provides real-time tennis match predictions including: - * - Match winner prediction - * - Current game winner prediction - * - Current set winner prediction - * - * @author Tennis Prediction Team - * @version 1.0.0 - */ -@SpringBootApplication -@EnableScheduling // Enable scheduling for periodic data updates -public class TennisPredictionApplication { - - public static void main(String[] args) { - SpringApplication.run(TennisPredictionApplication.class, args); - System.out.println("🎾 Tennis Prediction Application Started Successfully!"); - System.out.println("📊 Access the application at: http://localhost:8080/tennis-prediction"); - System.out.println("🗄️ H2 Database Console: http://localhost:8080/tennis-prediction/h2-console"); - } -} \ No newline at end of file diff --git a/src/main/java/com/tennis/controller/TennisPredictionController.java b/src/main/java/com/tennis/controller/TennisPredictionController.java deleted file mode 100644 index 3c3b73c7..00000000 --- a/src/main/java/com/tennis/controller/TennisPredictionController.java +++ /dev/null @@ -1,467 +0,0 @@ -package com.tennis.controller; - -import com.tennis.entity.*; -import com.tennis.repository.*; -import com.tennis.service.PredictionService; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.*; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; -import java.util.Map; -import java.util.HashMap; - -/** - * REST Controller for Tennis Prediction Application - * Provides endpoints for predictions, matches, players, and dashboard - */ -@Controller -@RequestMapping("/api") -@RequiredArgsConstructor -@Slf4j -public class TennisPredictionController { - - private final PredictionService predictionService; - private final PlayerRepository playerRepository; - private final MatchRepository matchRepository; - private final MatchPredictionRepository predictionRepository; - private final HeadToHeadRepository headToHeadRepository; - - // ==================== DASHBOARD ENDPOINTS ==================== - - /** - * Main dashboard page - */ - @GetMapping("/") - public String dashboard(Model model) { - log.info("Loading main dashboard"); - - // Get live matches - List liveMatches = matchRepository.findByMatchStatus("Live"); - - // Get recent predictions - List recentPredictions = predictionRepository.findRecentPredictions( - LocalDateTime.now().minusHours(24)); - - // Get top players - List topPlayers = playerRepository.findTop10ByOrderByCurrentRankingAsc(); - - // Calculate prediction accuracy - Double predictionAccuracy = predictionRepository.calculatePredictionAccuracy(); - - model.addAttribute("liveMatches", liveMatches); - model.addAttribute("recentPredictions", recentPredictions); - model.addAttribute("topPlayers", topPlayers); - model.addAttribute("predictionAccuracy", predictionAccuracy != null ? predictionAccuracy : 0.0); - - return "dashboard"; - } - - // ==================== PREDICTION ENDPOINTS ==================== - - /** - * Predict match winner - */ - @PostMapping("/predictions/match-winner/{matchId}") - @ResponseBody - public ResponseEntity predictMatchWinner(@PathVariable Long matchId) { - log.info("Predicting match winner for match ID: {}", matchId); - - Optional matchOpt = matchRepository.findById(matchId); - if (matchOpt.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - Match match = matchOpt.get(); - MatchPrediction prediction = predictionService.predictMatchWinner(match); - - return ResponseEntity.ok(prediction); - } - - /** - * Predict current game winner - */ - @PostMapping("/predictions/game-winner/{matchId}") - @ResponseBody - public ResponseEntity predictGameWinner(@PathVariable Long matchId) { - log.info("Predicting game winner for match ID: {}", matchId); - - Optional matchOpt = matchRepository.findById(matchId); - if (matchOpt.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - Match match = matchOpt.get(); - MatchPrediction prediction = predictionService.predictCurrentGameWinner(match); - - return ResponseEntity.ok(prediction); - } - - /** - * Predict current set winner - */ - @PostMapping("/predictions/set-winner/{matchId}") - @ResponseBody - public ResponseEntity predictSetWinner(@PathVariable Long matchId) { - log.info("Predicting set winner for match ID: {}", matchId); - - Optional matchOpt = matchRepository.findById(matchId); - if (matchOpt.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - Match match = matchOpt.get(); - MatchPrediction prediction = predictionService.predictCurrentSetWinner(match); - - return ResponseEntity.ok(prediction); - } - - /** - * Get all predictions for a match - */ - @GetMapping("/predictions/match/{matchId}") - @ResponseBody - public ResponseEntity> getMatchPredictions(@PathVariable Long matchId) { - log.info("Getting predictions for match ID: {}", matchId); - - Optional matchOpt = matchRepository.findById(matchId); - if (matchOpt.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - List predictions = predictionRepository.findByMatchOrderByPredictionTimestampDesc(matchOpt.get()); - return ResponseEntity.ok(predictions); - } - - /** - * Get latest prediction for a match and type - */ - @GetMapping("/predictions/latest/{matchId}/{predictionType}") - @ResponseBody - public ResponseEntity getLatestPrediction( - @PathVariable Long matchId, - @PathVariable String predictionType) { - log.info("Getting latest {} prediction for match ID: {}", predictionType, matchId); - - Optional matchOpt = matchRepository.findById(matchId); - if (matchOpt.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - Optional predictionOpt = predictionRepository - .findFirstByMatchAndPredictionTypeOrderByPredictionTimestampDesc(matchOpt.get(), predictionType); - - return predictionOpt.map(ResponseEntity::ok) - .orElse(ResponseEntity.notFound().build()); - } - - /** - * Get prediction accuracy statistics - */ - @GetMapping("/predictions/accuracy") - @ResponseBody - public ResponseEntity> getPredictionAccuracy() { - log.info("Getting prediction accuracy statistics"); - - Double overallAccuracy = predictionRepository.calculatePredictionAccuracy(); - List correctPredictions = predictionRepository.findByIsCorrectTrueOrderByPredictionTimestampDesc(); - List incorrectPredictions = predictionRepository.findByIsCorrectFalseOrderByPredictionTimestampDesc(); - - Map stats = new HashMap<>(); - stats.put("overallAccuracy", overallAccuracy != null ? overallAccuracy : 0.0); - stats.put("correctPredictions", correctPredictions.size()); - stats.put("incorrectPredictions", incorrectPredictions.size()); - stats.put("totalVerifiedPredictions", correctPredictions.size() + incorrectPredictions.size()); - - return ResponseEntity.ok(stats); - } - - // ==================== MATCH ENDPOINTS ==================== - - /** - * Get all matches - */ - @GetMapping("/matches") - @ResponseBody - public ResponseEntity> getAllMatches() { - log.info("Getting all matches"); - List matches = matchRepository.findAll(); - return ResponseEntity.ok(matches); - } - - /** - * Get live matches - */ - @GetMapping("/matches/live") - @ResponseBody - public ResponseEntity> getLiveMatches() { - log.info("Getting live matches"); - List liveMatches = matchRepository.findByMatchStatus("Live"); - return ResponseEntity.ok(liveMatches); - } - - /** - * Get match by ID - */ - @GetMapping("/matches/{matchId}") - @ResponseBody - public ResponseEntity getMatchById(@PathVariable Long matchId) { - log.info("Getting match by ID: {}", matchId); - - Optional matchOpt = matchRepository.findById(matchId); - return matchOpt.map(ResponseEntity::ok) - .orElse(ResponseEntity.notFound().build()); - } - - /** - * Get matches by tournament - */ - @GetMapping("/matches/tournament/{tournamentName}") - @ResponseBody - public ResponseEntity> getMatchesByTournament(@PathVariable String tournamentName) { - log.info("Getting matches for tournament: {}", tournamentName); - List matches = matchRepository.findByTournamentNameIgnoreCaseOrderByStartTimeDesc(tournamentName); - return ResponseEntity.ok(matches); - } - - /** - * Get matches by surface - */ - @GetMapping("/matches/surface/{surface}") - @ResponseBody - public ResponseEntity> getMatchesBySurface(@PathVariable String surface) { - log.info("Getting matches on surface: {}", surface); - List matches = matchRepository.findBySurfaceIgnoreCaseOrderByStartTimeDesc(surface); - return ResponseEntity.ok(matches); - } - - /** - * Create new match - */ - @PostMapping("/matches") - @ResponseBody - public ResponseEntity createMatch(@RequestBody Match match) { - log.info("Creating new match: {} vs {}", - match.getPlayer1().getName(), match.getPlayer2().getName()); - - Match savedMatch = matchRepository.save(match); - return ResponseEntity.ok(savedMatch); - } - - /** - * Update match - */ - @PutMapping("/matches/{matchId}") - @ResponseBody - public ResponseEntity updateMatch(@PathVariable Long matchId, @RequestBody Match match) { - log.info("Updating match ID: {}", matchId); - - if (!matchRepository.existsById(matchId)) { - return ResponseEntity.notFound().build(); - } - - match.setId(matchId); - Match updatedMatch = matchRepository.save(match); - return ResponseEntity.ok(updatedMatch); - } - - // ==================== PLAYER ENDPOINTS ==================== - - /** - * Get all players - */ - @GetMapping("/players") - @ResponseBody - public ResponseEntity> getAllPlayers() { - log.info("Getting all players"); - List players = playerRepository.findAll(); - return ResponseEntity.ok(players); - } - - /** - * Get player by ID - */ - @GetMapping("/players/{playerId}") - @ResponseBody - public ResponseEntity getPlayerById(@PathVariable Long playerId) { - log.info("Getting player by ID: {}", playerId); - - Optional playerOpt = playerRepository.findById(playerId); - return playerOpt.map(ResponseEntity::ok) - .orElse(ResponseEntity.notFound().build()); - } - - /** - * Get player by name - */ - @GetMapping("/players/name/{playerName}") - @ResponseBody - public ResponseEntity getPlayerByName(@PathVariable String playerName) { - log.info("Getting player by name: {}", playerName); - - Optional playerOpt = playerRepository.findByNameIgnoreCase(playerName); - return playerOpt.map(ResponseEntity::ok) - .orElse(ResponseEntity.notFound().build()); - } - - /** - * Get top ranked players - */ - @GetMapping("/players/top") - @ResponseBody - public ResponseEntity> getTopPlayers() { - log.info("Getting top ranked players"); - List topPlayers = playerRepository.findTop10ByOrderByCurrentRankingAsc(); - return ResponseEntity.ok(topPlayers); - } - - /** - * Get players by country - */ - @GetMapping("/players/country/{country}") - @ResponseBody - public ResponseEntity> getPlayersByCountry(@PathVariable String country) { - log.info("Getting players from country: {}", country); - List players = playerRepository.findByCountryIgnoreCase(country); - return ResponseEntity.ok(players); - } - - /** - * Get players by surface performance - */ - @GetMapping("/players/surface/{surface}") - @ResponseBody - public ResponseEntity> getPlayersBySurface(@PathVariable String surface) { - log.info("Getting players by surface performance: {}", surface); - List players = playerRepository.findPlayersBySurfacePerformance(surface, 0.6); - return ResponseEntity.ok(players); - } - - /** - * Search players by name - */ - @GetMapping("/players/search/{namePattern}") - @ResponseBody - public ResponseEntity> searchPlayers(@PathVariable String namePattern) { - log.info("Searching players with pattern: {}", namePattern); - List players = playerRepository.findByNameContainingIgnoreCase(namePattern); - return ResponseEntity.ok(players); - } - - /** - * Create new player - */ - @PostMapping("/players") - @ResponseBody - public ResponseEntity createPlayer(@RequestBody Player player) { - log.info("Creating new player: {}", player.getName()); - - Player savedPlayer = playerRepository.save(player); - return ResponseEntity.ok(savedPlayer); - } - - /** - * Update player - */ - @PutMapping("/players/{playerId}") - @ResponseBody - public ResponseEntity updatePlayer(@PathVariable Long playerId, @RequestBody Player player) { - log.info("Updating player ID: {}", playerId); - - if (!playerRepository.existsById(playerId)) { - return ResponseEntity.notFound().build(); - } - - player.setId(playerId); - Player updatedPlayer = playerRepository.save(player); - return ResponseEntity.ok(updatedPlayer); - } - - // ==================== HEAD-TO-HEAD ENDPOINTS ==================== - - /** - * Get head-to-head record between two players - */ - @GetMapping("/head-to-head/{player1Id}/{player2Id}") - @ResponseBody - public ResponseEntity getHeadToHead(@PathVariable Long player1Id, @PathVariable Long player2Id) { - log.info("Getting head-to-head record between players: {} and {}", player1Id, player2Id); - - Optional player1Opt = playerRepository.findById(player1Id); - Optional player2Opt = playerRepository.findById(player2Id); - - if (player1Opt.isEmpty() || player2Opt.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - Optional h2hOpt = headToHeadRepository - .findByPlayer1AndPlayer2OrPlayer2AndPlayer1(player1Opt.get(), player2Opt.get(), - player2Opt.get(), player1Opt.get()); - - return h2hOpt.map(ResponseEntity::ok) - .orElse(ResponseEntity.notFound().build()); - } - - /** - * Get head-to-head records for a player - */ - @GetMapping("/head-to-head/player/{playerId}") - @ResponseBody - public ResponseEntity> getPlayerHeadToHead(@PathVariable Long playerId) { - log.info("Getting head-to-head records for player: {}", playerId); - - Optional playerOpt = playerRepository.findById(playerId); - if (playerOpt.isEmpty()) { - return ResponseEntity.notFound().build(); - } - - List h2hRecords = headToHeadRepository - .findByPlayer1OrPlayer2OrderByTotalMatchesDesc(playerOpt.get(), playerOpt.get()); - - return ResponseEntity.ok(h2hRecords); - } - - // ==================== STATISTICS ENDPOINTS ==================== - - /** - * Get application statistics - */ - @GetMapping("/statistics") - @ResponseBody - public ResponseEntity> getStatistics() { - log.info("Getting application statistics"); - - Map stats = new HashMap<>(); - - // Player statistics - long totalPlayers = playerRepository.count(); - List topPlayers = playerRepository.findTop10ByOrderByCurrentRankingAsc(); - - // Match statistics - long totalMatches = matchRepository.count(); - List liveMatches = matchRepository.findByMatchStatus("Live"); - List completedMatches = matchRepository.findByMatchStatus("Completed"); - - // Prediction statistics - long totalPredictions = predictionRepository.count(); - Double predictionAccuracy = predictionRepository.calculatePredictionAccuracy(); - List recentPredictions = predictionRepository.findRecentPredictions( - LocalDateTime.now().minusHours(24)); - - stats.put("totalPlayers", totalPlayers); - stats.put("topPlayers", topPlayers.size()); - stats.put("totalMatches", totalMatches); - stats.put("liveMatches", liveMatches.size()); - stats.put("completedMatches", completedMatches.size()); - stats.put("totalPredictions", totalPredictions); - stats.put("predictionAccuracy", predictionAccuracy != null ? predictionAccuracy : 0.0); - stats.put("recentPredictions", recentPredictions.size()); - - return ResponseEntity.ok(stats); - } -} \ No newline at end of file diff --git a/src/main/java/com/tennis/entity/HeadToHead.java b/src/main/java/com/tennis/entity/HeadToHead.java deleted file mode 100644 index 21f62ef4..00000000 --- a/src/main/java/com/tennis/entity/HeadToHead.java +++ /dev/null @@ -1,125 +0,0 @@ -package com.tennis.entity; - -import jakarta.persistence.*; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; - -import java.time.LocalDateTime; - -/** - * HeadToHead entity representing the head-to-head record between two players - * Stores match history and statistics between specific player pairs - */ -@Entity -@Table(name = "head_to_head") -@Data -@NoArgsConstructor -@AllArgsConstructor -public class HeadToHead { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne - @JoinColumn(name = "player1_id", nullable = false) - private Player player1; - - @ManyToOne - @JoinColumn(name = "player2_id", nullable = false) - private Player player2; - - @Column(name = "total_matches") - private Integer totalMatches; - - @Column(name = "player1_wins") - private Integer player1Wins; - - @Column(name = "player2_wins") - private Integer player2Wins; - - // Surface-specific head-to-head records - @Column(name = "hard_court_matches") - private Integer hardCourtMatches; - - @Column(name = "hard_court_player1_wins") - private Integer hardCourtPlayer1Wins; - - @Column(name = "clay_court_matches") - private Integer clayCourtMatches; - - @Column(name = "clay_court_player1_wins") - private Integer clayCourtPlayer1Wins; - - @Column(name = "grass_court_matches") - private Integer grassCourtMatches; - - @Column(name = "grass_court_player1_wins") - private Integer grassCourtPlayer1Wins; - - @Column(name = "last_match_date") - private LocalDateTime lastMatchDate; - - @Column(name = "last_match_tournament") - private String lastMatchTournament; - - @Column(name = "last_match_surface") - private String lastMatchSurface; - - @Column(name = "last_match_winner") - private String lastMatchWinner; // "player1" or "player2" - - @Column(name = "created_at") - private LocalDateTime createdAt; - - @Column(name = "updated_at") - private LocalDateTime updatedAt; - - @PrePersist - protected void onCreate() { - createdAt = LocalDateTime.now(); - updatedAt = LocalDateTime.now(); - } - - @PreUpdate - protected void onUpdate() { - updatedAt = LocalDateTime.now(); - } - - /** - * Calculate player1's win rate against player2 - * @return win rate as percentage - */ - public Double getPlayer1WinRate() { - if (totalMatches == 0) return 0.0; - return (double) player1Wins / totalMatches * 100; - } - - /** - * Calculate player2's win rate against player1 - * @return win rate as percentage - */ - public Double getPlayer2WinRate() { - if (totalMatches == 0) return 0.0; - return (double) player2Wins / totalMatches * 100; - } - - /** - * Get head-to-head record for a specific surface - * @param surface the surface type - * @return win rate for player1 on that surface - */ - public Double getSurfaceWinRate(String surface) { - switch (surface.toLowerCase()) { - case "hard": - return hardCourtMatches > 0 ? (double) hardCourtPlayer1Wins / hardCourtMatches * 100 : 0.0; - case "clay": - return clayCourtMatches > 0 ? (double) clayCourtPlayer1Wins / clayCourtMatches * 100 : 0.0; - case "grass": - return grassCourtMatches > 0 ? (double) grassCourtPlayer1Wins / grassCourtMatches * 100 : 0.0; - default: - return getPlayer1WinRate(); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/tennis/entity/Match.java b/src/main/java/com/tennis/entity/Match.java deleted file mode 100644 index cf7fdabf..00000000 --- a/src/main/java/com/tennis/entity/Match.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.tennis.entity; - -import jakarta.persistence.*; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * Match entity representing a tennis match - * Stores live match data, scores, and current match state - */ -@Entity -@Table(name = "matches") -@Data -@NoArgsConstructor -@AllArgsConstructor -public class Match { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne - @JoinColumn(name = "player1_id", nullable = false) - private Player player1; - - @ManyToOne - @JoinColumn(name = "player2_id", nullable = false) - private Player player2; - - @Column(name = "tournament_name") - private String tournamentName; - - @Column(name = "match_type") - private String matchType; // "Best of 3", "Best of 5" - - @Column(name = "surface") - private String surface; // "Hard", "Clay", "Grass" - - @Column(name = "match_status") - private String matchStatus; // "Scheduled", "Live", "Completed", "Cancelled" - - @Column(name = "start_time") - private LocalDateTime startTime; - - @Column(name = "end_time") - private LocalDateTime endTime; - - // Current Score - @Column(name = "player1_sets_won") - private Integer player1SetsWon = 0; - - @Column(name = "player2_sets_won") - private Integer player2SetsWon = 0; - - @Column(name = "current_set") - private Integer currentSet = 1; - - @Column(name = "player1_games_current_set") - private Integer player1GamesCurrentSet = 0; - - @Column(name = "player2_games_current_set") - private Integer player2GamesCurrentSet = 0; - - @Column(name = "player1_points_current_game") - private Integer player1PointsCurrentGame = 0; - - @Column(name = "player2_points_current_game") - private Integer player2PointsCurrentGame = 0; - - @Column(name = "current_server") - private String currentServer; // "player1" or "player2" - - // Live Statistics - @Column(name = "player1_aces") - private Integer player1Aces = 0; - - @Column(name = "player2_aces") - private Integer player2Aces = 0; - - @Column(name = "player1_double_faults") - private Integer player1DoubleFaults = 0; - - @Column(name = "player2_double_faults") - private Integer player2DoubleFaults = 0; - - @Column(name = "player1_first_serve_percentage") - private Double player1FirstServePercentage = 0.0; - - @Column(name = "player2_first_serve_percentage") - private Double player2FirstServePercentage = 0.0; - - @Column(name = "player1_break_points_won") - private Integer player1BreakPointsWon = 0; - - @Column(name = "player2_break_points_won") - private Integer player2BreakPointsWon = 0; - - @Column(name = "player1_break_points_opportunities") - private Integer player1BreakPointsOpportunities = 0; - - @Column(name = "player2_break_points_opportunities") - private Integer player2BreakPointsOpportunities = 0; - - @Column(name = "player1_total_points_won") - private Integer player1TotalPointsWon = 0; - - @Column(name = "player2_total_points_won") - private Integer player2TotalPointsWon = 0; - - @Column(name = "total_points_played") - private Integer totalPointsPlayed = 0; - - // Set History (JSON format for simplicity) - @Column(name = "set_scores", columnDefinition = "TEXT") - private String setScores; // JSON array of set scores - - @Column(name = "created_at") - private LocalDateTime createdAt; - - @Column(name = "updated_at") - private LocalDateTime updatedAt; - - // Relationships - @OneToMany(mappedBy = "match", cascade = CascadeType.ALL) - private List predictions; - - @PrePersist - protected void onCreate() { - createdAt = LocalDateTime.now(); - updatedAt = LocalDateTime.now(); - } - - @PreUpdate - protected void onUpdate() { - updatedAt = LocalDateTime.now(); - } - - /** - * Get current match score in standard tennis format - * @return formatted score string - */ - public String getCurrentScore() { - return String.format("%d-%d (%d-%d)", - player1SetsWon, player2SetsWon, - player1GamesCurrentSet, player2GamesCurrentSet); - } - - /** - * Get current game score in tennis points format - * @return game score (0, 15, 30, 40, AD) - */ - public String getCurrentGameScore() { - return String.format("%s-%s", - convertPointsToTennisScore(player1PointsCurrentGame), - convertPointsToTennisScore(player2PointsCurrentGame)); - } - - /** - * Convert points to tennis score format - * @param points number of points - * @return tennis score string - */ - private String convertPointsToTennisScore(Integer points) { - switch (points) { - case 0: return "0"; - case 1: return "15"; - case 2: return "30"; - case 3: return "40"; - default: return "AD"; - } - } - - /** - * Check if match is completed - * @return true if match is finished - */ - public boolean isCompleted() { - return "Completed".equals(matchStatus); - } - - /** - * Check if match is live - * @return true if match is currently being played - */ - public boolean isLive() { - return "Live".equals(matchStatus); - } - - /** - * Get match winner - * @return player name or null if match not completed - */ - public String getWinner() { - if (!isCompleted()) return null; - return player1SetsWon > player2SetsWon ? player1.getName() : player2.getName(); - } -} \ No newline at end of file diff --git a/src/main/java/com/tennis/entity/MatchPrediction.java b/src/main/java/com/tennis/entity/MatchPrediction.java deleted file mode 100644 index 3dc4cdf4..00000000 --- a/src/main/java/com/tennis/entity/MatchPrediction.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.tennis.entity; - -import jakarta.persistence.*; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; - -import java.time.LocalDateTime; - -/** - * MatchPrediction entity representing prediction results for a tennis match - * Stores various types of predictions with confidence scores - */ -@Entity -@Table(name = "match_predictions") -@Data -@NoArgsConstructor -@AllArgsConstructor -public class MatchPrediction { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @ManyToOne - @JoinColumn(name = "match_id", nullable = false) - private Match match; - - @Column(name = "prediction_type") - private String predictionType; // "MATCH_WINNER", "CURRENT_GAME_WINNER", "CURRENT_SET_WINNER" - - @Column(name = "predicted_winner") - private String predictedWinner; // "player1", "player2" - - @Column(name = "confidence_score") - private Double confidenceScore; // 0.0 to 1.0 - - @Column(name = "player1_win_probability") - private Double player1WinProbability; // 0.0 to 1.0 - - @Column(name = "player2_win_probability") - private Double player2WinProbability; // 0.0 to 1.0 - - // Factors that influenced the prediction - @Column(name = "ranking_factor") - private Double rankingFactor; - - @Column(name = "head_to_head_factor") - private Double headToHeadFactor; - - @Column(name = "surface_factor") - private Double surfaceFactor; - - @Column(name = "recent_form_factor") - private Double recentFormFactor; - - @Column(name = "live_stats_factor") - private Double liveStatsFactor; - - @Column(name = "momentum_factor") - private Double momentumFactor; - - @Column(name = "prediction_reasoning") - private String predictionReasoning; // Detailed explanation of the prediction - - @Column(name = "prediction_timestamp") - private LocalDateTime predictionTimestamp; - - @Column(name = "is_correct") - private Boolean isCorrect; // null if prediction not yet verified - - @Column(name = "created_at") - private LocalDateTime createdAt; - - @Column(name = "updated_at") - private LocalDateTime updatedAt; - - @PrePersist - protected void onCreate() { - createdAt = LocalDateTime.now(); - updatedAt = LocalDateTime.now(); - predictionTimestamp = LocalDateTime.now(); - } - - @PreUpdate - protected void onUpdate() { - updatedAt = LocalDateTime.now(); - } - - /** - * Get the predicted winner's name - * @return player name - */ - public String getPredictedWinnerName() { - if ("player1".equals(predictedWinner)) { - return match.getPlayer1().getName(); - } else if ("player2".equals(predictedWinner)) { - return match.getPlayer2().getName(); - } - return "Unknown"; - } - - /** - * Get confidence level as a string - * @return confidence level description - */ - public String getConfidenceLevel() { - if (confidenceScore >= 0.8) return "Very High"; - if (confidenceScore >= 0.6) return "High"; - if (confidenceScore >= 0.4) return "Medium"; - if (confidenceScore >= 0.2) return "Low"; - return "Very Low"; - } - - /** - * Get the most influential factor - * @return factor name with highest weight - */ - public String getMostInfluentialFactor() { - Double maxFactor = Math.max(Math.max(rankingFactor, headToHeadFactor), - Math.max(surfaceFactor, recentFormFactor)); - maxFactor = Math.max(maxFactor, Math.max(liveStatsFactor, momentumFactor)); - - if (maxFactor.equals(rankingFactor)) return "Player Ranking"; - if (maxFactor.equals(headToHeadFactor)) return "Head-to-Head Record"; - if (maxFactor.equals(surfaceFactor)) return "Surface Performance"; - if (maxFactor.equals(recentFormFactor)) return "Recent Form"; - if (maxFactor.equals(liveStatsFactor)) return "Live Match Statistics"; - if (maxFactor.equals(momentumFactor)) return "Match Momentum"; - - return "Unknown"; - } - - /** - * Check if prediction is verified - * @return true if prediction has been verified - */ - public boolean isVerified() { - return isCorrect != null; - } -} \ No newline at end of file diff --git a/src/main/java/com/tennis/entity/Player.java b/src/main/java/com/tennis/entity/Player.java deleted file mode 100644 index 22cecb2a..00000000 --- a/src/main/java/com/tennis/entity/Player.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.tennis.entity; - -import jakarta.persistence.*; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.AllArgsConstructor; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * Player entity representing a tennis player - * Stores comprehensive player information including rankings, statistics, and performance data - */ -@Entity -@Table(name = "players") -@Data -@NoArgsConstructor -@AllArgsConstructor -public class Player { - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @Column(nullable = false, unique = true) - private String name; - - @Column(nullable = false) - private String country; - - @Column(name = "current_ranking") - private Integer currentRanking; - - @Column(name = "career_high_ranking") - private Integer careerHighRanking; - - @Column(name = "age") - private Integer age; - - @Column(name = "height_cm") - private Integer heightCm; - - @Column(name = "weight_kg") - private Integer weightKg; - - @Column(name = "playing_style") - private String playingStyle; // e.g., "Aggressive Baseline", "Serve and Volley" - - @Column(name = "preferred_hand") - private String preferredHand; // "Right", "Left" - - // Surface Performance Statistics (0.0 to 1.0) - @Column(name = "hard_court_win_rate") - private Double hardCourtWinRate; - - @Column(name = "clay_court_win_rate") - private Double clayCourtWinRate; - - @Column(name = "grass_court_win_rate") - private Double grassCourtWinRate; - - // Service Statistics - @Column(name = "first_serve_percentage") - private Double firstServePercentage; - - @Column(name = "first_serve_win_rate") - private Double firstServeWinRate; - - @Column(name = "second_serve_win_rate") - private Double secondServeWinRate; - - @Column(name = "aces_per_match") - private Double acesPerMatch; - - @Column(name = "double_faults_per_match") - private Double doubleFaultsPerMatch; - - // Return Statistics - @Column(name = "first_serve_return_win_rate") - private Double firstServeReturnWinRate; - - @Column(name = "second_serve_return_win_rate") - private Double secondServeReturnWinRate; - - @Column(name = "break_points_converted_percentage") - private Double breakPointsConvertedPercentage; - - // Recent Form (last 10 matches) - @Column(name = "recent_form_win_rate") - private Double recentFormWinRate; - - @Column(name = "matches_played_this_year") - private Integer matchesPlayedThisYear; - - @Column(name = "wins_this_year") - private Integer winsThisYear; - - @Column(name = "created_at") - private LocalDateTime createdAt; - - @Column(name = "updated_at") - private LocalDateTime updatedAt; - - // Relationships - @OneToMany(mappedBy = "player1", cascade = CascadeType.ALL) - private List headToHeadAsPlayer1; - - @OneToMany(mappedBy = "player2", cascade = CascadeType.ALL) - private List headToHeadAsPlayer2; - - @PrePersist - protected void onCreate() { - createdAt = LocalDateTime.now(); - updatedAt = LocalDateTime.now(); - } - - @PreUpdate - protected void onUpdate() { - updatedAt = LocalDateTime.now(); - } - - /** - * Calculate overall win rate for the player - * @return overall win rate as percentage - */ - public Double getOverallWinRate() { - if (matchesPlayedThisYear == 0) return 0.0; - return (double) winsThisYear / matchesPlayedThisYear * 100; - } - - /** - * Get best surface for the player - * @return surface name with highest win rate - */ - public String getBestSurface() { - if (hardCourtWinRate >= clayCourtWinRate && hardCourtWinRate >= grassCourtWinRate) { - return "Hard Court"; - } else if (clayCourtWinRate >= grassCourtWinRate) { - return "Clay Court"; - } else { - return "Grass Court"; - } - } -} \ No newline at end of file diff --git a/src/main/java/com/tennis/repository/HeadToHeadRepository.java b/src/main/java/com/tennis/repository/HeadToHeadRepository.java deleted file mode 100644 index 41096420..00000000 --- a/src/main/java/com/tennis/repository/HeadToHeadRepository.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.tennis.repository; - -import com.tennis.entity.HeadToHead; -import com.tennis.entity.Player; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -import java.util.List; -import java.util.Optional; - -/** - * Repository interface for HeadToHead entity - * Provides database operations for head-to-head records - */ -@Repository -public interface HeadToHeadRepository extends JpaRepository { - - /** - * Find head-to-head record between two players - * @param player1 first player - * @param player2 second player - * @return optional head-to-head record - */ - Optional findByPlayer1AndPlayer2OrPlayer2AndPlayer1(Player player1, Player player2, Player player2Again, Player player1Again); - - /** - * Find head-to-head records for a player - * @param player player to search for - * @return list of head-to-head records involving the player - */ - List findByPlayer1OrPlayer2OrderByTotalMatchesDesc(Player player1, Player player2); - - /** - * Find head-to-head records with minimum matches - * @param minMatches minimum number of matches - * @return list of head-to-head records with minimum matches - */ - List findByTotalMatchesGreaterThanEqualOrderByTotalMatchesDesc(Integer minMatches); - - /** - * Find head-to-head records by surface - * @param surface surface type - * @param minMatches minimum matches on surface - * @return list of head-to-head records for surface - */ - @Query("SELECT h FROM HeadToHead h WHERE " + - "(:surface = 'hard' AND h.hardCourtMatches >= :minMatches) OR " + - "(:surface = 'clay' AND h.clayCourtMatches >= :minMatches) OR " + - "(:surface = 'grass' AND h.grassCourtMatches >= :minMatches) " + - "ORDER BY " + - "CASE WHEN :surface = 'hard' THEN h.hardCourtPlayer1Wins * 1.0 / h.hardCourtMatches " + - "WHEN :surface = 'clay' THEN h.clayCourtPlayer1Wins * 1.0 / h.clayCourtMatches " + - "WHEN :surface = 'grass' THEN h.grassCourtPlayer1Wins * 1.0 / h.grassCourtMatches " + - "ELSE 0.0 END DESC") - List findBySurfaceAndMinMatches(@Param("surface") String surface, @Param("minMatches") Integer minMatches); - - /** - * Find recent head-to-head records - * @param days number of days to look back - * @return list of recent head-to-head records - */ - @Query("SELECT h FROM HeadToHead h WHERE h.lastMatchDate >= :startDate ORDER BY h.lastMatchDate DESC") - List findRecentHeadToHeadRecords(@Param("startDate") java.time.LocalDateTime startDate); - - /** - * Find head-to-head records by tournament - * @param tournamentName tournament name - * @return list of head-to-head records in tournament - */ - List findByLastMatchTournamentIgnoreCaseOrderByLastMatchDateDesc(String tournamentName); - - /** - * Find head-to-head records by winner - * @param winner winner of last match ("player1" or "player2") - * @return list of head-to-head records with that winner - */ - List findByLastMatchWinnerOrderByLastMatchDateDesc(String winner); - - /** - * Find head-to-head records with close records (similar win rates) - * @param maxWinRateDifference maximum difference in win rates - * @return list of head-to-head records with close records - */ - @Query("SELECT h FROM HeadToHead h WHERE ABS(h.player1Wins * 1.0 / h.totalMatches - h.player2Wins * 1.0 / h.totalMatches) <= :maxDifference AND h.totalMatches > 0 ORDER BY h.totalMatches DESC") - List findCloseHeadToHeadRecords(@Param("maxDifference") Double maxWinRateDifference); - - /** - * Find dominant head-to-head records (one player clearly better) - * @param minWinRateDifference minimum difference in win rates - * @return list of dominant head-to-head records - */ - @Query("SELECT h FROM HeadToHead h WHERE ABS(h.player1Wins * 1.0 / h.totalMatches - h.player2Wins * 1.0 / h.totalMatches) >= :minDifference AND h.totalMatches > 0 ORDER BY ABS(h.player1Wins * 1.0 / h.totalMatches - h.player2Wins * 1.0 / h.totalMatches) DESC") - List findDominantHeadToHeadRecords(@Param("minDifference") Double minWinRateDifference); -} \ No newline at end of file diff --git a/src/main/java/com/tennis/repository/MatchPredictionRepository.java b/src/main/java/com/tennis/repository/MatchPredictionRepository.java deleted file mode 100644 index 59989045..00000000 --- a/src/main/java/com/tennis/repository/MatchPredictionRepository.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.tennis.repository; - -import com.tennis.entity.Match; -import com.tennis.entity.MatchPrediction; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; - -/** - * Repository interface for MatchPrediction entity - * Provides database operations for prediction data - */ -@Repository -public interface MatchPredictionRepository extends JpaRepository { - - /** - * Find predictions by match - * @param match match to search for - * @return list of predictions for that match - */ - List findByMatchOrderByPredictionTimestampDesc(Match match); - - /** - * Find predictions by prediction type - * @param predictionType type of prediction - * @return list of predictions of that type - */ - List findByPredictionTypeOrderByPredictionTimestampDesc(String predictionType); - - /** - * Find predictions by match and type - * @param match match to search for - * @param predictionType type of prediction - * @return list of predictions for match and type - */ - List findByMatchAndPredictionTypeOrderByPredictionTimestampDesc(Match match, String predictionType); - - /** - * Find latest prediction for a match and type - * @param match match to search for - * @param predictionType type of prediction - * @return latest prediction - */ - Optional findFirstByMatchAndPredictionTypeOrderByPredictionTimestampDesc(Match match, String predictionType); - - /** - * Find predictions by confidence score range - * @param minConfidence minimum confidence score - * @param maxConfidence maximum confidence score - * @return list of predictions in confidence range - */ - List findByConfidenceScoreBetweenOrderByConfidenceScoreDesc(Double minConfidence, Double maxConfidence); - - /** - * Find high confidence predictions - * @param minConfidence minimum confidence threshold - * @return list of high confidence predictions - */ - List findByConfidenceScoreGreaterThanEqualOrderByConfidenceScoreDesc(Double minConfidence); - - /** - * Find predictions by date range - * @param startDate start date - * @param endDate end date - * @return list of predictions in date range - */ - List findByPredictionTimestampBetweenOrderByPredictionTimestampDesc(LocalDateTime startDate, LocalDateTime endDate); - - /** - * Find verified predictions (where isCorrect is not null) - * @return list of verified predictions - */ - List findByIsCorrectIsNotNullOrderByPredictionTimestampDesc(); - - /** - * Find correct predictions - * @return list of predictions that were correct - */ - List findByIsCorrectTrueOrderByPredictionTimestampDesc(); - - /** - * Find incorrect predictions - * @return list of predictions that were incorrect - */ - List findByIsCorrectFalseOrderByPredictionTimestampDesc(); - - /** - * Find predictions by predicted winner - * @param predictedWinner predicted winner ("player1" or "player2") - * @return list of predictions with that winner - */ - List findByPredictedWinnerOrderByPredictionTimestampDesc(String predictedWinner); - - /** - * Find predictions for live matches - * @return list of predictions for live matches - */ - @Query("SELECT mp FROM MatchPrediction mp WHERE mp.match.matchStatus = 'Live' ORDER BY mp.predictionTimestamp DESC") - List findPredictionsForLiveMatches(); - - /** - * Find predictions by match status - * @param matchStatus match status - * @return list of predictions for matches with that status - */ - @Query("SELECT mp FROM MatchPrediction mp WHERE mp.match.matchStatus = :matchStatus ORDER BY mp.predictionTimestamp DESC") - List findByMatchStatus(@Param("matchStatus") String matchStatus); - - /** - * Find predictions by surface - * @param surface surface type - * @return list of predictions for matches on that surface - */ - @Query("SELECT mp FROM MatchPrediction mp WHERE mp.match.surface = :surface ORDER BY mp.predictionTimestamp DESC") - List findBySurface(@Param("surface") String surface); - - /** - * Calculate prediction accuracy - * @return prediction accuracy percentage - */ - @Query("SELECT (COUNT(CASE WHEN mp.isCorrect = true THEN 1 END) * 100.0 / COUNT(mp)) FROM MatchPrediction mp WHERE mp.isCorrect IS NOT NULL") - Double calculatePredictionAccuracy(); - - /** - * Find predictions by tournament - * @param tournamentName tournament name - * @return list of predictions for matches in that tournament - */ - @Query("SELECT mp FROM MatchPrediction mp WHERE mp.match.tournamentName = :tournamentName ORDER BY mp.predictionTimestamp DESC") - List findByTournament(@Param("tournamentName") String tournamentName); - - /** - * Find recent predictions - * @param hours number of hours to look back - * @return list of recent predictions - */ - @Query("SELECT mp FROM MatchPrediction mp WHERE mp.predictionTimestamp >= :startTime ORDER BY mp.predictionTimestamp DESC") - List findRecentPredictions(@Param("startTime") LocalDateTime startTime); -} \ No newline at end of file diff --git a/src/main/java/com/tennis/repository/MatchRepository.java b/src/main/java/com/tennis/repository/MatchRepository.java deleted file mode 100644 index 4fa672f0..00000000 --- a/src/main/java/com/tennis/repository/MatchRepository.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.tennis.repository; - -import com.tennis.entity.Match; -import com.tennis.entity.Player; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; - -/** - * Repository interface for Match entity - * Provides database operations for match data - */ -@Repository -public interface MatchRepository extends JpaRepository { - - /** - * Find matches by status - * @param status match status - * @return list of matches with that status - */ - List findByMatchStatus(String status); - - /** - * Find live matches - * @return list of currently live matches - */ - List findByMatchStatusOrderByStartTimeDesc(String status); - - /** - * Find matches by player - * @param player player to search for - * @return list of matches involving the player - */ - List findByPlayer1OrPlayer2OrderByStartTimeDesc(Player player1, Player player2); - - /** - * Find matches by tournament - * @param tournamentName tournament name - * @return list of matches in that tournament - */ - List findByTournamentNameIgnoreCaseOrderByStartTimeDesc(String tournamentName); - - /** - * Find matches by surface - * @param surface surface type - * @return list of matches on that surface - */ - List findBySurfaceIgnoreCaseOrderByStartTimeDesc(String surface); - - /** - * Find matches between two specific players - * @param player1 first player - * @param player2 second player - * @return list of matches between these players - */ - List findByPlayer1AndPlayer2OrPlayer2AndPlayer1OrderByStartTimeDesc( - Player player1, Player player2, Player player2Again, Player player1Again); - - /** - * Find matches by date range - * @param startDate start date - * @param endDate end date - * @return list of matches in date range - */ - List findByStartTimeBetweenOrderByStartTimeDesc(LocalDateTime startDate, LocalDateTime endDate); - - /** - * Find completed matches - * @return list of completed matches - */ - List findByMatchStatusOrderByEndTimeDesc(String status); - - /** - * Find matches by player with status - * @param player player to search for - * @param status match status - * @return list of matches for player with specific status - */ - @Query("SELECT m FROM Match m WHERE (m.player1 = :player OR m.player2 = :player) AND m.matchStatus = :status ORDER BY m.startTime DESC") - List findByPlayerAndStatus(@Param("player") Player player, @Param("status") String status); - - /** - * Find matches by surface and status - * @param surface surface type - * @param status match status - * @return list of matches on surface with status - */ - List findBySurfaceIgnoreCaseAndMatchStatusOrderByStartTimeDesc(String surface, String status); - - /** - * Find recent matches - * @param days number of days to look back - * @return list of recent matches - */ - @Query("SELECT m FROM Match m WHERE m.startTime >= :startDate ORDER BY m.startTime DESC") - List findRecentMatches(@Param("startDate") LocalDateTime startDate); - - /** - * Find matches with specific score pattern - * @param player1SetsWon sets won by player1 - * @param player2SetsWon sets won by player2 - * @return list of matches with that score - */ - List findByPlayer1SetsWonAndPlayer2SetsWon(Integer player1SetsWon, Integer player2SetsWon); - - /** - * Find matches by tournament and status - * @param tournamentName tournament name - * @param status match status - * @return list of matches in tournament with status - */ - List findByTournamentNameIgnoreCaseAndMatchStatusOrderByStartTimeDesc(String tournamentName, String status); -} \ No newline at end of file diff --git a/src/main/java/com/tennis/repository/PlayerRepository.java b/src/main/java/com/tennis/repository/PlayerRepository.java deleted file mode 100644 index 53df75db..00000000 --- a/src/main/java/com/tennis/repository/PlayerRepository.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.tennis.repository; - -import com.tennis.entity.Player; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; - -import java.util.List; -import java.util.Optional; - -/** - * Repository interface for Player entity - * Provides database operations for player data - */ -@Repository -public interface PlayerRepository extends JpaRepository { - - /** - * Find player by name (case-insensitive) - * @param name player name - * @return optional player - */ - Optional findByNameIgnoreCase(String name); - - /** - * Find players by country - * @param country country name - * @return list of players from that country - */ - List findByCountryIgnoreCase(String country); - - /** - * Find players by ranking range - * @param minRanking minimum ranking - * @param maxRanking maximum ranking - * @return list of players in ranking range - */ - List findByCurrentRankingBetweenOrderByCurrentRankingAsc(Integer minRanking, Integer maxRanking); - - /** - * Find top ranked players - * @param limit number of players to return - * @return list of top ranked players - */ - List findTop10ByOrderByCurrentRankingAsc(); - - /** - * Find players by surface performance - * @param surface surface type (hard, clay, grass) - * @param minWinRate minimum win rate - * @return list of players with good performance on surface - */ - @Query("SELECT p FROM Player p WHERE " + - "CASE WHEN :surface = 'hard' THEN p.hardCourtWinRate " + - "WHEN :surface = 'clay' THEN p.clayCourtWinRate " + - "WHEN :surface = 'grass' THEN p.grassCourtWinRate " + - "ELSE 0.0 END >= :minWinRate " + - "ORDER BY " + - "CASE WHEN :surface = 'hard' THEN p.hardCourtWinRate " + - "WHEN :surface = 'clay' THEN p.clayCourtWinRate " + - "WHEN :surface = 'grass' THEN p.grassCourtWinRate " + - "ELSE 0.0 END DESC") - List findPlayersBySurfacePerformance(@Param("surface") String surface, @Param("minWinRate") Double minWinRate); - - /** - * Find players by recent form - * @param minWinRate minimum recent form win rate - * @return list of players with good recent form - */ - List findByRecentFormWinRateGreaterThanEqualOrderByRecentFormWinRateDesc(Double minWinRate); - - /** - * Search players by name containing pattern - * @param namePattern name pattern to search - * @return list of matching players - */ - List findByNameContainingIgnoreCase(String namePattern); - - /** - * Find players by playing style - * @param playingStyle playing style - * @return list of players with that style - */ - List findByPlayingStyleIgnoreCase(String playingStyle); - - /** - * Find players by preferred hand - * @param preferredHand preferred hand (Right, Left) - * @return list of players with that hand preference - */ - List findByPreferredHandIgnoreCase(String preferredHand); -} \ No newline at end of file diff --git a/src/main/java/com/tennis/service/DataInitializationService.java b/src/main/java/com/tennis/service/DataInitializationService.java deleted file mode 100644 index 7a612b4a..00000000 --- a/src/main/java/com/tennis/service/DataInitializationService.java +++ /dev/null @@ -1,265 +0,0 @@ -package com.tennis.service; - -import com.tennis.entity.*; -import com.tennis.repository.*; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.CommandLineRunner; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; -import java.util.Arrays; -import java.util.List; - -/** - * Service to initialize the database with sample data - * Populates players, matches, and head-to-head records for testing - */ -@Service -@RequiredArgsConstructor -@Slf4j -public class DataInitializationService implements CommandLineRunner { - - private final PlayerRepository playerRepository; - private final MatchRepository matchRepository; - private final HeadToHeadRepository headToHeadRepository; - private final MatchPredictionRepository predictionRepository; - - @Override - public void run(String... args) throws Exception { - log.info("Initializing database with sample data..."); - - // Initialize players - initializePlayers(); - - // Initialize head-to-head records - initializeHeadToHeadRecords(); - - // Initialize matches - initializeMatches(); - - log.info("Database initialization completed successfully!"); - } - - /** - * Initialize sample players - */ - private void initializePlayers() { - log.info("Creating sample players..."); - - List players = Arrays.asList( - // Top 10 ATP Players (as of 2024) - createPlayer("Novak Djokovic", "Serbia", 1, 1, 36, 188, 77, - "Aggressive Baseline", "Right", 0.85, 0.78, 0.82, - 0.68, 0.78, 0.62, 8.5, 2.1, 0.32, 0.58, 0.42, 0.88, 25, 22), - - createPlayer("Carlos Alcaraz", "Spain", 2, 1, 20, 183, 80, - "Aggressive Baseline", "Right", 0.82, 0.75, 0.79, - 0.65, 0.76, 0.60, 7.2, 2.8, 0.35, 0.62, 0.45, 0.85, 28, 24), - - createPlayer("Daniil Medvedev", "Russia", 3, 1, 27, 198, 83, - "Defensive Baseline", "Right", 0.78, 0.72, 0.75, - 0.62, 0.74, 0.58, 6.8, 2.5, 0.38, 0.65, 0.48, 0.82, 30, 25), - - createPlayer("Jannik Sinner", "Italy", 4, 3, 22, 188, 76, - "Aggressive Baseline", "Right", 0.80, 0.73, 0.77, - 0.64, 0.75, 0.59, 7.5, 2.3, 0.36, 0.61, 0.44, 0.87, 32, 28), - - createPlayer("Andrey Rublev", "Russia", 5, 5, 26, 188, 75, - "Aggressive Baseline", "Right", 0.76, 0.70, 0.73, - 0.60, 0.72, 0.56, 6.2, 2.7, 0.40, 0.68, 0.50, 0.79, 35, 30), - - createPlayer("Stefanos Tsitsipas", "Greece", 6, 3, 25, 193, 89, - "All-Court", "Right", 0.79, 0.74, 0.76, - 0.63, 0.73, 0.57, 7.0, 2.4, 0.37, 0.63, 0.46, 0.81, 38, 32), - - createPlayer("Alexander Zverev", "Germany", 7, 2, 26, 198, 90, - "Aggressive Baseline", "Right", 0.77, 0.71, 0.74, - 0.61, 0.71, 0.55, 6.5, 2.6, 0.39, 0.66, 0.49, 0.80, 40, 35), - - createPlayer("Holger Rune", "Denmark", 8, 4, 20, 188, 77, - "Aggressive Baseline", "Right", 0.81, 0.76, 0.78, - 0.66, 0.77, 0.61, 7.8, 2.2, 0.34, 0.59, 0.43, 0.84, 42, 38), - - createPlayer("Hubert Hurkacz", "Poland", 9, 9, 26, 196, 82, - "Serve and Volley", "Right", 0.74, 0.68, 0.72, - 0.58, 0.70, 0.54, 8.2, 2.0, 0.33, 0.57, 0.41, 0.78, 45, 40), - - createPlayer("Taylor Fritz", "USA", 10, 8, 25, 196, 86, - "Aggressive Baseline", "Right", 0.75, 0.69, 0.73, - 0.59, 0.71, 0.55, 6.8, 2.4, 0.38, 0.64, 0.47, 0.77, 48, 42) - ); - - playerRepository.saveAll(players); - log.info("Created {} sample players", players.size()); - } - - /** - * Create a player with all attributes - */ - private Player createPlayer(String name, String country, Integer currentRanking, Integer careerHighRanking, - Integer age, Integer heightCm, Integer weightKg, String playingStyle, String preferredHand, - Double hardCourtWinRate, Double clayCourtWinRate, Double grassCourtWinRate, - Double firstServePercentage, Double firstServeWinRate, Double secondServeWinRate, - Double acesPerMatch, Double doubleFaultsPerMatch, Double firstServeReturnWinRate, - Double secondServeReturnWinRate, Double breakPointsConvertedPercentage, - Double recentFormWinRate, Integer matchesPlayedThisYear, Integer winsThisYear) { - - Player player = new Player(); - player.setName(name); - player.setCountry(country); - player.setCurrentRanking(currentRanking); - player.setCareerHighRanking(careerHighRanking); - player.setAge(age); - player.setHeightCm(heightCm); - player.setWeightKg(weightKg); - player.setPlayingStyle(playingStyle); - player.setPreferredHand(preferredHand); - player.setHardCourtWinRate(hardCourtWinRate); - player.setClayCourtWinRate(clayCourtWinRate); - player.setGrassCourtWinRate(grassCourtWinRate); - player.setFirstServePercentage(firstServePercentage); - player.setFirstServeWinRate(firstServeWinRate); - player.setSecondServeWinRate(secondServeWinRate); - player.setAcesPerMatch(acesPerMatch); - player.setDoubleFaultsPerMatch(doubleFaultsPerMatch); - player.setFirstServeReturnWinRate(firstServeReturnWinRate); - player.setSecondServeReturnWinRate(secondServeReturnWinRate); - player.setBreakPointsConvertedPercentage(breakPointsConvertedPercentage); - player.setRecentFormWinRate(recentFormWinRate); - player.setMatchesPlayedThisYear(matchesPlayedThisYear); - player.setWinsThisYear(winsThisYear); - - return player; - } - - /** - * Initialize head-to-head records - */ - private void initializeHeadToHeadRecords() { - log.info("Creating sample head-to-head records..."); - - List players = playerRepository.findAll(); - - // Create some sample head-to-head records - for (int i = 0; i < players.size() - 1; i++) { - for (int j = i + 1; j < players.size(); j++) { - Player player1 = players.get(i); - Player player2 = players.get(j); - - HeadToHead h2h = new HeadToHead(); - h2h.setPlayer1(player1); - h2h.setPlayer2(player2); - - // Generate realistic head-to-head data - int totalMatches = (int) (Math.random() * 10) + 1; - int player1Wins = (int) (Math.random() * totalMatches); - int player2Wins = totalMatches - player1Wins; - - h2h.setTotalMatches(totalMatches); - h2h.setPlayer1Wins(player1Wins); - h2h.setPlayer2Wins(player2Wins); - - // Surface-specific records - h2h.setHardCourtMatches((int) (totalMatches * 0.4)); - h2h.setHardCourtPlayer1Wins((int) (h2h.getHardCourtMatches() * Math.random())); - h2h.setClayCourtMatches((int) (totalMatches * 0.35)); - h2h.setClayCourtPlayer1Wins((int) (h2h.getClayCourtMatches() * Math.random())); - h2h.setGrassCourtMatches((int) (totalMatches * 0.25)); - h2h.setGrassCourtPlayer1Wins((int) (h2h.getGrassCourtMatches() * Math.random())); - - h2h.setLastMatchDate(LocalDateTime.now().minusDays((int) (Math.random() * 365))); - h2h.setLastMatchTournament("Australian Open"); - h2h.setLastMatchSurface("Hard"); - h2h.setLastMatchWinner(Math.random() > 0.5 ? "player1" : "player2"); - - headToHeadRepository.save(h2h); - } - } - - log.info("Created sample head-to-head records"); - } - - /** - * Initialize sample matches - */ - private void initializeMatches() { - log.info("Creating sample matches..."); - - List players = playerRepository.findAll(); - - // Create some live and completed matches - List matches = Arrays.asList( - // Live match - createMatch(players.get(0), players.get(1), "Australian Open", "Best of 5", "Hard", "Live", - LocalDateTime.now().minusHours(2), null, 1, 0, 1, 4, 3, 30, 40, "player1", - 8, 5, 2, 1, 0.72, 0.68, 2, 1, 3, 2, 45, 42, 87), - - // Completed match - createMatch(players.get(2), players.get(3), "Wimbledon", "Best of 5", "Grass", "Completed", - LocalDateTime.now().minusDays(1), LocalDateTime.now().minusDays(1).plusHours(3), - 3, 1, 3, 6, 4, 40, 30, "player1", 12, 8, 1, 2, 0.75, 0.70, 4, 2, 6, 3, 78, 65, 143), - - // Scheduled match - createMatch(players.get(4), players.get(5), "French Open", "Best of 5", "Clay", "Scheduled", - LocalDateTime.now().plusHours(2), null, 0, 0, 1, 0, 0, 0, 0, "player1", - 0, 0, 0, 0, 0.0, 0.0, 0, 0, 0, 0, 0, 0, 0), - - // Live match with close score - createMatch(players.get(6), players.get(7), "US Open", "Best of 5", "Hard", "Live", - LocalDateTime.now().minusHours(1), null, 1, 1, 2, 5, 5, 40, 40, "player2", - 6, 7, 1, 1, 0.68, 0.71, 1, 1, 2, 2, 52, 51, 103) - ); - - matchRepository.saveAll(matches); - log.info("Created {} sample matches", matches.size()); - } - - /** - * Create a match with all attributes - */ - private Match createMatch(Player player1, Player player2, String tournamentName, String matchType, - String surface, String matchStatus, LocalDateTime startTime, LocalDateTime endTime, - Integer player1SetsWon, Integer player2SetsWon, Integer currentSet, - Integer player1GamesCurrentSet, Integer player2GamesCurrentSet, - Integer player1PointsCurrentGame, Integer player2PointsCurrentGame, String currentServer, - Integer player1Aces, Integer player2Aces, Integer player1DoubleFaults, Integer player2DoubleFaults, - Double player1FirstServePercentage, Double player2FirstServePercentage, - Integer player1BreakPointsWon, Integer player2BreakPointsWon, - Integer player1BreakPointsOpportunities, Integer player2BreakPointsOpportunities, - Integer player1TotalPointsWon, Integer player2TotalPointsWon, Integer totalPointsPlayed) { - - Match match = new Match(); - match.setPlayer1(player1); - match.setPlayer2(player2); - match.setTournamentName(tournamentName); - match.setMatchType(matchType); - match.setSurface(surface); - match.setMatchStatus(matchStatus); - match.setStartTime(startTime); - match.setEndTime(endTime); - match.setPlayer1SetsWon(player1SetsWon); - match.setPlayer2SetsWon(player2SetsWon); - match.setCurrentSet(currentSet); - match.setPlayer1GamesCurrentSet(player1GamesCurrentSet); - match.setPlayer2GamesCurrentSet(player2GamesCurrentSet); - match.setPlayer1PointsCurrentGame(player1PointsCurrentGame); - match.setPlayer2PointsCurrentGame(player2PointsCurrentGame); - match.setCurrentServer(currentServer); - match.setPlayer1Aces(player1Aces); - match.setPlayer2Aces(player2Aces); - match.setPlayer1DoubleFaults(player1DoubleFaults); - match.setPlayer2DoubleFaults(player2DoubleFaults); - match.setPlayer1FirstServePercentage(player1FirstServePercentage); - match.setPlayer2FirstServePercentage(player2FirstServePercentage); - match.setPlayer1BreakPointsWon(player1BreakPointsWon); - match.setPlayer2BreakPointsWon(player2BreakPointsWon); - match.setPlayer1BreakPointsOpportunities(player1BreakPointsOpportunities); - match.setPlayer2BreakPointsOpportunities(player2BreakPointsOpportunities); - match.setPlayer1TotalPointsWon(player1TotalPointsWon); - match.setPlayer2TotalPointsWon(player2TotalPointsWon); - match.setTotalPointsPlayed(totalPointsPlayed); - - return match; - } -} \ No newline at end of file diff --git a/src/main/java/com/tennis/service/PredictionService.java b/src/main/java/com/tennis/service/PredictionService.java deleted file mode 100644 index 2425c8a2..00000000 --- a/src/main/java/com/tennis/service/PredictionService.java +++ /dev/null @@ -1,454 +0,0 @@ -package com.tennis.service; - -import com.tennis.entity.*; -import com.tennis.repository.*; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; - -import java.util.HashMap; -import java.util.Map; - -/** - * Service class for tennis match predictions - * Implements algorithms for predicting match winner, current game winner, and current set winner - */ -@Service -@RequiredArgsConstructor -@Slf4j -public class PredictionService { - - private final PlayerRepository playerRepository; - private final MatchRepository matchRepository; - private final MatchPredictionRepository predictionRepository; - private final HeadToHeadRepository headToHeadRepository; - - // Weight factors for different prediction components - private static final double RANKING_WEIGHT = 0.15; - private static final double HEAD_TO_HEAD_WEIGHT = 0.20; - private static final double SURFACE_WEIGHT = 0.15; - private static final double RECENT_FORM_WEIGHT = 0.15; - private static final double LIVE_STATS_WEIGHT = 0.25; - private static final double MOMENTUM_WEIGHT = 0.10; - - /** - * Predict match winner - * @param match the match to predict - * @return prediction result - */ - public MatchPrediction predictMatchWinner(Match match) { - log.info("Predicting match winner for match: {} vs {}", - match.getPlayer1().getName(), match.getPlayer2().getName()); - - // Calculate base probabilities - double player1Probability = calculatePlayer1WinProbability(match); - double player2Probability = 1.0 - player1Probability; - - // Determine predicted winner - String predictedWinner = player1Probability > player2Probability ? "player1" : "player2"; - double confidenceScore = Math.max(player1Probability, player2Probability); - - // Calculate factor weights - Map factors = calculatePredictionFactors(match); - - // Create prediction reasoning - String reasoning = buildPredictionReasoning(match, factors, predictedWinner, confidenceScore); - - // Create and save prediction - MatchPrediction prediction = new MatchPrediction(); - prediction.setMatch(match); - prediction.setPredictionType("MATCH_WINNER"); - prediction.setPredictedWinner(predictedWinner); - prediction.setConfidenceScore(confidenceScore); - prediction.setPlayer1WinProbability(player1Probability); - prediction.setPlayer2WinProbability(player2Probability); - prediction.setRankingFactor(factors.get("ranking")); - prediction.setHeadToHeadFactor(factors.get("headToHead")); - prediction.setSurfaceFactor(factors.get("surface")); - prediction.setRecentFormFactor(factors.get("recentForm")); - prediction.setLiveStatsFactor(factors.get("liveStats")); - prediction.setMomentumFactor(factors.get("momentum")); - prediction.setPredictionReasoning(reasoning); - - return predictionRepository.save(prediction); - } - - /** - * Predict current game winner - * @param match the match to predict - * @return prediction result - */ - public MatchPrediction predictCurrentGameWinner(Match match) { - log.info("Predicting current game winner for match: {} vs {}", - match.getPlayer1().getName(), match.getPlayer2().getName()); - - // For game prediction, focus more on serving and current momentum - double player1Probability = calculateGameWinProbability(match, true); - double player2Probability = 1.0 - player1Probability; - - String predictedWinner = player1Probability > player2Probability ? "player1" : "player2"; - double confidenceScore = Math.max(player1Probability, player2Probability); - - Map factors = calculateGamePredictionFactors(match); - String reasoning = buildGamePredictionReasoning(match, factors, predictedWinner, confidenceScore); - - MatchPrediction prediction = new MatchPrediction(); - prediction.setMatch(match); - prediction.setPredictionType("CURRENT_GAME_WINNER"); - prediction.setPredictedWinner(predictedWinner); - prediction.setConfidenceScore(confidenceScore); - prediction.setPlayer1WinProbability(player1Probability); - prediction.setPlayer2WinProbability(player2Probability); - prediction.setRankingFactor(factors.get("ranking")); - prediction.setHeadToHeadFactor(factors.get("headToHead")); - prediction.setSurfaceFactor(factors.get("surface")); - prediction.setRecentFormFactor(factors.get("recentForm")); - prediction.setLiveStatsFactor(factors.get("liveStats")); - prediction.setMomentumFactor(factors.get("momentum")); - prediction.setPredictionReasoning(reasoning); - - return predictionRepository.save(prediction); - } - - /** - * Predict current set winner - * @param match the match to predict - * @return prediction result - */ - public MatchPrediction predictCurrentSetWinner(Match match) { - log.info("Predicting current set winner for match: {} vs {}", - match.getPlayer1().getName(), match.getPlayer2().getName()); - - double player1Probability = calculateSetWinProbability(match, true); - double player2Probability = 1.0 - player1Probability; - - String predictedWinner = player1Probability > player2Probability ? "player1" : "player2"; - double confidenceScore = Math.max(player1Probability, player2Probability); - - Map factors = calculateSetPredictionFactors(match); - String reasoning = buildSetPredictionReasoning(match, factors, predictedWinner, confidenceScore); - - MatchPrediction prediction = new MatchPrediction(); - prediction.setMatch(match); - prediction.setPredictionType("CURRENT_SET_WINNER"); - prediction.setPredictedWinner(predictedWinner); - prediction.setConfidenceScore(confidenceScore); - prediction.setPlayer1WinProbability(player1Probability); - prediction.setPlayer2WinProbability(player2Probability); - prediction.setRankingFactor(factors.get("ranking")); - prediction.setHeadToHeadFactor(factors.get("headToHead")); - prediction.setSurfaceFactor(factors.get("surface")); - prediction.setRecentFormFactor(factors.get("recentForm")); - prediction.setLiveStatsFactor(factors.get("liveStats")); - prediction.setMomentumFactor(factors.get("momentum")); - prediction.setPredictionReasoning(reasoning); - - return predictionRepository.save(prediction); - } - - /** - * Calculate player1's win probability for the match - */ - private double calculatePlayer1WinProbability(Match match) { - Player player1 = match.getPlayer1(); - Player player2 = match.getPlayer2(); - - // Base probability from rankings - double rankingProb = calculateRankingProbability(player1, player2); - - // Head-to-head probability - double h2hProb = calculateHeadToHeadProbability(player1, player2, match.getSurface()); - - // Surface performance probability - double surfaceProb = calculateSurfaceProbability(player1, player2, match.getSurface()); - - // Recent form probability - double formProb = calculateRecentFormProbability(player1, player2); - - // Live stats probability - double liveStatsProb = calculateLiveStatsProbability(match); - - // Momentum probability - double momentumProb = calculateMomentumProbability(match); - - // Weighted average - double weightedProb = (rankingProb * RANKING_WEIGHT) + - (h2hProb * HEAD_TO_HEAD_WEIGHT) + - (surfaceProb * SURFACE_WEIGHT) + - (formProb * RECENT_FORM_WEIGHT) + - (liveStatsProb * LIVE_STATS_WEIGHT) + - (momentumProb * MOMENTUM_WEIGHT); - - return Math.max(0.1, Math.min(0.9, weightedProb)); // Clamp between 0.1 and 0.9 - } - - /** - * Calculate game win probability - */ - private double calculateGameWinProbability(Match match, boolean isPlayer1) { - // For game prediction, focus more on serving and current game state - double serveAdvantage = 0.6; // Server has advantage - double currentScoreFactor = calculateCurrentScoreFactor(match, isPlayer1); - double serveQualityFactor = calculateServeQualityFactor(match, isPlayer1); - - return (serveAdvantage + currentScoreFactor + serveQualityFactor) / 3.0; - } - - /** - * Calculate set win probability - */ - private double calculateSetWinProbability(Match match, boolean isPlayer1) { - // For set prediction, consider current set score and overall match momentum - double currentSetScoreFactor = calculateCurrentSetScoreFactor(match, isPlayer1); - double matchMomentumFactor = calculateMatchMomentumFactor(match, isPlayer1); - double overallMatchProbability = calculatePlayer1WinProbability(match); - - if (!isPlayer1) { - overallMatchProbability = 1.0 - overallMatchProbability; - } - - return (currentSetScoreFactor + matchMomentumFactor + overallMatchProbability) / 3.0; - } - - /** - * Calculate ranking-based probability - */ - private double calculateRankingProbability(Player player1, Player player2) { - if (player1.getCurrentRanking() == null || player2.getCurrentRanking() == null) { - return 0.5; // Neutral if rankings not available - } - - int rankDiff = player2.getCurrentRanking() - player1.getCurrentRanking(); - // Higher ranked player has advantage - return 0.5 + (rankDiff * 0.02); // Each ranking difference = 2% advantage - } - - /** - * Calculate head-to-head probability - */ - private double calculateHeadToHeadProbability(Player player1, Player player2, String surface) { - // This would typically query the HeadToHead repository - // For now, return neutral probability - return 0.5; - } - - /** - * Calculate surface performance probability - */ - private double calculateSurfaceProbability(Player player1, Player player2, String surface) { - double player1SurfaceRate = getPlayerSurfaceWinRate(player1, surface); - double player2SurfaceRate = getPlayerSurfaceWinRate(player2, surface); - - if (player1SurfaceRate + player2SurfaceRate == 0) { - return 0.5; - } - - return player1SurfaceRate / (player1SurfaceRate + player2SurfaceRate); - } - - /** - * Get player's win rate on specific surface - */ - private double getPlayerSurfaceWinRate(Player player, String surface) { - switch (surface.toLowerCase()) { - case "hard": - return player.getHardCourtWinRate() != null ? player.getHardCourtWinRate() : 0.5; - case "clay": - return player.getClayCourtWinRate() != null ? player.getClayCourtWinRate() : 0.5; - case "grass": - return player.getGrassCourtWinRate() != null ? player.getGrassCourtWinRate() : 0.5; - default: - return 0.5; - } - } - - /** - * Calculate recent form probability - */ - private double calculateRecentFormProbability(Player player1, Player player2) { - double player1Form = player1.getRecentFormWinRate() != null ? player1.getRecentFormWinRate() : 0.5; - double player2Form = player2.getRecentFormWinRate() != null ? player2.getRecentFormWinRate() : 0.5; - - if (player1Form + player2Form == 0) { - return 0.5; - } - - return player1Form / (player1Form + player2Form); - } - - /** - * Calculate live statistics probability - */ - private double calculateLiveStatsProbability(Match match) { - if (match.getTotalPointsPlayed() == 0) { - return 0.5; - } - - double player1PointRate = (double) match.getPlayer1TotalPointsWon() / match.getTotalPointsPlayed(); - return player1PointRate; - } - - /** - * Calculate momentum probability - */ - private double calculateMomentumProbability(Match match) { - // Simple momentum calculation based on recent points won - // In a real implementation, this would be more sophisticated - return 0.5; - } - - /** - * Calculate current score factor for game prediction - */ - private double calculateCurrentScoreFactor(Match match, boolean isPlayer1) { - int playerPoints = isPlayer1 ? match.getPlayer1PointsCurrentGame() : match.getPlayer2PointsCurrentGame(); - int opponentPoints = isPlayer1 ? match.getPlayer2PointsCurrentGame() : match.getPlayer1PointsCurrentGame(); - - if (playerPoints == opponentPoints) return 0.5; - if (playerPoints > opponentPoints) return 0.7; - return 0.3; - } - - /** - * Calculate serve quality factor - */ - private double calculateServeQualityFactor(Match match, boolean isPlayer1) { - if ("player1".equals(match.getCurrentServer()) && isPlayer1) { - return match.getPlayer1FirstServePercentage() != null ? match.getPlayer1FirstServePercentage() / 100.0 : 0.5; - } else if ("player2".equals(match.getCurrentServer()) && !isPlayer1) { - return match.getPlayer2FirstServePercentage() != null ? match.getPlayer2FirstServePercentage() / 100.0 : 0.5; - } - return 0.5; - } - - /** - * Calculate current set score factor - */ - private double calculateCurrentSetScoreFactor(Match match, boolean isPlayer1) { - int playerGames = isPlayer1 ? match.getPlayer1GamesCurrentSet() : match.getPlayer2GamesCurrentSet(); - int opponentGames = isPlayer1 ? match.getPlayer2GamesCurrentSet() : match.getPlayer1GamesCurrentSet(); - - if (playerGames == opponentGames) return 0.5; - if (playerGames > opponentGames) return 0.7; - return 0.3; - } - - /** - * Calculate match momentum factor - */ - private double calculateMatchMomentumFactor(Match match, boolean isPlayer1) { - int playerSets = isPlayer1 ? match.getPlayer1SetsWon() : match.getPlayer2SetsWon(); - int opponentSets = isPlayer1 ? match.getPlayer2SetsWon() : match.getPlayer1SetsWon(); - - if (playerSets == opponentSets) return 0.5; - if (playerSets > opponentSets) return 0.7; - return 0.3; - } - - /** - * Calculate prediction factors for detailed analysis - */ - private Map calculatePredictionFactors(Match match) { - Map factors = new HashMap<>(); - - Player player1 = match.getPlayer1(); - Player player2 = match.getPlayer2(); - - factors.put("ranking", calculateRankingProbability(player1, player2)); - factors.put("headToHead", calculateHeadToHeadProbability(player1, player2, match.getSurface())); - factors.put("surface", calculateSurfaceProbability(player1, player2, match.getSurface())); - factors.put("recentForm", calculateRecentFormProbability(player1, player2)); - factors.put("liveStats", calculateLiveStatsProbability(match)); - factors.put("momentum", calculateMomentumProbability(match)); - - return factors; - } - - /** - * Calculate game prediction factors - */ - private Map calculateGamePredictionFactors(Match match) { - Map factors = new HashMap<>(); - - // For game prediction, adjust weights - factors.put("ranking", 0.1); - factors.put("headToHead", 0.1); - factors.put("surface", 0.1); - factors.put("recentForm", 0.1); - factors.put("liveStats", 0.4); // Higher weight for live stats - factors.put("momentum", 0.2); // Higher weight for momentum - - return factors; - } - - /** - * Calculate set prediction factors - */ - private Map calculateSetPredictionFactors(Match match) { - Map factors = new HashMap<>(); - - // For set prediction, balance between overall match and current state - factors.put("ranking", 0.15); - factors.put("headToHead", 0.15); - factors.put("surface", 0.15); - factors.put("recentForm", 0.15); - factors.put("liveStats", 0.25); - factors.put("momentum", 0.15); - - return factors; - } - - /** - * Build prediction reasoning - */ - private String buildPredictionReasoning(Match match, Map factors, String predictedWinner, double confidence) { - StringBuilder reasoning = new StringBuilder(); - reasoning.append("Match Winner Prediction: "); - reasoning.append(predictedWinner.equals("player1") ? match.getPlayer1().getName() : match.getPlayer2().getName()); - reasoning.append(" (Confidence: ").append(String.format("%.1f%%", confidence * 100)).append(")\n\n"); - - reasoning.append("Key Factors:\n"); - reasoning.append("- Ranking Factor: ").append(String.format("%.1f%%", factors.get("ranking") * 100)).append("\n"); - reasoning.append("- Head-to-Head: ").append(String.format("%.1f%%", factors.get("headToHead") * 100)).append("\n"); - reasoning.append("- Surface Performance: ").append(String.format("%.1f%%", factors.get("surface") * 100)).append("\n"); - reasoning.append("- Recent Form: ").append(String.format("%.1f%%", factors.get("recentForm") * 100)).append("\n"); - reasoning.append("- Live Statistics: ").append(String.format("%.1f%%", factors.get("liveStats") * 100)).append("\n"); - reasoning.append("- Match Momentum: ").append(String.format("%.1f%%", factors.get("momentum") * 100)); - - return reasoning.toString(); - } - - /** - * Build game prediction reasoning - */ - private String buildGamePredictionReasoning(Match match, Map factors, String predictedWinner, double confidence) { - StringBuilder reasoning = new StringBuilder(); - reasoning.append("Current Game Winner Prediction: "); - reasoning.append(predictedWinner.equals("player1") ? match.getPlayer1().getName() : match.getPlayer2().getName()); - reasoning.append(" (Confidence: ").append(String.format("%.1f%%", confidence * 100)).append(")\n\n"); - - reasoning.append("Game-specific Factors:\n"); - reasoning.append("- Current Server: ").append("player1".equals(match.getCurrentServer()) ? match.getPlayer1().getName() : match.getPlayer2().getName()).append("\n"); - reasoning.append("- Serve Quality: ").append(String.format("%.1f%%", factors.get("liveStats") * 100)).append("\n"); - reasoning.append("- Game Momentum: ").append(String.format("%.1f%%", factors.get("momentum") * 100)); - - return reasoning.toString(); - } - - /** - * Build set prediction reasoning - */ - private String buildSetPredictionReasoning(Match match, Map factors, String predictedWinner, double confidence) { - StringBuilder reasoning = new StringBuilder(); - reasoning.append("Current Set Winner Prediction: "); - reasoning.append(predictedWinner.equals("player1") ? match.getPlayer1().getName() : match.getPlayer2().getName()); - reasoning.append(" (Confidence: ").append(String.format("%.1f%%", confidence * 100)).append(")\n\n"); - - reasoning.append("Set-specific Factors:\n"); - reasoning.append("- Current Set Score: ").append(match.getPlayer1GamesCurrentSet()).append("-").append(match.getPlayer2GamesCurrentSet()).append("\n"); - reasoning.append("- Overall Match Score: ").append(match.getPlayer1SetsWon()).append("-").append(match.getPlayer2SetsWon()).append("\n"); - reasoning.append("- Set Momentum: ").append(String.format("%.1f%%", factors.get("momentum") * 100)); - - return reasoning.toString(); - } -} \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties deleted file mode 100644 index 3126208c..00000000 --- a/src/main/resources/application.properties +++ /dev/null @@ -1,36 +0,0 @@ -# Server Configuration -server.port=8080 -server.servlet.context-path=/tennis-prediction - -# H2 Database Configuration -spring.datasource.url=jdbc:h2:mem:tennisdb -spring.datasource.driverClassName=org.h2.Driver -spring.datasource.username=sa -spring.datasource.password=password -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect - -# H2 Console Configuration (for development) -spring.h2.console.enabled=true -spring.h2.console.path=/h2-console - -# JPA/Hibernate Configuration -spring.jpa.hibernate.ddl-auto=create-drop -spring.jpa.show-sql=true -spring.jpa.properties.hibernate.format_sql=true - -# Thymeleaf Configuration -spring.thymeleaf.cache=false -spring.thymeleaf.prefix=classpath:/templates/ -spring.thymeleaf.suffix=.html - -# Logging Configuration -logging.level.com.tennis=DEBUG -logging.level.org.springframework.web=DEBUG - -# External API Configuration (for FlashScore or similar) -tennis.api.base-url=https://api.flashscore.com -tennis.api.key=your-api-key-here - -# Application specific properties -tennis.prediction.model.threshold=0.6 -tennis.prediction.update-interval=30000 \ No newline at end of file diff --git a/src/main/resources/templates/dashboard.html b/src/main/resources/templates/dashboard.html deleted file mode 100644 index 28c72ad2..00000000 --- a/src/main/resources/templates/dashboard.html +++ /dev/null @@ -1,435 +0,0 @@ - - - - - - Tennis Match Prediction Dashboard - - - - - - - - - - - - -
- -
-
-

- - Tennis Match Prediction Dashboard -

-

- Real-time predictions powered by AI algorithms analyzing player statistics, head-to-head records, and live match data -

-
-
- - -
-
-
-
- -

Players

-

10

- Top ranked players -
-
-
-
-
-
- -

Live Matches

-

0

- Currently playing -
-
-
-
-
-
- -

Predictions

-

0

- Last 24 hours -
-
-
-
-
-
- -

Accuracy

-

0.0%

- Prediction success rate -
-
-
-
- - -
- -
-
-
- - Live Matches -
-
-
- -

No live matches at the moment

-
- -
-
-
-
-
Player 1 vs Player 2
- LIVE -
-
1-0 (4-3)
-
- Tournament - Surface - Set 1 -
-
-
- - -
-
-
-
-
-
- - -
-
-
- - Top Players -
-
-
-
-
- 1 - Player Name -
-
-
Hard Court
- Country -
-
-
-
-
-
-
- - -
-
-
-
- - Recent Predictions -
-
-
- -

No recent predictions

-
- -
-
-
-
Predicted Winner
- Prediction Type -
-
- High -
- 85.5% -
-
- 14:30 -
- Ranking -
-
-
-
-
-
-
-
- - - - - -
-
- Loading... -
-
- - - - - - - - \ No newline at end of file diff --git a/target/classes/application.properties b/target/classes/application.properties deleted file mode 100644 index 3126208c..00000000 --- a/target/classes/application.properties +++ /dev/null @@ -1,36 +0,0 @@ -# Server Configuration -server.port=8080 -server.servlet.context-path=/tennis-prediction - -# H2 Database Configuration -spring.datasource.url=jdbc:h2:mem:tennisdb -spring.datasource.driverClassName=org.h2.Driver -spring.datasource.username=sa -spring.datasource.password=password -spring.jpa.database-platform=org.hibernate.dialect.H2Dialect - -# H2 Console Configuration (for development) -spring.h2.console.enabled=true -spring.h2.console.path=/h2-console - -# JPA/Hibernate Configuration -spring.jpa.hibernate.ddl-auto=create-drop -spring.jpa.show-sql=true -spring.jpa.properties.hibernate.format_sql=true - -# Thymeleaf Configuration -spring.thymeleaf.cache=false -spring.thymeleaf.prefix=classpath:/templates/ -spring.thymeleaf.suffix=.html - -# Logging Configuration -logging.level.com.tennis=DEBUG -logging.level.org.springframework.web=DEBUG - -# External API Configuration (for FlashScore or similar) -tennis.api.base-url=https://api.flashscore.com -tennis.api.key=your-api-key-here - -# Application specific properties -tennis.prediction.model.threshold=0.6 -tennis.prediction.update-interval=30000 \ No newline at end of file diff --git a/target/classes/com/tennis/TennisPredictionApplication.class b/target/classes/com/tennis/TennisPredictionApplication.class deleted file mode 100644 index f0ba795f5916f82bd290a4fef844385700ba995c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1222 zcma)6+fGwK6kWrurB=ZrMexGl1xpnU;fb_Jf~e7?Dxst%`ZPTq+QHK^%{g;a-hJ}L zU*H$iM2Jy7z<+7{1LK}Ur8VgTO**SHduFYfz4q>}Ki`i5+{bbX0~kzTD2-u^FpTes zx5Dv+Uw2+q_oQnWM%I+C%sRthZlRJul40J}O~**zSD~{L!&V?`$~8*+8?Bb7Tw#Bv zkixkH(rKK>1%|v1>Q2}SlwaQsL{q-g!5gQlwQAOnk#khv+0R2EWYkp zDH}^xTqyNpcC~Nhd*f_se^=F`KvX^1BSFhHTpYzXE+&vkV*;1{dw+R9G_pxo(Gg`~ z@+yho3hjR=ga@p9z4G7NVk&)c6%;WDNZ zm`URbt};x-ul-+xAz{;FJj%ypZ$AFLzLLashNta=pY5+7`9{pnO+#|gwSo&%;0AZr7~0e|g0YhF<@2anmBEg6g&|Y2cdCd$*?DJi$TU>QkSm?7+KR;A6pFHx&Gjpi z3dKcGC&r0BVRHVNG!0$b61Fyt3}|DjtfRn{kCnY+$KI~HJ?1W1-x#L1Bj2c|tf)}g zYV&<<;!Ys0^}ap#%H{3^!lQ diff --git a/target/classes/com/tennis/controller/TennisPredictionController.class b/target/classes/com/tennis/controller/TennisPredictionController.class deleted file mode 100644 index b15e7912191db00b3046ddc5543e87fdeedf1fa7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18553 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 ZkBE?1{Q59Q=}6_U>PS^28mXp+{{UV@pE&>k diff --git a/target/classes/com/tennis/entity/HeadToHead.class b/target/classes/com/tennis/entity/HeadToHead.class deleted file mode 100644 index 22591f8fad5c2adde3ced95ac8de56724e2e407b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14102 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 diff --git a/target/classes/com/tennis/entity/Match.class b/target/classes/com/tennis/entity/Match.class deleted file mode 100644 index c3c597a1127744159e92aab6bb4cac30b1d1251c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27930 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 LRAZXaLDv5OQ4>R& diff --git a/target/classes/com/tennis/entity/MatchPrediction.class b/target/classes/com/tennis/entity/MatchPrediction.class deleted file mode 100644 index 71afb2120a94af0c0555ce06743f88c9d12ba3de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14611 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 Nw{hZDQ4&*R{V%XoAjbdz diff --git a/target/classes/com/tennis/entity/Player.class b/target/classes/com/tennis/entity/Player.class deleted file mode 100644 index 76afe65bee7edfe36cb41b8cf2713135c89f50c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21563 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

eoEo@XDSAK>RX=jVCn=LP&6r+*~; zTT!~B8s~E9s$z^L{=pWMpRcV-;W`h~zxeOgT7r=_sOHbar<^-4gCmtW{`N>5#xlw# zKBqt{;&ThMDsEL3Xl>l8F3|e8Ra2l%aVuP)EpaPSpzU$1wm>`MRk=R zFm81gs3~rB6=-tYvN){RnoywnxYb>teBA0OP~fVpm1`(sPA%M%Y5a3tPFy}}CPVP~ zAnb??x96zjBQn0eN=h8z!V$JdWCVSUlsKLwEF}&DiAaf~H)^HCK^IXeajZn0lsLq} zloCfK)Jus23OEG&hzwnCloDUxH%W!Z2kCHB4Tr&S+zJPpaAXLFa&YVg2TO2t1BWAU`~YA0^9?;;sq-B; zUt04mGhYkyJuY9o;$9S?=kDF;-3S2xGzw~ndt_L6BcyxrSwDl$x-ut@i2I<7pu^vf S=csrHZ&64E@vwN5tUm%+Vo#|6 diff --git a/target/classes/com/tennis/repository/HeadToHeadRepository.class b/target/classes/com/tennis/repository/HeadToHeadRepository.class deleted file mode 100644 index 7e58283a7180db7f4e705ba83d47bb3dd7eac40d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3677 zcmc&%-Etc>6h3Q`7^i8WkW$i8D*8j5lz3x9DUF-VIQE7XoVeH?GR$zJ+OoZ2t#!3> zTi@^~yaqE|@Bq99Pr(htk+t4kJ8QD-WZ+_LNk`}BlfH8#{qgs2zXQN7?4%)Oz-G(s zo04&Ed!}Fm*R!Q7M&@Hi+f7&f)`P(`EEw?a34K9Lhw`pjdv?NFG7U=x+;>IS^ajG_ z-HxDr_RQb8r z-Mrt;H0&;?awwPqzx=O=9>pwLxbMY1M7%Y%Kf$ilM4O5IQPY*wIi#}HV_t=MEdvhT z2vBsntF|Z6apznNB|!L4BaA}%S}=;c+w4(pJs(nMF50_U&69C9JmHdcnJC79S?=51 zUnT>rBuWVazor9k3`K{w80N`g#L0uGlZI4zSxgpd+S3LNIDRu52|{114>5WB?0eg@ zpE(#iMiYGWvS<}FLYXP!&Yk_#KH6N*O zE`%CyFO*LVT2(~6jlo;EO%7sq^ERB=6-M>S-dY0LD}f z!a*YYWSX6(SGTB(N_AqPiAllnu;cPcm%D`sRX z##^({=4dB?_UoD3UfOSDdpUjcm`!^bIj6}M)&V`OFjF0((>BN>RRZa&5R6|dqqE2! z*^W|bN~Rfgamt1PHx$DvE*4iBn`o;jiCM?L{`&>+&w$rhfOFr2$r9Q;jKY9X_iy*_Gl&;)Q+4qIp)Q2W4b0sZJFp!j_gXYvCQpZ)x;kUQj19@ddlhr#Xu!#aqO0&BEQ}qX<{FAZ@in-P{RlY+gZQ zpTI5O82Y&#__;G{=LI{CUh!W- diff --git a/target/classes/com/tennis/repository/MatchPredictionRepository.class b/target/classes/com/tennis/repository/MatchPredictionRepository.class deleted file mode 100644 index 2428fe2daf11db93e8fb596470634fff6ffa9f74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4080 zcmb_fU3(Kn6h0d%wL%L;P!WL@(I%kX2Bc_13;D$Qq)APJJU(7cH`8|NW_CL}Tg;6& z{wpv10sbf-&+K>7gl?!8X?OO_Idk6ke9YN@{{8E30N8|=^N`cPFztaMDd)^J1a)ke zNm~q!9U{%cT|xWIl+5OxSTYY6G`M<1PKaRt0$R2CKI>C%(ynO>TA}g{r98~Y zF=0?@>*=hj+1{Q-OQ|S^ZzfdT;(+nQq6Uit@_Tyy>pL0Fiq{WsWtbf3<9#V8!3NMf zB)op?5$kQhN6K(I%#o^_vMsCATc_GZ)b>ULl`6+*LlCT5$f?BFM$?G{C4O=wX3H5JP ziWlF_j)%A9fd0%}hNWEQ+?GVOBa~srWW2h6@~9YM` zqmRuE>iz2<>YX}1tok=^@VARcd#=8zuP7f^^meCK@933Z)V2^AdZyCXzx(xCy<62_ zIiSivBe0;sCEseaa?a__M#@@7r|ymN8qXRd1Q(|hoEo~06}g6Q0V!S#&~`nsPfS&h zZuE3GGs;jE3Ezkwvr&EvJBjI8*btJ`Dx0P!h&j~YdQ@Ki#1i&E4gL)M%U9d4TD^R= z+^wrDXsPJ3sIbu&i8ZD7l%S~BTeX7zKrgPXt*+^Y9%v4nLgDPZN=$Bd^;Wy5w_Y`y zIQ#|t^=waY9RIk~U`fV{7QWKpWM(EuEhs|A-elwThH|b$O>`?E7Aq0wTYrk3rCqBs z@rT%~npu0`@eJ%ts@g4;Zt6l&9%d}3KT;z`@NH3=UOR95uE+v1bym~HVOve^A9OKC zOxj=;l6uGQHA#e$&z4n1HpXkBb1se=)Rs7$8;M20`TFCiYiTFblUxyph#2=yfWB4Qy-$cWo#>Q`< z_%pbjoU6ovOLtIo7xYB)a}?c+#b2QKK75JLg6&`7dSz^#A6pmF2p`0z6vBtNH5ZwJ zuYH*Y-=O(b7Yy96hPoFb;);px_})kG7=@P=@81U6Mbv(h)?S~k{q&UfI% diff --git a/target/classes/com/tennis/repository/MatchRepository.class b/target/classes/com/tennis/repository/MatchRepository.class deleted file mode 100644 index db252d12b8d85f00a2596df6fe1735445555eae2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3264 zcmc&$TT|0O6h2#l3L=W){T3CJixOM!R#2d2)F~7iM#m>-ZI=>kH+8essSo}O|BMg* z0DqL@Np?+AO=1U`@geQ*o;}~WpR?b8eEkLh3$T!d41uYd(=sLF+;&aD+Ky{WM|90K zDr-B{V4sBn0!Mf02WmDcZ&snVkR_??xCADr%b^TQdYFY7b<~k|(=6MrETAH5Ozt@K4eH60Od#iw zt09IhyTK7nFal5dfO}kyIDm0!OKp5%5hYFip=3qWnON?k#zJn{EmmZ1jlitBx6!0s zCUO;_7Ww$gtJ5(u6-ObN661$#TgfA!S9t<-U%=D7l2_JlIUT_<0$i@+@AC$C1Y4ml zi?@1A_FN}0r%V13$?i;^RgOo@rvsES#B zsX=W{KyPz;`{lo>mL74P-$B+dGx?D*9`E0xE<1_kVV0d5Z5F9yUa=HZEyoaIJT;6Z zEu_ba`OSD;t={Ydc)G1uRenVplQy%&>tV&8h-M*X9Jp+U#JIK3k=7X=Tf38LQRG zn&Ep8H?N+RswHE(HLono84JcEwKOVK@s#MalB^ujB6?@eS(!#H&^@f^? z7L)EPhX>OjuMY@3h&uK;m#o2rZcYB{=GRe-^Cj6uepMmpUDq#l3D&pePjyba1 zW@gAyz$Yhx1NaT%EA}uxOS5ngGBAw0L6nAnhw#h5D3T5*lg8kP<{HkxQREm8IFBLc z@hIm+K=MFOL`f%mNT=Ym1|1&=K+oWnv%$4{a2=g9?ZOPq;=!p5?&j3VWVjqbIXB>DsD@`q2sV#o6K-i)=vPlm z<=5Qra`L{MQ7NI2omX?~io3>PDtIG*1lCEdA0_pmkdR4^pmdPEzyG4~- z$wWwCg5#0ERNL)yDkFjC#vu(pYig-rT)J{E4b|u9Y&L;g_aiPvtRucP#zE5!B^oF@ z$yEX`4sl@&nujTxNC<>#Q~n9_RAcfhW4tB0Ow{6fLAD+`1fJ-QUvtU&OjNaW@3HiJ zr|72#E>GPMm>$q?8PWMiqhlhxsUqz7!Rksa9v#uyrN3aU>|>7cHLrXnB_Gz}b|iY# zVOvb}d@-Qh!6JIB2bor-mbiu=ZF{Uxr+cp+Ce~EaT>e2NQKCKjpX`kZU? zH*^usI_JKms#~xz%;sU+^j*Y6jP*MCg?bSqW`3iJ z`rlpMTm`?!D*T zd)~e0o_p>&-+Sjh{?+|IA)uZ`5ot2Q>^SmRce&VlxdtUF2&lS$|*Z)Z>K7Q0+{~8`q=Wmz{yTqTrfu4}RC;j!A z&95xkR(!m_{#D`Kd7i)i1*zEliogC{c|LNQtl3h74x)pZj5g7;v-Zr73}Y}J1vn<; zsc}{Ezf?7Jz@asczC05A|ET!})lO^PmHERqm%;uQMv}2asI)*Ou{;oiu+W3#ed}ZtO-h^pp zH-@tx8Y-Mo8k9RJds{)I*PsXt=&yg#-ZR+Fc3Y6ng8+^3_N2L~a;0qGet-QN?)$HZ z0uO!H-%#o*F5eaCcP{Zqd(mtVnCMHwr@Zb;^Qz+#8YZ}N$a8d8|D2=E`afu|aU7IlOBJNM;C~up=Eg|8-Aq=l z?KhLMRzHTzTVf`AB5^424O`Ft`d1uz8_L}ge9oNepLZS8pR|%D`RiY{wH>5KnMO1v zV(_C-jyS}hqVq*&yeE?E_BTv&*Oy&oJmY$_-@6Kb+g_a@JqRV?f)0Itq$?ixS z?D)4(&58uVS$mM4!DJ+~nw5C0T$PB$OvrD)-Q;hmbk?N77N7j}&$!aQU@I?3ufPGe zMmEI~$;!paXc_~&hVXY-OC$84O|sZu|B_7<(p&U)fZj3aUHXgb#{1IISWROx8QFxe z>5rtEqp3909#fC-IHN<>tvB1!b&iMEZwOnRK#BJa`hY$}Z+3KBY4#>y28rY*rm5a7 zp3F8lQEq^ zOvhz}?Bh=y6q!fR=k!H@zBK47`Wj28<6L&SfF!BtW_SgFi>1IX%m6Q}nD+7xKGeCp z+5>2r$UcMf1!(x^3X+&FRRM#8f`I}lGrc_0V@h42!6T%u5Ovr$@pN*NRF5=x6pu#8 zm+HP`60l)qB;E~-A%WhrVy@#A6f}{?7#x<@isiKkwq>#j@!fe-7>W%p5e7dP8auTF z;|wm9su8GaG6fDS>=D*-gU7q|t9AXsol-y1;0lp=H24L^K&F=TrkL)l(%{J&4V^(6BO-9?Pc&(_q~M}(EFbBTV-&y zw9BNIBqOQRV1^k6&lHAnU|1YYrqX&Rt}v5rP;122!rlhYayuE|aio(`_Az+2FqEK^ z7U0QvyY9uqv7f=;5)M&JBOoFM(9lxeKEU8Pt_b$z7DxJG=^UQ92G0|o@*FW&n(4k| z+%rtQ!41MTK39+-dB?2x(F^dz) z9?!5%1}_zJC;5zyYC%tC9Vp}A7w3AunZ`j@T{LecRyEU4e#c|Bk_Dx?^P9J!AOmpBm8TIR>9A z%(?!-Gujq|&y&%LG5rAt;$gVJ;0vV(vHbxC&v=D=F@Hb6ml%90Uxumcc#@9xm^d`I zMPfK+o2_`lV#gBzfa6__4rQtHH}u=GOP^O6d^KMKSk)7a_oWu;&^=-5LC$&%^R_I& zbp~J0Hy}_$+U7{g-mM}6Hh~j5hIw<^svzHlo!i)#N+)q05Q$eF(rd=0!&?l#RlNFG zZ-=b_d2s}>csj^GK*W@#7UtUxzC)PB*0Q6w^d&nYfQY;eTe?@Dj%Nk=&g=tr%WA&c z;2+DIVegwTVZdhK55Cu6i|@lKiMw#m^#d4W`YtfYz$W+N5Z=M}2lxSlALNIasyx2I zgF}XURj>iD$RHr%Mt)CVcB+E>UrbY6AmZE)$P5NMz92s`%uPa%eK#RD2@JS8&LgPf zhqRdn`KK_F1!gK;ndqq8H^@JSoXt4x=R1H>i8cMw;3veI3bi#gVFBezgnwo5ulXqe z0Q-2YJ7jg(H#j}7s&n0;M*&0e(Z5|YjG5X4?6N^SSl2~)g!#X(8amnkqzwPct-*hC zynnB+;g0;;tm=aN8yM>9Xb(_(dm435Lvr3U#~v@CS5*<8cT6T^MM;NNRE*c1rBS`T;fOmWbhmOXLvfj zw+5U70E*YHJ$^uoKEPNvg5Sa^hTq2N$+I7K{X&r69riGy1uzl3cMAB}$wx?bjAS1g z{8w>>0{;gbtv)lL^=}4$EUgAwwQQ}MdJ%ee@}~y>T^i&t;kaC>{>h?>c81w90#ip+-te8CslPmmsvHa=AtuDwNArI}BIYP({Ke@Yw0g z0lxMzN?wsMOAIwOm#=nMzEVS#iSi_xX63;_J}I4yH`D~_!~@3!`AbuUp(f=v)w)fS z4YivzNj!B#^qvXi?cEKvM=ne4V3xfMrH@4w1HB9!Ts+_&y;T`XpO6MvYj?#u!%#D2 zV1YW0Y@Wk|v(9@PYE~{&?NFwD3^iMrb{n>*Lwb7?$#kDw=-c|*&rsjWW%u?ug#7?R z&B+yEmd48V8ai^$HPpOZrrM!Q^@eH?CV_{ZRz3OlLbZT>0kzP*MA7lZ4(;$I>Oey+ zR!i`1FV4BqHu(W%z)vvE`X+~h^YM^Z>I&6Tbx=SZY^Y|1yU}rje=S)YX|u0f3V>DZ zA7tbX#}nz`0#hkmhzx$SE}#wp($Uqu^5aTJ5<6i-BH3NDE|Eyr!1Ll#t-Tq)4B#>h zm%rw$t6ataz-iFCDw2%Kvs39yS~4x>bpop`Tk7$M-D4&2yg_KMn50d)kp27a)}wqWU&ndz=X`wCny_uwZS z`Ps+;p`b#x?y{FZ7;z|u)??|v62D;0+ z?$GWk+v%XDign+3`2itu^?=3m+;`y2>%?Z;3%J)9kaL6QRs)B4QL=26@?Bd3mZ_^2 z2mXp-SO!iQFc%~3IqWmxx`jsA{m+tveD+Bn>(Ra*DT**%*&w_v=U|zo!frrc(%AW+IK9S0h)?_f>lrk=~T5s9ZGp>C7z=AX-A=)d^d48u!9N|RarC|sR(JT)RyVmyTGJW z3-WS3Oa(sdm`tPai9#4(3yh^{R7q8;742i~4%K056`s(wTCEO;kZVBuP_9)+g34#L z8ikT?J5UK(@;{{U@~ZDs8FjoKHB|TzO#6`mBH?AuOLB!zZIHijM)av8Glv~YDX z&Dc&g#WY*z`{{gtPt6=n&(-;Soj2%wfzB7{d@=G+ne;jqnMF-4YkXDV=J4`-JnDgq zL5!jMgk=RXdtiGoJY)EkI&anaDxDv$^R+rZQs+nO+!p9qO^fKE3DRpRGCgp9Rd`*v z-H%5-@OTho=x4&xf-Kx2Gq&g2rMs|)w>w?0YwVfDG#%G@ug-1ZlA0FLLlx4iOj{4^ zuL`Hb{Q*46;93)os+;j_&v>JLd9%(>(D_L^w}m)G)2HeDbe(@k=V$5sY@MHrJX9$I z$h7sqfvWJ9aC;Dsl0xOkoPiGpX%B3x^nBfgJ-n@6TL%~F`ipgbiOw(6`Tjb;Lg%tT zp(!$eOj{2etO{Qhz9uBo)l(K#jG;$_XAQFOb)su~VQtOYQrw{Xv!%F6)3@mSHl1(P zxy^Hjrneyv?J2#=y!FT-DErRv-67Go*qAfvp9#4ZnLTM+!}sV;Yyr;Fv|VFqdb`f= z*ZG4w|B22Y*7-){p{dfV%-kLt>fRZCEEGhA3?C{+He^qU%*ABScebYOZf%ilF(55? zexdWnb#5EL6Po@N@=%owAXB%8hQgl;|0Yx*wK^-;V?QR((DRgVMl^0u)n2YYo6En3p#&M=k`jxq-l{jguOLI&)puopep>w@T;Lhsg=2F!yiL>Y|PV9xoya= z>s~hN+@6zH9R*Q@KJLu1t zz_0@-k;KF1X%Blp%>=zSJZvqEquI1C{w<;X=ycHM)Bd!L4xoo=4t+`ca{LOaIZl;6OtDrxi=Dbm~EU%K5 z=N$#Qn^xp~mk!Oll2+zD5Bd#i_2tuHzHzk5*9v+a9qv1o*7z=>wZ5l7XQ$ERJ0D{%j6cRZDWW9tKO`S)?& zoYJz=YK#44rPD1gC@Y;|u~Al9=Ce42BH!X76n=}xq6k=Ah9YS31QZ1pPeM^>@op$a zSiC0+!{TWuMp`@_#VCtwP>i;?7DdS7eNl|Dcz+aOi|bGnSv(&_vBixjN-SQ4VywkW zP>i$qpt90CA*~$~JGA66Dxe-3O>umTm_RV=rQPT_M8+i6GDY8_G|i_zI*|IQnKn=h zZKSodi6XR_y6AYkaRORS#J`iU(kIh7bP8Qar_$wg8eK=ERTn4$3tLqbR6tYf@orF4-Jl9I6;nO1 zLg9;p8lkBKC__`dphjxyI8dWBl>{|fQz=j(O{GDN(NrI(u%`M!6=`Y%sA5fR1XZG` zO^|A=rZ$5b2WhTX$Ey>lRAYyu#;FK2--gtV)PdBA)P)p9T94F?6hn$5C6IcNjzdZ! zrI6A{eMtRC8;~|4Z9>|NL6v+O1p$IhQKeJvp@}I9x|N&nMelr{!{;VRP|W4%gW>*Y|R{&M)(C=Zmz&mv?VD!{RF~zP8L? z#5Y=evy``4yj6H2#dO7`*HA$b|L|5q{f{iZtLh%Ur_8^Dx5Epbp2xR-_3P6W@*P^i zKgnWEpZ0{CNj`i#7nZjLi*f-?!H$?k7tuVrn3mEdw305RHFOyrOIK2iuEPGg8vEy3 zIukqQ0=gcxH_`2MGd)7L(9_sKf2P~$Q~Cjqq}%bS${jq7e#oO^%Cj3Y*Gsguq;Ua!=kNuM=C64? z6$VJjGY4p*{KxO6jC%l-U!&*YTX8ABI-tJuH8vT(2iLC?eTGRW`4-x?^StQ*^Kchx zvtEXW2ibYxA>IiTUY+NfakbB-u;@kn7?!+_88CA5!Z zoybHSpr2*f_^(gj!Ef5=r-F zkJB&cW%_Tfr=N2ZJ;5FHB%e>e;zvP0iSIGrrQfJ=^jiRnr*RB@SgoaJ5lEhckAGfo z>`L3(-HoVBXCtnqN_7^%iqc?3j5MwtS7Ez)}iDp{4RsjIdM? zg<+`?C`MXp6pB%n8iQiArHWC6EHw_r7)zC-2wQ3*iXux@qA0f16ciJqj0M5q%IG+IEdK?{Dil3w$!#Eer6;XtylD zC!@{=coE=}QRjdX;FD43f)e19QQrgQ*VGnuo(4V{bv`HoJ{ffZY(#)hMqLO>fKNtU z1WJHUMqLa_fKNt!ACv%}jJgDr0H2Jy6qEp;jJgbC2=K|M%TXu5C!?+aCBP@6t^_5( zC!?+cCBP@6u6BS=MqL9+fKNtUi&ohO8Fd|~QcYbCN+5DZ-2h6ycFw39L5x{Y?)I`kWm+BUED^+OF)Hjj0L5WyWbvDvDNarGb4`~b1`A8QaU5IoM(#1&MN4f;* zQl!g}E=Rfo=}M%lkgi6$2I*R)>yWNTx&i4%q??d#hA_Nb0;AXX~94CPh#sm7}6 zd+EKZ>G$&MRWt78d#cKO_o_vA;SC#6`!%91(wlX*{Z@A2%k>qPEPT1X!8MqaI?ObV5`RR@+t6kBMb`*2u#izZlYNMV(T& Nt2?9*x~(z-Q)Ecbb&bRi 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 diff --git a/target/classes/templates/dashboard.html b/target/classes/templates/dashboard.html deleted file mode 100644 index 28c72ad2..00000000 --- a/target/classes/templates/dashboard.html +++ /dev/null @@ -1,435 +0,0 @@ - - - - - - Tennis Match Prediction Dashboard - - - - - - - - - - -

- -
- -
-
-

- - Tennis Match Prediction Dashboard -

-

- Real-time predictions powered by AI algorithms analyzing player statistics, head-to-head records, and live match data -

-
-
- - -
-
-
-
- -

Players

-

10

- Top ranked players -
-
-
-
-
-
- -

Live Matches

-

0

- Currently playing -
-
-
-
-
-
- -

Predictions

-

0

- Last 24 hours -
-
-
-
-
-
- -

Accuracy

-

0.0%

- Prediction success rate -
-
-
-
- - -
- -
-
-
- - Live Matches -
-
-
- -

No live matches at the moment

-
- -
-
-
-
-
Player 1 vs Player 2
- LIVE -
-
1-0 (4-3)
-
- Tournament - Surface - Set 1 -
-
-
- - -
-
-
-
-
-
- - -
-
-
- - Top Players -
-
-
-
-
- 1 - Player Name -
-
-
Hard Court
- Country -
-
-
-
-
-
-
- - -
-
-
-
- - Recent Predictions -
-
-
- -

No recent predictions

-
- -
-
-
-
Predicted Winner
- Prediction Type -
-
- High -
- 85.5% -
-
- 14:30 -
- Ranking -
-
-
-
-
-
-
-
- - - - - -
-
- Loading... -
-
- - - - - - - - \ No newline at end of file diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst deleted file mode 100644 index ac8dd12f..00000000 --- a/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst +++ /dev/null @@ -1,12 +0,0 @@ -com/tennis/entity/MatchPrediction.class -com/tennis/controller/TennisPredictionController.class -com/tennis/TennisPredictionApplication.class -com/tennis/repository/MatchRepository.class -com/tennis/entity/HeadToHead.class -com/tennis/service/DataInitializationService.class -com/tennis/entity/Player.class -com/tennis/entity/Match.class -com/tennis/repository/HeadToHeadRepository.class -com/tennis/service/PredictionService.class -com/tennis/repository/PlayerRepository.class -com/tennis/repository/MatchPredictionRepository.class diff --git a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst deleted file mode 100644 index 5a232d9a..00000000 --- a/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst +++ /dev/null @@ -1,12 +0,0 @@ -/workspace/src/main/java/com/tennis/repository/PlayerRepository.java -/workspace/src/main/java/com/tennis/repository/MatchRepository.java -/workspace/src/main/java/com/tennis/entity/HeadToHead.java -/workspace/src/main/java/com/tennis/controller/TennisPredictionController.java -/workspace/src/main/java/com/tennis/service/PredictionService.java -/workspace/src/main/java/com/tennis/repository/MatchPredictionRepository.java -/workspace/src/main/java/com/tennis/entity/MatchPrediction.java -/workspace/src/main/java/com/tennis/repository/HeadToHeadRepository.java -/workspace/src/main/java/com/tennis/service/DataInitializationService.java -/workspace/src/main/java/com/tennis/TennisPredictionApplication.java -/workspace/src/main/java/com/tennis/entity/Match.java -/workspace/src/main/java/com/tennis/entity/Player.java