├── .gitignore
├── README.md
├── src
├── core
│ └── NaturalNumber.java
└── ladder
│ ├── LadderGame.java
│ ├── LadderGameFactory.java
│ ├── LadderRunner.java
│ ├── LadderSize.java
│ ├── Marker.java
│ ├── Node.java
│ ├── Position.java
│ ├── RandomNaturalNumber.java
│ ├── Row.java
│ └── creator
│ ├── LadderCreator.java
│ ├── ManualLadderCreator.java
│ └── RandomLadderCreator.java
└── test
├── core
├── ArrayListTest.java
└── NaturalNumberTest.java
└── ladder
├── LadderGameTest.java
├── LadderRunnerTest.java
├── MarkerTest.java
├── NodeTest.java
├── PositionTest.java
├── RandomNaturalNumberTest.java
├── RowTest.java
└── creator
└── RandomLadderCreatorTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.iml
3 | out/
4 | require.txt
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 자바지기 박재성님 TDD강의
2 | > 다음 달에 [코드스쿼드 TDD, 리팩토링 강의](http://codesquad.kr/page/specialTdd.html)를 수강하기 전에 유투브에서 자바지기님의 사다리게임을 구현하는 TDD 강좌가 있어서 정주행 하게 되었다.
3 |
4 |
5 | ### 사다리 게임 강좌 목록
6 | ##### 0. 요구사항 분석
7 | - 요구사항 분석
8 |
9 | ##### 1. 일단 사다리 게임 구현해 보기
10 | - step1-1
11 | - step1-2
12 | - step1-3
13 |
14 | ##### 2. 사다리게임 구현
15 | - step2-1 사다리 좌우 이동 기능 구현
16 | - step2-2 사다리 여러행 추가, 2차원 배열로 바꿈
17 | - step2-3 리팩토링 (Row클래스 추출, if문 조건확인 로직 메소드 추출)
18 |
19 | ##### 3. 리팩토링
20 | - step3-1 Ladder Test를 RowTest로 이동 / Row의 moveRow -> move로 rename /moveRow() 메서드 리팩토링 부분을 찾아보기
21 | - step3-2 isLeftDirection메서드명 isRightDirection rename / -1, 0, 1 상수값을 enum 타입으로 정의
22 | - step3-3 Ladder, Row 클래스, 필드, 메소드 접근제어자 처리
23 | - step3-4 Ladder,Row 클래스 예외처리 (생성자 drawLine메서드)
24 |
25 | ##### 4. 객체 추출 리팩토링
26 | - step4-1 NaturalNumber 클래스 추가, Ladder, Row클래스에서 사용하던 int형 값들을 NaturalNumber객체 값으로 리팩토링
27 | - step4-2 좌우 이동 기능을 하는 Marker 클래스 추가(단일 책임) Ladder클래스 run메소드, Row클래스 move메소드에서 Marker 사용하도록 리팩토링
28 | - step4-3 현재 위치의 상태를 나타내는 Node 클래스 추가 Row내 Direction Enum클래스 제거
29 | - step4-4 리팩토링 패키지, 접근제어자 정리, 소스 가독성을 위한 메소드 추출 작업
30 |
31 | ##### 5. 디버깅 로그메시지 출력기능
32 | - step5-1 디버깅 로그 메시지 출력 기능(StringBuilder 사용)
33 | - step5-2 디버깅 로그메시지 출력기능 리팩토링, 이중for문 제거, if else문 enum처리
34 | - step5-3 디버깅 로그메시지 출력기능 리팩토링, height, persons쌍 Position 객체 추출
35 |
36 | ##### 6. 클래스 분리 및 선 Random 생성
37 | - step6-1 SOLID원칙 중 단일책임의 원칙 적용. 클래스 분리 Ladder -> LadderGame, LadderRunner, LadderCreator 분리
38 | - step6-2 RandomLadderCreator 클래스 생성, Random 생성시 발생하는 요구사항 분석
39 | - step6-3 총 position 수 구하기, 사다리 크기에 따라 ratio값에 따라 생성되는 선의 수를 결정 사다리 생성시 크기값을 담당하는 객체 추출 int값을 2차원 배열 위치 값으로 변환
40 | - step6-4 LadderSize 클래스 추출
41 | - step6-5 RandomLadderCreator 랜덤값 유효성 검증
42 |
43 | ##### 7. 인터페이스 추출 및 DI
44 | - step7-1 LadderGame에 RandomLadderCreator 붙이기
45 | - step7-2 ManualLadderCreator, RandomLadderCreator -> LadderCreator 인터페이스 분리
46 | - step7-3 LadderCreate 기능을 LadderCreatorFactory에 위임, ladder.creator패키지 생성 및 접근 제어자 수정
47 | - step7-4 LadderCreator DI 적용
48 | - step7-5 상속을 통한 RandomLadderCreator 중복 제거
49 | - step7-6 조합을 통한 RandomLadderCreator 중복 제거
50 |
51 | ##### 8. Collection을 사용한 리팩토링
52 | - step8-1 리팩토링 RandomNaturalNumber 생성
53 | - step8-2 리팩토링 RandomLadderCreator Array사용하는 부분 -> Collection의 List로 변경
54 | - step8-3 리팩토링 RandomLadderCreator NaturalNumber isFirst() 구현
55 | - step8-4 RandomLadderCreator클래스의 generateRandomPositions() 복잡한 로직을 Collection비교 방법으로 리팩토링
56 |
57 | #### 후기
58 | - 일주일간 틈틈이 한강좌씩 따라하다 보니 TDD방식으로 코딩하는게 이런거다하는 몸소 느낄 수 있었다.
59 | - 테스트 클래스가 있다보니 리팩토링 할 때 마음 놓고 수정할 수 있어서 if else문으로 짜여진 복잡도가 높은 로직도 step by step으로 리팩토링이 가능했다. 실패하던 빨간색 테스트 케이스를 실행해서 녹색불이 들어왔을 때 짜릿한 성취감을 느낄 수 있었다.
60 | - 기능단위의 test클래스를 먼저 만들고 기능을 구현하다보니 자연스럽게 SOLID원칙 중에 단일책임의 원칙을 생각하면서 클래스를 만들 수 있게 되었다. 나머지 다른 원칙들도 어떻게 적용되는지 공부가 더 필요하다.
61 | - 사전 과제로 내주신 기본적인 git 사용법을 익히기 위해 source tree나 ide에서 제공하는 git 기능을 사용하지 않고 terminal에서 git명령어를 직접 사용하였다. commit로그도 최대한 상세하게 남겼다. oh-my-zsh을 설치해서 사용하니 터미널에서도 이쁜 commit 로그를 볼 수 있어서 좋았다.
62 |
--------------------------------------------------------------------------------
/src/core/NaturalNumber.java:
--------------------------------------------------------------------------------
1 | package core;
2 |
3 | import java.util.Objects;
4 |
5 | public class NaturalNumber {
6 |
7 | private static final int INTERVAL = 1;
8 | private static final int FIRST_OF_NATURAL_NUMBER = 1;
9 | private int number;
10 |
11 | public NaturalNumber(int number) {
12 | if (number < 1) {
13 | throw new IllegalArgumentException(String.format("자연수는 1 이상이어야 합니다. 현재 값은 : %d", number));
14 | }
15 | this.number = number;
16 | }
17 |
18 | public int getNumber() {
19 | return this.number;
20 | }
21 |
22 | public int toArrayIndex() {
23 | return this.number - INTERVAL;
24 | }
25 |
26 | public NaturalNumber multiply(NaturalNumber operand) {
27 | return new NaturalNumber(this.number * operand.number);
28 | }
29 |
30 | public static NaturalNumber createFromArrayIndex(int index) {
31 | return new NaturalNumber(index + INTERVAL);
32 | }
33 |
34 | public boolean isFirst() {
35 | return isFirst(getNumber());
36 | }
37 |
38 | public boolean isFirst(int number) {
39 | return number == FIRST_OF_NATURAL_NUMBER;
40 | }
41 |
42 | @Override
43 | public boolean equals(Object o) {
44 | if (this == o) {
45 | return true;
46 | }
47 | if (!(o instanceof NaturalNumber)) {
48 | return false;
49 | }
50 | NaturalNumber that = (NaturalNumber) o;
51 | return number == that.number;
52 | }
53 |
54 | @Override
55 | public int hashCode() {
56 |
57 | return Objects.hash(number);
58 | }
59 |
60 | @Override
61 | public String toString() {
62 | return number + "";
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/ladder/LadderGame.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 | import ladder.creator.LadderCreator;
5 |
6 | class LadderGame {
7 |
8 | private LadderCreator ladderCreator;
9 |
10 | public LadderGame(LadderCreator ladderCreator) {
11 | this.ladderCreator = ladderCreator;
12 | }
13 |
14 | void drawLine(NaturalNumber height, NaturalNumber startPosition) {
15 | ladderCreator.drawLine(height, startPosition);
16 | }
17 |
18 | Marker run(Marker nthOfPerson) {
19 | LadderRunner runner = new LadderRunner(ladderCreator.getLadder());
20 | return runner.run(nthOfPerson);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/ladder/LadderGameFactory.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 | import ladder.creator.ManualLadderCreator;
5 | import ladder.creator.RandomLadderCreator;
6 |
7 | public class LadderGameFactory {
8 |
9 | private LadderGameFactory() {
10 | }
11 |
12 | static LadderGame randomLadderGame(NaturalNumber height, NaturalNumber noOfPerson) {
13 | ManualLadderCreator manualLadderCreator = new ManualLadderCreator(height, noOfPerson);
14 | RandomLadderCreator ladderCreator = new RandomLadderCreator(manualLadderCreator);
15 | return new LadderGame(ladderCreator);
16 | }
17 |
18 | static LadderGame manualLadderGame(NaturalNumber height, NaturalNumber noOfPerson) {
19 | ManualLadderCreator ladderCreator = new ManualLadderCreator(height, noOfPerson);
20 | return new LadderGame(ladderCreator);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/ladder/LadderRunner.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | class LadderRunner {
4 |
5 | private Row[] rows;
6 |
7 | LadderRunner(Row[] rows) {
8 | this.rows = rows;
9 | }
10 |
11 | Marker run(Marker nthOfPerson) {
12 | for (int i = 0; i < rows.length; i++) {
13 | Row row = rows[i];
14 | System.out.println("Before : ");
15 | System.out.println(generate(rows, Position.createFromArrayIndex(i, nthOfPerson.toArrayIndex())));
16 | nthOfPerson = row.move(nthOfPerson);
17 | System.out.println("After : ");
18 | System.out.println(generate(rows, Position.createFromArrayIndex(i, nthOfPerson.toArrayIndex())));
19 | }
20 | return nthOfPerson;
21 | }
22 |
23 | static String generate(Row[] rows, Position position) {
24 | StringBuilder sb = new StringBuilder();
25 | for (int i = 0; i < rows.length; i++) {
26 | Row row = rows[i];
27 | row.generateRow(sb, i, position);
28 | }
29 |
30 | return sb.toString();
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/ladder/LadderSize.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 |
5 | public class LadderSize {
6 |
7 | private NaturalNumber height;
8 | private NaturalNumber noOfPerson;
9 |
10 | private LadderSize(NaturalNumber height, NaturalNumber noOfPerson) {
11 | this.height = height;
12 | this.noOfPerson = noOfPerson;
13 | }
14 |
15 | public NaturalNumber getHeight() {
16 | return height;
17 | }
18 |
19 | public NaturalNumber getNoOfPerson() {
20 | return noOfPerson;
21 | }
22 |
23 | static LadderSize create(int height, int noOfPerson) {
24 | return new LadderSize(new NaturalNumber(height), new NaturalNumber(noOfPerson));
25 | }
26 |
27 | public static LadderSize create(NaturalNumber height, NaturalNumber nthOfPersion) {
28 | return new LadderSize(height, nthOfPersion);
29 | }
30 |
31 | public Position getPosition(RandomNaturalNumber randomNaturalNumber) {
32 | int positionOfHeight = randomNaturalNumber.getPositionOfHeight(noOfPerson.getNumber());
33 | int positionOfPerson = randomNaturalNumber.getPositionOfPerson(noOfPerson.getNumber());
34 | return Position.create(positionOfHeight, positionOfPerson);
35 | }
36 |
37 | public int getCountOfLine(double ratio) {
38 | NaturalNumber totalPositions = getTotalPosition();
39 | return (int) (totalPositions.getNumber() * ratio);
40 | }
41 |
42 | public NaturalNumber getTotalPosition() {
43 | return height.multiply(noOfPerson);
44 | }
45 |
46 | public boolean isMultipleOfPerson(RandomNaturalNumber randomPosition) {
47 | return randomPosition.isMultipleOfPerson(noOfPerson.getNumber());
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/ladder/Marker.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 |
5 | class Marker extends NaturalNumber {
6 |
7 | Marker(int number) {
8 | super(number);
9 | }
10 |
11 | public Marker moveRight() {
12 | return new Marker(getNumber() + 1);
13 | }
14 |
15 | public Marker moveLeft() {
16 | return new Marker(getNumber() - 1);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/ladder/Node.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import java.util.Objects;
4 |
5 | public class Node {
6 |
7 | enum Direction {
8 | LEFT(-1), CENTER(0), RIGHT(1);
9 | private int symbol;
10 |
11 | private Direction(int symbol) {
12 | this.symbol = symbol;
13 | }
14 | }
15 |
16 | private Direction direction;
17 |
18 | private Node(Direction direction) {
19 | this.direction = direction;
20 | }
21 |
22 | Direction getDirection() {
23 | return direction;
24 | }
25 |
26 | void changeRight() {
27 | this.direction = Direction.RIGHT;
28 | }
29 |
30 | void changeLeft() {
31 | this.direction = Direction.LEFT;
32 | }
33 |
34 | boolean isRightDirection() {
35 | return direction == Direction.RIGHT;
36 | }
37 |
38 | boolean isLeftDirection() {
39 | return direction == Direction.LEFT;
40 | }
41 |
42 | void appendSymbol(StringBuilder builder) {
43 | builder.append(direction.symbol);
44 | }
45 |
46 | Marker move(Marker marker) {
47 | if (isRightDirection()) {
48 | return marker.moveRight();
49 | }
50 |
51 | if (isLeftDirection()) {
52 | return marker.moveLeft();
53 | }
54 |
55 | return marker;
56 | }
57 |
58 | static Node createCenterNode() {
59 | return new Node(Direction.CENTER);
60 | }
61 |
62 | static Node createRightNode() {
63 | return new Node(Direction.RIGHT);
64 | }
65 |
66 | static Node createLeftNode() {
67 | return new Node(Direction.LEFT);
68 | }
69 |
70 | @Override
71 | public boolean equals(Object o) {
72 | if (this == o) {
73 | return true;
74 | }
75 | if (o == null || getClass() != o.getClass()) {
76 | return false;
77 | }
78 | Node node = (Node) o;
79 | return direction == node.direction;
80 | }
81 |
82 | @Override
83 | public int hashCode() {
84 | return Objects.hash(direction);
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/ladder/Position.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 | import java.util.Objects;
5 |
6 | public class Position {
7 |
8 | private NaturalNumber height;
9 | private NaturalNumber nthOfPerson;
10 |
11 | private Position(NaturalNumber height, NaturalNumber nthOfPerson) {
12 | this.height = height;
13 | this.nthOfPerson = nthOfPerson;
14 | }
15 |
16 | static Position create(int height, int nthOfPerson) {
17 | return create(new NaturalNumber(height), new NaturalNumber(nthOfPerson));
18 | }
19 |
20 | static Position create(NaturalNumber height, NaturalNumber nthOfPersion) {
21 | return new Position(height, nthOfPersion);
22 | }
23 |
24 | static Position createFromArrayIndex(int height, int nthOfPerson) {
25 | return new Position(NaturalNumber.createFromArrayIndex(height), NaturalNumber.createFromArrayIndex(nthOfPerson));
26 | }
27 |
28 | public NaturalNumber getHeight() {
29 | return height;
30 | }
31 |
32 | public NaturalNumber getNthOfPerson() {
33 | return nthOfPerson;
34 | }
35 |
36 | @Override
37 | public boolean equals(Object o) {
38 | if (this == o) {
39 | return true;
40 | }
41 | if (o == null || getClass() != o.getClass()) {
42 | return false;
43 | }
44 | Position position = (Position) o;
45 | return Objects.equals(height, position.height) &&
46 | Objects.equals(nthOfPerson, position.nthOfPerson);
47 | }
48 |
49 | @Override
50 | public int hashCode() {
51 | return Objects.hash(height, nthOfPerson);
52 | }
53 |
54 | @Override
55 | public String toString() {
56 | return "Position{" +
57 | "height=" + height +
58 | ", nthOfPerson=" + nthOfPerson +
59 | '}';
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/ladder/RandomNaturalNumber.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 |
7 | public class RandomNaturalNumber extends NaturalNumber {
8 |
9 | public RandomNaturalNumber(int number) {
10 | super(number);
11 | }
12 |
13 | public int getPositionOfPerson(int noOfPerson) {
14 | int remainder = this.getNumber() % noOfPerson;
15 | if (remainder == 0) {
16 | return noOfPerson;
17 | }
18 | return remainder;
19 | }
20 |
21 | public int getPositionOfHeight(int noOfPerson) {
22 | double ceilDevideEnd = Math.ceil(this.getNumber() / (double) noOfPerson);
23 | return new Double(ceilDevideEnd).intValue();
24 | }
25 |
26 | public boolean isMultipleOfPerson(int noOfPerson) {
27 | int remainder = this.getNumber() % noOfPerson;
28 | if (remainder == 0) {
29 | return true;
30 | }
31 | return false;
32 | }
33 |
34 | public RandomNaturalNumber before() {
35 | return new RandomNaturalNumber(toArrayIndex());
36 | }
37 |
38 | public RandomNaturalNumber next() {
39 | return new RandomNaturalNumber(getNumber() + 1);
40 | }
41 |
42 | public List checkedNaturalNumbers(NaturalNumber noOfPerson) {
43 | List naturalNumbers = new ArrayList<>();
44 |
45 | int remainder = this.getNumber() % noOfPerson.getNumber();
46 | if (!isFirst(remainder)) {
47 | naturalNumbers.add(before());
48 | }
49 | naturalNumbers.add(this);
50 | naturalNumbers.add(next());
51 | return naturalNumbers;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/ladder/Row.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 |
5 | public class Row {
6 | private Node[] nodes;
7 |
8 | public Row(NaturalNumber noOfPerson) {
9 | nodes = new Node[noOfPerson.getNumber()];
10 | for (int i = 0; i < nodes.length; i++) {
11 | nodes[i] = Node.createCenterNode();
12 | }
13 | }
14 |
15 | public void drawLine(NaturalNumber startPosition) {
16 | int startIndex = startPosition.toArrayIndex();
17 | if (isOverNoOfPersons(startIndex)) {
18 | throw new IllegalArgumentException(String.format("시작점 Index값은 %d 미만이어야 합니다. 현재 값 : %d", nodes.length - 1, startIndex));
19 | }
20 |
21 | if (nodes[startIndex].isLeftDirection()) {
22 | throw new IllegalArgumentException("선을 그을 수 없는 위치입니다.");
23 | }
24 |
25 | nodes[startIndex].changeRight();
26 | nodes[startIndex + 1].changeLeft();
27 | }
28 |
29 | private boolean isOverNoOfPersons(int startIndex) {
30 | // 사람수 5일경우 선 시작 위치는 4이상이 될 수 없다. 즉 3까지 허용
31 | return startIndex >= nodes.length - 1;
32 | }
33 |
34 | Marker move(Marker marker) {
35 | return nodes[marker.toArrayIndex()].move(marker);
36 | }
37 |
38 | // public Node[] getNodes() {
39 | // return this.nodes;
40 | // }
41 |
42 | void generateRow(StringBuilder sb, int currentHeight, Position position) {
43 | for (int j = 0; j < nodes.length; j++) {
44 | Node node = nodes[j];
45 | node.appendSymbol(sb);
46 |
47 | if (position.equals(Position.createFromArrayIndex(currentHeight, j))) {
48 | sb.append("*");
49 | }
50 |
51 | sb.append(" ");
52 | }
53 | sb.append("\n");
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/ladder/creator/LadderCreator.java:
--------------------------------------------------------------------------------
1 | package ladder.creator;
2 |
3 | import core.NaturalNumber;
4 | import ladder.LadderSize;
5 | import ladder.Row;
6 |
7 | public interface LadderCreator {
8 |
9 | void drawLine(NaturalNumber height, NaturalNumber startPosition);
10 |
11 | Row[] getLadder();
12 |
13 | LadderSize getLadderSize();
14 | }
15 |
--------------------------------------------------------------------------------
/src/ladder/creator/ManualLadderCreator.java:
--------------------------------------------------------------------------------
1 | package ladder.creator;
2 |
3 | import core.NaturalNumber;
4 | import ladder.LadderSize;
5 | import ladder.Row;
6 |
7 | public class ManualLadderCreator implements LadderCreator {
8 |
9 | private Row[] rows;
10 | private LadderSize ladderSize;
11 |
12 | public ManualLadderCreator(NaturalNumber height, NaturalNumber noOfPerson) {
13 | rows = new Row[height.getNumber()];
14 | ladderSize = LadderSize.create(height, noOfPerson);
15 | for (int i = 0; i < height.getNumber(); i++) {
16 | rows[i] = new Row(noOfPerson);
17 | }
18 | }
19 |
20 | public LadderSize getLadderSize() {
21 | return ladderSize;
22 | }
23 |
24 | @Override
25 | public void drawLine(NaturalNumber height, NaturalNumber startPosition) {
26 | if (isOverHeight(height)) {
27 | throw new IllegalArgumentException(
28 | String.format("사다리 최대 높이를 넘어섰습니다.현재 값은 : %d", height.getNumber()));
29 | }
30 |
31 | rows[height.toArrayIndex()].drawLine(startPosition);
32 | }
33 |
34 | @Override
35 | public Row[] getLadder() {
36 | return this.rows;
37 | }
38 |
39 | private boolean isOverHeight(NaturalNumber height) {
40 | return height.toArrayIndex() > rows.length - 1;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/ladder/creator/RandomLadderCreator.java:
--------------------------------------------------------------------------------
1 | package ladder.creator;
2 |
3 | import core.NaturalNumber;
4 | import java.util.ArrayList;
5 | import java.util.List;
6 | import java.util.Random;
7 | import ladder.LadderSize;
8 | import ladder.Position;
9 | import ladder.RandomNaturalNumber;
10 | import ladder.Row;
11 |
12 | public class RandomLadderCreator implements LadderCreator {
13 |
14 | private static final double DEFAULT_LINE_RATIO = 0.3;
15 | private LadderCreator ladderCreator;
16 | private LadderSize ladderSize;
17 |
18 | public RandomLadderCreator(LadderCreator ladderCreator) {
19 | this.ladderCreator = ladderCreator;
20 | this.ladderSize = ladderCreator.getLadderSize();
21 | List startPositions = generateStartPositions();
22 | for (Position position : startPositions) {
23 | ladderCreator.drawLine(position.getHeight(), position.getNthOfPerson());
24 | }
25 | }
26 |
27 | @Override
28 | public void drawLine(NaturalNumber height, NaturalNumber startPosition) {
29 | throw new UnsupportedOperationException("RandomLadderCreator에서는 drawLine 메서드를 호출할 수 없습니다.");
30 | }
31 |
32 | @Override
33 | public Row[] getLadder() {
34 | return this.ladderCreator.getLadder();
35 | }
36 |
37 | @Override
38 | public LadderSize getLadderSize() {
39 | return this.ladderSize;
40 | }
41 |
42 | List generateStartPositions() {
43 | List numbers = generateRandomPositions();
44 | return toPositions(numbers);
45 | }
46 |
47 | List generateRandomPositions() {
48 | NaturalNumber totalPositions = ladderSize.getTotalPosition();
49 | int countOfLine = ladderSize.getCountOfLine(DEFAULT_LINE_RATIO);
50 | List randomPositions = new ArrayList<>();
51 |
52 | do {
53 | RandomNaturalNumber randomPosition = randInt(1, totalPositions.getNumber());
54 | if (ladderSize.isMultipleOfPerson(randomPosition)) {
55 | continue;
56 | }
57 |
58 | // 아래 로직을 Collection비교를 통한 방법으로 리팩토링
59 | List checkedNaturalNumbers = randomPosition.checkedNaturalNumbers(ladderSize.getNoOfPerson());
60 | checkedNaturalNumbers.retainAll(randomPositions);
61 |
62 | // 체크넘버에 포함되어 있지 않으면 추가 (retainAll은 교집합 추출)
63 | if (checkedNaturalNumbers.isEmpty()) {
64 | randomPositions.add(randomPosition);
65 | System.out.println(String.format("random position : %s", randomPosition));
66 | }
67 |
68 | // if (randomPositions.contains(randomPosition)) {
69 | // continue;
70 | // }
71 | //
72 | // if (randomPositions.contains(new RandomNaturalNumber(randomPosition.getNumber() + 1))) {
73 | // continue;
74 | // }
75 | //
76 | // if (randomPosition.isFirst()) {
77 | // randomPositions.add(randomPosition);
78 | // System.out.println(String.format("random position : %s", randomPosition));
79 | // } else {
80 | // if (randomPositions.contains(new RandomNaturalNumber(randomPosition.toArrayIndex()))) {
81 | // continue;
82 | // }
83 | //
84 | // randomPositions.add(randomPosition);
85 | // System.out.println(String.format("random position : %s", randomPosition));
86 | // }
87 | } while (randomPositions.size() < countOfLine);
88 |
89 | return randomPositions;
90 | }
91 |
92 | List toPositions(List randomNumbers) {
93 | List positions = new ArrayList<>(randomNumbers.size());
94 | for (RandomNaturalNumber randomNumber : randomNumbers) {
95 | positions.add(ladderSize.getPosition(randomNumber));
96 | //System.out.println("ladderSize.getPosition(randomNumber) = " + ladderSize.getPosition(randomNumber));
97 | }
98 | return positions;
99 | }
100 |
101 | static RandomNaturalNumber randInt(int min, int max) {
102 | Random rand = new Random();
103 | return new RandomNaturalNumber(rand.nextInt((max - min) + 1) + min);
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/test/core/ArrayListTest.java:
--------------------------------------------------------------------------------
1 | package core;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import junit.framework.TestCase;
6 |
7 | public class ArrayListTest extends TestCase {
8 |
9 | public void testRetainAll() {
10 | List values = new ArrayList<>();
11 | values.add(1);
12 | values.add(2);
13 | values.add(3);
14 | List values2 = new ArrayList<>();
15 | values2.add(2);
16 | values2.add(3);
17 |
18 | values.retainAll(values2);
19 | //System.out.println(values);
20 | //System.out.println(values2);
21 | assertTrue(values.size() == 2);
22 | }
23 |
24 | public void testRetainAll2() {
25 | List values = new ArrayList<>();
26 | values.add(1);
27 | values.add(2);
28 | values.add(3);
29 | List values2 = new ArrayList<>();
30 | values2.add(4);
31 |
32 | values.retainAll(values2);
33 | //System.out.println(values);
34 | //System.out.println(values2);
35 | assertTrue(values.size() == 0);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/test/core/NaturalNumberTest.java:
--------------------------------------------------------------------------------
1 | package core;
2 |
3 | import junit.framework.TestCase;
4 | import ladder.RandomNaturalNumber;
5 |
6 | public class NaturalNumberTest extends TestCase {
7 |
8 | public void testCreate() {
9 | NaturalNumber number = new NaturalNumber(1);
10 | assertEquals(1, number.getNumber());
11 | }
12 |
13 | public void testCreateWhenUnderZero() {
14 | try {
15 | NaturalNumber number = new NaturalNumber(0);
16 | fail("IllegalArgumentException 에러가 발생해야 한다.");
17 | } catch (IllegalArgumentException e) {
18 | assertTrue(true);
19 | }
20 | }
21 |
22 | public void testToArrayIndex() {
23 | NaturalNumber number = new NaturalNumber(3);
24 | assertEquals(2, number.toArrayIndex());
25 | }
26 |
27 | public void testCreateFromArrayIndex() {
28 | NaturalNumber actual = NaturalNumber.createFromArrayIndex(1);
29 | assertEquals(new NaturalNumber(2), actual);
30 | }
31 |
32 | public void testMultiply() {
33 | NaturalNumber number = new NaturalNumber(3);
34 | NaturalNumber actual = number.multiply(new NaturalNumber(4));
35 | assertEquals(new NaturalNumber(12), actual);
36 | }
37 |
38 | public void testIsFirst() {
39 | NaturalNumber number = new NaturalNumber(1);
40 | assertTrue(number.isFirst());
41 |
42 | number = new NaturalNumber(2);
43 | assertFalse(number.isFirst());
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/test/ladder/LadderGameTest.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 | import junit.framework.TestCase;
5 |
6 | public class LadderGameTest extends TestCase {
7 |
8 | public void testRunBigLadder() {
9 | LadderGame ladderGame = LadderGameFactory.randomLadderGame(new NaturalNumber(4), new NaturalNumber(6));
10 | Marker result = ladderGame.run(new Marker(2));
11 | System.out.println(result);
12 | }
13 |
14 | public void testRunWhenRandomLadderAndDrawLine() {
15 | try {
16 | LadderGame ladderGame = LadderGameFactory.randomLadderGame(new NaturalNumber(10), new NaturalNumber(6));
17 | ladderGame.drawLine(new NaturalNumber(1), new NaturalNumber(1));
18 | fail();
19 | } catch (Exception e) {
20 | assertTrue(true);
21 | }
22 | }
23 |
24 | public void testRunWhenRandomLadder() {
25 | LadderGame ladderGame = LadderGameFactory.randomLadderGame(new NaturalNumber(3), new NaturalNumber(4));
26 | Marker result = ladderGame.run(new Marker(2));
27 | System.out.println(result);
28 | }
29 |
30 | public void testRunWhenManualLadder() {
31 | // 1 -1 0 0
32 | // 0 1 -1 0
33 | // 0 0 1 -1
34 | LadderGame ladderGame = LadderGameFactory.manualLadderGame(new NaturalNumber(3), new NaturalNumber(4));
35 | ladderGame.drawLine(new NaturalNumber(1), new NaturalNumber(1));
36 | ladderGame.drawLine(new NaturalNumber(2), new NaturalNumber(2));
37 | ladderGame.drawLine(new NaturalNumber(3), new NaturalNumber(3));
38 |
39 | assertEquals(new Marker(4), ladderGame.run(new Marker(1)));
40 | assertEquals(new Marker(1), ladderGame.run(new Marker(2)));
41 | assertEquals(new Marker(2), ladderGame.run(new Marker(3)));
42 | assertEquals(new Marker(3), ladderGame.run(new Marker(4)));
43 | }
44 |
45 | public void testDrawLineWhenOverNoOfRows() {
46 | try {
47 | LadderGame ladderGame = LadderGameFactory.manualLadderGame(new NaturalNumber(3), new NaturalNumber(4));
48 | ladderGame.drawLine(new NaturalNumber(4), new NaturalNumber(4));
49 | fail("IllegalArgumentException 에러가 발생해야 한다.");
50 | } catch (IllegalArgumentException e) {
51 | assertTrue(true);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/test/ladder/LadderRunnerTest.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 | import junit.framework.TestCase;
5 |
6 | public class LadderRunnerTest extends TestCase {
7 | public void testGenerateWhenNoLine() {
8 | Row[] rows = new Row[3];
9 | for (int i = 0; i < rows.length; i++) {
10 | rows[i] = new Row(new NaturalNumber(3));
11 | }
12 |
13 | String result = LadderRunner.generate(rows, Position.create(1, 1));
14 | assertEquals("0* 0 0 \n0 0 0 \n0 0 0 \n", result);
15 | }
16 |
17 | public void testGenerateWhenLine() {
18 | Row[] rows = new Row[3];
19 | for (int i = 0; i < rows.length; i++) {
20 | rows[i] = new Row(new NaturalNumber(3));
21 | }
22 | rows[0].drawLine(new NaturalNumber(1));
23 | String result = LadderRunner.generate(rows, Position.create(1, 1));
24 | assertEquals("1* -1 0 \n0 0 0 \n0 0 0 \n", result);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/test/ladder/MarkerTest.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import junit.framework.TestCase;
4 |
5 | public class MarkerTest extends TestCase {
6 |
7 | public void testMoveRight() {
8 | Marker marker = new Marker(3);
9 | assertEquals(new Marker(4), marker.moveRight());
10 | }
11 |
12 | public void testMoveLeft() {
13 | Marker marker = new Marker(3);
14 | assertEquals(new Marker(2), marker.moveLeft());
15 | }
16 | }
--------------------------------------------------------------------------------
/test/ladder/NodeTest.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import junit.framework.TestCase;
4 |
5 | import static ladder.Node.Direction.*;
6 |
7 | public class NodeTest extends TestCase {
8 |
9 | public void testCreateCenter() {
10 | Node node = Node.createCenterNode();
11 | assertEquals(CENTER, node.getDirection());
12 | }
13 |
14 | public void testChangeRight() {
15 | Node node = Node.createCenterNode();
16 | node.changeRight();
17 | assertEquals(Node.createRightNode(), node);
18 | }
19 |
20 | public void testChangeLeft() {
21 | Node node = Node.createCenterNode();
22 | node.changeLeft();
23 | assertEquals(Node.createLeftNode(), node);
24 | }
25 |
26 | public void testMoveRight() {
27 | Node node = Node.createRightNode();
28 | Marker marker = node.move(new Marker(3));
29 | assertEquals(new Marker(4), marker);
30 | }
31 |
32 | public void testMoveLeft() {
33 | Node node = Node.createLeftNode();
34 | Marker marker = node.move(new Marker(3));
35 | assertEquals(new Marker(2), marker);
36 | }
37 |
38 | public void testMoveCenter() {
39 | Node node = Node.createCenterNode();
40 | Marker marker = node.move(new Marker(3));
41 | assertEquals(new Marker(3), marker);
42 | }
43 |
44 | public void testSymbol() {
45 | Node node = Node.createCenterNode();
46 | StringBuilder sb = new StringBuilder();
47 | node.appendSymbol(sb);
48 | assertEquals("0", sb.toString());
49 | // node = Node.createLeftNode();
50 | // assertEquals(-1, node.getSymbol());
51 | // node = Node.createRightNode();
52 | // assertEquals(1, node.getSymbol());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/test/ladder/PositionTest.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 | import junit.framework.TestCase;
5 |
6 | public class PositionTest extends TestCase {
7 |
8 | public void testCreate() {
9 | Position position = Position.create(new NaturalNumber(3), new NaturalNumber(4));
10 | Position position2 = Position.create(3, 4);
11 | assertEquals(position, position2);
12 | }
13 |
14 | public void testCreateFromArrayIndex() {
15 | Position arrayPosition = Position.createFromArrayIndex(2, 3);
16 | Position position = Position.create(new NaturalNumber(3), new NaturalNumber(4));
17 | assertEquals(position, arrayPosition);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/test/ladder/RandomNaturalNumberTest.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 | import java.util.List;
5 | import junit.framework.TestCase;
6 |
7 | public class RandomNaturalNumberTest extends TestCase {
8 |
9 | public void testGetPositionOfPerson() {
10 | RandomNaturalNumber number = new RandomNaturalNumber(4);
11 | int actual = number.getPositionOfPerson(3);
12 | // 1 2 3
13 | // 4 5 6 => 높이는 2, 사람의 위치는 1
14 | assertEquals(1, actual);
15 | }
16 |
17 | public void testGetPositionOfHeight() {
18 | RandomNaturalNumber number = new RandomNaturalNumber(4);
19 | int actual = number.getPositionOfHeight(3);
20 | assertEquals(2, actual);
21 | }
22 |
23 | public void testIsMultipleOfPerson() {
24 | RandomNaturalNumber randomNumber = new RandomNaturalNumber(8);
25 | assertTrue(randomNumber.isMultipleOfPerson(4));
26 | randomNumber = new RandomNaturalNumber(5);
27 | assertFalse(randomNumber.isMultipleOfPerson(3));
28 | }
29 |
30 | public void testRandomNumberEquals() {
31 | assertTrue(new RandomNaturalNumber(1).equals(new NaturalNumber(1)));
32 | assertTrue(new NaturalNumber(1).equals(new RandomNaturalNumber(1)));
33 | }
34 |
35 | public void testCheckedNaturalNumbers() {
36 | RandomNaturalNumber randomNumber = new RandomNaturalNumber(2);
37 | List naturalNumbers = randomNumber.checkedNaturalNumbers(new NaturalNumber(3));
38 | assertTrue(naturalNumbers.size() == 3);
39 | }
40 |
41 | public void testCheckNaturalNumbersWheFirst() {
42 | RandomNaturalNumber randomNumber = new RandomNaturalNumber(4);
43 | List naturalNumbers = randomNumber.checkedNaturalNumbers(new NaturalNumber(3));
44 | assertTrue(naturalNumbers.size() == 2);
45 | }
46 | }
--------------------------------------------------------------------------------
/test/ladder/RowTest.java:
--------------------------------------------------------------------------------
1 | package ladder;
2 |
3 | import core.NaturalNumber;
4 | import junit.framework.TestCase;
5 |
6 | public class RowTest extends TestCase {
7 |
8 | private Row row;
9 |
10 | public void setUp() throws Exception {
11 | row = new Row(new NaturalNumber(3));
12 | }
13 |
14 | public void testStartPositionWhenOvernoOfPersons() {
15 | try {
16 | row.drawLine(new NaturalNumber(3));
17 | fail("IllegalArgumentException 에러가 발생해야 한다.");
18 | } catch (IllegalArgumentException e) {
19 | assertTrue(true);
20 | }
21 | }
22 |
23 | public void testDrawLineWhenAlreadyDrawingPoint() {
24 | try {
25 | row.drawLine(new NaturalNumber(1));
26 | row.drawLine(new NaturalNumber(2));
27 | fail("IllegalArgumentException 에러가 발생해야 한다.");
28 | } catch (IllegalArgumentException e) {
29 | assertTrue(true);
30 | }
31 | }
32 |
33 | public void testMoveWhenNoLine() {
34 | NaturalNumber target = row.move(new Marker(1));
35 | assertEquals(1, target.getNumber());
36 |
37 | target = row.move(new Marker(3));
38 | assertEquals(3, target.getNumber());
39 | }
40 |
41 | public void testMoveWhenLineLeft() {
42 | // 0 1 1
43 | row.drawLine(new NaturalNumber(2));
44 | NaturalNumber target = row.move(new Marker(3));
45 | assertEquals(2, target.getNumber());
46 | }
47 |
48 | public void testMoveWhenLineRight() {
49 | // 0 1 1
50 | row.drawLine(new NaturalNumber(2));
51 | NaturalNumber target = row.move(new Marker(2));
52 | assertEquals(3, target.getNumber());
53 | }
54 | }
--------------------------------------------------------------------------------
/test/ladder/creator/RandomLadderCreatorTest.java:
--------------------------------------------------------------------------------
1 | package ladder.creator;
2 |
3 | import core.NaturalNumber;
4 | import java.util.List;
5 | import junit.framework.TestCase;
6 | import ladder.Position;
7 |
8 | public class RandomLadderCreatorTest extends TestCase {
9 |
10 | public void testGenerateStartPositions() {
11 | ManualLadderCreator manualLadderCreator = new ManualLadderCreator(new NaturalNumber(3), new NaturalNumber(4));
12 | RandomLadderCreator creator = new RandomLadderCreator(manualLadderCreator);
13 | List positions = creator.generateStartPositions();
14 | for (Position position : positions) {
15 | System.out.println(String.format("position : %s", position));
16 |
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------