Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
67e2b71
docs: update README.md
wmakerjun Dec 15, 2020
ffc39f6
Docs: 구현할 기능 목록 추가
bwyoo1229 Dec 19, 2020
3b5dfe6
Feat: 앱 실행 시 초기 길찾기 기능 화면 보여주기
bwyoo1229 Dec 19, 2020
a08071e
Feat: 출발역, 도착역, 라디오 인풋 입력 받기
bwyoo1229 Dec 19, 2020
1ce618d
Feat: 결과 테이블 만들어서 보여주기
bwyoo1229 Dec 19, 2020
b1f81d5
Feat: 역, 노선, 구간 데이터를 초기화 하기
bwyoo1229 Dec 19, 2020
9cd18f0
Feat: 역, 구간 데이터를 이용해 최단 거리를 구할 노드와 간선 생성
bwyoo1229 Dec 19, 2020
063ebec
Feat: 역, 구간 데이터를 이용해 최소 시간을 구할 노드와 간선 생성
bwyoo1229 Dec 19, 2020
f57c528
Fix: 메소드 명 수정
bwyoo1229 Dec 19, 2020
0a12028
Feat: 최단 거리 경로와 최단 거리 구하기
bwyoo1229 Dec 19, 2020
590efb5
Feat: 최단 시간 경로와 최단 시간 구하기
bwyoo1229 Dec 19, 2020
5c3c0b5
Feat: 최단 거리 경로의 총 시간을 구하기
bwyoo1229 Dec 19, 2020
52b0a3b
Feat: 최단 시간 경로의 총 거리를 구하기
bwyoo1229 Dec 19, 2020
94bc67e
Feat: 역 이름이 2글자 이내로 입력 시 에러처리
bwyoo1229 Dec 19, 2020
903dfec
Feat: 도착역과 출발역이 같을 시 예외처리
bwyoo1229 Dec 19, 2020
3c5307e
Feat: 입력된 역이 등록된 역이 아닐경우 예외처리
bwyoo1229 Dec 19, 2020
421de5c
Feat: 테이블을 출력할때마다 새로운 데이터로 출력
bwyoo1229 Dec 19, 2020
c3cc570
Feat: 연결된 역이 아닐 경우 예외처리
bwyoo1229 Dec 19, 2020
eb9c31f
Docs: README.md 업데이트
bwyoo1229 Dec 19, 2020
620e450
Fix: alert 중첩 오류 해결
bwyoo1229 Jan 28, 2021
e721b8f
Update README.md
bwyoo1229 Jan 28, 2021
538c952
Update README.md
bwyoo1229 Jan 28, 2021
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
51 changes: 50 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,50 @@
# javascript-subway-final
# 🚇 지하철 노선도 경로 조회 미션
- 등록된 지하철 노선도에서 최단 거리와 최단 시간 경로를 조회하는 기능을 구현한다.
- **해당 프로그램은 바닐라 자바스크립트로 구현하였습니다.**

## 💻 빠른 시작

```
git clone https://github.com/bwyoo1229/javascript-subway-map-precourse.git
```

<hr />

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

## 💻 프로그래밍 실행 결과
### 경로 조회
<img src="/images/path_result.gif" width="100%">

## 🖋 구현할 기능 목록
#### 역, 노선, 구간 데이터
- [x] 역, 노선, 구간 데이터를 만들어서 기본 데이터 초기화 한다.
- 구간의 데이터를 양방향으로 고려해야 한다.
- [x] 초기화된 역, 노선, 구간 데이터를 이용해 최단거리를 구할 노드와 간선들을 생성한다.
- [x] 초기화된 역, 노선, 구간 데이터를 이용해 최소시간을 구할 노드와 간선들을 생성한다.
#### 인풋
- [x] 출발역, 도착역의 입력을 받아야한다
- 예외처리는 `alert`로 알려준다.
- [x] 예외: 출발역과 도착역은 2글자 이상이다.
- [x] 예외: 출발역과 도착역이 같을 수 없다.
- [x] 예외: 노선에 이미 등록된 역만 입력 받을 수 있다.
- [x] 최단거리, 최소거리 라디오 입력을 받아야 한다.
#### 아웃풋
- [x] 초기 지하철 길찾기 화면을 만들어 보여줘야 한다.
- [x] 결과 테이블을 만들어서 보여줘야 한다.
- [x] 새로운 값이 입력될때 마다 새로운 테이블을 만들어서 새롭게 보여줘야 한다.
#### 최단거리
- [x] 최단 경로 라이브러리를 이용해서 노드와 거리 정보를 받은 후 최단 거리를 구한다.
- [x] 최단 거리의 총 시간을 구한다.
#### 최소시간
- [x] 최단 경로 라이브러리를 이용해서 노드와 시간 정보를 받은 후 최소 시간을 구한다.
- [x] 최소 시간의 총 거리를 구한다.

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.
8 changes: 8 additions & 0 deletions index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
body {
font-family: sans-serif;
}

