Skip to content

[이건창] 좌표 계산기 구현 #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: this-is-spear
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
9dbc7ad
Merge pull request #1 from object-oriented-thinking/this-is-spear
this-is-spear Jul 11, 2022
1689cb0
docs : 요구사항 정리
this-is-spear Jul 11, 2022
4a24249
docs : 요구사항 정리
this-is-spear Jul 11, 2022
2ac06a6
feat : StringExpression TDD로 구현
this-is-spear Jul 11, 2022
fe1e84d
docs : 모델링 수정
this-is-spear Jul 11, 2022
d1a0e1c
feat : Coordinate TDD로 구현
this-is-spear Jul 11, 2022
af55d21
refact : 식을 계산하는 기능 테스트 및 구현
this-is-spear Jul 12, 2022
edcde57
feat : LineCalculator TDD로 구현
this-is-spear Jul 12, 2022
1a87ea0
Merge branch 'this-is-spear-done' of https://github.com/object-orient…
this-is-spear Jul 12, 2022
27b8260
docs : 수정된 요구사항
this-is-spear Jul 18, 2022
26a0232
Refact : Line, Rectangle, Coordinate 객체 기능 구현 및 테스트
this-is-spear Jul 18, 2022
dd4dc9c
Refact : 코드 악취 제거
this-is-spear Jul 18, 2022
67d70b0
Refact : CoordinatesCalculator 기능 재정의
this-is-spear Jul 18, 2022
697d164
Feat : CoordinatesCalculator 기능 구현 및 테스트 진행
this-is-spear Jul 18, 2022
7e446be
Fix : 거리 계산 수정
this-is-spear Jul 18, 2022
1c050e0
Feat : Main 클래스 구현
this-is-spear Jul 18, 2022
bb6ba17
Refact : 답을 구하는 방식 변경
this-is-spear Jul 18, 2022
589b963
Docs : 요구사항 추가
this-is-spear Jul 18, 2022
c727b99
Fix : Rectangle 예외 메시지 수정 및 접근 제어자 변경
this-is-spear Jul 18, 2022
f0c939e
Feat : 삼각형 기능 구현 및 테스트 진행
this-is-spear Jul 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 94 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,101 @@
## [NEXTSTEP 플레이그라운드의 미션 진행 과정](https://github.com/next-step/nextstep-docs/blob/master/playground/README.md)
# 좌표 계산기

---
## 학습 효과를 높이기 위해 추천하는 미션 진행 방법
## 선 길이

---
1. 피드백 강의 전까지 미션 진행
> 피드백 강의 전까지 혼자 힘으로 미션 진행. 미션을 진행하면서 하나의 작업이 끝날 때 마다 add, commit
> 예를 들어 다음 숫자 야구 게임의 경우 0, 1, 2단계까지 구현을 완료한 후 push
### 기능 요구사항

