Rename 'CT326_Programming_III' to 'CT326: Programming III'

This commit is contained in:
2023-12-09 16:50:55 +00:00
parent a7e7f78f52
commit 066ec2d356
193 changed files with 0 additions and 0 deletions

View File

@ -0,0 +1,81 @@
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.time.LocalDate;
/**
* class representing a player's achievement
*/
public class Achievement {
private String achievementName;
private String description;
private LocalDate dateOfAward;
/**
* constructor for the Achievement class
* @param achievementName a String representation of the name of the Achievement
* @param description a String describing the Achievement
* @param dateOfAward a LocalDate representing the date that the Achievement was awarded
*/
public Achievement(String achievementName, String description, LocalDate dateOfAward) {
this.achievementName = achievementName;
this.description = description;
this.dateOfAward = dateOfAward;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Achievement) {
Achievement toCompare = (Achievement) obj;
if (!achievementName.equals(toCompare.achievementName)) {
return false;
}
if (!description.equals(toCompare.description)) {
return false;
}
if (!dateOfAward.equals(toCompare.dateOfAward)) {
return false;
}
return true;
}
else { return false; }
}
/**
* getter method for the achievementName field
* @return a String representation of the name of the Achievement
*/
public String getAchievementName() { return achievementName; }
/**
* setter method for the achievementName field
* @param achievementName a String representation of the name of the Achievement
*/
public void setAchievementName(String achievementName) { this.achievementName = achievementName; }
/**
* getter method for the description field
* @return a String describing the Achievement
*/
public String getDescription() { return description; }
/**
* setter method for the description field
* @param description a String describing the Achievement
*/
public void setDescription(String description) { this.description = description; }
/**
* getter method for the dateOfAward field
* @return a LocalDate representing the date that the Achievement was awarded
*/
public LocalDate getDateOfAward() { return dateOfAward; }
/**
* setter method for the dateOfAward field
* @param dateOfAward a LocalDate representing the date that the Achievement was awarded
*/
public void setDateOfAward(LocalDate dateOfAward) { this.dateOfAward = dateOfAward; }
}

View File