table, th, td {
border: 1px solid black;
text-align: center;
}
12 changes: 12 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>지하철 길찾기</title>
<link rel="stylesheet" href="index.css">
</head>
<body>
<div id="app"></div>
<script type="module" src="src/index.js"></script>
</body>
</html>
4 changes: 4 additions & 0 deletions src/controllers/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const RADIO_SHORTEST_DISTANCE_VALUE = 'shortest-distance';
export const RADIO_SHORTEST_TIME_VALUE = 'shortest-time';
export const SHORTEST_DISTANCE_KOR = '최단거리';
export const SHORTEST_TIME_KOR = '최소시간';
78 changes: 78 additions & 0 deletions src/controllers/subway-path-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import SubwayDistanceMap from '../models/subway-distance-map-model.js';
import SubwayTimeMap from '../models/subway-time-map-model.js';
import SubwayPathInput from '../views/subway-path-input.js';
import SubwayPathOutput from '../views/Subway-path-output.js';
import {isNotValidInput} from '../services/validation.js';
import {
RADIO_SHORTEST_DISTANCE_VALUE,
RADIO_SHORTEST_TIME_VALUE,
SHORTEST_TIME_KOR,
SHORTEST_DISTANCE_KOR
} from './constants.js';

export default class SubwayPathController {
constructor() {
this.subwayPathOutput = new SubwayPathOutput();
this.subwayPathInput = new SubwayPathInput();
this.subwayDistanceMap = new SubwayDistanceMap();
this.subwayTimeMap = new SubwayTimeMap();

this.handleSearchInputs();
}

handleSearchInputs = () => {
this.subwayPathInput.bindSearchButton(this.getResultData);
}

getResultData = searchInputs => {
let departureStationName;
let arrivalStationName;
let radioSelect;

[departureStationName, arrivalStationName, radioSelect] = [...searchInputs];

if (isNotValidInput(departureStationName, arrivalStationName)) {
return;
}

this.getSelectedRadioData(radioSelect, departureStationName, arrivalStationName);
}

getSelectedRadioData = (radioSelect, departureStationName, arrivalStationName) => {
if (radioSelect == RADIO_SHORTEST_DISTANCE_VALUE) {
this.getShortestDistanceData(departureStationName, arrivalStationName)
} else if (radioSelect == RADIO_SHORTEST_TIME_VALUE) {
this.getShortestTimeData(departureStationName, arrivalStationName);
}
}

getShortestDistanceData = (departureStationName, arrivalStationName) => {
const radioSelect = SHORTEST_DISTANCE_KOR;
const shortestDistancePath = this.subwayDistanceMap.getShortestDistancePath(departureStationName, arrivalStationName);
let shortestTotalDistance;
let totalTime;

[shortestTotalDistance, totalTime] = this.subwayDistanceMap.getShortestTotalDistanceAndTotalTime(shortestDistancePath);

this.renderShortestDistanceResult([radioSelect, shortestTotalDistance, totalTime, shortestDistancePath]);
}

renderShortestDistanceResult = resultTableData => {
this.subwayPathOutput.renderResult(resultTableData);
}

getShortestTimeData = (departureStationName, arrivalStationName) => {
const radioSelect = SHORTEST_TIME_KOR;
const shortestTimePath = this.subwayTimeMap.getShortestTimePath(departureStationName, arrivalStationName);
let shortestTotalTime;
let totalDistance;

[shortestTotalTime, totalDistance] = this.subwayTimeMap.getShortestTotalTimeAndTotalDistance(shortestTimePath);

this.renderShortestDistanceResult([radioSelect, totalDistance, shortestTotalTime, shortestTimePath]);
}

renderShortestTimeResult = resultTableData => {
this.subwayPathOutput.renderResult(resultTableData);
}
}
14 changes: 14 additions & 0 deletions src/data/line-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export const lines = [
{
name: '2호선',
stations: ['교대', '강남', '역삼']
},
{
name: '3호선',
stations: ['교대', '남부터미널', '양재', '매봉']
},
{
name: '신분당선',
stations: ['강남', '양재', '양재시민의숲']
},
]
37 changes: 37 additions & 0 deletions src/data/section-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
export const sections = [
{
connectedStations :['교대', '강남'],
distance: 2,
time: 3
},
{
connectedStations :['강남', '역삼'],
distance: 2,
time: 3
},
{
connectedStations :['교대', '남부터미널'],
distance: 3,
time: 2
},
{
connectedStations :['남부터미널', '양재'],
distance: 6,
time: 5
},
{
connectedStations :['양재', '매봉'],
distance: 1,
time: 1
},
{
connectedStations :['강남', '양재'],
distance: 2,
time: 8
},
{
connectedStations :['양재', '양재시민의숲'],
distance: 10,
time: 3
},
]
23 changes: 23 additions & 0 deletions src/data/station-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export const stations = [
{
name: '교대'
},
{
name: '강남'
},
{
name: '역삼'
},
{
name: '남부터미널'
},
{
name: '양재'
},
{
name: '매봉'
},
{
name: '양재시민의 숲'
},
]
9 changes: 9 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import SubwayPathController from './controllers/subway-path-controller.js';

