aeds2/tps/fonte/tp02/TP02Q13 - Mergesort em Java/Character.java

575 lines
19 KiB
Java

/**
* @path TP02Q01 - Classe em Java/Characters.java
* @description Java class of all characters from Harry Potter's saga with merge sort algorithm
* @author Pedro Lopes - github.com/httpspedroh
* @version 1.0
* @update 2024-04-09
*/
// ---------------------------------------------------------------------------------------------------- //
// Imports
import java.util.Scanner;
import java.util.UUID;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.text.SimpleDateFormat;
// ---------------------------------------------------------------------------------------------------- //
public class Character {
static SimpleDateFormat ddf = new SimpleDateFormat("dd-MM-yyyy");
// Global variables
public static final String FILE_PATH = "/tmp/characters.csv";
public static ArrayList<Character> allCharacters = new ArrayList<Character>();
// -------------------------- //
// Attributes
private UUID id;
private String name;
private ArrayList<String> alternateNames;
private String house;
private String ancestry;
private String species;
private String patronus;
private boolean hogwartsStaff;
private boolean hogwartsStudent;
private String actorName;
private boolean alive;
private Date birthDate;
private int yearOfBirth;
private String eyeColour;
private String gender;
private String hairColour;
private boolean wizard;
// -------------------------- //
// Empty constructor
public Character() {
this.id = UUID.randomUUID();
this.name = "";
this.alternateNames = new ArrayList<String>();
this.house = "";
this.ancestry = "";
this.species = "";
this.patronus = "";
this.hogwartsStaff = false;
this.hogwartsStudent = false;
this.actorName = "";
this.alive = false;
this.birthDate = null;
this.yearOfBirth = 0;
this.eyeColour = "";
this.gender = "";
this.hairColour = "";
this.wizard = false;
}
// Constructor
public Character(UUID id, String name, ArrayList<String> alternateNames, String house, String ancestry, String species, String patronus, boolean hogwartsStaff, boolean hogwartsStudent, String actorName, boolean alive, Date birthDate, int yearOfBirth, String eyeColour, String gender, String hairColour, boolean wizard) {
this.id = id;
this.name = name;
this.alternateNames = alternateNames;
this.house = house;
this.ancestry = ancestry;
this.species = species;
this.patronus = patronus;
this.hogwartsStaff = hogwartsStaff;
this.hogwartsStudent = hogwartsStudent;
this.actorName = actorName;
this.alive = alive;
this.birthDate = birthDate;
this.yearOfBirth = yearOfBirth;
this.eyeColour = eyeColour;
this.gender = gender;
this.hairColour = hairColour;
this.wizard = wizard;
}
// -------------------------- //
// Gets
public UUID getId() { return this.id; }
public String getName() { return this.name; }
public String getHouse() { return this.house; }
public String getAncestry() { return this.ancestry; }
public String getSpecies() { return this.species; }
public String getPatronus() { return this.patronus; }
public boolean getHogwartsStaff() { return this.hogwartsStaff; }
public boolean getHogwartsStudent() { return this.hogwartsStudent; }
public String getActorName() { return this.actorName; }
public boolean getAlive() { return this.alive; }
public Date getBirthDate() { return this.birthDate; }
public int getYearOfBirth() { return this.yearOfBirth; }
public String getEyeColour() { return this.eyeColour; }
public String getGender() { return this.gender; }
public String getHairColour() { return this.hairColour; }
public boolean getWizard() { return this.wizard; }
public String getAlternateNames() {
// Construct string e.g. {item1, item2, item3}
String alternateNames = "{";
for(int i = 0; i < this.alternateNames.size(); i++) {
alternateNames += this.alternateNames.get(i);
if(i < this.alternateNames.size() - 1) alternateNames += ", ";
}
alternateNames += "}";
return alternateNames;
}
// Sets
public void setId(UUID id) { this.id = id; }
public void setName(String name) { this.name = name; }
public void setAlternateNames(ArrayList<String> alternateNames) { this.alternateNames = alternateNames; }
public void setHouse(String house) { this.house = house; }
public void setAncestry(String ancestry) { this.ancestry = ancestry; }
public void setSpecies(String species) { this.species = species; }
public void setPatronus(String patronus) { this.patronus = patronus; }
public void setHogwartsStaff(boolean hogwartsStaff) { this.hogwartsStaff = hogwartsStaff; }
public void setHogwartsStudent(boolean hogwartsStudent) { this.hogwartsStudent = hogwartsStudent; }
public void setActorNane(String actorName) { this.actorName = actorName; }
public void setAlive(boolean alive) { this.alive = alive; }
public void setBirthDate(Date birthDate) { this.birthDate = birthDate; }
public void setYearOfBirth(int yearOfBirth) { this.yearOfBirth = yearOfBirth; }
public void setEyeColour(String eyeColour) { this.eyeColour = eyeColour; }
public void setGender(String gender) { this.gender = gender; }
public void setHairColour(String hairColour) { this.hairColour = hairColour; }
public void setWizard(boolean wizard) { this.wizard = wizard; }
// -------------------------- //
// Clone
public Character clone() { return new Character(this.id, this.name, this.alternateNames, this.house, this.ancestry, this.species, this.patronus, this.hogwartsStaff, this.hogwartsStudent, this.actorName, this.alive, this.birthDate, this.yearOfBirth, this.eyeColour, this.gender, this.hairColour, this.wizard); }
// -------------------------- //
// Print
public void print() {
System.out.println("["
+ this.getId() + " ## "
+ this.getName() + " ## "
+ this.getAlternateNames() + " ## "
+ (this.getHouse() == "" ? "N/A" : this.getHouse()) + " ## "
+ (this.getAncestry() == "" ? "N/A" : this.getAncestry()) + " ## "
+ (this.getSpecies() == "" ? "N/A" : this.getSpecies()) + " ## "
+ (this.getPatronus() == "" ? "N/A" : this.getPatronus()) + " ## "
+ (this.getHogwartsStaff() ? "true" : "false") + " ## "
+ (this.getHogwartsStudent() ? "true" : "false") + " ## "
+ (this.getActorName() == "" ? "N/A" : this.getActorName()) + " ## "
+ (this.getAlive() ? "true" : "false") + " ## "
+ (this.getBirthDate() == null ? "N/A" : ddf.format(this.getBirthDate())) + " ## "
+ (this.getYearOfBirth() == 0 ? "N/A" : this.getYearOfBirth()) + " ## "
+ (this.getEyeColour() == "" ? "N/A" : this.getEyeColour()) + " ## "
+ (this.getGender() == "" ? "N/A" : this.getGender()) + " ## "
+ (this.getHairColour() == "" ? "N/A" : this.getHairColour()) + " ## "
+ (this.getWizard() ? "true" : "false") + "]");
}
// -------------------------- //
public static ArrayList<String> extractNames(String input) {
ArrayList<String> names = new ArrayList<>();
// Clean input
String cleanedInput = input.substring(1, input.length() - 1);
// Check if input contains double quotes
if (cleanedInput.contains("\"\"")) {
String[] parts = cleanedInput.split("\", ");
for (String part : parts) names.add(part.replace("\"", "").replace("'", ""));
}
else {
// Split input by comma and space
String[] parts = cleanedInput.split(", ");
for (String part : parts) names.add(part.replace("'", ""));
}
return names;
}
// -------------------------- //
// Read
public void read(String line) {
// ---------------------- //
// Start position
int positionStart = 0;
int positionEnd = 0;
// ---------------------- //
// Set id
positionEnd = line.indexOf(";", positionStart);
this.setId(UUID.fromString(line.substring(positionStart, positionEnd)));
// ---------------------- //
// Set name
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setName(line.substring(positionStart, positionEnd));
// ---------------------- //
// Set alternate names
positionStart = positionEnd + 1;
if(line.charAt(positionStart) == '[') { // If first character is '[', has one or no names
if(line.charAt(positionStart + 1) == ']') {
positionEnd = positionStart + 2;
this.setAlternateNames(new ArrayList<String>());
}
else {
positionEnd = line.indexOf("];", positionStart);
this.setAlternateNames(extractNames(line.substring(positionStart, positionEnd++)));
}
}
// ---------------------- //
// Set house
positionStart = positionEnd;
positionEnd = line.indexOf(";", ++positionStart);
this.setHouse(line.substring(positionStart, positionEnd));
// ---------------------- //
// Set ancestry
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setAncestry(line.substring(positionStart, positionEnd));
// ---------------------- //
// Set species
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setSpecies(line.substring(positionStart, positionEnd));
// ---------------------- //
// Set patronus
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setPatronus(line.substring(positionStart, positionEnd));
// ---------------------- //
// Set hogwartsStaff
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setHogwartsStaff("VERDADEIRO".equals(line.substring(positionStart, positionEnd)));
// ---------------------- //
// Set hogwartsStudent
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setHogwartsStudent("VERDADEIRO".equals(line.substring(positionStart, positionEnd)));
// ---------------------- //
// Set actor name
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setActorNane(line.substring(positionStart, positionEnd));
// ---------------------- //
// Set alive
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setAlive("VERDADEIRO".equals(line.substring(positionStart, positionEnd)));
// ---------------------- //
// Set date of birth
positionStart = positionEnd;
positionEnd = line.indexOf(";", ++positionStart);
try { this.setBirthDate(ddf.parse(line.substring(positionStart, positionEnd))); }
catch(Exception e) { this.setBirthDate(null); }
// ---------------------- //
// Set year of birth
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
try { this.setYearOfBirth(Integer.parseInt(line.substring(positionStart, positionEnd))); }
catch(Exception e) { this.setYearOfBirth(0); }
// ---------------------- //
// Set eye colour
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setEyeColour(line.substring(positionStart, positionEnd));
// ---------------------- //
// Set gender
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setGender(line.substring(positionStart, positionEnd));
// ---------------------- //
// Set hair colour
positionStart = positionEnd + 1;
positionEnd = line.indexOf(";", positionStart);
this.setHairColour(line.substring(positionStart, positionEnd));
// ---------------------- //
// Set wizard
positionStart = positionEnd + 1;
this.setWizard("VERDADEIRO".equals(line.substring(positionStart, line.length())));
// ---------------------- //
}
// -------------------------- //
// Compare method
public int compareTo(Character other) {
// Compare by actorName
int actorNameComparison = this.actorName.compareTo(other.actorName);
// If actorName is the same, compare by name
if(actorNameComparison != 0) return actorNameComparison;
else return this.name.compareTo(other.name);
}
// ---------------------------------------------------------------------------------------------------- //
// Read all characters function
public static void startCharacters() {
// Initialize variables
try {
FileInputStream fstream = new FileInputStream(FILE_PATH);
BufferedReader br = new BufferedReader(new InputStreamReader(fstream));
// ---------------------- //
// Explode CSV file
String line = br.readLine();
while((line = br.readLine()) != null) {
// Initialize character
Character character = new Character();
// Read line
character.read(line);
// Add character to array
allCharacters.add(character);
}
// Close CSV file
fstream.close();
}
catch(IOException e) { e.printStackTrace(); }
}
// ---------------------------------------------------------------------------------------------------- //
// Search by id function
public static Character searchById(UUID id, ArrayList<Character> characters) {
// Search for character
for(int i = 0; i < characters.size(); i++) {
if(characters.get(i).getId().equals(id)) return characters.get(i);
}
return null;
}
// ---------------------------------------------------------------------------------------------------- //
// Merge sort helper function
public static int mergeSort(ArrayList<Character> arr, int l, int r) {
if(l < r) {
int mid = (l + r) / 2;
int leftComparisons = mergeSort(arr, l, mid);
int rightComparisons = mergeSort(arr, mid + 1, r);
int mergeComparisons = merge(arr, l, mid, r);
return leftComparisons + rightComparisons + mergeComparisons;
}
return 0;
}
// Merge function
public static int merge(ArrayList<Character> arr, int l, int mid, int r) {
int comparisons = 0;
int n1 = mid - l + 1;
int n2 = r - mid;
ArrayList<Character> leftArr = new ArrayList<Character>();
ArrayList<Character> rightArr = new ArrayList<Character>();
for(int i = 0; i < n1; i++) leftArr.add(arr.get(l + i));
for(int i = 0; i < n2; i++) rightArr.add(arr.get(mid + 1 + i));
int i = 0, j = 0, k = l;
while(i < n1 && j < n2) {
// Compare characters and increment comparisons
comparisons++;
if(leftArr.get(i).getActorName().compareTo(rightArr.get(j).getActorName()) < 0 ||
(leftArr.get(i).getActorName().equals(rightArr.get(j).getActorName()) &&
leftArr.get(i).getName().compareTo(rightArr.get(j).getName()) <= 0)) {
arr.set(k, leftArr.get(i));
i++;
}
else {
arr.set(k, rightArr.get(j));
j++;
}
k++;
}
while (i < n1) {
arr.set(k, leftArr.get(i));
i++;
k++;
}
while (j < n2) {
arr.set(k, rightArr.get(j));
j++;
k++;
}
return comparisons;
}
// ---------------------------------------------------------------------------------------------------- //
public static void main(String[] args) {
// ----------------------------------------------------------------- //
// #1 - Start - Read all characters in CSV file
startCharacters();
// ----------------------------------------------------------------- //
// #2 - Read input and print characters from pub.in id entries and add to mainCharacters array
// Initialize mainCharacters array
ArrayList<Character> mainCharacters = new ArrayList<Character>();
// Initialize scanner
Scanner inScanner = new Scanner(System.in);
// Initialize character
Character character = new Character();
// Read first line
String line = inScanner.nextLine();
// While line is not "FIM"
while(!line.equals("FIM")) {
// Get id
UUID id = UUID.fromString(line);
// Search for character
character = searchById(id, allCharacters);
// Print character
if(character != null) mainCharacters.add(character);
// Read line
line = inScanner.nextLine();
}
// ----------------------------------------------------------------- //
// #3 - Order mainCharacters array by key "actorName" using counting sort, in draw case, order by key "name"
// Start benchmark
long startTime = System.currentTimeMillis();
int comparisons = 0;
// ----------------- //
// Merge sort
comparisons = mergeSort(mainCharacters, 0, mainCharacters.size() - 1);
// ----------------- //
// Save benchmark in file
Arq.openWrite("753045_mergesort.txt");
Arq.print("753045\t" + (System.currentTimeMillis() - startTime) + "ms\t" + comparisons);
Arq.close();
// ----------------- //
// Print mainCharacters array
for(int i = 0; i < mainCharacters.size(); i++) mainCharacters.get(i).print();
// ----------------------------------------------------------------- //
// Close scanner
inScanner.close();
}
}
// ---------------------------------------------------------------------------------------------------- //