@ -0,0 +1,260 @@
/**
* enum for each ISO 3166 Alpha-2 country Code
*/
public enum Country {
// Explanation of how this data was sourced:
// the following ISO 3166 Alpha-2 Codes were taken from the CSV file found here: https://pkgstore.datahub.io/core/country-list/data_csv/data/d7c9d7cfb42cb69f4422dec222dbbaa8/data_csv.csv
// the CSV file was cleaned to have UNIX line endings (as it had Windows line endings, and I am on GNU/Linux) with the command `tr -d '\r' < data_csv.csv > clean_data.csv `
// they were then parsed & read into this Java source file with the Vim / GNU AWK command `:read !awk -F',' '{gsub(/\"/, ""); print $NF ",\t// " $1}' clean_data.csv`
// finally, the block was indented in Vim and a `;` appended to the last value
AF, // Afghanistan
AX, // Åland Islands
AL, // Albania
DZ, // Algeria
AS, // American Samoa
AD, // Andorra
AO, // Angola
AI, // Anguilla
AQ, // Antarctica
AG, // Antigua and Barbuda
AR, // Argentina
AM, // Armenia
AW, // Aruba
AU, // Australia
AT, // Austria
AZ, // Azerbaijan
BS, // Bahamas
BH, // Bahrain
BD, // Bangladesh
BB, // Barbados
BY, // Belarus
BE, // Belgium
BZ, // Belize
BJ, // Benin
BM, // Bermuda
BT, // Bhutan
BO, // Bolivia
BQ, // Bonaire
BA, // Bosnia and Herzegovina
BW, // Botswana
BV, // Bouvet Island
BR, // Brazil
IO, // British Indian Ocean Territory
BN, // Brunei Darussalam
BG, // Bulgaria
BF, // Burkina Faso
BI, // Burundi
KH, // Cambodia
CM, // Cameroon
CA, // Canada
CV, // Cape Verde
KY, // Cayman Islands
CF, // Central African Republic
TD, // Chad
CL, // Chile
CN, // China
CX, // Christmas Island
CC, // Cocos (Keeling) Islands
CO, // Colombia
KM, // Comoros
CG, // Congo
CD, // Congo
CK, // Cook Islands
CR, // Costa Rica
CI, // Côte d'Ivoire
HR, // Croatia
CU, // Cuba
CW, // Curaçao
CY, // Cyprus
CZ, // Czech Republic
DK, // Denmark
DJ, // Djibouti
DM, // Dominica
DO, // Dominican Republic
EC, // Ecuador
EG, // Egypt
SV, // El Salvador
GQ, // Equatorial Guinea
ER, // Eritrea
EE, // Estonia
ET, // Ethiopia
FK, // Falkland Islands (Malvinas)
FO, // Faroe Islands
FJ, // Fiji
FI, // Finland
FR, // France
GF, // French Guiana
PF, // French Polynesia
TF, // French Southern Territories
GA, // Gabon
GM, // Gambia
GE, // Georgia
DE, // Germany
GH, // Ghana
GI, // Gibraltar
GR, // Greece
GL, // Greenland
GD, // Grenada
GP, // Guadeloupe
GU, // Guam
GT, // Guatemala
GG, // Guernsey
GN, // Guinea
GW, // Guinea-Bissau
GY, // Guyana
HT, // Haiti
HM, // Heard Island and McDonald Islands
VA, // Holy See (Vatican City State)
HN, // Honduras
HK, // Hong Kong
HU, // Hungary
IS, // Iceland
IN, // India
ID, // Indonesia
IR, // Iran
IQ, // Iraq
IE, // Ireland
IM, // Isle of Man
IL, // Israel
IT, // Italy
JM, // Jamaica
JP, // Japan
JE, // Jersey
JO, // Jordan
KZ, // Kazakhstan
KE, // Kenya
KI, // Kiribati
KP, // Korea
KR, // Korea
KW, // Kuwait
KG, // Kyrgyzstan
LA, // Lao People's Democratic Republic
LV, // Latvia
LB, // Lebanon
LS, // Lesotho
LR, // Liberia
LY, // Libya
LI, // Liechtenstein
LT, // Lithuania
LU, // Luxembourg
MO, // Macao
MK, // Macedonia
MG, // Madagascar
MW, // Malawi
MY, // Malaysia
MV, // Maldives
ML, // Mali
MT, // Malta
MH, // Marshall Islands
MQ, // Martinique
MR, // Mauritania
MU, // Mauritius
YT, // Mayotte
MX, // Mexico
FM, // Micronesia
MD, // Moldova
MC, // Monaco
MN, // Mongolia
ME, // Montenegro
MS, // Montserrat
MA, // Morocco
MZ, // Mozambique
MM, // Myanmar
NA, // Namibia
NR, // Nauru
NP, // Nepal
NL, // Netherlands
NC, // New Caledonia
NZ, // New Zealand
NI, // Nicaragua
NE, // Niger
NG, // Nigeria
NU, // Niue
NF, // Norfolk Island
MP, // Northern Mariana Islands
NO, // Norway
OM, // Oman
PK, // Pakistan
PW, // Palau
PS, // Palestine
PA, // Panama
PG, // Papua New Guinea
PY, // Paraguay
PE, // Peru
PH, // Philippines
PN, // Pitcairn
PL, // Poland
PT, // Portugal
PR, // Puerto Rico
QA, // Qatar
RE, // Réunion
RO, // Romania
RU, // Russian Federation
RW, // Rwanda
BL, // Saint Barthélemy
SH, // Saint Helena
KN, // Saint Kitts and Nevis
LC, // Saint Lucia
MF, // Saint Martin (French part)
PM, // Saint Pierre and Miquelon
VC, // Saint Vincent and the Grenadines
WS, // Samoa
SM, // San Marino
ST, // Sao Tome and Principe
SA, // Saudi Arabia
SN, // Senegal
RS, // Serbia
SC, // Seychelles
SL, // Sierra Leone
SG, // Singapore
SX, // Sint Maarten (Dutch part)
SK, // Slovakia
SI, // Slovenia
SB, // Solomon Islands
SO, // Somalia
ZA, // South Africa
GS, // South Georgia and the South Sandwich Islands
SS, // South Sudan
ES, // Spain
LK, // Sri Lanka
SD, // Sudan
SR, // Suriname
SJ, // Svalbard and Jan Mayen
SZ, // Swaziland
SE, // Sweden
CH, // Switzerland
SY, // Syrian Arab Republic
TW, // Taiwan
TJ, // Tajikistan
TZ, // Tanzania
TH, // Thailand
TL, // Timor-Leste
TG, // Togo
TK, // Tokelau
TO, // Tonga
TT, // Trinidad and Tobago
TN, // Tunisia
TR, // Turkey
TM, // Turkmenistan
TC, // Turks and Caicos Islands
TV, // Tuvalu
UG, // Uganda
UA, // Ukraine
AE, // United Arab Emirates
GB, // United Kingdom
US, // United States
UM, // United States Minor Outlying Islands
UY, // Uruguay
UZ, // Uzbekistan
VU, // Vanuatu
VE, // Venezuela
VN, // Viet Nam
VG, // Virgin Islands
VI, // Virgin Islands
WF, // Wallis and Futuna
EH, // Western Sahara
YE, // Yemen
ZM, // Zambia
ZW; // Zimbabwe
}

View File

@ -0,0 +1,184 @@
import java.io.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* class to represent a player
*/
public class Player implements Serializable {
private String id;
private String username;
private Country country;
private LocalDate joinDate;
private List<Achievement> achievements;
private static final String serializeAchievementsTo = "achievements.csv";
/**
* constructor for the Player class
* @param id a String representing the player's ID
* @param username a String representing the player's username
* @param country a Country object representing the country to which the player belongs
* @param joinDate a LocalDate object representing the date that the player joined the team
* @param achievements a List of Achievement objects awarded to the player
*/
public Player(String id, String username, Country country, LocalDate joinDate, List<Achievement> achievements) {
this.id = id;
this.username = username;
this.country = country;
this.joinDate = joinDate;
this.achievements = achievements;
}
/**
* overridden method to compare two objects for equality
* @param obj the object to be compared
* @return boolean - true if the objects have all the same fields equals, false otherwise
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof Player) {
Player toCompare = (Player) obj;
if (!id.equals(toCompare.id)) {
return false;
}
if (!username.equals(toCompare.username)) {
return false;
}
if (!country.equals(toCompare.country)) {
return false;
}
if (!joinDate.equals(toCompare.joinDate)) {
return false;
}
if (!achievements.equals(toCompare.achievements)) {
return false;
} // note that if the lists are in different orders, this will return false
return true;
}
else { return false; }
}
/**
* method to deserialize the Player object and to read in its achievements from a CSV file
* @param out ObjectOutputStream
* @throws IOException
*/
@Serial
private void writeObject(ObjectOutputStream out) throws IOException {
// would be inappropriate to catch IOExceptions here - should be caught in the code attempting to serialize the object
out.writeObject(id);
out.writeObject(username);
out.writeObject(country);
out.writeObject(joinDate);
// deliberate design choice here to not use the writeObject method of the Achievement class
// serializing Achievements in the context of a Player's list of Achievements should be treated differently to serializing, say, a single, isolated Achievement
// there may be times when we want to serialize an Achievement without reference to a Player, without a CSV file
// writing out Achievements to CSV file
FileWriter writer = new FileWriter(serializeAchievementsTo, true); // append set to true
for (Achievement achievement : achievements) {
writer.write(id + "," + achievement.getAchievementName() + "," + achievement.getDescription() + "," + achievement.getDateOfAward().toString() + "\n");
}
writer.close();
}
/**
* method to serialize the Player object and to write out its achievements to a CSV file
* @param in ObjectInputStream
* @throws IOException
* @throws ClassNotFoundException
*/
@Serial
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
// would be inappropriate to catch exceptions here - should be caught in the code attempting to de-serialize the object
id = (String) in.readObject();
username = (String) in.readObject();
country = (Country) in.readObject();
joinDate = (LocalDate) in.readObject();
achievements = new ArrayList<>();
FileReader fileReader = new FileReader(serializeAchievementsTo);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
String[] cols = line.split(",");
// only adding to list of achievements if the player ids match
if (cols[0].equals(id)) {
achievements.add(new Achievement(cols[1], cols[2], LocalDate.parse(cols[3], DateTimeFormatter.ofPattern("yyyy-MM-dd"))));
}
}
bufferedReader.close();
}
/**
* getter method for the ID field
* @return a String representing the player's ID
*/
public String getId() { return id; }
/**
* setter method for the id field
* @param id String representing the player's ID
*/
public void setId(String id) { this.id = id; }
/**
* getter method for the username field
* @return a String representing the player's username
*/
public String getUsername() { return username; }
/**
* setter method for the username field
* @param username String representing the player's username
*/
public void setUsername(String username) { this.username = username; }
/**
* getter method for the country field
* @return a Country object
*/
public Country getCountry() { return country; }
/**
* setter method for the country field
* @param country a Country object
*/
public void setCountry(Country country) { this.country = country; }
/**
* getter method for the joinDate field
* @return a LocalDate representing the date when the player joined the team
*/
public LocalDate getJoinDate() { return joinDate; }
/**
* setter method for the joinDate field
* @param joinDate LocalDate representing the date when the player joined the team
*/
public void setJoinDate(LocalDate joinDate) { this.joinDate = joinDate; }
/**
* getter method for the achievements field
* @return a list of Achievement objects
*/
public List<Achievement> getAchievements() { return achievements; }
/**
* setter method for the achievements field
* @param achievements a list of Achievement objects
*/
public void setAchievements(List<Achievement> achievements) { this.achievements = achievements; }
}

View File

