diff --git a/FSG_FILE.fsg b/FSG_FILE.fsg
new file mode 100644
index 0000000000..6402376973
Binary files /dev/null and b/FSG_FILE.fsg differ
diff --git a/FSG_FILE.xml b/FSG_FILE.xml
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/XML_FILE.xml b/XML_FILE.xml
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/src/net/sf/freecol/common/io/FreeColSQLReader.java b/src/net/sf/freecol/common/io/FreeColSQLReader.java
new file mode 100644
index 0000000000..a7c6370097
--- /dev/null
+++ b/src/net/sf/freecol/common/io/FreeColSQLReader.java
@@ -0,0 +1,82 @@
+/**
+ * Copyright (C) 2002-2022 The FreeCol Team
+ *
+ * This file is part of FreeCol.
+ *
+ * FreeCol is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * FreeCol is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FreeCol. If not, see .
+ */
+
+package net.sf.freecol.common.io;
+import java.io.Closeable;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * This code creates a `FreeColSQLReader` class that connects to an
+ * SQLite database and is capable of executing queries.
+ * It maintains a connection to the SQLite file and a statement object used to
+ * execute the queries. The `ReadScopeType` is also included in the implementation,
+ * similar to the XML implementation.
+ */
+public class FreeColSQLReader implements Closeable {
+
+ private static final Logger logger = Logger.getLogger(FreeColSQLReader.class.getName());
+
+ /**
+ * Enum representing the scope of the data reading.
+ */
+ public enum ReadScopeType {
+ CLIENT, // Only the client-visible information
+ SERVER, // Full server-visible information
+ LOAD // Absolutely everything needed to load the game state
+ }
+
+ private Connection connection;
+ private Statement statement;
+ private final ReadScopeType readScope;
+
+ public FreeColSQLReader(String dbPath, ReadScopeType scope) throws SQLException {
+ this.connection = DriverManager.getConnection("jdbc:sqlite:" + dbPath);
+ this.statement = connection.createStatement();
+ this.readScope = (scope == null) ? ReadScopeType.LOAD : scope;
+ }
+
+ /**
+ * Executes a query and returns the result set.
+ *
+ * @param query SQL query to execute.
+ * @return ResultSet containing the result of the query.
+ * @throws SQLException If the query execution fails.
+ */
+ public ResultSet executeQuery(String query) throws SQLException {
+ return statement.executeQuery(query);
+ }
+
+ @Override
+ public void close() {
+ try {
+ if (statement != null) statement.close();
+ if (connection != null) connection.close();
+ } catch (SQLException e) {
+ logger.log(Level.WARNING, "Failed to close resources", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/net/sf/freecol/common/io/FreeColSQLWriter.java b/src/net/sf/freecol/common/io/FreeColSQLWriter.java
new file mode 100644
index 0000000000..6918c3e19d
--- /dev/null
+++ b/src/net/sf/freecol/common/io/FreeColSQLWriter.java
@@ -0,0 +1,133 @@
+/**
+ * Copyright (C) 2002-2022 The FreeCol Team
+ *
+ * This file is part of FreeCol.
+ *
+ * FreeCol is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * FreeCol is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with FreeCol. If not, see .
+ */
+
+package net.sf.freecol.common.io;
+
+import java.io.Closeable;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+
+/**
+ * `FreeColSQLWriter` class to save game data into an SQLite database.
+ * It consists of the `saveGameData` method that saves general game data,
+ * player data, turn data, and tile data. Additional game components can be saved
+ * in a similar manner using prepared statements. The `close()`
+ * method ensures that the database connection is closed when done.
+ */
+public class FreeColSQLWriter implements Closeable {
+
+ private static final Logger logger = Logger.getLogger(FreeColSQLWriter.class.getName());
+
+ /**
+ * Enum representing the scope of the data writing.
+ */
+ public enum WriteScopeType {
+ CLIENT, // Only the client-visible information
+ SERVER, // Full server-visible information
+ SAVE // Absolutely everything needed to save the game state
+ };
+
+ private Connection connection;
+ private WriteScopeType writeScope;
+
+ public FreeColSQLWriter(String dbPath, WriteScopeType scope) throws SQLException {
+ this.connection = DriverManager.getConnection("jdbc:sqlite:" + dbPath);
+ this.writeScope = (scope == null) ? WriteScopeType.SAVE : scope;
+ }
+
+ /**
+ * Executes an SQL update statement.
+ *
+ * @param update SQL update statement to execute.
+ * @throws SQLException If the statement execution fails.
+ */
+ public void executeUpdate(String update) throws SQLException {
+ try (PreparedStatement pstmt = connection.prepareStatement(update)) {
+ pstmt.executeUpdate();
+ }
+ }
+
+ /**
+ * Save game data to the SQLite database.
+ *
+ * @param game The Game object to save.
+ * @throws SQLException If any error occurs during saving.
+ */
+ public void saveGameData(Game game) throws SQLException {
+ // Save general game data
+ String sqlGame = "INSERT OR REPLACE INTO game (id, options) VALUES(?, ?)";
+ try (PreparedStatement pstmt = connection.prepareStatement(sqlGame)) {
+ pstmt.setInt(1, game.getId());
+ pstmt.setString(2, game.getGameOptions().toString());
+ pstmt.executeUpdate();
+ }
+
+ // Save player data
+ String sqlPlayer = "INSERT OR REPLACE INTO player (id, name, nation) VALUES(?, ?, ?)";
+ for (Player player : game.getPlayers()) {
+ try (PreparedStatement pstmt = connection.prepareStatement(sqlPlayer)) {
+ pstmt.setInt(1, player.getId());
+ pstmt.setString(2, player.getName());
+ pstmt.setString(3, player.getNation().getName());
+ pstmt.executeUpdate();
+ }
+ }
+
+ // Save turn data
+ String sqlTurn = "UPDATE game SET turn = ? WHERE id
+ // Save turn data
+ String sqlTurn = "UPDATE game SET turn = ? WHERE id = ?";
+ try (PreparedStatement pstmt = connection.prepareStatement(sqlTurn)) {
+ pstmt.setInt(1, game.getTurn());
+ pstmt.setInt(2, game.getId());
+ pstmt.executeUpdate();
+ }
+
+ // Save tile data
+ String sqlTile = "INSERT OR REPLACE INTO tile (x, y, terrain_type, owner, game_id) VALUES(?, ?, ?, ?, ?)";
+ for (Tile tile : game.getMap().getAllTiles()) {
+ try (PreparedStatement pstmt = connection.prepareStatement(sqlTile)) {
+ pstmt.setInt(1, tile.getX());
+ pstmt.setInt(2, tile.getY());
+ pstmt.setString(3, tile.getTerrainType().getName());
+ pstmt.setString(4, tile.getOwner().getName());
+ pstmt.setInt(5, game.getId());
+ pstmt.executeUpdate();
+ }
+ }
+
+ // Additional game components can be saved similarly with prepared statements
+ }
+
+ @Override
+ public void close() {
+ try {
+ if (connection != null) {
+ connection.close();
+ }
+ } catch (SQLException e) {
+ logger.log(Level.WARNING, "Failed to close resources", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/net/sf/freecol/common/io/FreeColXMLWriter.java b/src/net/sf/freecol/common/io/FreeColXMLWriter.java
index 8926892302..1dc44030f2 100644
--- a/src/net/sf/freecol/common/io/FreeColXMLWriter.java
+++ b/src/net/sf/freecol/common/io/FreeColXMLWriter.java
@@ -385,6 +385,7 @@ public void writeAttribute(String attributeName, Enum> value)
*/
public void writeAttribute(String attributeName, Object value)
throws XMLStreamException {
+ logger.log(Level.WARNING, "Writing attribute:" + attributeName + ", with value of: " + String.valueOf(value));
xmlStreamWriter.writeAttribute(attributeName, String.valueOf(value));
}
diff --git a/src/net/sf/freecol/common/model/sql/generate_sql_tables.sql b/src/net/sf/freecol/common/model/sql/generate_sql_tables.sql
new file mode 100644
index 0000000000..0ab2491902
--- /dev/null
+++ b/src/net/sf/freecol/common/model/sql/generate_sql_tables.sql
@@ -0,0 +1,84 @@
+-- Create game table
+CREATE TABLE IF NOT EXISTS game (
+ id INTEGER PRIMARY KEY,
+ difficulty TEXT,
+ mapFile TEXT,
+ gameOptions TEXT,
+ language TEXT,
+ turns INTEGER,
+ graphicalOptions TEXT,
+ soundOptions TEXT,
+ turn INTEGER
+);
+
+-- Create player table
+CREATE TABLE IF NOT EXISTS player (
+ id INTEGER PRIMARY KEY,
+ game_id INTEGER,
+ name TEXT,
+ color TEXT,
+ flag TEXT,
+ playerPreferences TEXT,
+ FOREIGN KEY (game_id) REFERENCES game (id) ON DELETE CASCADE
+);
+
+-- Create native table
+CREATE TABLE IF NOT EXISTS natives (
+ id INTEGER PRIMARY KEY,
+ game_id INTEGER,
+ name TEXT,
+ color TEXT,
+ type TEXT,
+ FOREIGN KEY (game_id) REFERENCES game (id) ON DELETE CASCADE
+);
+
+-- Create faction table
+CREATE TABLE IF NOT EXISTS factions (
+ id INTEGER PRIMARY KEY,
+ game_id INTEGER,
+ name TEXT,
+ FOREIGN KEY (game_id) REFERENCES game (id) ON DELETE CASCADE
+);
+
+-- ... The existing unit, city, and tile table creation statements remain unchanged
+
+-- Create building table
+CREATE TABLE IF NOT EXISTS building (
+ id INTEGER PRIMARY KEY,
+ game_id INTEGER,
+ city_id INTEGER,
+ type TEXT,
+ x INTEGER,
+ y INTEGER,
+ FOREIGN KEY (game_id) REFERENCES game (id) ON DELETE CASCADE,
+ FOREIGN KEY (city_id) REFERENCES city (id) ON DELETE CASCADE
+);
+
+-- Create resource (goods) table
+CREATE TABLE IF NOT EXISTS goods (
+ id INTEGER PRIMARY KEY,
+ game_id INTEGER,
+ type TEXT,
+ available INTEGER,
+ FOREIGN KEY (game_id) REFERENCES game (id) ON DELETE CASCADE
+);
+
+-- Create highscore table
+CREATE TABLE IF NOT EXISTS highScores (
+ id INTEGER PRIMARY KEY,
+ game_id INTEGER,
+ player_id INTEGER,
+ score INTEGER,
+ FOREIGN KEY (game_id) REFERENCES game (id) ON DELETE CASCADE,
+ FOREIGN KEY (player_id) REFERENCES player (id) ON DELETE CASCADE
+);
+
+-- Create foundingFathers table
+CREATE TABLE IF NOT EXISTS foundingFathers (
+ id INTEGER PRIMARY KEY,
+ game_id INTEGER,
+ name TEXT,
+ bonus TEXT,
+ improvement TEXT,
+ FOREIGN KEY (game_id) REFERENCES game (id) ON DELETE CASCADE
+);
diff --git a/src/net/sf/freecol/tools/FSGConverter.java b/src/net/sf/freecol/tools/FSGConverter.java
index 874beb264e..2a935799e5 100644
--- a/src/net/sf/freecol/tools/FSGConverter.java
+++ b/src/net/sf/freecol/tools/FSGConverter.java
@@ -118,9 +118,9 @@ private void convertToXML(InputStream ins, OutputStream outs)
return;
}
in.reset();
- if (!"= 2 && args[0].endsWith("output:xml")) {
- File in = new File(args[1]);
+ String[] actual_args = {"FSG_FILE:xml", "5c812fa4_Голландцы_1494.fsg"};
+ if (actual_args.length >= 2 && actual_args[0].endsWith("output:xml")) {
+ File in = new File(actual_args[1]);
if (!in.exists()) {
printUsage();
System.exit(1);
}
File out;
- if (args.length >= 3) {
- out = new File(args[2]);
+ if (actual_args.length >= 3) {
+ out = new File(actual_args[2]);
} else {
String name = in.getName();
String filename = name.replaceAll("." + FreeCol.FREECOL_SAVE_EXTENSION, ".xml");
diff --git a/src/net/sf/freecol/tools/SaveGameValidator.java b/src/net/sf/freecol/tools/SaveGameValidator.java
index e6240b78b2..eb3094b792 100644
--- a/src/net/sf/freecol/tools/SaveGameValidator.java
+++ b/src/net/sf/freecol/tools/SaveGameValidator.java
@@ -40,22 +40,35 @@
/**
* Validate a saved game.
*/
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+
public class SaveGameValidator {
+ /**
+ * Main method to validate game save.
+ *
+ * @param args command line arguments containing the SQLite database file paths
+ * @throws Exception if there is any error during execution
+ */
public static void main(String[] args) throws Exception {
-
- SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
- File schemaLocation = new File("schema/data/data-savedGame.xsd");
- Schema schema = factory.newSchema(schemaLocation);
- Validator saveGameValidator = schema.newValidator();
+ // Load SQLite JDBC driver
+ Class.forName("org.sqlite.JDBC");
List allFiles = new ArrayList<>();
for (String name : args) {
File file = new File(name);
if (file.exists()) {
if (file.isDirectory()) {
- allFiles.addAll(FreeColDirectories.getSavegameFileList(file));
- } else if (FreeColDirectories.saveGameFilter.test(file)) {
+ // You need to implement getSQLiteDatabaseFileList method to list SQLite files in the directory
+ allFiles.addAll(getSQLiteDatabaseFileList(file));
+ } else {
+ // You can use any custom file filter, if required
allFiles.add(file);
}
}
@@ -63,25 +76,118 @@ public static void main(String[] args) throws Exception {
int ret = 0;
for (File file : allFiles) {
- //System.out.println("Processing file " + file.getPath());
- try {
- FreeColSavegameFile mapFile = new FreeColSavegameFile(file);
- try (InputStream in = mapFile.getSavegameInputStream()) {
- saveGameValidator.validate(new StreamSource(in));
- }
+ System.out.println("Processing file " + file.getPath());
+ try (Connection connection = DriverManager.getConnection("jdbc:sqlite:" + file.getPath())) {
+ ret = validateSaveGame(connection) ? 0 : Math.max(ret, 1);
System.out.println("Successfully validated " + file.getName());
- } catch (SAXParseException e) {
- System.out.println(e.getMessage()
- + " at line=" + e.getLineNumber()
- + " column=" + e.getColumnNumber());
- ret = Math.max(ret, 1);
- } catch (IOException | SAXException e) {
- System.out.println("Failed to read " + file.getName());
+ } catch (Exception e) {
+ System.out.println("Failed to read or validate " + file.getName());
ret = 2;
}
}
System.exit(ret);
}
-}
+ /**
+ * Validates game save based on the SQLite database file.
+ *
+ * @param connection SQLite database connection
+ * @return true if the game save is valid, false otherwise
+ * @throws Exception if any error occurs during validation
+ */
+ private static boolean validateSaveGame(Connection connection) throws Exception {
+ Statement stmt = connection.createStatement();
+ ResultSet rs;
+
+ // Validate game table
+ rs = stmt.executeQuery("SELECT * FROM game");
+ if (!rs.next()) {
+ System.out.println("No game data found in the 'game' table");
+ return false;
+ }
+ rs.close();
+
+ // Validate player table
+ rs = stmt.executeQuery("SELECT * FROM player");
+ if (!rs.next()) {
+ System.out.println("No player data found in the 'player' table");
+ return false;
+ }
+ rs.close();
+
+
+ // Validate natives table
+ rs = stmt.executeQuery("SELECT * FROM natives");
+ if (!rs.next()) {
+ System.out.println("No native data found in the 'natives' table");
+ return false;
+ }
+ rs.close();
+
+ // Validate factions table
+ rs = stmt.executeQuery("SELECT * FROM factions");
+ if (!rs.next()) {
+ System.out.println("No faction data found in the 'factions' table");
+ return false;
+ }
+ rs.close();
+
+ // Validate building table
+ rs = stmt.executeQuery("SELECT * FROM building");
+ if (!rs.next()) {
+ System.out.println("No building data found in the 'building' table");
+ return false;
+ }
+ rs.close();
+ // Validate goods table
+ rs = stmt.executeQuery("SELECT * FROM goods");
+ if (!rs.next()) {
+ System.out.println("No goods data found in the 'goods' table");
+ return false;
+ }
+ rs.close();
+
+ // Validate highScores table
+ rs = stmt.executeQuery("SELECT * FROM highScores");
+ if (!rs.next()) {
+ System.out.println("No highScores data found in the 'highScores' table");
+ return false;
+ }
+ rs.close();
+
+ // Validate foundingFathers table
+ rs = stmt.executeQuery("SELECT * FROM foundingFathers");
+ if (!rs.next()) {
+ System.out.println("No foundingFathers data found in the 'foundingFathers' table");
+ return false;
+ }
+ rs.close();
+
+ stmt.close();
+
+ // All validations passed
+ return true;
+ }
+
+ /**
+ * Gets a list of SQLite database files in the given directory.
+ *
+ * @param directory Directory containing the SQLite database files
+ * @return a List of SQLite database files
+ */
+ private static List getSQLiteDatabaseFileList(File directory) {
+ List sqliteFiles = new ArrayList<>();
+ File[] files = directory.listFiles();
+
+ if (files != null) {
+ for (File file : files) {
+ if (file.isFile() && file.getName().toLowerCase().endsWith(".sqlite")) {
+ sqliteFiles.add(file);
+ }
+ }
+ }
+
+ return sqliteFiles;
+ }
+}
diff --git a/test/src/net/sf/freecol/common/io/SQLInteractionsTests.java b/test/src/net/sf/freecol/common/io/SQLInteractionsTests.java
new file mode 100644
index 0000000000..75d973f778
--- /dev/null
+++ b/test/src/net/sf/freecol/common/io/SQLInteractionsTests.java
@@ -0,0 +1,169 @@
+package net.sf.freecol.common.io;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+
+/**
+ * These tests save and load various game objects like the game itself,
+ * players, and tiles, and then compare the saved and loaded values to
+ * ensure they match. Use these tests as a guide to extend
+ * them for any additional game components.
+ */
+public class SQLInteractionsTests {
+
+ private static final String DB_PATH = "test_db.sqlite";
+
+ private FreeColSQLWriter writer;
+ private FreeColSQLReader reader;
+ private Connection connection;
+
+ @BeforeEach
+ public void setUp() throws SQLException {
+ writer = new FreeColSQLWriter(DB_PATH, FreeColSQLWriter.WriteScopeType.SAVE);
+ reader = new FreeColSQLReader(DB_PATH, FreeColSQLReader.ReadScopeType.CLIENT);
+ connection = DriverManager.getConnection("jdbc:sqlite:" + DB_PATH);
+
+ // Create the necessary tables for testing
+ connection.createStatement().execute(
+ "CREATE TABLE IF NOT EXISTS game (id INTEGER, options TEXT, turn INTEGER);"
+ );
+ }
+
+ @AfterEach
+ public void tearDown() throws IOException, SQLException {
+ writer.close();
+ reader.close();
+ connection.close();
+
+ // Remove the test database file
+ File dbFile = new File(DB_PATH);
+ if (dbFile.exists()) {
+ dbFile.delete();
+ }
+ }
+
+ @Test
+ public void testSaveGame() throws SQLException {
+ Game game = new Game(1, "options");
+ game.setTurn(5);
+
+ writer.saveGameData(game);
+
+ ResultSet resultSet = reader.executeQuery("SELECT * FROM game WHERE id = 1");
+ resultSet.next();
+
+ int turn = resultSet.getInt("turn");
+ String options = resultSet.getString("options");
+
+ assertEquals(5, turn, "Turn value should be 5");
+ assertEquals("options", options, "Game options should be 'options'");
+ }
+
+ @Test
+ public void testSavePlayer() throws SQLException {
+ Game game = new Game(1, "options");
+ game.addPlayer(new Player(game, "player1", "nation1"));
+ game.addPlayer(new Player(game, "player2", "nation2"));
+
+ writer.saveGameData(game);
+
+ ResultSet resultSet = reader.executeQuery("SELECT * FROM player");
+ int playerCount = 0;
+ while (resultSet.next()) {
+ String playerName = resultSet.getString("name");
+ String nation = resultSet.getString("nation");
+
+ assertEquals("player" + (playerCount + 1), playerName, "Check saved player name");
+ assertEquals("nation" + (playerCount + 1), nation, "Check saved player nation");
+
+ playerCount++;
+ }
+
+ assertEquals(2, playerCount, "There should be exactly 2 players saved in the database");
+ }
+
+ @Test
+ public void testSaveTile() throws SQLException {
+ Game game = new Game(1, "options");
+
+ // Add some tiles to the game map
+ game.getMap().addTile(new Tile(1, 1, "grass", "player1"));
+ game.getMap().addTile(new Tile(1, 2, "forest", "player2"));
+
+ writer.saveGameData(game);
+
+ ResultSet resultSet = reader.executeQuery("SELECT * FROM tile");
+ int tileCount = 0;
+ while (resultSet.next()) {
+ int x = resultSet.getInt("x");
+ int y = resultSet.getInt("y");
+ String terrainType = resultSet.getString("terrain_type");
+ String owner = resultSet.getString("owner");
+
+ assertEquals(1, x, "Check saved tile x-coordinate");
+ assertEquals(tileCount + 1, y, "Check saved tile y-coordinate");
+ assertEquals("player" + (tileCount + 1), owner, "Check saved tile owner");
+
+ if (tileCount == 0) {
+ assertEquals("grass", terrainType, "First tile should be grass");
+ } else {
+ assertEquals("forest", terrainType, "Second tile should be forest");
+ }
+
+ tileCount++;
+ }
+
+ assertEquals(2, tileCount, "There should be exactly 2 tiles saved in the database");
+ }
+
+ @Test
+ public void testLoadGame() throws SQLException {
+ // Save test game data first
+ Game game = new Game(1, "options");
+ game.setTurn(5);
+ writer.saveGameData(game);
+
+ // Now load it using reader
+ Game loadedGame = reader.readGame();
+
+ assertEquals(1, loadedGame.getId(), "Loaded game ID should be 1");
+ assertEquals("options", loadedGame.getGameOptions().toString(), "Loaded game options should be 'options'");
+ assertEquals(5, loadedGame.getTurn(), "Loaded game turn should be 5");
+ }
+
+ @Test
+ public void testLoadPlayers() throws SQLException {
+ // Save test game data first
+ Game game = new Game(1, "options");
+ game.addPlayer(new Player(game, "player1", "nation1"));
+ game.addPlayer(new Player(game, "player2", "nation2"));
+ writer.saveGameData(game);
+
+ // Now load the saved game using the reader
+ Game loadedGame = reader.readGame();
+
+ assertEquals(game.getPlayers().size(), loadedGame.getPlayers().size(), "Both saved and loaded games have the same number of players");
+
+ for (int i = 0; i < game.getPlayers().size(); i++) {
+ Player originalPlayer = game.getPlayers().get(i);
+ Player loadedPlayer = loadedGame.getPlayers().get(i);
+
+ assertEquals(originalPlayer.getId(), loadedPlayer.getId(), "Both saved and loaded player IDs should match");
+ assertEquals(originalPlayer.getName(), loadedPlayer.getName(), "Both saved and loaded player names should match");
+ assertEquals(originalPlayer.getNation().getName(), loadedPlayer.getNation().getName(), "Both saved and loaded player nations should match");
+ }
+ }
+
+ // You can add more tests for loading tiles and other game components similarly
+}
\ No newline at end of file