Skip to content
26 changes: 26 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -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] 평점평균은 소수점 셋째 자리에서 반올림하여 둘째 자리까지 표현한다.
1 change: 1 addition & 0 deletions src/main/java/gpacalc/Application.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
public class Application {
public static void main(String[] args) {
//TODO: 구현
new GradeCalculator().run();
}
}
39 changes: 39 additions & 0 deletions src/main/java/gpacalc/Grade.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
47 changes: 47 additions & 0 deletions src/main/java/gpacalc/GradeCalculator.java
Original file line number Diff line number Diff line change
@@ -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]);
}
}
49 changes: 49 additions & 0 deletions src/main/java/gpacalc/GradeCalculatorIO.java
Original file line number Diff line number Diff line change
@@ -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();
}
}
48 changes: 48 additions & 0 deletions src/main/java/gpacalc/GradeCalculatorUtil.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
54 changes: 54 additions & 0 deletions src/main/java/gpacalc/Subject.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
44 changes: 44 additions & 0 deletions src/test/java/gpacalc/GradeCalculatorUtilTest.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
14 changes: 14 additions & 0 deletions src/test/java/gpacalc/GradeTest.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
24 changes: 24 additions & 0 deletions src/test/java/gpacalc/SubjectTest.java
Original file line number Diff line number Diff line change
@@ -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);
}
}