Skip to content

Instantly share code, notes, and snippets.

@dadiletta
Created March 30, 2025 19:37
Show Gist options
  • Save dadiletta/2310e45953e3bcb8db3cf151c7c75d06 to your computer and use it in GitHub Desktop.
Save dadiletta/2310e45953e3bcb8db3cf151c7c75d06 to your computer and use it in GitHub Desktop.
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