-
-
Save dadiletta/2310e45953e3bcb8db3cf151c7c75d06 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import java.io.BufferedReader; | |
| import java.io.FileReader; | |
| import java.io.IOException; | |
| import java.util.ArrayList; | |
| import java.util.Collections; | |
| import java.util.HashMap; | |
| import java.util.Map; | |
| /** | |
| * The GameDataManager class handles importing video game data from CSV files | |
| * and provides methods for analyzing the entire dataset. | |
| */ | |
| public class GameDataManager { | |
| // ArrayList to store all game records | |
| private ArrayList<GameDataRow> games; | |
| /** | |
| * Constructor initializes an empty list of games | |
| */ | |
| public GameDataManager() { | |
| games = new ArrayList<GameDataRow>(); | |
| } | |
| /** | |
| * Loads game data from a CSV file | |
| * @param filename the path to the CSV file | |
| * @return the number of records successfully loaded | |
| */ | |
| public int loadFromCSV(String filename) { | |
| int recordsLoaded = 0; | |
| try (BufferedReader br = new BufferedReader(new FileReader(filename))) { | |
| String line; | |
| // Skip header line | |
| line = br.readLine(); | |
| while ((line = br.readLine()) != null) { | |
| // Parse the CSV line | |
| String[] values = parseCsvLine(line); | |
| // Check if we have enough values | |
| if (values.length >= 17) { | |
| try { | |
| // Parse all fields with appropriate error handling | |
| int index = parseIntOrZero(values[0]); | |
| String name = values[1].trim(); | |
| String platform = values[2].trim(); | |
| float yearOfRelease = parseFloatOrZero(values[3]); | |
| String genre = values[4].trim(); | |
| String publisher = values[5].trim(); | |
| float naSales = parseFloatOrZero(values[6]); | |
| float euSales = parseFloatOrZero(values[7]); | |
| float jpSales = parseFloatOrZero(values[8]); | |
| float otherSales = parseFloatOrZero(values[9]); | |
| float globalSales = parseFloatOrZero(values[10]); | |
| float criticScore = parseFloatOrZero(values[11]); | |
| float criticCount = parseFloatOrZero(values[12]); | |
| String userScore = values[13].trim(); | |
| float userCount = parseFloatOrZero(values[14]); | |
| String developer = values[15].trim(); | |
| String rating = values[16].trim(); | |
| // Create new GameDataRow object and add to list | |
| games.add(new GameDataRow(index, name, platform, yearOfRelease, genre, publisher, | |
| naSales, euSales, jpSales, otherSales, globalSales, | |
| criticScore, criticCount, userScore, userCount, | |
| developer, rating)); | |
| recordsLoaded++; | |
| } catch (NumberFormatException e) { | |
| System.err.println("Error parsing number in line: " + line); | |
| } | |
| } | |
| } | |
| } catch (IOException e) { | |
| System.err.println("Error reading file: " + e.getMessage()); | |
| } | |
| return recordsLoaded; | |
| } | |
| /** | |
| * Helper method to parse a CSV line handling quoted values | |
| */ | |
| private String[] parseCsvLine(String line) { | |
| ArrayList<String> tokens = new ArrayList<>(); | |
| boolean inQuotes = false; | |
| StringBuilder token = new StringBuilder(); | |
| for (int i = 0; i < line.length(); i++) { | |
| char c = line.charAt(i); | |
| if (c == '"') { | |
| inQuotes = !inQuotes; | |
| } else if (c == ',' && !inQuotes) { | |
| tokens.add(token.toString()); | |
| token = new StringBuilder(); | |
| } else { | |
| token.append(c); | |
| } | |
| } | |
| // Add the last token | |
| tokens.add(token.toString()); | |
| return tokens.toArray(new String[0]); | |
| } | |
| /** | |
| * Helper method to parse an integer value or return 0 if it can't be parsed | |
| */ | |
| private int parseIntOrZero(String value) { | |
| try { | |
| return Integer.parseInt(value.trim()); | |
| } catch (NumberFormatException e) { | |
| return 0; | |
| } | |
| } | |
| /** | |
| * Helper method to parse a float value or return 0 if it can't be parsed | |
| */ | |
| private float parseFloatOrZero(String value) { | |
| try { | |
| return Float.parseFloat(value.trim()); | |
| } catch (NumberFormatException e) { | |
| return 0.0f; | |
| } | |
| } | |
| /** | |
| * Get the total number of games in the dataset | |
| */ | |
| public int getGameCount() { | |
| return games.size(); | |
| } | |
| /** | |
| * Get a game at a specific index | |
| */ | |
| public GameDataRow getGame(int index) { | |
| if (index >= 0 && index < games.size()) { | |
| return games.get(index); | |
| } | |
| return null; | |
| } | |
| /** | |
| * Find games by title (partial match) | |
| */ | |
| public ArrayList<GameDataRow> findGamesByTitle(String title) { | |
| ArrayList<GameDataRow> results = new ArrayList<GameDataRow>(); | |
| for (GameDataRow game : games) { | |
| if (game.getName().toLowerCase().contains(title.toLowerCase())) { | |
| results.add(game); | |
| } | |
| } | |
| return results; | |
| } | |
| /** | |
| * Find games by developer (partial match) | |
| */ | |
| public ArrayList<GameDataRow> findGamesByDeveloper(String developer) { | |
| ArrayList<GameDataRow> results = new ArrayList<GameDataRow>(); | |
| for (GameDataRow game : games) { | |
| if (game.getDeveloper() != null && | |
| game.getDeveloper().toLowerCase().contains(developer.toLowerCase())) { | |
| results.add(game); | |
| } | |
| } | |
| return results; | |
| } | |
| /** | |
| * Get games by specific platform | |
| */ | |
| public ArrayList<GameDataRow> getGamesByPlatform(String platform) { | |
| ArrayList<GameDataRow> results = new ArrayList<GameDataRow>(); | |
| for (GameDataRow game : games) { | |
| if (game.getPlatform().equalsIgnoreCase(platform)) { | |
| results.add(game); | |
| } | |
| } | |
| return results; | |
| } | |
| /** | |
| * Get games with specific rating | |
| */ | |
| public ArrayList<GameDataRow> getGamesByRating(String rating) { | |
| ArrayList<GameDataRow> results = new ArrayList<GameDataRow>(); | |
| for (GameDataRow game : games) { | |
| if (game.getRating().equalsIgnoreCase(rating)) { | |
| results.add(game); | |
| } | |
| } | |
| return results; | |
| } | |
| /** | |
| * Get top N games by global sales | |
| */ | |
| public ArrayList<GameDataRow> getTopGames(int n) { | |
| if (n <= 0 || games.isEmpty()) { | |
| return new ArrayList<GameDataRow>(); | |
| } | |
| // Create a copy of the games list to avoid modifying the original | |
| ArrayList<GameDataRow> sortedGames = new ArrayList<GameDataRow>(games); | |
| // Sort using the Comparable implementation (by global sales) | |
| Collections.sort(sortedGames); | |
| // Return the top N (or all if n > size) | |
| int count = Math.min(n, sortedGames.size()); | |
| return new ArrayList<GameDataRow>(sortedGames.subList(0, count)); | |
| } | |
| /** | |
| * Get top N games by critic score (minimum 10 critics) | |
| */ | |
| public ArrayList<GameDataRow> getTopRatedGames(int n) { | |
| if (n <= 0 || games.isEmpty()) { | |
| return new ArrayList<GameDataRow>(); | |
| } | |
| // Create a copy with only games that have sufficient critic reviews | |
| ArrayList<GameDataRow> ratedGames = new ArrayList<GameDataRow>(); | |
| for (GameDataRow game : games) { | |
| if (game.hasCriticReviews() && game.getCriticCount() >= 10) { | |
| ratedGames.add(game); | |
| } | |
| } | |
| // Sort by critic score (descending) | |
| Collections.sort(ratedGames, (g1, g2) -> Float.compare(g2.getCriticScore(), g1.getCriticScore())); | |
| // Return the top N (or all if n > size) | |
| int count = Math.min(n, ratedGames.size()); | |
| return new ArrayList<GameDataRow>(ratedGames.subList(0, count)); | |
| } | |
| /** | |
| * Calculate the average global sales across all games | |
| */ | |
| public float getAverageGlobalSales() { | |
| if (games.isEmpty()) { | |
| return 0.0f; | |
| } | |
| float sum = 0.0f; | |
| for (GameDataRow game : games) { | |
| sum += game.getGlobalSales(); | |
| } | |
| return sum / games.size(); | |
| } | |
| /** | |
| * Calculate the average critic score across games with critic scores | |
| */ | |
| public float getAverageCriticScore() { | |
| int count = 0; | |
| float sum = 0.0f; | |
| for (GameDataRow game : games) { | |
| if (game.getCriticScore() > 0) { | |
| sum += game.getCriticScore(); | |
| count++; | |
| } | |
| } | |
| return count > 0 ? sum / count : 0.0f; | |
| } | |
| /** | |
| * Calculate total sales by region | |
| * @return array with total sales for each region [NA, EU, JP, Other] | |
| */ | |
| public float[] getTotalSalesByRegion() { | |
| float[] totals = new float[4]; | |
| for (GameDataRow game : games) { | |
| totals[0] += game.getNaSales(); | |
| totals[1] += game.getEuSales(); | |
| totals[2] += game.getJpSales(); | |
| totals[3] += game.getOtherSales(); | |
| } | |
| return totals; | |
| } | |
| /** | |
| * Get the distribution of games by genre | |
| * @return map of genre to count of games | |
| */ | |
| public Map<String, Integer> getGenreDistribution() { | |
| Map<String, Integer> distribution = new HashMap<String, Integer>(); | |
| for (GameDataRow game : games) { | |
| String genre = game.getGenre(); | |
| distribution.put(genre, distribution.getOrDefault(genre, 0) + 1); | |
| } | |
| return distribution; | |
| } | |
| /** | |
| * Get the distribution of games by rating | |
| * @return map of rating to count of games | |
| */ | |
| public Map<String, Integer> getRatingDistribution() { | |
| Map<String, Integer> distribution = new HashMap<String, Integer>(); | |
| for (GameDataRow game : games) { | |
| String rating = game.getRating(); | |
| if (rating != null && !rating.isEmpty()) { | |
| distribution.put(rating, distribution.getOrDefault(rating, 0) + 1); | |
| } | |
| } | |
| return distribution; | |
| } | |
| /** | |
| * Get the average sales by platform | |
| * @return map of platform to average global sales | |
| */ | |
| public Map<String, Float> getAverageSalesByPlatform() { | |
| Map<String, Float> totalSales = new HashMap<String, Float>(); | |
| Map<String, Integer> counts = new HashMap<String, Integer>(); | |
| for (GameDataRow game : games) { | |
| String platform = game.getPlatform(); | |
| totalSales.put(platform, totalSales.getOrDefault(platform, 0.0f) + game.getGlobalSales()); | |
| counts.put(platform, counts.getOrDefault(platform, 0) + 1); | |
| } | |
| Map<String, Float> averages = new HashMap<String, Float>(); | |
| for (String platform : totalSales.keySet()) { | |
| averages.put(platform, totalSales.get(platform) / counts.get(platform)); | |
| } | |
| return averages; | |
| } | |
| /** | |
| * Get the average critic scores by platform | |
| * @return map of platform to average critic score | |
| */ | |
| public Map<String, Float> getAverageCriticScoreByPlatform() { | |
| Map<String, Float> totalScores = new HashMap<String, Float>(); | |
| Map<String, Integer> counts = new HashMap<String, Integer>(); | |
| for (GameDataRow game : games) { | |
| if (game.getCriticScore() > 0) { | |
| String platform = game.getPlatform(); | |
| totalScores.put(platform, totalScores.getOrDefault(platform, 0.0f) + game.getCriticScore()); | |
| counts.put(platform, counts.getOrDefault(platform, 0) + 1); | |
| } | |
| } | |
| Map<String, Float> averages = new HashMap<String, Float>(); | |
| for (String platform : totalScores.keySet()) { | |
| averages.put(platform, totalScores.get(platform) / counts.get(platform)); | |
| } | |
| return averages; | |
| } | |
| /** | |
| * Find the top publisher by total sales | |
| */ | |
| public String getTopPublisher() { | |
| Map<String, Float> publisherSales = new HashMap<String, Float>(); | |
| for (GameDataRow game : games) { | |
| String publisher = game.getPublisher(); | |
| publisherSales.put(publisher, | |
| publisherSales.getOrDefault(publisher, 0.0f) + game.getGlobalSales()); | |
| } | |
| String topPublisher = ""; | |
| float maxSales = 0.0f; | |
| for (Map.Entry<String, Float> entry : publisherSales.entrySet()) { | |
| if (entry.getValue() > maxSales) { | |
| maxSales = entry.getValue(); | |
| topPublisher = entry.getKey(); | |
| } | |
| } | |
| return topPublisher; | |
| } | |
| /** | |
| * Get sales trends by year | |
| * @return map of year to total global sales | |
| */ | |
| public Map<Integer, Float> getSalesTrendsByYear() { | |
| Map<Integer, Float> yearlyTrends = new HashMap<Integer, Float>(); | |
| for (GameDataRow game : games) { | |
| int year = (int)game.getYearOfRelease(); | |
| if (year > 0) { // Skip entries with unknown years | |
| yearlyTrends.put(year, | |
| yearlyTrends.getOrDefault(year, 0.0f) + game.getGlobalSales()); | |
| } | |
| } | |
| return yearlyTrends; | |
| } | |
| /** | |
| * Get games released in a specific year | |
| */ | |
| public ArrayList<GameDataRow> getGamesByYear(int year) { | |
| ArrayList<GameDataRow> results = new ArrayList<GameDataRow>(); | |
| for (GameDataRow game : games) { | |
| if ((int)game.getYearOfRelease() == year) { | |
| results.add(game); | |
| } | |
| } | |
| return results; | |
| } | |
| /** | |
| * Get games with high critic-user score discrepancy | |
| * (difference greater than threshold) | |
| */ | |
| public ArrayList<GameDataRow> getGamesWithCriticUserDiscrepancy(float threshold) { | |
| ArrayList<GameDataRow> results = new ArrayList<GameDataRow>(); | |
| for (GameDataRow game : games) { | |
| if (game.hasCriticReviews() && game.hasUserReviews()) { | |
| // Convert critic score to scale of 10 to match user score | |
| float normalizedCriticScore = game.getCriticScore() / 10.0f; | |
| float userScore = game.getUserScoreNumeric(); | |
| if (Math.abs(normalizedCriticScore - userScore) > threshold) { | |
| results.add(game); | |
| } | |
| } | |
| } | |
| return results; | |
| } | |
| /** | |
| * Main method for testing the GameDataManager class | |
| */ | |
| public static void main(String[] args) { | |
| GameDataManager manager = new GameDataManager(); | |
| // Try to load the CSV file from the current directory | |
| int loaded = manager.loadFromCSV("video_games.csv"); | |
| if (loaded == 0) { | |
| System.out.println("WARNING: No records loaded. Please check if the file exists."); | |
| System.out.println("Current working directory: " + System.getProperty("user.dir")); | |
| System.out.println("Place the CSV file in this directory: " + System.getProperty("user.dir")); | |
| } else { | |
| System.out.println("Loaded " + loaded + " game records."); | |
| } | |
| // DEMONSTRATION 1: BASIC DATA EXPLORATION | |
| // Find and display top 5 games by sales | |
| ArrayList<GameDataRow> topGames = manager.getTopGames(5); | |
| System.out.println("\n===== TOP 5 GAMES BY GLOBAL SALES ====="); | |
| for (GameDataRow game : topGames) { | |
| System.out.println(game.getName() + " (" + game.getPlatform() + ") - " + | |
| game.getGlobalSales() + " million units"); | |
| } | |
| // DEMONSTRATION 2: REGIONAL SALES ANALYSIS | |
| // Display sales by region | |
| float[] regionalSales = manager.getTotalSalesByRegion(); | |
| String[] regions = {"North America", "Europe", "Japan", "Other"}; | |
| System.out.println("\n===== TOTAL SALES BY REGION ====="); | |
| for (int i = 0; i < regions.length; i++) { | |
| System.out.printf("%s: %.2f million units\n", regions[i], regionalSales[i]); | |
| } | |
| // DEMONSTRATION 3: GENRE DISTRIBUTION | |
| // Display genre distribution | |
| Map<String, Integer> genreDistribution = manager.getGenreDistribution(); | |
| System.out.println("\n===== GAMES BY GENRE ====="); | |
| for (Map.Entry<String, Integer> entry : genreDistribution.entrySet()) { | |
| System.out.println(entry.getKey() + ": " + entry.getValue() + " games"); | |
| } | |
| // DEMONSTRATION 4: SEARCH FUNCTIONALITY | |
| // Find games with "Mario" in the title | |
| ArrayList<GameDataRow> marioGames = manager.findGamesByTitle("Mario"); | |
| System.out.println("\n===== MARIO GAMES ====="); | |
| System.out.println("Found " + marioGames.size() + " games with 'Mario' in the title"); | |
| for (int i = 0; i < Math.min(5, marioGames.size()); i++) { | |
| System.out.println("- " + marioGames.get(i).getName() + " (" + | |
| marioGames.get(i).getPlatform() + ")"); | |
| } | |
| // DEMONSTRATION 5: CRITIC SCORES | |
| // Find top rated games | |
| ArrayList<GameDataRow> topRatedGames = manager.getTopRatedGames(5); | |
| System.out.println("\n===== TOP 5 GAMES BY CRITIC SCORE ====="); | |
| for (GameDataRow game : topRatedGames) { | |
| System.out.printf("%s - %.1f/100 (%d critics)\n", | |
| game.getName(), game.getCriticScore(), (int)game.getCriticCount()); | |
| } | |
| // DEMONSTRATION 6: PUBLISHER ANALYSIS | |
| // Display top publisher | |
| String topPublisher = manager.getTopPublisher(); | |
| System.out.println("\n===== TOP PUBLISHER BY SALES ====="); | |
| System.out.println("Top publisher: " + topPublisher); | |
| // DEMONSTRATION 7: PLATFORM ANALYSIS | |
| // Average sales by platform (top 5) | |
| Map<String, Float> platformSales = manager.getAverageSalesByPlatform(); | |
| System.out.println("\n===== AVERAGE SALES BY PLATFORM (TOP 5) ====="); | |
| platformSales.entrySet().stream() | |
| .sorted((e1, e2) -> Float.compare(e2.getValue(), e1.getValue())) | |
| .limit(5) | |
| .forEach(e -> System.out.printf("%s: %.2f million units\n", e.getKey(), e.getValue())); | |
| // DEMONSTRATION 8: RATINGS ANALYSIS | |
| // Distribution of game ratings | |
| Map<String, Integer> ratingDistribution = manager.getRatingDistribution(); | |
| System.out.println("\n===== GAMES BY RATING ====="); | |
| for (Map.Entry<String, Integer> entry : ratingDistribution.entrySet()) { | |
| if (entry.getKey() != null && !entry.getKey().isEmpty()) { | |
| System.out.println(entry.getKey() + ": " + entry.getValue() + " games"); | |
| } | |
| } | |
| // DEMONSTRATION 9: CRITIC-USER SCORE COMPARISON | |
| // Find games where critics and users disagree | |
| ArrayList<GameDataRow> controversialGames = manager.getGamesWithCriticUserDiscrepancy(3.0f); | |
| System.out.println("\n===== GAMES WITH CRITIC-USER SCORE DISCREPANCY ====="); | |
| System.out.println("Found " + controversialGames.size() + " games with significant score differences"); | |
| for (int i = 0; i < Math.min(5, controversialGames.size()); i++) { | |
| GameDataRow game = controversialGames.get(i); | |
| System.out.printf("%s - Critic: %.1f/100, User: %s/10\n", | |
| game.getName(), game.getCriticScore(), game.getUserScore()); | |
| } | |
| // STUDENT CHALLENGE IDEAS: | |
| // 1. Find games from a specific year with the highest sales | |
| // 2. Compare sales between different genres | |
| // 3. Find publishers with the most highly-rated games | |
| // 4. Analyze the relationship between critic scores and sales | |
| // 5. Discover which platform has the highest-rated games on average | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment