Skip to content

[사다리] 이예진 사다리 게임 구현 (1-5단계) #66

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

Merged
merged 6 commits into from
Jun 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# java-ladder : 사다리 - 함수형 프로그래밍

## Level1. 사다리 출력

### - 요구사항

- [x] 네이버 사다리 게임을 참고하여 도메인을 분석하여 구현한다.
- [x] 사다리는 4x4 크기로 고정되고, 연결 여부는 랜덤으로 결정한다.
- [x] 사다리 타기가 정상적으로 동작하려면 라인이 겹치지 않도록 해야 한다.
- [x] 모든 엔티티를 작게 유지한다.
- [x] 3개 이상의 인스턴스 변수를 가진 클래스를 쓰지 않는다.

## Level2. 사다리 생성

### - 요구사항

- [x] 사다리는 크기를 입력 받아 생성할 수 있다. (넓이 & 높이)

## Level3. 사다리 타기

### - 요구사항

- [x] 사다리의 시작 지점과 도착 지점을 출력한다.

## Level4. 게임 실행

### - 요구사항

- [x] 사다리 게임에 참여하는 사람에 이름을 최대 5글자까지 부여할 수 있다. 사다리를 출력할 때 사람 이름도 같이 출력한다.
- [x] 사람 이름은 쉼표(,)를 기준으로 구분한다.
- [x] 개인별 이름을 입력하면 개인별 결과를 출력하고, "all"을 입력하면 전체 참여자의 실행 결과를 출력한다.

## Level5. 리팩토링

### - 요구사항

- [x] 학습 테스트를 통해 학습한 내용을 반영한다. 자바에서 제공하는 함수형 문법을 적용해보고, 어떠한 차이가 있는지 경험한다.
13 changes: 13 additions & 0 deletions src/main/java/ladder/controller/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package ladder.controller;

import ladder.view.InputView;
import ladder.view.OutputView;

public class Application {
public static void main(String[] args) {
InputView inputView = new InputView();
OutputView outputView = new OutputView();
LadderGame game = new LadderGame(inputView, outputView);
game.play();
}
}
56 changes: 56 additions & 0 deletions src/main/java/ladder/controller/LadderGame.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package ladder.controller;

import java.util.List;
import java.util.stream.Collectors;
import ladder.model.Ladder;
import ladder.model.LadderResult;
import ladder.model.Participants;
import ladder.model.Point;
import ladder.model.Result;
import ladder.view.InputView;
import ladder.view.OutputView;

public class LadderGame {

private final InputView inputView;
private final OutputView outputView;

public LadderGame(InputView inputView, OutputView outputView) {
this.inputView = inputView;
this.outputView = outputView;
}

public void play() {
Participants participants = inputView.inputParticipants();
List<Result> results = inputView.inputResults();
int height = inputView.inputHeight();

Ladder ladder = Ladder.create(participants.size(), height);
outputView.printLadder(ladder, participants, results);

String resultRequest = inputView.inputGameResult();
processResult(ladder, participants, results, resultRequest);
}

private void processResult(Ladder ladder, Participants participants, List<Result> results,
String resultRequest) {
List<Point> ladderResults = ladder.result();
List<Result> mappedResults = mapResults(results, ladderResults);
LadderResult ladderResult = new LadderResult(participants, mappedResults);
printGameResults(resultRequest, ladderResult);
}

private void printGameResults(String result, LadderResult gameLadderResult) {
if ("all".equals(result)) {
outputView.printAllResults(gameLadderResult);
return;
}
outputView.printSingleResult(gameLadderResult.getResult(result));
}

private List<Result> mapResults(List<Result> inputResults, List<Point> ladderResults) {
return ladderResults.stream()
.map(point -> inputResults.get(point.getEnd()))
.collect(Collectors.toList());
}
}
63 changes: 63 additions & 0 deletions src/main/java/ladder/model/Ladder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package ladder.model;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class Ladder {

private final List<Line> lines;

private Ladder(List<Line> lines) {
this.lines = lines;
}

public static Ladder create(int width, int height) {
return new Ladder(
IntStream.range(0, height)
.mapToObj(i -> Line.create(width))
.collect(Collectors.toList())
);
}

public List<Line> getLines() {
return lines;
}

public List<Point> result() {
int width = lines.get(0).getPoints().size() + 1;
return IntStream.range(0, width)
.mapToObj(start -> new Point(start, getEndPoint(start))) // 출발점과 도착점을 Point로 묶음
.collect(Collectors.toList());
}

private int getEndPoint(int start) {
int position = start;

for (Line line : lines) {
position = move(position, line.getPoints());
}

return position;
}

private int move(int position, List<Boolean> points) {
if (canMoveLeft(position, points)) {
return position - 1;
}

if (canMoveRight(position, points)) {
return position + 1;
}

return position;
}

private boolean canMoveLeft(int position, List<Boolean> points) {
return position > 0 && points.get(position - 1);
}

private boolean canMoveRight(int position, List<Boolean> points) {
return position < points.size() && points.get(position);
}
}
31 changes: 31 additions & 0 deletions src/main/java/ladder/model/LadderResult.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ladder.model;

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

public class LadderResult {

private final Participants participants;
private final List<Result> results;

public LadderResult(Participants participants, List<Result> results) {
this.participants = participants;
this.results = results;
}

public List<Result> getAll() {
return new ArrayList<>(results);
}

public List<Name> getParticipants() {
return participants.getParticipantsNameList();
}

public Result getResult(String participant) {
return participants.getParticipantsNameList().stream()
.filter(name -> name.matches(participant))
.findFirst()
.map(name -> results.get(participants.getParticipantsNameList().indexOf(name)))
.orElseThrow(() -> new IllegalArgumentException("존재하지 않는 참가자입니다."));
}
}
40 changes: 40 additions & 0 deletions src/main/java/ladder/model/Line.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package ladder.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Line {

private static final Random random = new Random();
private final List<Boolean> points;

private Line(List<Boolean> points) {
this.points = points;
}

public List<Boolean> getPoints() {
return new ArrayList<>(points);
}

public static Line create(int width) {
List<Boolean> connections = new ArrayList<>();
for (int i = 0; i < width - 1; i++) {
// 새로운 라인 연결 여부
boolean shouldConnect = isConnectable(i, connections);
connections.add(shouldConnect);
}
return new Line(connections);
}

private static boolean isConnectable(int currentIndex, List<Boolean> connections) {
// 첫 번째 위치라면? 바로 Random 값 설정
if (currentIndex == 0) {
return random.nextBoolean();
}

// 바로 이전 연결 여부를 확인 -> 연속된 라인(true) 방지
boolean previousConnected = connections.get(currentIndex - 1);
return !previousConnected && new Random().nextBoolean();
}
}
42 changes: 42 additions & 0 deletions src/main/java/ladder/model/Name.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package ladder.model;

import java.util.Objects;

public class Name {

private static final int MAX_LENGTH = 5;
private final String value;

public Name(String value) {
if (value.length() > MAX_LENGTH) {
throw new IllegalArgumentException("이름은 최대 5글자까지 가능합니다.");
}
this.value = value;
}

public boolean matches(String other) {
return value.equals(other);
}

@Override
public String toString() {
return value;
}
Comment on lines +21 to +24

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Name의 경우 필드가 하나만 존재해서, toString을 정의하여 사용해도 되지만...
toString의 사용은 디버깅 또는 로깅 목적으로 사용하는 것이 바람직해요.
https://stackoverflow.com/questions/2329168/when-to-use-tostring-method

특정 클래스는 toString을 정의하지 않는다면 코드 간 일관성이 떨어지게 되고, 이는 유지보수성의 저하로 이어지게 될 거예요.
(이전 리뷰에도 남겼지만, toString이 사용자의 응답에 영향이 간다는 것을 쉽게 알아차리기 힘들어요)


@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Name name = (Name) o;
return Objects.equals(value, name.value);
}

@Override
public int hashCode() {
return Objects.hash(value);
}
}
25 changes: 25 additions & 0 deletions src/main/java/ladder/model/Participants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package ladder.model;

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

public class Participants {

private final List<Name> names;

private Participants(List<Name> names) {
this.names = names;
}

public static Participants of(List<Name> names) {
return new Participants(new ArrayList<>(names));
}

public int size() {
return names.size();
}

public List<Name> getParticipantsNameList() {
return new ArrayList<>(names);
}
}
44 changes: 44 additions & 0 deletions src/main/java/ladder/model/Point.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package ladder.model;

import java.util.Objects;

public class Point {

private final int start;
private final int end;

public Point(int start, int end) {
this.start = start;
this.end = end;
}

public int getStart() {
return start;
}

public int getEnd() {
return end;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Point point = (Point) o;
return start == point.start && end == point.end;
}

@Override
public int hashCode() {
return Objects.hash(start, end);
}

@Override
public String toString() {
return "Point{" + "start=" + start + ", end=" + end + '}';
}
Comment on lines +40 to +43

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위 Name 리뷰에서 이어지는 내용인데, Name의 toString을 재정의해서 사용자의 응답에 사용했다면, 해당 메서드의 toString 또한 사용자의 응답에 사용해도 될까요?

}
31 changes: 31 additions & 0 deletions src/main/java/ladder/model/Result.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package ladder.model;

public class Result {

private final String value;

public Result(String value) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException("결과 값은 비어있을 수 없습니다.");
}
this.value = value;
}

@Override
public String toString() {
return value;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Result result = (Result) o;
return value.equals(result.value);
}

@Override
public int hashCode() {
return value.hashCode();
}
}
Loading