@ -0,0 +1,155 @@
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.*;
import java.io.*;
import java.time.LocalDate;
import java.util.ArrayList;
/**
* JUnit tests to test the serialization ability of the Player class
*/
public class TestSerialization {
// assuming that the instruction "Use a test-driven development approach to implement the serialization of Player objects" only applies to the serialization, and not the other functionality
/**
* method that runs after each test and deletes the achievements.csv and players.ser files
*/
@AfterEach
void deleteFiles() {
File achievementsFile = new File("achievements.csv");
achievementsFile.delete();
File playersFile = new File("player.ser");
playersFile.delete();
}
/**
* test that creates 5 player objects, serializes them, and compares them to the deserialized objects
* @throws IOException
* @throws ClassNotFoundException
*/
@Test
void serializeFivePlayers() throws IOException, ClassNotFoundException {
// deliberately not catching potential IOExceptions - we want the tests to fail if these are thrown
FileOutputStream players_file = new FileOutputStream("players.ser");
ObjectOutputStream players_out = new ObjectOutputStream(players_file);
ObjectInputStream players_in = new ObjectInputStream(new FileInputStream("players.ser"));
ArrayList<Player> players = new ArrayList<>(); // array of players to be serialized
// creating some unique players
// player 0
players.add(new Player("0", "player0", Country.IE, LocalDate.now(),
new ArrayList<>() {{
add(new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6)));
}}
));
// player 1
players.add(new Player("1", "player1", Country.JP, LocalDate.now(),
new ArrayList<>() {{
add(new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6)));
add(new Achievement("Another Award", "An award for something else", LocalDate.of(1996, 7, 6)));
}}
));
// player 2
players.add(new Player("2", "player2", Country.UA, LocalDate.now(),
new ArrayList<>() {{
add(new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6)));
add(new Achievement("Another Award", "An award for something else", LocalDate.of(1996, 7, 6)));
add(new Achievement("Yet Another Award", "An award for something else entirely", LocalDate.of(2023, 8, 6)));
}}
));
// player 3
players.add(new Player("3", "player3", Country.AD, LocalDate.now(),
new ArrayList<>() {{
add(new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6)));
add(new Achievement("Another Award", "An award for something else", LocalDate.of(1996, 7, 6)));
add(new Achievement("Yet Another Award", "An award for something else entirely", LocalDate.of(2023, 8, 6)));
add(new Achievement("A fourth award", "An award that comes after three previous awards", LocalDate.of(2022, 8, 3)));
}}
));
// player 4
players.add(new Player("4", "player4", Country.DE, LocalDate.now(),
new ArrayList<>() {{
add(new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6)));
add(new Achievement("Another Award", "An award for something else", LocalDate.of(1996, 7, 6)));
add(new Achievement("Yet Another Award", "An award for something else entirely", LocalDate.of(2023, 8, 6)));
add(new Achievement("A fourth award", "An award that comes after three previous awards", LocalDate.of(2022, 8, 3)));
add(new Achievement("The final award", "The last award anyone will ever get", LocalDate.of(2030, 12, 25)));
}}
));
for (Player player : players) {
players_out.writeObject(player);
}
// looping over each player and comparing it to the de-serialized player
// doing this in a separate loop to separate writing and reading
for (Player player : players) {
// deliberately not catching exceptions here - we want the test to fail if exceptions are thrown
Player dplayer = (Player) players_in.readObject();
assertEquals(player, dplayer);
}
players_out.close();
players_file.close();
}
/**
* test the equals() method of the Player class
*/
@Test
void testPlayerDotEquals() {
// creating two identical players
Player player1 = new Player("0", "player0", Country.IE, LocalDate.now(),
new ArrayList<>(){{ add(new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6))); }}
);
Player player2 = new Player("0", "player0", Country.IE, LocalDate.now(),
new ArrayList<>(){{ add(new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6))); }}
);
// assertEquals uses the objects equals() method, so it suffices for this test
assertEquals(player1, player2);
}
/**
* test the equals() method of the Achievement class
*/
@Test
void testAchievementDotEquals() {
Achievement achievement1 = new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6));
Achievement achievement2 = new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6));
assertEquals(achievement1, achievement2);
}
/**
* test serializing & de-serializing just one player
* @throws IOException
* @throws ClassNotFoundException
*/
@Test
void testSerializePlayer() throws IOException, ClassNotFoundException {
// deliberately not catching potential IOExceptions - we want the tests to fail if these are thrown
FileOutputStream players_file = new FileOutputStream("players.ser");
ObjectOutputStream players_out = new ObjectOutputStream(players_file);
ObjectInputStream players_in = new ObjectInputStream(new FileInputStream("players.ser"));
Player player = new Player("0", "player0", Country.IE, LocalDate.now(),
new ArrayList<>(){{ add(new Achievement("Something Award", "An award for something that was especially something", LocalDate.of(2004, 7, 6))); }}
);
// serializing player object, de-serializing it, and comparing them
players_out.writeObject(player);
Player dplayer = (Player) players_in.readObject();
players_out.close();
players_file.close();
assertEquals(player, dplayer);
}
}