diff --git a/registrar/src/registrar/Main.java b/registrar/src/registrar/Main.java index fcedc41..347d41d 100644 --- a/registrar/src/registrar/Main.java +++ b/registrar/src/registrar/Main.java @@ -9,6 +9,30 @@ class Examples { new Cons(2, new Cons(3, new Mt())) ); + Teacher singer; + Teacher wormwood; + + Course singing; + Course arithmetic; + Course clobbering; + + Student calvin; + Student hobbes; + Student susie; + + void init() { + singer = new Teacher("Mr. Singer"); + wormwood = new Teacher("Ms. Wormwood"); + + singing = new Course("Singing", singer); + arithmetic = new Course("Arithmetic", wormwood); + clobbering = new Course("Introduction to Clobbering", wormwood); + + calvin = new Student("Calvin"); + hobbes = new Student("Hobbes"); + susie = new Student("Susie Derkins"); + } + void testILoUniqAppend(Tester t) { t.checkExpect(testList.uniqAppend(2), testList); t.checkExpect( @@ -25,6 +49,90 @@ class Examples { ) ); } + + void testILoHas(Tester t) { + t.checkExpect(testList.has(2), true); + t.checkExpect(testList.has(6), false); + } + + void testILoDropFirst(Tester t) { + t.checkExpect( + testList.dropFirst(2), + new Cons(1, new Cons(3, new Mt())) + ); + } + + void testCourse(Tester t) { + init(); + t.checkExpect(singing.teacher, singer); + t.checkExpect( + singer.courses, + new Cons(singing, new Mt()) + ); + } + + void testStudentEnroll(Tester t) { + init(); + calvin.enroll(arithmetic); + t.checkExpect( + calvin.courses, + new Cons(arithmetic, new Mt()) + ); + t.checkExpect( + arithmetic.students, + new Cons(calvin, new Mt()) + ); + t.checkExpect(calvin.takesCourse(arithmetic), true); + calvin.enroll(arithmetic); + t.checkExpect( + calvin.courses, + new Cons(arithmetic, new Mt()) + ); + t.checkExpect( + arithmetic.students, + new Cons(calvin, new Mt()) + ); + + singing.setTeacher(wormwood); + t.checkExpect(singing.teacher, wormwood); + t.checkExpect( + wormwood.courses, + new Cons( + arithmetic, + new Cons( + clobbering, + new Cons(singing, new Mt()) + ) + ) + ); + t.checkExpect(singer.courses, new Mt()); + } + + void testStudentClassmates(Tester t) { + init(); + + calvin.enroll(singing); + hobbes.enroll(singing); + susie.enroll(arithmetic); + + t.checkExpect(calvin.classmates(hobbes), true); + t.checkExpect(hobbes.classmates(calvin), true); + t.checkExpect(calvin.classmates(susie), false); + t.checkExpect(susie.classmates(hobbes), false); + } + + void testTeacherDejaVu(Tester t) { + init(); + + calvin.enroll(arithmetic); + calvin.enroll(clobbering); + hobbes.enroll(clobbering); + susie.enroll(singing); + + t.checkExpect(wormwood.dejavu(calvin), true); + t.checkExpect(singer.dejavu(susie), false); + t.checkExpect(wormwood.dejavu(hobbes), false); + } } class School { @@ -46,7 +154,7 @@ class Course { Course(String name, Teacher teacher, ILo students) { this.name = name; this.teacher = teacher; - this.teacher.assignCourse(this); + teacher.assignCourse(this); this.students = students; } @@ -54,6 +162,29 @@ class Course { Course(String name, Teacher teacher) { this(name, teacher, new Mt()); } + + // Effect: Adds a student. + void addStudent(Student student) { + // Make sure there's no way to add a student to a course without + // being enrolled. + if (!student.takesCourse(this)) student.enroll(this); + this.students = this.students.uniqAppend(student); + } + + // Effect: Sets the teacher. + void setTeacher(Teacher newTeacher) { + if (!newTeacher.equals(this.teacher)) { + this.teacher.removeCourse(this); + this.teacher = newTeacher; + this.teacher.assignCourse(this); + } + // If the teacher is the same, do nothing. + } + + // Is this Course taught by the Teacher? + boolean taughtBy(Teacher teacher) { + return this.teacher.equals(teacher); + } } class Teacher { @@ -73,11 +204,25 @@ class Teacher { // Effect: Assigns the given Course to this Teacher. void assignCourse(Course course) { - this.courses.uniqAppend(course); + if (!course.taughtBy(this)) course.setTeacher(this); + this.courses = this.courses.uniqAppend(course); } - // Effect: Enrolls the given Student in this Course. - void enroll(Student student) {} + // Does this Teacher teach the Course? + boolean teaches(Course course) { + return this.courses.has(course); + } + + // Effect: Removes a Course from this Teacher. + // ASSUMES THIS TEACHER WILL BE REPLACED. + void removeCourse(Course course) { + this.courses = this.courses.dropFirst(course); + } + + // Is the Student in one or more of this Teacher's Courses? + boolean dejavu(Student student) { + return this.courses.moreMap(new StudentTakesCourse(student)); + } } class Student { @@ -99,14 +244,53 @@ class Student { // Effect: Enrolls this student in the given course. void enroll(Course course) { - course.enroll(this); - this.courses.uniqAppend(course); + this.courses = this.courses.uniqAppend(course); + course.addStudent(this); + } + + // Does the student take this course? + boolean takesCourse(Course course) { + return this.courses.has(course); + } + + // Are they in any of the same Courses as this Student? + boolean classmates(Student student) { + return this.courses.orMap(new StudentTakesCourse(student)); + } +} + +interface Question { + boolean ask(A a); +} + +class StudentTakesCourse implements Question { + + Student student; + + StudentTakesCourse(Student student) { + this.student = student; + } + + public boolean ask(Course course) { + return this.student.takesCourse(course); } } interface ILo { // Uniquely append an element (i.e., leaves list unchanged if element is already present.) ILo uniqAppend(A a); + + // Drop first instance of element from a list. + ILo dropFirst(A a); + + // Does the list have this? + boolean has(A a); + + // Do any of the elements satisfy the predicate? + boolean orMap(Question question); + + // Do more than one of the elements satisfy the predicate? + boolean moreMap(Question question); } class Cons implements ILo { @@ -123,6 +307,23 @@ class Cons implements ILo { if (this.first.equals(a)) return this; else return new Cons(this.first, this.rest.uniqAppend(a)); } + + public ILo dropFirst(A a) { + if (this.first.equals(a)) return this.rest; + else return new Cons(this.first, this.rest.dropFirst(a)); + } + + public boolean has(A a) { + return this.first.equals(a) || this.rest.has(a); + } + + public boolean orMap(Question question) { + return question.ask(this.first) || this.rest.orMap(question); + } + + public boolean moreMap(Question question) { + return question.ask(this.first) && this.rest.orMap(question); + } } class Mt implements ILo { @@ -130,4 +331,20 @@ class Mt implements ILo { public ILo uniqAppend(A a) { return new Cons(a, this); } + + public ILo dropFirst(A a) { + throw new Error("Could not find element to drop in list."); + } + + public boolean has(A a) { + return false; + } + + public boolean orMap(Question question) { + return false; + } + + public boolean moreMap(Question question) { + return false; + } }