import java.util.*; interface ScorableWork { Integer getScore(); int getStudentId(); } class StudentComparator implements Comparator<ScorableWork> { public int compare(final ScorableWork sw1, final ScorableWork sw2) { final int score1 = sw1.getScore(); final int score2 = sw2.getScore(); if (score1 > score2) return -1; else if (score1 < score2) return 1; else { final int id1 = sw1.getStudentId(); final int id2 = sw2.getStudentId(); if (id1 < id2) return -1; else if (id1 > id2) return 1; else return 0; } } } class StudentAnswers implements ScorableWork { private final int studentId; private final int[] answerArray; private Integer score = null; public StudentAnswers(final int studentId, final int[] answerArray) { this.studentId = studentId; this.answerArray = answerArray; } public StudentAnswers gradeUsing(AnswerKey key) { score = key.countNumberCorrect(answerArray); return this; } public int getStudentId() { return studentId; } public Integer getScore() { return score; } public Integer getPercentCorrect() { if (score == null) return null; return (score * 100) / answerArray.length; } public String toString() { final StringBuilder sb = new StringBuilder("Student #" + studentId + ":"); for (int answer : answerArray) { sb.append(" " + answer); } sb.append(" " + getPercentCorrect() + "%"); return sb.toString() + "\n"; } } class AnswerKey { private final int[] answerArray; public AnswerKey(final int[] answerArray) { this.answerArray = answerArray; } public int countNumberCorrect(final int[] answerArray) { if (answerArray == null || this.answerArray == null) return 0; final int n = Math.min(answerArray.length, this.answerArray.length); int score = 0; for (int i = 0; i < n; i++) { if (this.answerArray[i] == answerArray[i]) score++; } return score; } public String toString() { final StringBuilder sb = new StringBuilder("Answer Key:"); for (int answer : answerArray) { sb.append(" " + answer); } return sb.toString() + "\n"; } } class Exam { private final static StudentComparator comparator = new StudentComparator(); private final int examId; private final AnswerKey answerKey; private final List<StudentAnswers> studentAnswersList; private final int numQuestions; private final int numStudents; public Exam(final int examId, final int[][] answerGrid) { this.examId = examId; numQuestions = answerGrid[0].length; numStudents = answerGrid.length - 1; answerKey = new AnswerKey(answerGrid[0]); studentAnswersList = new ArrayList<StudentAnswers>(); for (int i = 0; i < numStudents; i++) { final int studentId = i + 1; final StudentAnswers studentAnswers = new StudentAnswers(studentId, answerGrid[studentId]); studentAnswersList.add(studentAnswers.gradeUsing(answerKey)); } Collections.sort(studentAnswersList, comparator); } public String toString() { final StringBuilder sb = new StringBuilder(answerKey.toString()); for (StudentAnswers studentAnswers: studentAnswersList) { sb.append(studentAnswers.toString()); } return sb.toString(); } } abstract class ExamAnswerCube { protected final int numExams, numChoices, numQuestions, numStudents; private final int[][][] answerCube; private final List<Exam> exams = new ArrayList<Exam>(); public ExamAnswerCube(final int numChoices, final int numQuestions, final int numStudents, final int numExams) { this.numChoices = numChoices; this.numQuestions = numQuestions; this.numStudents = numStudents; this.numExams = numExams; answerCube = getAllAnswerSetsForAllExams(); int examId = 0; for (int[][] answerGrid : answerCube) exams.add(new Exam(++examId, answerGrid)); } /** Returns a 3-dimensional array of answers. * * First dimension: * answerSets[0] is the set of answer sets for the first exam. * answerSets[1] is the set of answer sets for the second exam. * etc. * * Second dimension: * answerSets[i][0] is the answer key for an exam. * answerSets[i][j], j > 0, is the jth student's set of answers. * * Third dimension: * answerSets[i][j][0] is an answer to the first question of an exam. * answerSets[i][j][1] is an answer to the second question of an exam. * etc. */ private int[][][] getAllAnswerSetsForAllExams() { int[][][] answerSets = new int[numExams][][]; for (int i = 0; i < numExams; i = i + 1) { answerSets[i] = getAllAnswerSetsForOneExam(); } return answerSets; } private int[][] getAllAnswerSetsForOneExam() { int[][] answerSets = new int[numStudents + 1][]; answerSets[0] = getAnswerKey(); for (int i = 1; i <= numStudents; i = i + 1) { answerSets[i] = getStudentAnswers(); } return answerSets; } protected abstract int[] getAnswerKey(); protected abstract int[] getStudentAnswers(); public String toString() { StringBuilder sb = new StringBuilder(); for (Exam exam : exams) sb.append(exam.toString() + "\n"); return sb.toString(); } } final class RandomExamAnswerCube extends ExamAnswerCube { public RandomExamAnswerCube(final int numChoices, final int numQuestions, final int numStudents, final int numExams) { super(numChoices, numQuestions, numStudents, numExams); } protected int[] getAnswerKey() { return getRandomAnswers(); } protected int[] getStudentAnswers() { return getRandomAnswers(); } private int[] getRandomAnswers() { // An answer is an integer in the range [0, numChoices). // answerSet[0] is the answer for the first question. // answerSet[1] is the answer for the second question. // etc. int[] answerSet = new int[numQuestions]; for (int i = 0; i < numQuestions; i = i + 1) { answerSet[i] = (int)(Math.random() * numChoices); } return answerSet; } } public class MyClass { public static void main(final String args[]) { final int n = args.length, numChoices = n > 0 ? Integer.parseInt(args[0]) : 5, numQuestions = n > 1 ? Integer.parseInt(args[1]) : 10, numStudents = n > 2 ? Integer.parseInt(args[2]) : 25, numExams = n > 3 ? Integer.parseInt(args[3]) : 1; ExamAnswerCube cube = new RandomExamAnswerCube(numChoices, numQuestions, numStudents, numExams); System.out.println(cube); } }