![mission baseball](https://raw.githubusercontent.com/next-step/nextstep-docs/master/playground/images/mission_baseball.png)
- 사용자가 점에 대한 좌표 정보를 입력하는 메뉴를 구성한다.
- 좌표 정보는 괄호"(", ")"로 둘러쌓여 있으며 쉼표(,)로 x값과 y값을 구분한다.
- X, Y좌표 모두 최대 24까지만 입력할 수 있다.
- 입력 범위를 초과할 경우 에러 문구를 출력하고 다시 입력을 받는다.
- 정상적인 좌표값을 입력한 경우, 해당 좌표에 특수문자를 표시한다.
- 좌표값을 두 개 입력한 경우, 두 점을 있는 직선으로 가정한다. 좌표값과 좌표값 사이는 '-' 문자로 구분한다.
- 직선인 경우는 두 점 사이 거리를 계산해서 출력한다.

---
2. 피드백 앞 단계까지 미션 구현을 완료한 후 피드백 강의를 학습한다.
### 이벤트

---
3. Git 브랜치를 master 또는 main으로 변경한 후 피드백을 반영하기 위한 새로운 브랜치를 생성한 후 처음부터 다시 미션 구현을 도전한다.
1. 사용자가 식을 입력했다.
2. 식이 계산됐다.

```
git branch -a // 모든 로컬 브랜치 확인
git checkout master // 기본 브랜치가 master인 경우
git checkout main // 기본 브랜치가 main인 경우

git checkout -b 브랜치이름
ex) git checkout -b apply-feedback
```
### 모델링

- 선 길이 계산기
- 행위
- 식을 입력 받아 좌표 그래프에 그리고 직선상의 거리를 계산한다.
- 좌표
- 상태
- x값과 y값을 가진다.
- 좌표는 0이상 24이하의 자연수이다.
- 행위
- 좌표를 입력받으면 직선상의 거리를 계산한다.
- 좌표 그래프
- 행위
- 좌표 두 개를 입력 받아 표를 그린다.
- 표를 그린다.
- 표에 점을 찍는다.
- 표를 출력한다.


### 추가된 요구사항

- 좌표값을 두 개 입력한 경우, 두 점을 있는 직선으로 가정한다. 좌표값과 좌표값 사이는 '-' 문자로 구분한다.
- 좌표값을 네 개 입력한 경우, 네 점을 연결하는 사각형으로 가정한다.
- 네 점이 뒤틀어진 사다리꼴이나 마름모는 제외하고 직사각형만 허용하도록 검사한다.
- 사각형인 경우 사각형의 넓이를 계산해서 출력한다.

- 좌표계산기
- 행위
- 입력을 받습니다.
- 입력이 선 인지 직사각형인지 판단합니다.
- 답을 가져옵니다.
- 도형에게 좌표를 가져옵니다.
- 도형
- 행위
- 답을 출력합니다.
- 좌표를 출력합니다.
- 선
- 상태
- 좌표 두 개를 가지고 있습니다.
- 행위
- 답을 출력합니다.
- 답은 길이입니다.
- 좌표를 출력합니다.
- 직사각형
- 상태
- 좌표 네 개를 가지고 있습니다.
- 네 점이 뒤틀어진 사다리꼴이나 마름모가 아닌 직사각형만 됩니다.
- 행위
- 답을 출력합니다.
- 넓이를 계산합니다.
- 좌표를 출력합니다.
- 좌표 그래프
- 행위
- 좌표 두 개를 입력 받아 표를 그립니다.
- 표를 그립니다.
- 표에 점을 찍습니다.
- 표를 출력합니다.
- 좌표
- 상태
- x값과 y값을 가집니다.
- 좌표는 0이상 24이하의 자연수입니다.
- 행위
- 좌표를 입력받습니다.
- 입력되는 식은 정규 표현식에 맞아야 합니다.
- 입력되는 좌표는 숫자가 들어가야 합니다.


### 추가된 요구사항

- 좌표값을 두 개 입력한 경우, 두 점을 있는 직선으로 가정한다. 좌표값과 좌표값 사이는 '-' 문자로 구분한다.
- 좌표값을 세 개 입력한 경우, 세 점을 연결하는 삼각형으로 가정한다.
- 삼각형인 경우 삼각형의 넓이를 계산해서 출력한다.

삼각형
- 상태
- 좌표 세 개를 가지고 있습니다.
- 행위
- 답을 출력합니다.
- 답은 넓이입니다.
- 헤론의 공식을 통해 넓이를 구합니다.
- 좌표를 출력합니다.
34 changes: 34 additions & 0 deletions src/main/java/coordinate/CoordinateMain.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package coordinate;

import coordinate.domain.Coordinate;
import coordinate.domain.CoordinateGraphClient;
import coordinate.domain.CoordinateInputClient;
import coordinate.domain.CoordinatesCalculator;

import java.util.List;

public class CoordinateMain {

public static void main(String[] args) {
coordinate.domain.CoordinateInputClient coordinateInputClient = new CoordinateInputClient() {
@Override
public String inputString() {
return "(10,10)-(14,15)";
}
};
coordinate.domain.CoordinateGraphClient coordinateGraphClient = new CoordinateGraphClient() {
@Override
public boolean displayGraph(List<Coordinate> coordinates) {
return true;
}
};

CoordinatesCalculator calculator = new CoordinatesCalculator(coordinateInputClient.inputString());

// display
coordinateGraphClient.displayGraph(calculator.findCoordinates());

// print result
System.out.println("답은 " + calculator.getResult() + "입니다.");
}
}
60 changes: 60 additions & 0 deletions src/main/java/coordinate/domain/Coordinate.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package coordinate.domain;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Coordinate {
private final double x;
private final double y;

private static final String X = "x";
private static final String Y = "y";

private final static Pattern PATTERN = Pattern
.compile("\\((?<" + X + ">\\d+),(?<" + Y + ">\\d+)\\)");


public Coordinate(String expression) {
Matcher matcher = PATTERN.matcher(expression);
if (!matcher.matches()) {
throw new IllegalArgumentException();
}

String stringX = matcher.group(X);
String stringY = matcher.group(Y);

isNumber(stringX);
isNumber(stringY);

if (validationNumber(stringX)) {
throw new IllegalArgumentException();
}
if (validationNumber(stringY)) {
throw new IllegalArgumentException();
}

x = Double.parseDouble(stringX);
y = Double.parseDouble(stringY);

}

private boolean validationNumber(String number) {
return 1.0 > Double.parseDouble(number) || Double.parseDouble(number) > 24.0;
}

private void isNumber(String stringX) {
try {
Double.parseDouble(stringX);
} catch (NumberFormatException e) {
throw new IllegalArgumentException();
}
}

public double getX() {
return x;
}

public double getY() {
return y;
}
}
7 changes: 7 additions & 0 deletions src/main/java/coordinate/domain/CoordinateGraphClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package coordinate.domain;

import java.util.List;

public interface CoordinateGraphClient {
boolean displayGraph(List<Coordinate> coordinates);
}
5 changes: 5 additions & 0 deletions src/main/java/coordinate/domain/CoordinateInputClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package coordinate.domain;

public interface CoordinateInputClient {
String inputString();
}
39 changes: 39 additions & 0 deletions src/main/java/coordinate/domain/CoordinatesCalculator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package coordinate.domain;

import java.util.List;

public class CoordinatesCalculator {
private static final String REGEX = "-";
private final Shapes shapes;

public CoordinatesCalculator(String expression) {
if (expression.split(REGEX).length == 2) {
shapes = new Line(expression);
return;
}

if (expression.split(REGEX).length == 3) {
shapes = new Triangle(expression);
return;
}

if (expression.split(REGEX).length == 4) {
shapes = new Rectangle(expression);
return;
}

throw new IllegalArgumentException();
}

public Shapes getShapes() {
return shapes;
}

public Double getResult() {
return shapes.getResult();
}

public List<Coordinate> findCoordinates() {
return shapes.findCoordinates();
}
}
46 changes: 46 additions & 0 deletions src/main/java/coordinate/domain/Line.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package coordinate.domain;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static java.lang.Math.abs;

public class Line implements Shapes {
public static final String REGEX = "-";
private final List<Coordinate> coordinates;

public Line(String expression) {

if (!expression.contains(REGEX)) {
throw new IllegalArgumentException("식이 틀렸습니다.");
}

if (expression.split(REGEX).length != 2) {
throw new IllegalArgumentException("좌표는 두개 만 들어가야 합니다.");
}

List<Coordinate> coordinateList = Arrays.asList(
new Coordinate(expression.split(REGEX)[0]),
new Coordinate(expression.split(REGEX)[1])
);

this.coordinates = coordinateList;
}

@Override
public double getResult() {
return getDistance(coordinates.get(0), coordinates.get(1));
}

@Override
public List<Coordinate> findCoordinates() {
return new ArrayList<>(coordinates);
}

private double getDistance(Coordinate coordinate, Coordinate otherCoordinate) {
return Math.sqrt(
abs((coordinate.getX() - otherCoordinate.getX()) * (coordinate.getX() - otherCoordinate.getX())
+ (coordinate.getY() - otherCoordinate.getY()) * (coordinate.getY() - otherCoordinate.getY())));
}
}
72 changes: 72 additions & 0 deletions src/main/java/coordinate/domain/Rectangle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package coordinate.domain;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static java.lang.Math.abs;

public class Rectangle implements Shapes {
public static final String REGEX = "-";
private final List<Coordinate> coordinates;

public Rectangle(String expression) {

if (!expression.contains(REGEX)) {
throw new IllegalArgumentException("식이 틀렸습니다.");
}

if (expression.split(REGEX).length != 4) {
throw new IllegalArgumentException("좌표는 네 개 만 들어가야 합니다.");
}

List<Coordinate> coordinateList = Arrays.asList(
new Coordinate(expression.split(REGEX)[0]),
new Coordinate(expression.split(REGEX)[1]),
new Coordinate(expression.split(REGEX)[2]),
new Coordinate(expression.split(REGEX)[3])
);

List<Double> distanceList = Arrays.asList(
getDistance(coordinateList.get(0), coordinateList.get(1)),
getDistance(coordinateList.get(1), coordinateList.get(2)),
getDistance(coordinateList.get(2), coordinateList.get(3)),
getDistance(coordinateList.get(3), coordinateList.get(0))
);

if (distanceList.stream().distinct().count() != 2) {
throw new IllegalArgumentException();
}

this.coordinates = coordinateList;
}

@Override
public double getResult() {
return getArea(coordinates);
}

private double getArea(List<Coordinate> coordinates) {
List<Double> distanceList = Arrays.asList(
getDistance(coordinates.get(0), coordinates.get(1)),
getDistance(coordinates.get(1), coordinates.get(2)),
getDistance(coordinates.get(2), coordinates.get(3)),
getDistance(coordinates.get(3), coordinates.get(0))
);
return distanceList.stream().distinct()
.reduce((double1, double2) -> double1 * double2)
.orElseThrow(IllegalArgumentException::new);
}

@Override
public List<Coordinate> findCoordinates() {
return new ArrayList<>(coordinates);
}

private double getDistance(Coordinate coordinate, Coordinate otherCoordinate) {
return Math.sqrt(
abs((coordinate.getX() - otherCoordinate.getX()) * (coordinate.getX() - otherCoordinate.getX())
+ (coordinate.getY() - otherCoordinate.getY()) * (coordinate.getY() - otherCoordinate.getY())));
}

}
Loading