diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..6e86ed79a --- /dev/null +++ b/docs/README.md @@ -0,0 +1,66 @@ +미션 - 지하철 노선도 경로 조회 미션 +======================== + +우아한테크코스 프리코스 온라인 테스트 +------------------------ + +
+ + +### 지하철 노선도 경로 조회 미션 + +``` +목표 : 등록된 지하철 노선도에서 경로를 조회하는 기능을 구현한다. +``` + + +
+ +*** + +
+ +### 기능 구현 목록 + +1. [x] 프로그램 시작 시 주어진 역, 노선, 구간 정보로 초기 설정을 한다. + + +1. [x] 시작 화면을 출력 클래스에 구현한다. + + +1. [x] 원하는 기능을 선택하는 화면을 구현한다. + - [예외사항] 사용자 입력이 주어진 선택지가 아닌 값으로 입력된다.(공백 포함) + + +1. [X] 경로 기준을 선택하는 화면을 구현한다. + + +1. [x] 출발역을 입력받는 화면을 구현한다. + - [예외사항] 출발역이 역 목록에 존재하지 않는다. + + +1. [x] 도착역을 입력받는 화면을 구현한다. + - [예외사항] 도착역이 역 목록에 존재하지 않는다. + - [예외사항] 도착역이 입력받은 출발역과 같다. + + +1. [x] 조회 결과를 출력하는 화면을 구현한다. + + +1. [x] 거리를 기준으로 최단거리 경로를 연산하는 클래스를 구현한다. + + +1. [x] 시간을 기준으로 최단시간 경로를 연산하는 클래스를 구현한다. + + + + +
+ +*** + +
+ +## 📝 License + +This project is [MIT](https://github.com/woowacourse/java-subway-path-precourse/blob/master/LICENSE.md) licensed. diff --git a/src/main/java/subway/Application.java b/src/main/java/subway/Application.java index 0bcf786cc..34b26e870 100644 --- a/src/main/java/subway/Application.java +++ b/src/main/java/subway/Application.java @@ -1,10 +1,13 @@ package subway; import java.util.Scanner; +import subway.Controller.SubwayRouteSearcher; public class Application { + public static void main(String[] args) { final Scanner scanner = new Scanner(System.in); // TODO: 프로그램 구현 + SubwayRouteSearcher.startProgram(scanner); } } diff --git a/src/main/java/subway/Controller/Initializer.java b/src/main/java/subway/Controller/Initializer.java new file mode 100644 index 000000000..3e71a5689 --- /dev/null +++ b/src/main/java/subway/Controller/Initializer.java @@ -0,0 +1,70 @@ +package subway.Controller; + +import java.util.Arrays; +import java.util.List; +import subway.domain.DistanceWeightRepository; +import subway.domain.Line; +import subway.domain.LineRepository; +import subway.domain.Station; +import subway.domain.StationRepository; +import subway.domain.TimeWeightRepository; + +public class Initializer { + + private static List INITIALSTATION = Arrays + .asList("교대역", "강남역", "역삼역", "남부터미널역", "양재역", "양재시민의숲역", "매봉역"); + private static List INITIALLINE = Arrays.asList("2호선", "3호선", "신분당선"); + private static List LINETWO = Arrays.asList("교대역", "강남역", "역삼역"); + private static int[] LINETWOTIME = {2, 3}; + private static int[] LINETWODISTANCE = {3, 3}; + private static List LINETHREE = Arrays.asList("교대역", "남부터미널역", "양재역", "매봉역"); + private static int[] LINETHREETIME = {3, 6, 1}; + private static int[] LINETHREEDISTANCE = {2, 5, 1}; + private static List LINESHINBUNDANG = Arrays.asList("강남역", "양재역", "양재시민의숲역"); + private static int[] LINESHINBUNDANGTIME = {2, 10}; + private static int[] LINESHINBUNDANGDISTANCE = {8, 3}; + private static List> INITIALLINESTATION = Arrays + .asList(LINETWO, LINETHREE, LINESHINBUNDANG); + + public static void setInitializeBaseSetting() { + setInitializeLine(INITIALLINE); + setInitializeStation(INITIALSTATION); + setInitialVertex(INITIALSTATION); + setInitialWeight(LINETWO, LINETWOTIME, LINETWODISTANCE); + setInitialWeight(LINETHREE, LINETHREETIME, LINETHREEDISTANCE); + setInitialWeight(LINESHINBUNDANG, LINESHINBUNDANGTIME, LINESHINBUNDANGDISTANCE); + } + + private static void setInitializeStation(List INITIALSTATION) { + for (String stationName : INITIALSTATION) { + Station station = new Station(stationName); + StationRepository.addStation(station); + } + } + + private static void setInitializeLine(List INITIALLINE) { + for (int i = 0; i < INITIALLINE.size(); i++) { + Line line = new Line(INITIALLINE.get(i)); + line.addLineStation(INITIALLINESTATION.get(i)); + LineRepository.addLine(line); + } + } + + private static void setInitialVertex(List stationNames) { + for (String stationName : stationNames) { + TimeWeightRepository.addStation(stationName); + DistanceWeightRepository.addStation(stationName); + } + } + + private static void setInitialWeight(List lineNumber, int[] timeWeight, + int[] distanceWeight) { + for (int i = 0; i < lineNumber.size() - 1; i++) { + TimeWeightRepository + .setStationEdgeTime(lineNumber.get(i), lineNumber.get(i + 1), timeWeight[i]); + DistanceWeightRepository + .setStationEdgeDistance(lineNumber.get(i), lineNumber.get(i + 1), + distanceWeight[i]); + } + } +} diff --git a/src/main/java/subway/Controller/MinDistanceCalculator.java b/src/main/java/subway/Controller/MinDistanceCalculator.java new file mode 100644 index 000000000..c0e3a9b6f --- /dev/null +++ b/src/main/java/subway/Controller/MinDistanceCalculator.java @@ -0,0 +1,21 @@ +package subway.Controller; + +import java.util.List; +import java.util.Scanner; +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.WeightedMultigraph; +import subway.Views.MainView; +import subway.Views.OutputView; +import subway.domain.DistanceWeightRepository; + +public class MinDistanceCalculator { + + public static void calculateMinDistance(Scanner scanner) { + String startStation = MainView.printStartStation(scanner); + String endStation = MainView.printEndStation(scanner, startStation); + + List result = DistanceWeightRepository + .getDijkstraShortestPath(startStation, endStation); + MainView.printResultScreen(scanner, result); + } +} diff --git a/src/main/java/subway/Controller/MinTimeCalculator.java b/src/main/java/subway/Controller/MinTimeCalculator.java new file mode 100644 index 000000000..180ce407f --- /dev/null +++ b/src/main/java/subway/Controller/MinTimeCalculator.java @@ -0,0 +1,18 @@ +package subway.Controller; + +import java.util.List; +import java.util.Scanner; +import subway.Views.MainView; +import subway.Views.OutputView; +import subway.domain.DistanceWeightRepository; + +public class MinTimeCalculator { + + public static void calculateMinTime(Scanner scanner) { + String startStation = MainView.printStartStation(scanner); + String endStation = MainView.printEndStation(scanner, startStation); + List result = + DistanceWeightRepository.getDijkstraShortestPath(startStation, endStation); + MainView.printResultScreen(scanner, result); + } +} diff --git a/src/main/java/subway/Controller/SubwayRouteSearcher.java b/src/main/java/subway/Controller/SubwayRouteSearcher.java new file mode 100644 index 000000000..be67effab --- /dev/null +++ b/src/main/java/subway/Controller/SubwayRouteSearcher.java @@ -0,0 +1,30 @@ +package subway.Controller; + +import java.util.Scanner; +import subway.Views.MainView; + +public class SubwayRouteSearcher { + + public static void startProgram(Scanner scanner) { + Initializer.setInitializeBaseSetting(); + MainView.printMainScreen(scanner); + } + + public static void selectMain(Scanner scanner, String userMainSelection) { + if (userMainSelection.equals("1")) { + MainView.printRouteScreen(scanner); + } + } + + public static void selectRoute(Scanner scanner, String userRouteSelection) { + if (userRouteSelection.equals("1")) { + MinDistanceCalculator.calculateMinDistance(scanner); + } + if (userRouteSelection.equals("2")) { + MinTimeCalculator.calculateMinTime(scanner); + } + if (userRouteSelection.equals("B")) { + MainView.printMainScreen(scanner); + } + } +} \ No newline at end of file diff --git a/src/main/java/subway/Views/InputView.java b/src/main/java/subway/Views/InputView.java new file mode 100644 index 000000000..58a301d5a --- /dev/null +++ b/src/main/java/subway/Views/InputView.java @@ -0,0 +1,25 @@ +package subway.Views; + +import java.util.Scanner; + +public class InputView { + + private final static String FUNCTIONSELECTION = "## 원하는 기능을 선택하세요."; + private final static String STARTSTATION = "## 출발역을 입력하세요."; + private final static String ENDSTATION = "## 도착역을 입력하세요."; + + protected static String getUserInput(Scanner scanner) { + System.out.println(FUNCTIONSELECTION); + return scanner.nextLine(); + } + + protected static String getStartStation(Scanner scanner) { + System.out.println(STARTSTATION); + return scanner.nextLine(); + } + + protected static String getEndStation(Scanner scanner) { + System.out.println(ENDSTATION); + return scanner.nextLine(); + } +} diff --git a/src/main/java/subway/Views/MainView.java b/src/main/java/subway/Views/MainView.java new file mode 100644 index 000000000..d70e345c9 --- /dev/null +++ b/src/main/java/subway/Views/MainView.java @@ -0,0 +1,94 @@ +package subway.Views; + +import java.util.Arrays; +import java.util.InputMismatchException; +import java.util.List; +import java.util.Scanner; +import subway.Controller.SubwayRouteSearcher; +import subway.utils.ErrorValidator; + +public class MainView { + + private final static List MAINSELECTLIST = Arrays.asList("1", "Q"); + private final static List ROUTESELECTLIST = Arrays.asList("1", "2", "B"); + + public static void printMainScreen(Scanner scanner) { + OutputView.printMainSelection(); + String userMainSelection = InputView.getUserInput(scanner); + System.out.println(); + checkUserInput(scanner, userMainSelection, MAINSELECTLIST); + SubwayRouteSearcher.selectMain(scanner, userMainSelection); + } + + public static void printRouteScreen(Scanner scanner) { + OutputView.printRouteSelection(); + String userRouteSelection = InputView.getUserInput(scanner); + System.out.println(); + checkUserInput(scanner, userRouteSelection, ROUTESELECTLIST); + SubwayRouteSearcher.selectRoute(scanner, userRouteSelection); + } + + public static void printResultScreen(Scanner scanner, List resultList) { + OutputView.printResultRoute(resultList); + System.out.println(); + MainView.printMainScreen(scanner); + } + + + private static void checkUserInput(Scanner scanner, String userSelection, + List SELECTLIST) { + try { + ErrorValidator.checkMainSelection(SELECTLIST, userSelection); + } catch (InputMismatchException e) { + System.out.println(e.getMessage()); + System.out.println(); + printMainScreen(scanner); + } + } + + public static String printStartStation(Scanner scanner) { + String startStaion = InputView.getStartStation(scanner); + System.out.println(); + checkStartStation(scanner, startStaion); + return startStaion; + } + + public static String printEndStation(Scanner scanner, String startStation) { + String endStaion = InputView.getEndStation(scanner); + System.out.println(); + checkEndStation(scanner, endStaion); + checkStartEndStation(scanner, startStation, endStaion); + return endStaion; + } + + private static void checkStartEndStation(Scanner scanner, String startStation, + String endStaion) { + try { + ErrorValidator.checkStartEndStation(startStation, endStaion); + } catch (InputMismatchException e) { + System.out.println(e.getMessage()); + System.out.println(); + printMainScreen(scanner); + } + } + + private static void checkStartStation(Scanner scanner, String startStaion) { + try { + ErrorValidator.checkStationRepository(startStaion); + } catch (InputMismatchException e) { + System.out.println(e.getMessage()); + System.out.println(); + printMainScreen(scanner); + } + } + + private static void checkEndStation(Scanner scanner, String endStaion) { + try { + ErrorValidator.checkStationRepository(endStaion); + } catch (InputMismatchException e) { + System.out.println(e.getMessage()); + System.out.println(); + printMainScreen(scanner); + } + } +} diff --git a/src/main/java/subway/Views/OutputView.java b/src/main/java/subway/Views/OutputView.java new file mode 100644 index 000000000..6499743f5 --- /dev/null +++ b/src/main/java/subway/Views/OutputView.java @@ -0,0 +1,47 @@ +package subway.Views; + +import java.util.List; +import java.util.Scanner; + +public class OutputView { + + private final static String MAINSCREEN = "## 메인 화면"; + private final static String ROUTESEARCHSELECTION = "1. 경로 조회"; + private final static String PROGRAMEXIT = "Q. 종료"; + private final static String ROUTESCREEN = "## 경로 기준"; + private final static String MINDISTANCEROUTE = "1. 최단 거리"; + private final static String MINTIMEROUTE = "2. 최소 시간"; + private final static String BACKOPTION = "B. 돌아가기"; + private final static String RESULTSCREEN = "## 조회 결과"; + private final static String INFORMATION = "[INFO] "; + private final static String SPLITLINE = "---"; + private final static String TOTALDISTANCE = "총 거리: %dkm"; + private final static String TOTALTIME = "총 소요 시간: %d분"; + + + protected static void printMainSelection() { + System.out.println(MAINSCREEN); + System.out.println(ROUTESEARCHSELECTION); + System.out.println(PROGRAMEXIT); + System.out.println(); + } + + protected static void printRouteSelection() { + System.out.println(ROUTESCREEN); + System.out.println(MINDISTANCEROUTE); + System.out.println(MINTIMEROUTE); + System.out.println(BACKOPTION); + System.out.println(); + } + + protected static void printResultRoute(List resultList) { + System.out.println(RESULTSCREEN); + System.out.println(INFORMATION + SPLITLINE); +// System.out.println(String.format(INFORMATION + TOTALDISTANCE, totalDistance)); +// System.out.println(String.format(INFORMATION + TOTALTIME, totalTime)); +// System.out.println(INFORMATION + SPLITLINE); + for (String result : resultList) { + System.out.println(INFORMATION + result); + } + } +} diff --git a/src/main/java/subway/domain/DistanceWeightRepository.java b/src/main/java/subway/domain/DistanceWeightRepository.java new file mode 100644 index 000000000..272fa0838 --- /dev/null +++ b/src/main/java/subway/domain/DistanceWeightRepository.java @@ -0,0 +1,28 @@ +package subway.domain; + +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.WeightedMultigraph; + +import java.util.List; + +public class DistanceWeightRepository { + + private static WeightedMultigraph distanceGraph = new WeightedMultigraph( + DefaultWeightedEdge.class); + + public static void addStation(String station) { + distanceGraph.addVertex(station); + } + + public static void setStationEdgeDistance(String startStation, String endStation, + int distance) { + distanceGraph.setEdgeWeight(distanceGraph.addEdge(startStation, endStation), distance); + } + + + public static List getDijkstraShortestPath(String startStation, String endStation) { + DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(distanceGraph); + return dijkstraShortestPath.getPath(startStation, endStation).getVertexList(); + } +} diff --git a/src/main/java/subway/domain/Line.java b/src/main/java/subway/domain/Line.java index f4d738d5a..4c5db2424 100644 --- a/src/main/java/subway/domain/Line.java +++ b/src/main/java/subway/domain/Line.java @@ -1,7 +1,12 @@ package subway.domain; +import java.util.ArrayList; +import java.util.List; + public class Line { + private String name; + private List lineStations = new ArrayList<>(); public Line(String name) { this.name = name; @@ -11,5 +16,10 @@ public String getName() { return name; } - // 추가 기능 구현 + public void addLineStation(List stationNames) { + for (String stationName : stationNames) { + Station station = new Station(stationName); + lineStations.add(station); + } + } } diff --git a/src/main/java/subway/domain/LineRepository.java b/src/main/java/subway/domain/LineRepository.java index 2c4a723c9..17753c602 100644 --- a/src/main/java/subway/domain/LineRepository.java +++ b/src/main/java/subway/domain/LineRepository.java @@ -6,6 +6,7 @@ import java.util.Objects; public class LineRepository { + private static final List lines = new ArrayList<>(); public static List lines() { diff --git a/src/main/java/subway/domain/Station.java b/src/main/java/subway/domain/Station.java index bdb142590..d9ea09d2c 100644 --- a/src/main/java/subway/domain/Station.java +++ b/src/main/java/subway/domain/Station.java @@ -1,6 +1,7 @@ package subway.domain; public class Station { + private String name; public Station(String name) { @@ -10,6 +11,4 @@ public Station(String name) { public String getName() { return name; } - - // 추가 기능 구현 } diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/StationRepository.java index 8ed9d103f..d3a7b6617 100644 --- a/src/main/java/subway/domain/StationRepository.java +++ b/src/main/java/subway/domain/StationRepository.java @@ -6,6 +6,7 @@ import java.util.Objects; public class StationRepository { + private static final List stations = new ArrayList<>(); public static List stations() { @@ -23,4 +24,13 @@ public static boolean deleteStation(String name) { public static void deleteAll() { stations.clear(); } + + public static boolean checkStation(String stationName) { + for (Station station : stations) { + if (station.getName().equals(stationName)) { + return true; + } + } + return false; + } } diff --git a/src/main/java/subway/domain/TimeWeightRepository.java b/src/main/java/subway/domain/TimeWeightRepository.java new file mode 100644 index 000000000..92deef6f8 --- /dev/null +++ b/src/main/java/subway/domain/TimeWeightRepository.java @@ -0,0 +1,27 @@ +package subway.domain; + +import org.jgrapht.alg.shortestpath.DijkstraShortestPath; +import org.jgrapht.graph.DefaultWeightedEdge; +import org.jgrapht.graph.WeightedMultigraph; + +import java.util.List; + +public class TimeWeightRepository { + + private static WeightedMultigraph timeGraph = new WeightedMultigraph( + DefaultWeightedEdge.class); + + public static void addStation(String station) { + timeGraph.addVertex(station); + } + + public static void setStationEdgeTime(String startStation, String endStation, int time) { + timeGraph.setEdgeWeight(timeGraph.addEdge(startStation, endStation), time); + + } + + public static List getDijkstraShortestPath(String startStation, String endStation) { + DijkstraShortestPath dijkstraShortestPath = new DijkstraShortestPath(timeGraph); + return dijkstraShortestPath.getPath(startStation, endStation).getVertexList(); + } +} diff --git a/src/main/java/subway/utils/ErrorValidator.java b/src/main/java/subway/utils/ErrorValidator.java new file mode 100644 index 000000000..fe9e49fb0 --- /dev/null +++ b/src/main/java/subway/utils/ErrorValidator.java @@ -0,0 +1,31 @@ +package subway.utils; + +import java.util.InputMismatchException; +import java.util.List; +import subway.domain.StationRepository; + +public class ErrorValidator { + + private final static String ERRORMESSAGE = "[ERROR] "; + private final static String WRONGUSERINPUT = "잘못된 입력입니다."; + private final static String WRONGSTATIONNAME = "존재하지 않는 역 이름입니다."; + private final static String SAMESTATIONNAME = "출발역과 도착역이 동일합니다."; + + public static void checkMainSelection(List MAINSELECTLIST, String userSelection) { + if (!MAINSELECTLIST.contains(userSelection)) { + throw new InputMismatchException(ERRORMESSAGE + WRONGUSERINPUT); + } + } + + public static void checkStationRepository(String stationName) { + if (!StationRepository.checkStation(stationName)) { + throw new InputMismatchException(ERRORMESSAGE + WRONGSTATIONNAME); + } + } + + public static void checkStartEndStation(String startStation, String endStaion) { + if (startStation.equals(endStaion)) { + throw new InputMismatchException(ERRORMESSAGE + SAMESTATIONNAME); + } + } +}