Skip to content
Open
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
13 changes: 13 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12,
"sourceType": "module"
},
"rules": {},
"parser": "babel-eslint"
}
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,56 @@
# javascript-subway-final
# 🚇 지하철 노선도 경로 조회 미션

- 등록된 지하철 노선도에서 경로를 조회하는 기능을 구현한다.

## 구현 기능 목록

### 초기 설정

- 프로그램 시작 시 역, 노선, 구간 데이터를 초기 설정 해야 한다.
- 거리 : 양의정수, 단위 km
- 소요시간 조건: 양의정수, 단위 분
- 아래의 사전 등록 정보로 반드시 초기 설정을 한다.

```
1. 지하철역으로 교대, 강남, 역삼, 남부터미널, 양재, 양재시민의숲, 매봉 역 정보가 등록되어 있다.
2. 지하철 노선으로 2호선, 3호선, 신분당선이 등록되어 있다.
3. 노선에 역이 아래와 같이 등록되어 있다.(왼쪽 끝이 상행 종점)
- 2호선: 교대 - ( 2km / 3분 ) - 강남 - ( 2km / 3분 ) - 역삼
- 3호선: 교대 - ( 3km / 2분 ) - 남부터미널 - ( 6km / 5분 ) - 양재 - ( 1km / 1분 ) - 매봉
- 신분당선: 강남 - ( 2km / 8분 ) - 양재 - ( 10km / 3분 ) - 양재시민의숲
```

<!-- - Dijkstra.js 라이브러리 활용
- 초기설정에서 모든 edge를 더해야 한다. `.addEdge(출발역, 도착역, 거리)` -->

### 경로 조회 기능

- [x] 출발역과 도착역을 입력받는다.
- [x] 최단거리 또는 최소시간 옵션을 선택한다.
- [x] 길찾기 버튼을 눌러 실행한다.

- 경로 조회 기능

- Dijkstra.js 라이브러리를 활용한다.
- 모든 가능한 경로를 찾는다.
- 경로 내 시간 / 거리를 모두 더한다.`.addEdge(출발역, 도착역, 거리)`
- 최단거리/최소시간을 찾는다. `findShortestPath`

- 출력한다: 선택한 옵션, 총 거리, 총 소요시간, 경로

### 입력값 예외 처리

- 출발역과 도착역은 2글자 이상이어야 한다.
- 존재하지 않는 역을 입력할 수 없다.
- 경로 조회 시 출발역과 도착역을 다르게 해야한다.
- 경로 조회 시 출발역과 도착역이 연결되지 않으면 경로를 조회할 수 없다.
- 그 외 정상적으로 프로그램이 수행되지 않은 경우 `alert`으로 에러를 출력한다.

### HTML Element

- 출발역을 입력하는 input 태그 id: `departure-station-name-input`
- 도착역을 입력하는 input 태그 id: `arrival-station-name-input`
- 최단거리, 최소시간을 선택하는 radio의 name 속성: `search-type`
- radio option의 default 값은 최단거리이다.
- 길찾기 버튼 id: `search-button`
- 결과는 `table`을 이용하여 보여준다.
Binary file added images/dijkstra_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/path_result.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/path_result.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>지하철 길찾기</title>
</head>

<body>
<div id="app">
<h1>지하철 길찾기</h1>
<label>
출발역
<input id="departure-station-name-input"/>
</label>
<br />

<label>
도착역
<input id="arrival-station-name-input" />
</label>
<br />

<input type="radio" name="search-type" value="distance" checked="checked" >최단거리</input>
<input type="radio" name="search-type" value="time" >최소시간</input>
<br />

<button id="search-button">길찾기</button>

<div>
<h2>결과</h2>
<label id="option-label"></label>