export default class SubwayPathApp {
constructor() {
this.subwayPathController = new SubwayPathController();
}
}

new SubwayPathApp();
65 changes: 65 additions & 0 deletions src/models/subway-distance-map-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import {stations} from '../data/station-data.js';
import {lines} from '../data/line-data.js';
import {sections} from '../data/section-data.js';
import Dijkstra from '../utils/Dijkstra.js';
import {isIncludesBothStations} from '../services/validation.js';

export default class SubwayDistanceMap {
constructor() {
this.subwayDistanceMap = new Dijkstra();

this.setSubwayStations();
this.setSubwayDistances();
}

setSubwayStations = () => {
for (let station of stations) {
this.subwayDistanceMap.addVertex(station.name);
}
}

setSubwayDistances = () => {
for (let section of sections) {
this.subwayDistanceMap.addEdge(section.connectedStations[0], section.connectedStations[1], section.distance);
}
}

getShortestDistancePath = (departureStation, arrivalStation) => {
const shortestDistancePath = this.subwayDistanceMap.findShortestPath(departureStation, arrivalStation);

return shortestDistancePath;
}

getShortestTotalDistanceAndTotalTime = shortestDistancePath => {
let shortestTotalSectionDistance = 0;
let totalSectionTime = 0;

for (let stationIndex = 1; stationIndex < shortestDistancePath.length; stationIndex++) {
let startStation = shortestDistancePath[stationIndex - 1];
let endStation = shortestDistancePath[stationIndex];
let sectionDistance = this.getSectionDistance(sections, startStation, endStation);
let sectionTime = this.getSectionTime(sections, startStation, endStation);

shortestTotalSectionDistance += sectionDistance;
totalSectionTime += sectionTime;
}

return [shortestTotalSectionDistance, totalSectionTime];
}

getSectionDistance = (sections, startStation, endStation) => {
for (let section of sections) {
if (isIncludesBothStations(section.connectedStations, startStation, endStation)) {
return section.distance;
}
}
}

getSectionTime = (sections, startStation, endStation) => {
for (let section of sections) {
if (isIncludesBothStations(section.connectedStations, startStation, endStation)) {
return section.time;
}
}
}
}
66 changes: 66 additions & 0 deletions src/models/subway-time-map-model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {stations} from '../data/station-data.js';
import {lines} from '../data/line-data.js';
import {sections} from '../data/section-data.js';
import Dijkstra from '../utils/Dijkstra.js';
import { isIncludesBothStations } from '../services/validation.js';

export default class SubwayTimeMap {
constructor() {
this.subwayTimeMap = new Dijkstra();

this.setSubwayStations();
this.setSubwayTimes();
}

setSubwayStations = () => {
for (let station of stations) {
this.subwayTimeMap.addVertex(station.name);
}
}

setSubwayTimes = () => {
for (let section of sections) {
this.subwayTimeMap.addEdge(section.connectedStations[0], section.connectedStations[1], section.time);
}
}

getShortestTimePath = (departureStation, arrivalStation) => {
const shortestTimePath = this.subwayTimeMap.findShortestPath(departureStation, arrivalStation);
console.log(this.subwayTimeMap);

return shortestTimePath;
}

getShortestTotalTimeAndTotalDistance = shortestTimePath => {
let shortestTotalSectionTime = 0;
let totalSectionDistance = 0;

for (let stationIndex = 1; stationIndex < shortestTimePath.length; stationIndex++) {
let startStation = shortestTimePath[stationIndex - 1];
let endStation = shortestTimePath[stationIndex];
let sectionTime = this.getSectionTime(sections, startStation, endStation);
let sectionDistance = this.getSectionDistance(sections, startStation, endStation);

shortestTotalSectionTime += sectionTime;
totalSectionDistance += sectionDistance;
}

return [shortestTotalSectionTime, totalSectionDistance]
}

getSectionTime = (sections, startStation, endStation) => {
for (let section of sections) {
if (isIncludesBothStations(section.connectedStations, startStation, endStation)) {
return section.time;
}
}
}

getSectionDistance = (sections, startStation, endStation) => {
for (let section of sections) {
if (isIncludesBothStations(section.connectedStations, startStation, endStation)) {
return section.distance;
}
}
}
}
4 changes: 4 additions & 0 deletions src/services/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export const MINIMUM_STATION_NAME_LENGTH = 2;
export const MINIMUM_STATION_NAME_LENGTH_ALERT = `${MINIMUM_STATION_NAME_LENGTH}자 이상의 이름을 입려해주세요.`;
export const SAME_STATION_ALERT = '시작 역과 도착역의 이름이 같습니다.';
export const NOT_ON_LINE_ALERT = '등록된 역이 아닙니다.';
Loading