diff --git a/README.md b/README.md
index d6299154c..87382a7c6 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,21 @@
+## ✅ 구현할 기능 목록
+- [x] 지하철 노선도 경로 조회 인터페이스
+ - [입출력 요구사항](#-입출력-요구사항)의 양식에 맞추어 출력을 한다.
+ - 존재하지 않는 기능의 입력이면 에러를 출력한다.
+- [x] 구간 모델 구현
+ - 구간에는 노선의 이름, 역 사이의 거리와 시간이 필요하다.
+- [x] 초기 설정 구현
+ - [기능 요구사항](#-기능-요구사항)에따라 초기 설정을 하도록 구현한다.
+- [x] 최단 경로 기능의 입력 구현
+ - 존재하지 않은 역의 입력인 경우 예외 처리
+ - 출발역과 도착역이 같은 경우 예외 처리
+- [x] 최단 경로 찾기 기능 구현
+ - 출발역과 도착역이 연결되어 있지 않으면 예외 처리
+- [ ] 총 이동거리 및 소요 시간 출력
+
## 🚀 기능 요구사항
> 프리코스 3주차 미션에서 사용한 코드를 참고해도 무관하다.
diff --git a/src/main/java/subway/Application.java b/src/main/java/subway/Application.java
index 0bcf786cc..ed1178f04 100644
--- a/src/main/java/subway/Application.java
+++ b/src/main/java/subway/Application.java
@@ -1,10 +1,15 @@
package subway;
+import java.io.PrintStream;
import java.util.Scanner;
+import subway.controller.MainController;
public class Application {
public static void main(String[] args) {
final Scanner scanner = new Scanner(System.in);
- // TODO: 프로그램 구현
+ final PrintStream printStream = new PrintStream(System.out);
+ InitialSetup.apply();
+ final MainController mainController = new MainController(scanner, printStream);
+ mainController.run();
}
}
diff --git a/src/main/java/subway/Error.java b/src/main/java/subway/Error.java
new file mode 100644
index 000000000..b9b8dba71
--- /dev/null
+++ b/src/main/java/subway/Error.java
@@ -0,0 +1,19 @@
+package subway;
+
+public enum Error {
+ OK("오류 없음"),
+ INVALID_MENU("존재하지 않는 기능입니다."),
+ SAME_STATIONS("출발역과 도착역이 동일합니다."),
+ STATION_NOT_EXISTS("존재하지 않는 역입니다."),
+ STATION_NOT_CONNECTED("역이 연결되어 있지 않습니다.");
+
+ private final String message;
+
+ private Error(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/src/main/java/subway/InitialSetup.java b/src/main/java/subway/InitialSetup.java
new file mode 100644
index 000000000..372892fd5
--- /dev/null
+++ b/src/main/java/subway/InitialSetup.java
@@ -0,0 +1,66 @@
+package subway;
+
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import subway.domain.Line;
+import subway.domain.LineRepository;
+import subway.domain.Station;
+import subway.domain.StationRepository;
+
+public class InitialSetup {
+ private static final String[] STATIONS =
+ {"교대역", "강남역", "역삼역", "남부터미널역", "양재역", "양재시민의숲역", "매봉역"};
+ private static final LinkedHashMap> STATIONS_OF_LINE =
+ new LinkedHashMap>();
+ private static final LinkedHashMap> DISTANCES_OF_LINE =
+ new LinkedHashMap>();
+ private static final LinkedHashMap> TIMES_OF_LINE =
+ new LinkedHashMap>();
+
+ static {
+ STATIONS_OF_LINE.put("2호선", Arrays.asList("교대역", "강남역", "역삼역"));
+ STATIONS_OF_LINE.put("3호선", Arrays.asList("교대역", "남부터미널역", "양재역", "매봉역"));
+ STATIONS_OF_LINE.put("신분당선", Arrays.asList("강남역", "양재역", "양재시민의숲역"));
+
+ DISTANCES_OF_LINE.put("2호선", Arrays.asList(2, 2));
+ DISTANCES_OF_LINE.put("3호선", Arrays.asList(3, 6, 1));
+ DISTANCES_OF_LINE.put("신분당선", Arrays.asList(2, 10));
+
+ TIMES_OF_LINE.put("2호선", Arrays.asList(3, 3));
+ TIMES_OF_LINE.put("3호선", Arrays.asList(2, 5, 1));
+ TIMES_OF_LINE.put("신분당선", Arrays.asList(8, 3));
+ }
+
+ public static void apply() {
+ applyStations();
+ applyLines();
+ }
+
+ private static void applyStations() {
+ for (String stationName : STATIONS) {
+ StationRepository.addStation(new Station(stationName));
+ }
+ }
+
+ private static void applyLines() {
+ for (String lineName : STATIONS_OF_LINE.keySet()) {
+ Line currentLine = new Line(lineName);
+ LineRepository.addLine(currentLine);
+ applyStationsOfLine(currentLine, STATIONS_OF_LINE.get(lineName));
+ }
+ }
+
+ private static void applyStationsOfLine(Line line, List stationNames) {
+ List distances = DISTANCES_OF_LINE.get(line.getName());
+ List times = TIMES_OF_LINE.get(line.getName());
+ for (int index = 0; index < stationNames.size(); index++) {
+ Station currentStation = StationRepository.getStationbyName(stationNames.get(index));
+ if (index == 0) {
+ line.registerFirstStation(currentStation);
+ continue;
+ }
+ line.pushSections(currentStation, distances.get(index - 1), times.get(index - 1));
+ }
+ }
+}
diff --git a/src/main/java/subway/Scene.java b/src/main/java/subway/Scene.java
new file mode 100644
index 000000000..eb385c372
--- /dev/null
+++ b/src/main/java/subway/Scene.java
@@ -0,0 +1,48 @@
+package subway;
+
+import java.io.PrintStream;
+import java.util.Scanner;
+import java.util.Stack;
+import subway.controller.MainViewController;
+import subway.controller.ViewController;
+
+public class Scene {
+ private final Scanner scanner;
+ private final PrintStream printStream;
+ private final Stack controllers = new Stack();
+
+ public Scene(Scanner scanner, PrintStream printStream) {
+ this.scanner = scanner;
+ this.printStream = printStream;
+ controllers.add(new MainViewController(scanner, printStream));
+ }
+
+ public void runCurrentView() {
+ ViewController viewController = controllers.peek();
+ viewController.run(this);
+ }
+
+ public void goView(ViewController controller) {
+ controllers.push(controller);
+ }
+
+ public void back() {
+ controllers.pop();
+ }
+
+ public void exit() {
+ controllers.clear();
+ }
+
+ public boolean isExit() {
+ return controllers.empty();
+ }
+
+ public Scanner getScanner() {
+ return scanner;
+ }
+
+ public PrintStream getPrinstream() {
+ return printStream;
+ }
+}
diff --git a/src/main/java/subway/controller/MainController.java b/src/main/java/subway/controller/MainController.java
new file mode 100644
index 000000000..2619f6481
--- /dev/null
+++ b/src/main/java/subway/controller/MainController.java
@@ -0,0 +1,19 @@
+package subway.controller;
+
+import java.io.PrintStream;
+import java.util.Scanner;
+import subway.Scene;
+
+public class MainController {
+ Scene scene;
+
+ public MainController(Scanner scanner, PrintStream printStream) {
+ scene = new Scene(scanner, printStream);
+ }
+
+ public void run() {
+ while (!scene.isExit()) {
+ scene.runCurrentView();
+ }
+ }
+}
diff --git a/src/main/java/subway/controller/MainViewController.java b/src/main/java/subway/controller/MainViewController.java
new file mode 100644
index 000000000..7b1ae0cfa
--- /dev/null
+++ b/src/main/java/subway/controller/MainViewController.java
@@ -0,0 +1,35 @@
+package subway.controller;
+
+import java.io.PrintStream;
+import java.util.Scanner;
+import java.util.function.BiConsumer;
+import subway.Error;
+import subway.Scene;
+import subway.menu.MainMenu;
+import subway.view.MainView;
+import subway.view.View;
+
+public class MainViewController extends ViewController {
+
+ public MainViewController(Scanner scanner, PrintStream printStream) {
+ view = new MainView(scanner, printStream);
+ }
+
+ @Override
+ public BiConsumer selectMenu() {
+ String input = view.requestMenu();
+ BiConsumer result = MainMenu.getAction(input);
+ if (result == null) {
+ view.printError(Error.INVALID_MENU);
+ }
+ return result;
+ }
+
+ public static void goSectionView(Scene scene, View view) {
+ scene.goView(new SectionViewController(scene.getScanner(), scene.getPrinstream()));
+ }
+
+ public static void exit(Scene scene, View view) {
+ scene.exit();
+ }
+}
diff --git a/src/main/java/subway/controller/SectionViewController.java b/src/main/java/subway/controller/SectionViewController.java
new file mode 100644
index 000000000..1b4b3bf73
--- /dev/null
+++ b/src/main/java/subway/controller/SectionViewController.java
@@ -0,0 +1,101 @@
+package subway.controller;
+
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Scanner;
+import java.util.function.BiConsumer;
+import subway.Error;
+import subway.Scene;
+import subway.domain.PathFinder;
+import subway.domain.Station;
+import subway.domain.StationRepository;
+import subway.menu.SectionMenu;
+import subway.view.SectionView;
+import subway.view.View;
+
+public class SectionViewController extends ViewController {
+
+ public SectionViewController(Scanner scanner, PrintStream printStream) {
+ view = new SectionView(scanner, printStream);
+ }
+
+ @Override
+ public BiConsumer selectMenu() {
+ String input = view.requestMenu();
+ BiConsumer result = SectionMenu.getAction(input);
+ if (result == null) {
+ view.printError(Error.INVALID_MENU);
+ }
+ return result;
+ }
+
+ public static void findMinDistance(Scene scene, View view) {
+ String departureInput = view.requestDepartureStation();
+ String arrivalInput = view.requestArrivalStation();
+ Error error = isValidStations(departureInput, arrivalInput);
+ if (error != Error.OK) {
+ view.printError(error);
+ return;
+ }
+ List path = findMinDistancePath(departureInput, arrivalInput, view);
+ if (path == null) {
+ return;
+ }
+ view.printPath(path);
+ scene.back();
+ }
+
+ private static List findMinDistancePath(String departureInput, String arrivalInput,
+ View view) {
+ Station departureStation = StationRepository.getStationbyName(departureInput);
+ Station arrivalStation = StationRepository.getStationbyName(arrivalInput);
+ List path = PathFinder.findMinDistancePath(departureStation, arrivalStation);
+ if (path == null) {
+ view.printError(Error.STATION_NOT_CONNECTED);
+ }
+ return path;
+ }
+
+ public static void findMinTime(Scene scene, View view) {
+ String departureInput = view.requestDepartureStation();
+ String arrivalInput = view.requestArrivalStation();
+ Error error = isValidStations(departureInput, arrivalInput);
+ if (error != Error.OK) {
+ view.printError(error);
+ return;
+ }
+ List path = findMinTimePath(departureInput, arrivalInput, view);
+ if (path == null) {
+ return;
+ }
+ view.printPath(path);
+ scene.back();
+ }
+
+ private static List findMinTimePath(String departureInput, String arrivalInput,
+ View view) {
+ Station departureStation = StationRepository.getStationbyName(departureInput);
+ Station arrivalStation = StationRepository.getStationbyName(arrivalInput);
+ List path = PathFinder.findMinTimePath(departureStation, arrivalStation);
+ if (path == null) {
+ view.printError(Error.STATION_NOT_CONNECTED);
+ }
+ return path;
+ }
+
+ private static Error isValidStations(String departureInput, String arrivalInput) {
+ if (departureInput.equals(arrivalInput)) {
+ return Error.SAME_STATIONS;
+ }
+ Station departureStation = StationRepository.getStationbyName(departureInput);
+ Station arrivalStation = StationRepository.getStationbyName(arrivalInput);
+ if ((departureStation == null) || (arrivalStation == null)) {
+ return Error.STATION_NOT_EXISTS;
+ }
+ return Error.OK;
+ }
+
+ public static void back(Scene scene, View view) {
+ scene.back();
+ }
+}
diff --git a/src/main/java/subway/controller/ViewController.java b/src/main/java/subway/controller/ViewController.java
new file mode 100644
index 000000000..6bd90aba1
--- /dev/null
+++ b/src/main/java/subway/controller/ViewController.java
@@ -0,0 +1,20 @@
+package subway.controller;
+
+import java.util.function.BiConsumer;
+import subway.Scene;
+import subway.view.View;
+
+public abstract class ViewController {
+ protected View view;
+
+ public ViewController() {}
+
+ abstract public BiConsumer selectMenu();
+
+ public void run(Scene scene) {
+ BiConsumer action = selectMenu();
+ if (action != null) {
+ action.accept(scene, view);;
+ }
+ }
+}
diff --git a/src/main/java/subway/domain/Line.java b/src/main/java/subway/domain/Line.java
index f4d738d5a..e8e391ca4 100644
--- a/src/main/java/subway/domain/Line.java
+++ b/src/main/java/subway/domain/Line.java
@@ -1,7 +1,15 @@
package subway.domain;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
public class Line {
private String name;
+ private List stations = new ArrayList();
+ private List distances = new ArrayList(); // 0번째와 1번째 station들의 관계는 0번째 인덱스에
+ // 존재한다.
+ private List times = new ArrayList();
public Line(String name) {
this.name = name;
@@ -11,5 +19,27 @@ public String getName() {
return name;
}
- // 추가 기능 구현
+ public List getStations() {
+ return Collections.unmodifiableList(stations);
+ }
+
+ public List getDistances() {
+ return Collections.unmodifiableList(distances);
+ }
+
+ public List getTimes() {
+ return Collections.unmodifiableList(times);
+ }
+
+ public void registerFirstStation(Station station) {
+ if (stations.isEmpty()) {
+ stations.add(station);
+ }
+ }
+
+ public void pushSections(Station station, int distance, int time) {
+ stations.add(station);
+ distances.add(distance);
+ times.add(time);
+ }
}
diff --git a/src/main/java/subway/domain/PathFinder.java b/src/main/java/subway/domain/PathFinder.java
new file mode 100644
index 000000000..2fefe2205
--- /dev/null
+++ b/src/main/java/subway/domain/PathFinder.java
@@ -0,0 +1,91 @@
+package subway.domain;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import org.jgrapht.GraphPath;
+import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
+import org.jgrapht.graph.DefaultWeightedEdge;
+import org.jgrapht.graph.WeightedMultigraph;
+
+public class PathFinder {
+
+ public static List findMinDistancePath(Station departure, Station arrival) {
+ WeightedMultigraph graph = initializeGraphForDistance();
+ DijkstraShortestPath dijkstraShortesPath =
+ new DijkstraShortestPath(graph);
+ GraphPath path =
+ dijkstraShortesPath.getPath(departure.getName(), arrival.getName());
+ if (path == null) {
+ return null;
+ }
+ return path.getVertexList();
+ }
+
+ public static List findMinTimePath(Station departure, Station arrival) {
+ WeightedMultigraph graph = initializeGraphForTime();
+ DijkstraShortestPath dijkstraShortesPath =
+ new DijkstraShortestPath(graph);
+ GraphPath path =
+ dijkstraShortesPath.getPath(departure.getName(), arrival.getName());
+ if (path == null) {
+ return null;
+ }
+ return path.getVertexList();
+ }
+
+ private static WeightedMultigraph initializeGraphForDistance() {
+ WeightedMultigraph graph =
+ new WeightedMultigraph(DefaultWeightedEdge.class);
+ List stationNames = StationRepository.stations().stream()
+ .map(station -> station.getName()).collect(Collectors.toList());
+ List lines = LineRepository.lines();
+ initializeStations(stationNames, graph);
+ initializeLinesForDistance(lines, graph);
+ return graph;
+ }
+
+ private static WeightedMultigraph initializeGraphForTime() {
+ WeightedMultigraph graph =
+ new WeightedMultigraph(DefaultWeightedEdge.class);
+ List stationNames = StationRepository.stations().stream()
+ .map(station -> station.getName()).collect(Collectors.toList());
+ List lines = LineRepository.lines();
+ initializeStations(stationNames, graph);
+ initializeLinesForTime(lines, graph);
+ return graph;
+ }
+
+ private static void initializeStations(List stationNames,
+ WeightedMultigraph graph) {
+ for (String stationName : stationNames) {
+ graph.addVertex(stationName);
+ }
+ }
+
+ private static void initializeLinesForDistance(List lines,
+ WeightedMultigraph graph) {
+ for (Line line : lines) {
+ List stations = line.getStations();
+ List distances = line.getDistances();
+ for (int index = 0; index < distances.size(); index++) {
+ String firstStation = stations.get(index).getName();
+ String secondStation = stations.get(index + 1).getName();
+ graph.setEdgeWeight(graph.addEdge(firstStation, secondStation),
+ distances.get(index));
+ }
+ }
+ }
+
+ private static void initializeLinesForTime(List lines,
+ WeightedMultigraph graph) {
+ for (Line line : lines) {
+ List stations = line.getStations();
+ List times = line.getTimes();
+ for (int index = 0; index < times.size(); index++) {
+ String firstStation = stations.get(index).getName();
+ String secondStation = stations.get(index + 1).getName();
+ graph.setEdgeWeight(graph.addEdge(firstStation, secondStation), times.get(index));
+ }
+ }
+ }
+}
diff --git a/src/main/java/subway/domain/StationRepository.java b/src/main/java/subway/domain/StationRepository.java
index 8ed9d103f..19e3f2563 100644
--- a/src/main/java/subway/domain/StationRepository.java
+++ b/src/main/java/subway/domain/StationRepository.java
@@ -23,4 +23,9 @@ public static boolean deleteStation(String name) {
public static void deleteAll() {
stations.clear();
}
+
+ public static Station getStationbyName(String name) {
+ return stations.stream().filter(station -> name.equals(station.getName())).findFirst()
+ .orElse(null);
+ }
}
diff --git a/src/main/java/subway/menu/MainMenu.java b/src/main/java/subway/menu/MainMenu.java
new file mode 100644
index 000000000..874ccb2b2
--- /dev/null
+++ b/src/main/java/subway/menu/MainMenu.java
@@ -0,0 +1,39 @@
+package subway.menu;
+
+import java.util.Arrays;
+import java.util.function.BiConsumer;
+import subway.Scene;
+import subway.controller.MainViewController;
+import subway.view.View;
+
+public enum MainMenu {
+ GO_SECTION_VIEW("1", "경로 조회", MainViewController::goSectionView),
+ EXIT("Q", "종료", MainViewController::exit);
+
+ private String key;
+ private String message;
+ private BiConsumer action;
+
+ private MainMenu(String key, String message, BiConsumer action) {
+ this.key = key;
+ this.message = message;
+ this.action = action;
+ }
+
+ public static BiConsumer getAction(String input) {
+ MainMenu selectedMenu = Arrays.asList(MainMenu.values()).stream()
+ .filter(menu -> input.equals(menu.key)).findFirst().orElse(null);
+ if (selectedMenu == null) {
+ return null;
+ }
+ return selectedMenu.action;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/src/main/java/subway/menu/SectionMenu.java b/src/main/java/subway/menu/SectionMenu.java
new file mode 100644
index 000000000..359011c41
--- /dev/null
+++ b/src/main/java/subway/menu/SectionMenu.java
@@ -0,0 +1,40 @@
+package subway.menu;
+
+import java.util.Arrays;
+import java.util.function.BiConsumer;
+import subway.Scene;
+import subway.controller.SectionViewController;
+import subway.view.View;
+
+public enum SectionMenu {
+ MIN_DISTANCE("1", "최단 거리", SectionViewController::findMinDistance),
+ MIN_TIME("2", "최소 시간", SectionViewController::findMinTime),
+ BACK("B", "돌아가기", SectionViewController::back);
+
+ private String key;
+ private String message;
+ private BiConsumer action;
+
+ private SectionMenu(String key, String message, BiConsumer action) {
+ this.key = key;
+ this.message = message;
+ this.action = action;
+ }
+
+ public static BiConsumer getAction(String input) {
+ SectionMenu selectedMenu = Arrays.asList(SectionMenu.values()).stream()
+ .filter(menu -> input.equals(menu.key)).findFirst().orElse(null);
+ if (selectedMenu == null) {
+ return null;
+ }
+ return selectedMenu.action;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/src/main/java/subway/view/MainView.java b/src/main/java/subway/view/MainView.java
new file mode 100644
index 000000000..26815847d
--- /dev/null
+++ b/src/main/java/subway/view/MainView.java
@@ -0,0 +1,27 @@
+package subway.view;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Scanner;
+import subway.menu.MainMenu;
+
+public class MainView extends View {
+ private static final String TITLE = "메인 화면";
+
+ public MainView(Scanner scanner, PrintStream printStream) {
+ super(scanner, printStream);
+ }
+
+ @Override
+ void printTitle() {
+ printStream.printf(TITLE_FORM, TITLE);
+ }
+
+ @Override
+ void printMenuList() {
+ Arrays.asList(MainMenu.values()).stream()
+ .forEach(menu -> printStream.printf(MENU_FORM, menu.getKey(), menu.getMessage()));
+ printStream.println();
+ }
+
+}
diff --git a/src/main/java/subway/view/SectionView.java b/src/main/java/subway/view/SectionView.java
new file mode 100644
index 000000000..7afa83835
--- /dev/null
+++ b/src/main/java/subway/view/SectionView.java
@@ -0,0 +1,26 @@
+package subway.view;
+
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.Scanner;
+import subway.menu.SectionMenu;
+
+public class SectionView extends View {
+ private static final String TITLE = "경로 기준";
+
+ public SectionView(Scanner scanner, PrintStream printStream) {
+ super(scanner, printStream);
+ }
+
+ @Override
+ void printTitle() {
+ printStream.printf(TITLE_FORM, TITLE);
+ }
+
+ @Override
+ void printMenuList() {
+ Arrays.asList(SectionMenu.values()).stream()
+ .forEach(menu -> printStream.printf(MENU_FORM, menu.getKey(), menu.getMessage()));
+ printStream.println();
+ }
+}
diff --git a/src/main/java/subway/view/View.java b/src/main/java/subway/view/View.java
new file mode 100644
index 000000000..f0e7b2d00
--- /dev/null
+++ b/src/main/java/subway/view/View.java
@@ -0,0 +1,71 @@
+package subway.view;
+
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Scanner;
+import subway.Error;
+
+public abstract class View {
+ private static final String DEPARTURE_STATION_MESSAGE = "출발역을 입력하세요.";
+ private static final String ARRIVAL_STATION_MESSAGE = "출발역을 입력하세요.";
+ private static final String MENU_SELECTION_MESSAGE = "원하는 기능을 선택하세요.";
+ private static final String BORDER = "---\n";
+ private static final String TOTAL_DISTANCE = "총 거리: ";
+ private static final String TOTAL_TIME = "총 소요 시간: ";
+ private static final String RESULT_TITLE = "조회 결과";
+ private static final String INFO_FORM = "[INFO] %s\n";
+ private static final String ERROR_FORM = "[ERROR] %s\n";
+ protected static final String TITLE_FORM = "## %s\n";
+ protected static final String MENU_FORM = "%s. %s\n";
+ protected final Scanner scanner;
+ protected final PrintStream printStream;
+
+ protected View(Scanner scanner, PrintStream printStream) {
+ this.scanner = scanner;
+ this.printStream = printStream;
+ }
+
+ abstract void printTitle();
+
+ abstract void printMenuList();
+
+ public String requestDepartureStation() {
+ printStream.printf(TITLE_FORM, DEPARTURE_STATION_MESSAGE);
+ String input = scanner.nextLine();
+ printStream.println();
+ return input;
+ }
+
+ public String requestArrivalStation() {
+ printStream.printf(TITLE_FORM, ARRIVAL_STATION_MESSAGE);
+ String input = scanner.nextLine();
+ printStream.println();
+ return input;
+ }
+
+ public String requestMenu() {
+ printTitle();
+ printMenuList();
+ printStream.printf(TITLE_FORM, MENU_SELECTION_MESSAGE);
+ String input = scanner.nextLine();
+ printStream.println();
+ return input;
+ }
+
+ public void printPath(List names) {
+ printStream.printf(TITLE_FORM, RESULT_TITLE);
+ printStream.print(BORDER);
+ printStream.printf(INFO_FORM, TOTAL_DISTANCE);
+ printStream.printf(INFO_FORM, TOTAL_TIME);
+ printStream.print(BORDER);
+ for (String name : names) {
+ printStream.printf(INFO_FORM, name);
+ }
+ printStream.println();
+ }
+
+ public void printError(Error error) {
+ printStream.printf(ERROR_FORM, error.getMessage());
+ printStream.println();
+ }
+}