Added a ton of documentation.
This commit is contained in:
		
							parent
							
								
									16b47f7e40
								
							
						
					
					
						commit
						0ecbdc1ec1
					
				
							
								
								
									
										6
									
								
								pom.xml
								
								
								
								
							
							
						
						
									
										6
									
								
								pom.xml
								
								
								
								
							| 
						 | 
					@ -37,6 +37,12 @@
 | 
				
			||||||
            <artifactId>commons-email</artifactId>
 | 
					            <artifactId>commons-email</artifactId>
 | 
				
			||||||
            <version>RELEASE</version>
 | 
					            <version>RELEASE</version>
 | 
				
			||||||
        </dependency>
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.jetbrains</groupId>
 | 
				
			||||||
 | 
					            <artifactId>annotations</artifactId>
 | 
				
			||||||
 | 
					            <version>16.0.2</version>
 | 
				
			||||||
 | 
					            <scope>compile</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
    </dependencies>
 | 
					    </dependencies>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
</project>
 | 
					</project>
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ public class Main {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final Logger logger = Logger.getGlobal();
 | 
					    private static final Logger logger = Logger.getGlobal();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void main(String[] args) throws IOException {
 | 
					    public static void main(String[] args) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Parsed command line arguments.
 | 
					        // Parsed command line arguments.
 | 
				
			||||||
        Map<String, String> userOptions = CommandLine.parseArgs(args);
 | 
					        Map<String, String> userOptions = CommandLine.parseArgs(args);
 | 
				
			||||||
| 
						 | 
					@ -32,11 +32,20 @@ public class Main {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        logger.info("Initializer for Github Repositories in Educational Organizations.");
 | 
					        logger.info("Initializer for Github Repositories in Educational Organizations.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        List<Team> teams = TeamGenerator.generateFromCSV(
 | 
					        // Get teams from CSV file.
 | 
				
			||||||
 | 
					        List<Team> teams;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            teams = TeamGenerator.generateFromCSV(
 | 
				
			||||||
                    userOptions.get("input"),
 | 
					                    userOptions.get("input"),
 | 
				
			||||||
                    Integer.parseInt(userOptions.get("teamsize"))
 | 
					                    Integer.parseInt(userOptions.get("teamsize"))
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            logger.info("Teams created: " + teams);
 | 
					            logger.info("Teams created: " + teams);
 | 
				
			||||||
 | 
					        } catch (IOException | ArrayIndexOutOfBoundsException e) {
 | 
				
			||||||
 | 
					            logger.severe("Unable to generate teams from CSV file, exiting.");
 | 
				
			||||||
 | 
					            System.exit(1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,16 +38,40 @@ public class TeamGenerator {
 | 
				
			||||||
            logger.severe("Invalid team size.");
 | 
					            logger.severe("Invalid team size.");
 | 
				
			||||||
            throw new IllegalArgumentException("Team size must be greater than or equal to 1. Got " + teamSize);
 | 
					            throw new IllegalArgumentException("Team size must be greater than or equal to 1. Got " + teamSize);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        logger.finest("Parsing CSV file.");
 | 
					        logger.fine("Parsing CSV file.");
 | 
				
			||||||
        Iterable<CSVRecord> records = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(new FileReader(filename));
 | 
					        Iterable<CSVRecord> records = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(new FileReader(filename));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        logger.finest("Reading all records into map.");
 | 
					        logger.fine("Reading all records into map.");
 | 
				
			||||||
        Map<Integer, Student> studentMap = readAllStudents(records, teamSize);
 | 
					        Map<Integer, Student> studentMap;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            studentMap = readAllStudents(records, teamSize);
 | 
				
			||||||
 | 
					        } catch (ArrayIndexOutOfBoundsException e) {
 | 
				
			||||||
 | 
					            logger.severe("Team size does not match column count in records.");
 | 
				
			||||||
 | 
					            throw new IllegalArgumentException("Team size does not match column count in records.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        logger.finest("Generating all valid teams from student map.");
 | 
					
 | 
				
			||||||
 | 
					        logger.fine("Generating all valid teams from student map.");
 | 
				
			||||||
        return generateAllValidTeams(studentMap, teamSize);
 | 
					        return generateAllValidTeams(studentMap, teamSize);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Generates all teams, given a mapping of all students to their student numbers. It will first try to generate
 | 
				
			||||||
 | 
					     * teams from students' preferences, and then take all students who are not in a team, and merge them into as many
 | 
				
			||||||
 | 
					     * teams as possible, and grouping all remainder single students into one final team.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * The algorithm works as follows:
 | 
				
			||||||
 | 
					     * For each student, try to create a team from their preferred partner numbers.
 | 
				
			||||||
 | 
					     *      Check if the team is valid by confirming that all their partners have the same preferred partners.
 | 
				
			||||||
 | 
					     *      If that's true, add this team, and remove all students in it from the list of singles.
 | 
				
			||||||
 | 
					     *      If it's not true, then the students will not be removed from the list of singles, and a warning is given.
 | 
				
			||||||
 | 
					     * After all students with preferred partners are placed in teams, the single students are merged, and their teams
 | 
				
			||||||
 | 
					     * are added afterwards.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param studentMap A mapping for each student to their student number.
 | 
				
			||||||
 | 
					     * @param teamSize The preferred maximum size for a team.
 | 
				
			||||||
 | 
					     * @return A list of teams, most of which are of teamSize size.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private static List<Team> generateAllValidTeams(Map<Integer, Student> studentMap, int teamSize) {
 | 
					    private static List<Team> generateAllValidTeams(Map<Integer, Student> studentMap, int teamSize) {
 | 
				
			||||||
        List<Student> singleStudents = new ArrayList<>(studentMap.values());
 | 
					        List<Student> singleStudents = new ArrayList<>(studentMap.values());
 | 
				
			||||||
        List<Team> teams = new ArrayList<>();
 | 
					        List<Team> teams = new ArrayList<>();
 | 
				
			||||||
| 
						 | 
					@ -56,13 +80,15 @@ public class TeamGenerator {
 | 
				
			||||||
        // For each student, try to make a team from its preferred partners.
 | 
					        // For each student, try to make a team from its preferred partners.
 | 
				
			||||||
        for (Map.Entry<Integer, Student> e : studentMap.entrySet()) {
 | 
					        for (Map.Entry<Integer, Student> e : studentMap.entrySet()) {
 | 
				
			||||||
            Team t = e.getValue().getPreferredTeam(studentMap);
 | 
					            Team t = e.getValue().getPreferredTeam(studentMap);
 | 
				
			||||||
 | 
					            logger.finest("Checking if student's preferred team is valid: " + t.getStudents());
 | 
				
			||||||
            // Check if the team is of a valid size, and is not a duplicate.
 | 
					            // Check if the team is of a valid size, and is not a duplicate.
 | 
				
			||||||
            // Note that at this stage, singles are treated as teams of 1, and thus not valid for any teamSize > 1.
 | 
					            // Note that at this stage, singles are treated as teams of 1, and thus not valid for any teamSize > 1.
 | 
				
			||||||
            if (t.isValid(teamSize) && !teams.contains(t)) {
 | 
					            if (t.isValid(teamSize) && !teams.contains(t)) {
 | 
				
			||||||
                t.setId(teamCount++);
 | 
					 | 
				
			||||||
                // Once we know this team is completely valid, we remove all the students in it from the list of singles.
 | 
					                // Once we know this team is completely valid, we remove all the students in it from the list of singles.
 | 
				
			||||||
 | 
					                t.setId(teamCount++);
 | 
				
			||||||
                singleStudents.removeAll(t.getStudents());
 | 
					                singleStudents.removeAll(t.getStudents());
 | 
				
			||||||
                teams.add(t);
 | 
					                teams.add(t);
 | 
				
			||||||
 | 
					                logger.fine("Created team: " + t);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -70,15 +96,27 @@ public class TeamGenerator {
 | 
				
			||||||
        return teams;
 | 
					        return teams;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Given a list of single students, this method generates as many teams as possible. that are as close to the team
 | 
				
			||||||
 | 
					     * size as possible.
 | 
				
			||||||
 | 
					     * @param singleStudents A list of students who have no preferred partners.
 | 
				
			||||||
 | 
					     * @param teamSize The preferred team size.
 | 
				
			||||||
 | 
					     * @param teamIndex The current number used in assigning an id to the team.
 | 
				
			||||||
 | 
					     * @return A list of teams comprising of single students.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private static List<Team> mergeSingleStudents(List<Student> singleStudents, int teamSize, int teamIndex) {
 | 
					    private static List<Team> mergeSingleStudents(List<Student> singleStudents, int teamSize, int teamIndex) {
 | 
				
			||||||
        List<Team> teams = new ArrayList<>();
 | 
					        List<Team> teams = new ArrayList<>();
 | 
				
			||||||
        while (!singleStudents.isEmpty()) {
 | 
					        while (!singleStudents.isEmpty()) {
 | 
				
			||||||
            Team t = new Team();
 | 
					            Team t = new Team();
 | 
				
			||||||
            t.setId(teamIndex++);
 | 
					            t.setId(teamIndex++);
 | 
				
			||||||
 | 
					            logger.fine("Creating new team of single students: " + t);
 | 
				
			||||||
            while (t.getStudentCount() < teamSize && !singleStudents.isEmpty()) {
 | 
					            while (t.getStudentCount() < teamSize && !singleStudents.isEmpty()) {
 | 
				
			||||||
                t.addStudent(singleStudents.remove(0));
 | 
					                Student s = singleStudents.remove(0);
 | 
				
			||||||
 | 
					                logger.finest("Single student: " + s);
 | 
				
			||||||
 | 
					                t.addStudent(s);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            teams.add(t);
 | 
					            teams.add(t);
 | 
				
			||||||
 | 
					            logger.fine("Created team: " + t);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return teams;
 | 
					        return teams;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -88,10 +126,12 @@ public class TeamGenerator {
 | 
				
			||||||
     * @param records The records in the CSV file.
 | 
					     * @param records The records in the CSV file.
 | 
				
			||||||
     * @param teamSize The preferred size of teams, or rather, the expected number of partners.
 | 
					     * @param teamSize The preferred size of teams, or rather, the expected number of partners.
 | 
				
			||||||
     * @return A map of all students in the file.
 | 
					     * @return A map of all students in the file.
 | 
				
			||||||
 | 
					     * @throws ArrayIndexOutOfBoundsException if the teamSize does not work with the columns in the record.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private static Map<Integer, Student> readAllStudents(Iterable<CSVRecord> records, int teamSize) {
 | 
					    private static Map<Integer, Student> readAllStudents(Iterable<CSVRecord> records, int teamSize) throws ArrayIndexOutOfBoundsException {
 | 
				
			||||||
        Map<Integer, Student> studentMap = new HashMap<>();
 | 
					        Map<Integer, Student> studentMap = new HashMap<>();
 | 
				
			||||||
        for (CSVRecord record : records) {
 | 
					        for (CSVRecord record : records) {
 | 
				
			||||||
 | 
					            logger.finest("Read record: " + record);
 | 
				
			||||||
            List<Integer> preferredIds = new ArrayList<>();
 | 
					            List<Integer> preferredIds = new ArrayList<>();
 | 
				
			||||||
            if (record.get(5).equals("Yes")) {
 | 
					            if (record.get(5).equals("Yes")) {
 | 
				
			||||||
                int columnOffset = 6;
 | 
					                int columnOffset = 6;
 | 
				
			||||||
| 
						 | 
					@ -102,6 +142,7 @@ public class TeamGenerator {
 | 
				
			||||||
            Student s = new Student(Integer.parseInt(record.get(3)), record.get(2), record.get(1), record.get(4), preferredIds);
 | 
					            Student s = new Student(Integer.parseInt(record.get(3)), record.get(2), record.get(1), record.get(4), preferredIds);
 | 
				
			||||||
            studentMap.put(s.getNumber(), s);
 | 
					            studentMap.put(s.getNumber(), s);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        logger.fine("Read " + studentMap.size() + " students from records.");
 | 
				
			||||||
        return studentMap;
 | 
					        return studentMap;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue