-
Notifications
You must be signed in to change notification settings - Fork 709
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
Step2 #1830
base: devcat36
Are you sure you want to change the base?
Step2 #1830
Changes from all commits
8c6aa5b
1f5acb8
e32131a
fae458d
2aa5b58
285e2ac
4601a1a
e286dd2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package nextstep.ladder; | ||
|
||
public interface GenerationStrategy { | ||
boolean shouldPlace(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package nextstep.ladder; | ||
|
||
public class Ladder { | ||
public final Natural height; | ||
public final Users users; | ||
public final Legs legs; | ||
|
||
public Ladder(Users users, Natural height, GenerationStrategy strategy) { | ||
this.height = height; | ||
this.users = users; | ||
legs = new Legs(height, users.size(), strategy); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package nextstep.ladder; | ||
|
||
public class LadderController { | ||
private static final LadderView view = new LadderView(); | ||
public static void main(String[] args) { | ||
var users = view.getUsers(); | ||
var height = view.getHeight(); | ||
|
||
var ladder = new Ladder(users, height, new RandomGenerationStrategy()); | ||
view.printResults(ladder); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package nextstep.ladder; | ||
|
||
import java.util.Scanner; | ||
|
||
public class LadderView { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Input / Output 클래스를 분리하는것도 좋아보입니다 😄 |
||
public Users getUsers() { | ||
System.out.println("참여할 사람 이름을 입력하세요. (이름은 쉼표(,)로 구분하세요)"); | ||
var userInput = new UsersInput(getConsoleInput()); | ||
return userInput.toUsers(); | ||
} | ||
|
||
public Natural getHeight() { | ||
System.out.println("최대 사다리 높이는 몇 개인가요?"); | ||
var naturalInput = new NaturalInput(getConsoleInput()); | ||
return naturalInput.toNatural(); | ||
} | ||
|
||
public void printResults(Ladder ladder) { | ||
System.out.println("실행결과"); | ||
|
||
ladder.users.forEach(user -> System.out.printf("%s\t", user)); | ||
printNewLine(); | ||
for (var level = ladder.height.value() - 1; level >= 0; level--) { | ||
printLevel(level, ladder); | ||
} | ||
} | ||
|
||
private static void printLevel(long level, Ladder ladder) { | ||
for (var place = 0; place < ladder.users.size().value() - 1; place++) { | ||
printColumn(); | ||
printLegIfExistsInLadder(new Position(level, place), ladder); | ||
} | ||
printColumn(); | ||
printNewLine(); | ||
} | ||
|
||
private static void printNewLine() { | ||
System.out.println(); | ||
} | ||
|
||
private static void printColumn() { | ||
System.out.print("|"); | ||
} | ||
|
||
private static void printLegIfExistsInLadder(Position position, Ladder ladder) { | ||
if (ladder.legs.hasLegOnRightSideOf(position)) { | ||
printFilledLeg(); | ||
return; | ||
} | ||
printEmptyLeg(); | ||
} | ||
|
||
private static void printEmptyLeg() { | ||
System.out.print(" "); | ||
} | ||
|
||
private static void printFilledLeg() { | ||
System.out.print("-----"); | ||
} | ||
|
||
private String getConsoleInput() { | ||
Scanner scanner = new Scanner(System.in); | ||
return scanner.nextLine(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package nextstep.ladder; | ||
|
||
import java.util.HashSet; | ||
import java.util.Set; | ||
import java.util.stream.LongStream; | ||
|
||
public class Legs { | ||
private final Set<Position> legLeftPositions; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Legs일급 컬렉션이 사다리 연결선의 정보를 가지는 Position을 가지는것 보다 Leg라는 클래스를 도출하여 사다리 가로 한줄과 연결선에 대한 정보를 가지는 Position의 구현은 어떻게 생각하시나요 ? |
||
|
||
public Legs(Natural height, Natural width, GenerationStrategy strategy) { | ||
legLeftPositions = new HashSet<>(); | ||
placeLegs(height, width, strategy); | ||
} | ||
|
||
private void placeLegs(Natural height, Natural width, GenerationStrategy strategy) { | ||
LongStream.range(0, height.value()) | ||
.mapToObj(Natural::new) | ||
.forEach(level -> placeLegsInLevel(level, width, strategy)); | ||
} | ||
|
||
private void placeLegsInLevel(Natural level, Natural width, GenerationStrategy strategy) { | ||
LongStream.range(0, width.value() - 1) | ||
.mapToObj(Natural::new) | ||
.map(place -> new Position(level, place)) | ||
.forEach(position -> placeLegWithStrategy(strategy, position)); | ||
} | ||
|
||
private void placeLegWithStrategy(GenerationStrategy strategy, Position position) { | ||
if (isLegPlaceableOnPosition(position) && strategy.shouldPlace()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. strategy는 매번 random boolean 값을 리턴하고, 현재 위치 기준으로 왼쪽 사다리 연결 선이 존재하는지 검증 👍 |
||
legLeftPositions.add(position); | ||
} | ||
} | ||
|
||
private boolean isLegPlaceableOnPosition(Position position) { | ||
return isOnTheLeftEdge(position) || !hasLegOnRightSideOf(position.getLeftPosition()); | ||
} | ||
|
||
private boolean isOnTheLeftEdge(Position position) { | ||
return position.place.value() == 0; | ||
} | ||
|
||
public boolean hasLegOnRightSideOf(Position position) { | ||
return legLeftPositions.contains(position); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package nextstep.ladder; | ||
|
||
public class Natural implements Comparable<Natural> { | ||
private final Long value; | ||
|
||
public Natural(long value) { | ||
if (value < 0) { | ||
throw new IllegalArgumentException("Negative value given for natural number"); | ||
} | ||
this.value = value; | ||
} | ||
|
||
public Long value() { | ||
return value; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (o instanceof Natural) { | ||
return value.equals(((Natural) o).value); | ||
} | ||
return false; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return value.hashCode(); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return value.toString(); | ||
} | ||
|
||
@Override | ||
public int compareTo(Natural o) { | ||
return value.compareTo(o.value); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package nextstep.ladder; | ||
|
||
public class NaturalInput { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NaturalInput을 활용하여 Natural객체를 생성하는것보단 Natural에 다양한 생성자를 정의해보는건 어떨까요 ? |
||
private final String input; | ||
|
||
public NaturalInput(String input) { | ||
this.input = input; | ||
checkInputIsNaturalNumber(); | ||
} | ||
|
||
public Natural toNatural() { | ||
return new Natural(Long.parseLong(input)); | ||
} | ||
|
||
private void checkInputIsNaturalNumber() { | ||
if (!input.matches("\\d+")) { | ||
throw new IllegalArgumentException("Input is not a natural number"); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package nextstep.ladder; | ||
|
||
import java.util.Objects; | ||
|
||
public class Position { | ||
public final Natural level; | ||
public final Natural place; | ||
|
||
public Position(Natural level, Natural place) { | ||
this.level = level; | ||
this.place = place; | ||
} | ||
|
||
public Position(long level, long place) { | ||
this.level = new Natural(level); | ||
this.place = new Natural(place); | ||
} | ||
|
||
public Position getLeftPosition() { | ||
return new Position(level.value(), place.value() - 1); | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (o instanceof Position) { | ||
var that = (Position) o; | ||
return level.equals(that.level) && place.equals(that.place); | ||
} | ||
return false; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(level, place); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package nextstep.ladder; | ||
|
||
import java.util.Random; | ||
|
||
public class RandomGenerationStrategy implements GenerationStrategy { | ||
private final Random random = new Random(); | ||
@Override | ||
public boolean shouldPlace() { | ||
return random.nextBoolean(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package nextstep.ladder; | ||
|
||
import java.util.Iterator; | ||
import java.util.List; | ||
|
||
public class Users implements Iterable<String> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 사다리 게임에 참여하는 유저가 1명 이하인경우 정상적인 게임이 동작할수 있을까요 ? |
||
private final List<String> users; | ||
|
||
public Users(List<String> users) { | ||
this.users = users; | ||
} | ||
|
||
@Override | ||
public Iterator<String> iterator() { | ||
return users.iterator(); | ||
} | ||
|
||
public Natural size() { | ||
return new Natural(users.size()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package nextstep.ladder; | ||
|
||
import java.util.Arrays; | ||
|
||
public class UsersInput { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NatualInput 코멘트와 동일합니다 😄 |
||
private final String input; | ||
|
||
public UsersInput(String input) { | ||
this.input = input; | ||
} | ||
|
||
public Users toUsers() { | ||
return new Users(Arrays.asList(input.replace(" ", "").split(","))); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package nextstep.ladder; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import java.util.List; | ||
|
||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; | ||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; | ||
|
||
public class LadderTest { | ||
@Test | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @DisplayName 을 활용하여 테스트의 의도를 명확하게 나타내보는건 어떠세요 ? |
||
public void levelAndUsersAreSet() { | ||
var levels = new Natural(5); | ||
var users = new Users(List.of("erik", "jake", "david")); | ||
|
||
var ladder = new Ladder(users, levels, () -> true); | ||
|
||
assertThat(ladder.height).isEqualTo(levels); | ||
assertThat(ladder.users).containsExactly("erik", "jake", "david"); | ||
} | ||
|
||
@Test | ||
public void throwErrorOnNegativeInputs() { | ||
assertThatThrownBy(() -> { | ||
var levels = new Natural(-1); | ||
var users = new Users(List.of()); | ||
new Ladder(users, levels, () -> true); | ||
}).isInstanceOf(IllegalArgumentException.class) | ||
.hasMessage("Negative value given for natural number"); | ||
} | ||
|
||
@Test | ||
public void legsAreNotPlacedConsecutively() { | ||
var height = new Natural(5); | ||
var users = new Users(List.of("erik", "jake", "david")); | ||
|
||
var ladder = new Ladder(users, height, () -> true); | ||
|
||
for (int level = 0; level < height.value(); level++) { | ||
assertThatLegsAreNotPlacedConsecutivelyInLevel(ladder, level, users.size().value()); | ||
} | ||
} | ||
|
||
private static void assertThatLegsAreNotPlacedConsecutivelyInLevel(Ladder ladder, long level, long width) { | ||
for (int place = 1; place < width; place++) { | ||
var currentPosition = new Position(level, place); | ||
var currentLeg = ladder.legs.hasLegOnRightSideOf(currentPosition); | ||
var leftLeg = ladder.legs.hasLegOnRightSideOf(currentPosition.getLeftPosition()); | ||
assert !(leftLeg && currentLeg); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package nextstep.ladder; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.ValueSource; | ||
|
||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy; | ||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; | ||
|
||
public class NaturalInputTest { | ||
@ParameterizedTest | ||
@ValueSource(strings = {"12wr23", " "}) | ||
public void throwErrorOnInvalidInputs(String input) { | ||
assertThatThrownBy(() -> new NaturalInput(input)) | ||
.isInstanceOf(IllegalArgumentException.class) | ||
.hasMessage("Input is not a natural number"); | ||
} | ||
|
||
@Test | ||
public void convertsInputToNatural() { | ||
var input = "5"; | ||
|
||
var natural = new NaturalInput(input).toNatural(); | ||
|
||
assertThat(natural.value()).isEqualTo(5L); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package nextstep.ladder; | ||
|
||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; | ||
|
||
public class UsersInputTest { | ||
@Test | ||
public void parseCommaSplicedUserInput() { | ||
var input = "pobi, honux, crong, jk"; | ||
|
||
var userInput = new UsersInput(input); | ||
|
||
assertThat(userInput.toUsers()).containsExactly("pobi", "honux", "crong", "jk"); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
도메인과 ui 의 패키지를 분리해보는것이 어떨까요 ?