diff --git a/docs/README.md b/docs/README.md index e69de29..e596bc1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -0,0 +1,26 @@ +# 기능 목록 + +## 1. 기능 목록 + +- [x] 사용자로부터 과목 정보를 입력받아 저장한다. +- [x] 저장된 과목 목록 정보를 출력한다. +- [x] 저장된 과목 목록 정보를 통해 취득 학점을 출력한다. +- [x] 저장된 과목 목록 정보를 통해 평점 평균을 출력한다. +- [x] 저장된 과목 목록 정보를 통해 전공 평점 평균을 출력한다. +- [x] 사용자가 잘못된 값을 입력할 경우 `IllegalArgumentException`을 발생시키고 애플리케이션을 종료한다. + +#### 1.1 IllegalArgumentException +- [x] 과목명은 공백 포함 10자 이내로 입력한다. +- [x] 과목명은 공백만으로 구성될 수 없다. +- [x] 학점은 1 ~ 4 사이의 정수만 입력한다. +- [x] 성적은 A+, A0, A-, B+, B0, B-, C+, C0, C-, D+, D0, D-, F, P, NP 중 하나만 입력한다. + +#### 1.2 취득 학점 계산 +- [x] NP, F 성적은 취득 학점에서 제외된다. + +#### 1.3 평점 평균 계산 +- [x] 평점평균 계산 공식 + - `평점평균` = `과목성적가중치의 총합` / `과목학점의 총합` + - `과목성적가중치` = `과목평점` * `과목학점` +- [x] P/NP 과목은 평점평균 계산에서 제외한다. +- [x] 평점평균은 소수점 셋째 자리에서 반올림하여 둘째 자리까지 표현한다. \ No newline at end of file diff --git a/src/main/java/gpacalc/Application.java b/src/main/java/gpacalc/Application.java index 57e79e1..5d07529 100644 --- a/src/main/java/gpacalc/Application.java +++ b/src/main/java/gpacalc/Application.java @@ -3,5 +3,6 @@ public class Application { public static void main(String[] args) { //TODO: 구현 + new GradeCalculator().run(); } } diff --git a/src/main/java/gpacalc/Grade.java b/src/main/java/gpacalc/Grade.java new file mode 100644 index 0000000..9b0dd86 --- /dev/null +++ b/src/main/java/gpacalc/Grade.java @@ -0,0 +1,39 @@ +package gpacalc; + +public enum Grade { + A_PLUS("A+",4.5), + A_ZERO("A0",4.0), + B_PLUS("B+",3.5), + B_ZERO("B0",3.0), + C_PLUS("C+",2.5), + C_ZERO("C0",2.0), + D_PLUS("D+",1.5), + D_ZERO("D0",1.0), + P("P",0.0), + NP("NP",0.0), + F("F",0.0); + private final String grade; + private final double score; + + Grade(String grade, double score){ + this.grade = grade; + this.score = score; + } + + public static Grade of(String grade){ + for(Grade g : Grade.values()){ + if(g.grade.equals(grade)){ + return g; + } + } + throw new IllegalArgumentException("잘못된 성적 입력입니다."); + } + + public double getScore(){ + return this.score; + } + + public String getGrade(){ + return this.grade; + } +} diff --git a/src/main/java/gpacalc/GradeCalculator.java b/src/main/java/gpacalc/GradeCalculator.java new file mode 100644 index 0000000..50ab7fe --- /dev/null +++ b/src/main/java/gpacalc/GradeCalculator.java @@ -0,0 +1,47 @@ +package gpacalc; + +public class GradeCalculator { + private Subject[] majorSubjects; + private Subject[] nonMajorSubjects; + private int acquiredCredit; + private double majorGPA; + + private double gpa; + + public void run() { + getSubjects(); + + calculateAcquiredCreditAndGPA(); + + printSubjectsResult(); + + printCalculatedResult(); + } + + private void getSubjects() { + majorSubjects=GradeCalculatorIO.inputMajorSubjects(); + System.out.println(); + + nonMajorSubjects=GradeCalculatorIO.inputNonMajorSubjects(); + System.out.println(); + } + + private void printSubjectsResult() { + System.out.println("<과목 목록>"); + GradeCalculatorIO.printSubjects(majorSubjects,"전공"); + GradeCalculatorIO.printSubjects(nonMajorSubjects,"교양"); + System.out.println(); + } + + private void printCalculatedResult() { + GradeCalculatorIO.printAcquiredCredit(acquiredCredit); + GradeCalculatorIO.printGPA(gpa); + GradeCalculatorIO.printMajorGPA(majorGPA); + } + + private void calculateAcquiredCreditAndGPA() { + acquiredCredit=GradeCalculatorUtil.calculateAcquiredCredit(majorSubjects,nonMajorSubjects); + gpa=GradeCalculatorUtil.calculateGPA(majorSubjects,nonMajorSubjects); + majorGPA=GradeCalculatorUtil.calculateGPA(majorSubjects,new Subject[0]); + } +} diff --git a/src/main/java/gpacalc/GradeCalculatorIO.java b/src/main/java/gpacalc/GradeCalculatorIO.java new file mode 100644 index 0000000..a37dc84 --- /dev/null +++ b/src/main/java/gpacalc/GradeCalculatorIO.java @@ -0,0 +1,49 @@ +package gpacalc; + +import camp.nextstep.edu.missionutils.Console; + +public class GradeCalculatorIO { + public static Subject[] inputMajorSubjects() { + System.out.println("전공 과목명과 이수학점, 평점을 입력해주세요(예시: 프로그래밍언어론-3-A+,소프트웨어공학-3-B+):"); + return inputToSubjects(Console.readLine()); + } + + public static Subject[] inputNonMajorSubjects() { + System.out.println("교양 과목명과 이수학점, 평점을 입력해주세요(예시: 선형대수학-3-C0,인간관계와자기성장-3-P):"); + return inputToSubjects(Console.readLine()); + } + + private static Subject[] inputToSubjects(String input){ + String[] subjectStrings = input.split(","); + Subject[] subjects = new Subject[subjectStrings.length]; + for (int i = 0; i < subjectStrings.length; i++) { + String[] subjectString = subjectStrings[i].split("-"); + subjects[i] = new Subject(subjectString[0], Integer.parseInt(subjectString[1]), Grade.of(subjectString[2])); + } + return subjects; + } + + public static void printSubjects(Subject[] subjects, String type){ + for (Subject subject : subjects) { + System.out.println("["+type+"] "+subject.getName() + "," + subject.getCredit() + "," + subject.getGrade().getGrade()); + } + } + + public static void printAcquiredCredit(int acquiredCredit){ + System.out.println("<취득학점>"); + System.out.println(acquiredCredit + "학점"); + System.out.println(); + } + + public static void printGPA(double gpa){ + System.out.println("<평점평균>"); + System.out.println(String.format("%.2f", gpa) + " / 4.5"); + System.out.println(); + } + + public static void printMajorGPA(double majorGPA){ + System.out.println("<전공 평점평균>"); + System.out.println(String.format("%.2f", majorGPA) + " / 4.5"); + System.out.println(); + } +} diff --git a/src/main/java/gpacalc/GradeCalculatorUtil.java b/src/main/java/gpacalc/GradeCalculatorUtil.java new file mode 100644 index 0000000..3d8ed46 --- /dev/null +++ b/src/main/java/gpacalc/GradeCalculatorUtil.java @@ -0,0 +1,48 @@ +package gpacalc; + +public class GradeCalculatorUtil { + public static int calculateAcquiredCredit(Subject[] majorSubjects, Subject[] nonMajorSubjects) { + int majorCredit = 0; + int nonMajorCredit = 0; + for (Subject subject : majorSubjects) { + majorCredit += subject.getAcquiredCredit(); + } + for (Subject subject : nonMajorSubjects) { + nonMajorCredit += subject.getAcquiredCredit(); + } + return majorCredit + nonMajorCredit; + } + + private static int calculateTotalGradeCredit(Subject[] majorSubjects, Subject[] nonMajorSubjects) { + int majorCredit = 0; + int nonMajorCredit = 0; + for (Subject subject : majorSubjects) { + if(subject.getGrade() != Grade.NP && subject.getGrade() != Grade.P) + majorCredit += subject.getCredit(); + } + for (Subject subject : nonMajorSubjects) { + if(subject.getGrade() != Grade.NP && subject.getGrade() != Grade.P) + nonMajorCredit += subject.getCredit(); + } + return majorCredit + nonMajorCredit; + } + + private static double calculateWeightedTotalGrade(Subject[] majorSubjects, Subject[] nonMajorSubjects) { + double majorTotalGrade = 0; + double nonMajorTotalGrade = 0; + for (Subject subject : majorSubjects) { + majorTotalGrade += subject.getGrade().getScore() * subject.getCredit(); + } + for (Subject subject : nonMajorSubjects) { + nonMajorTotalGrade += subject.getGrade().getScore() * subject.getCredit(); + } + return majorTotalGrade + nonMajorTotalGrade; + } + + public static double calculateGPA(Subject[] majorSubjects, Subject[] nonMajorSubjects) { + if (calculateTotalGradeCredit(majorSubjects, nonMajorSubjects) == 0) { + return 0; + } + return calculateWeightedTotalGrade(majorSubjects, nonMajorSubjects) / calculateTotalGradeCredit(majorSubjects, nonMajorSubjects); + } +} diff --git a/src/main/java/gpacalc/Subject.java b/src/main/java/gpacalc/Subject.java new file mode 100644 index 0000000..73dba37 --- /dev/null +++ b/src/main/java/gpacalc/Subject.java @@ -0,0 +1,54 @@ +package gpacalc; + + +public class Subject { + + private static final int MAX_CREDIT = 4; + + private static final int MIN_CREDIT = 1; + + private static final int MAX_NAME_LENGTH = 10; + + private final String name; + private final int credit; + private final Grade grade; + + public Subject(String name, int credit, Grade grade) { + checkNameValidation(name); + checkCreditValidation(credit); + this.name = name; + this.credit = credit; + this.grade = grade; + } + + private void checkNameValidation(String name) { + if (name.length()>MAX_NAME_LENGTH || name.isBlank()) { + throw new IllegalArgumentException("잘못된 과목명 입력입니다."); + } + } + + private void checkCreditValidation(int credit) { + if (credit < MIN_CREDIT || credit > MAX_CREDIT) { + throw new IllegalArgumentException("잘못된 학점 입력입니다."); + } + } + + public String getName() { + return name; + } + + public int getCredit() { + return credit; + } + + public Grade getGrade() { + return grade; + } + + public int getAcquiredCredit() { + if (grade == Grade.NP || grade == Grade.F) { + return 0; + } + return credit; + } +} diff --git a/src/test/java/gpacalc/GradeCalculatorUtilTest.java b/src/test/java/gpacalc/GradeCalculatorUtilTest.java new file mode 100644 index 0000000..875ab40 --- /dev/null +++ b/src/test/java/gpacalc/GradeCalculatorUtilTest.java @@ -0,0 +1,44 @@ +package gpacalc; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class GradeCalculatorUtilTest { + //given + Subject [] majorSubjects1; + Subject [] majorSubjects2; + Subject [] nonMajorSubjects1; + Subject [] nonMajorSubjects2; + @BeforeEach + void setup(){ + majorSubjects1 = new Subject[]{ + new Subject("데이타구조", 3, Grade.A_ZERO), + new Subject("자바프로그래밍언어", 3, Grade.B_PLUS) + }; + nonMajorSubjects1 = new Subject[]{ + new Subject("미술의이해", 3, Grade.A_PLUS), + new Subject("교양특론3", 3, Grade.NP) + }; + majorSubjects2 = new Subject[]{ + new Subject("데이타구조", 3, Grade.A_ZERO) + }; + nonMajorSubjects2 = new Subject[]{ + new Subject("미술의이해", 2, Grade.B_ZERO) + }; + } + @Test + void 평점평균계산테스트() { + assertEquals(4.0, GradeCalculatorUtil.calculateGPA(majorSubjects1, nonMajorSubjects1)); + assertEquals(3.6, GradeCalculatorUtil.calculateGPA(majorSubjects2, nonMajorSubjects2)); + } + + @AfterEach void tearDown() { + majorSubjects1 = null; + majorSubjects2 = null; + nonMajorSubjects1 = null; + nonMajorSubjects2 = null; + } +} \ No newline at end of file diff --git a/src/test/java/gpacalc/GradeTest.java b/src/test/java/gpacalc/GradeTest.java new file mode 100644 index 0000000..402bcd4 --- /dev/null +++ b/src/test/java/gpacalc/GradeTest.java @@ -0,0 +1,14 @@ +package gpacalc; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class GradeTest { + + @Test + void 허용되지않는성적예외처리() { + assertThatThrownBy(() -> Grade.of("PD")) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file diff --git a/src/test/java/gpacalc/SubjectTest.java b/src/test/java/gpacalc/SubjectTest.java new file mode 100644 index 0000000..b24cbe2 --- /dev/null +++ b/src/test/java/gpacalc/SubjectTest.java @@ -0,0 +1,24 @@ +package gpacalc; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class SubjectTest { + + @Test + void 과목명이공백만으로입력된경우예외처리() { + assertThatThrownBy(() -> new Subject(" ", 3, Grade.A_ZERO)) + .isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> new Subject(" ", 3, Grade.A_ZERO)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void 학점이범위밖인경우예외처리() { + assertThatThrownBy(() -> new Subject("실전프로젝트", 0, Grade.A_ZERO)) + .isInstanceOf(IllegalArgumentException.class); + assertThatThrownBy(() -> new Subject("실전프로젝트", 6, Grade.A_ZERO)) + .isInstanceOf(IllegalArgumentException.class); + } +} \ No newline at end of file