<table id="result-table" border="1">
<thead>
<th>총 거리</th>
<th>총 소요 시간</th>
</thead>
<tbody></tbody>
</table>
</div>
</div>
<script type="module" src="src/index.js"></script>
</body>
</html>
20 changes: 20 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "javascript-subway-path-precourse",
"version": "1.0.0",
"description": "- 등록된 지하철 노선도에서 경로를 조회하는 기능을 구현한다.",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/woowacourse/javascript-subway-path-precourse.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/woowacourse/javascript-subway-path-precourse/issues"
},
"homepage": "https://github.com/woowacourse/javascript-subway-path-precourse#readme"
}
66 changes: 66 additions & 0 deletions src/data/line.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
export const lines = [
{
name: "2호선",
sections: [
{
id: 0,
distance: 2,
time: 3,
departureStation: "교대", //id로?
arrivalStation: "강남",
},
{
id: 1,
distance: 2,
time: 3,
departureStation: "강남",
arrivalStation: "역삼",
},
],
},
{
name: "3호선",
sections: [
{
id: 0,
distance: 3,
time: 2,
departureStation: "교대",
arrivalStation: "남부터미널",
},
{
id: 1,
distance: 6,
time: 5,
departureStation: "남부터미널",
arrivalStation: "양재",
},
{
id: 2,
distance: 1,
time: 1,
departureStation: "양재",
arrivalStation: "매봉",
},
],
},
{
name: "신분당선",
sections: [
{
id: 0,
distance: 2,
time: 8,
departureStation: "강남",
arrivalStation: "양재",
},
{
id: 1,
distance: 10,
time: 3,
departureStation: "양재",
arrivalStation: "양재시민의숲",
},
],
},
];
30 changes: 30 additions & 0 deletions src/data/station.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export const stations = [
{
id: 0,
name: "교대",
},
{
id: 1,
name: "강남",
},
{
id: 2,
name: "역삼",
},
{
id: 3,
name: "남부터미널",
},
{
id: 4,
name: "양재",
},
{
id: 5,
name: "양재시민의숲",
},
{
id: 6,
name: "매봉",
},
];
85 changes: 85 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { lines } from "./data/line.js";
import StationService from "./service/station.service.js";
import SectionService from "./service/section.service.js";
import Dijkstra from "./utils/Dijkstra.js";
const dijkstra = new Dijkstra();

export default class App {
constructor() {
this.sectionService = new SectionService();
this.stationService = new StationService();

this.addClickEvent();
}

getDepartureStationInput() {
const depatureStationInputField = document.getElementById("departure-station-name-input");
return depatureStationInputField.value;
}

getArrivalStationInput() {
const arrivalStationInputField = document.getElementById("arrival-station-name-input");
return arrivalStationInputField.value;
}

getSearchTypeInput() {
const searchTypeInputField = document.querySelector('input[name="search-type"]:checked');
return searchTypeInputField.value;
}

validateStationNameLength(departureStationName, arrivalStationName) {
if (
departureStationName.length < this.stationService.MIN_STATION_NAME_LENGTH ||
arrivalStationName.length < this.stationService.MIN_STATION_NAME_LENGTH
) {
throw new Error("역 이름은 두글자 이상이어야 합니다.");
}
}

validateStationExist(departureStationName, arrivalStationName) {
const isDepartureStationExist = this.stationService.findByName(departureStationName).length;
const isArrivalStationExist = this.stationService.findByName(arrivalStationName).length;

if (!isDepartureStationExist || !isArrivalStationExist) {
throw new Error("존재하지 않는 역입니다.");
}
}

searchPath() {
try {
const departureStation = this.getDepartureStationInput();
const arrivalStation = this.getArrivalStationInput();
const searchType = this.getSearchTypeInput();
this.validateStationNameLength(departureStation, arrivalStation);
this.validateStationExist(departureStation, arrivalStation);

const paths = this.sectionService.findShortestPath(departureStation, arrivalStation);
this.renderPathTable(paths);
} catch (error) {
alert(error);
}
}

renderPathTable(paths) {
const pathRowHTML = `
<tr>
<td> ${paths.length}</td>
<td> </td>
</tr>
<tr>
<td colspan="2">${paths.join("->")} </td>
</tr>
`;
const table = document.getElementById("result-table").querySelector("tbody");
table.innerHTML = pathRowHTML;
}

addClickEvent() {
const button = document.getElementById("search-button");
button.addEventListener("click", () => {
this.searchPath();
});
}
}

const app = new App();
64 changes: 64 additions & 0 deletions src/service/section.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { lines } from "../data/line.js";
import Dijkstra from "../utils/Dijkstra.js";

export default class SectionService {
constructor() {
this.lines = lines;
this.paths = [];
}

findAllSections() {
const sections = [];
for (let line of lines) {
sections.push(...line.sections);
}
return sections;
}

findPath(departureStation, arrivalStation, paths) {
const sections = this.findSectionsByDepartureStation(departureStation);

for (let section of sections) {
//base contidition
if (section.arrivalStation === arrivalStation) {
paths.push(section);
this.paths.push(paths);
return paths;
}
const newPaths = [...paths];
newPaths.push(section);
this.findPath(section.arrivalStation, arrivalStation, newPaths);
}
return this.paths;
}

findShortestPath(departureStation, arrivalStation) {
this.paths = [];
const dijkstra = new Dijkstra();
const paths = this.findPath(departureStation, arrivalStation, []);
console.log(paths);

paths.forEach((path) => {
if (paths.length === 1) {
dijkstra.addEdge(path.departureStation, path.arrivalStation, path.distance);
} else {
path.forEach((section) => {
dijkstra.addEdge(section.departureStation, section.arrivalStation, section.distance);
});
}
});

const result = dijkstra.findShortestPath(departureStation, arrivalStation);
return result;
}

findSectionsByDepartureStation(departureStationName) {
const sections = this.findAllSections();

const targets = sections.filter((section) => {
return section.departureStation === departureStationName;
});

return targets;
}
}
Loading