Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
67e2b71
docs: update README.md
wmakerjun Dec 15, 2020
ecad6fc
initial commit
dudtjr913 Dec 19, 2020
5b2437f
Update : README.md - 기능 구현 목록 생성
dudtjr913 Dec 19, 2020
23ab33e
Update : HTML 초기 화면 구현
dudtjr913 Dec 19, 2020
5a0c84f
update : README.md - 기능 구현 목록 최신화
dudtjr913 Dec 19, 2020
5105f23
update : html에 js추가
dudtjr913 Dec 19, 2020
e3d5aca
update : README.md - 기능 구현 목록 최신화
dudtjr913 Dec 19, 2020
525b30f
feat : Subway class 생성 및 초기값 할당
dudtjr913 Dec 19, 2020
92b95c8
update : README.md - 기능 구현 목록 최신화
dudtjr913 Dec 19, 2020
096afca
Feat : 역 input의 유효성 검사
dudtjr913 Dec 19, 2020
4fbbc2e
Update : README.md - 기능 구현 목록 최신화
dudtjr913 Dec 19, 2020
f7ca623
Update : README.md - 최단거리/최소거리 선택 값 확인 추가
dudtjr913 Dec 19, 2020
29fff3a
bug : 동일한 역 검사 시 모두 실수로 arrival을 넣었다.
dudtjr913 Dec 19, 2020
2d3aa09
Feat : 최단거리/최소거리를 return하는 함수 구현 완료
dudtjr913 Dec 19, 2020
1ad329c
Update : README.md - 기능 구현 목록 최신화
dudtjr913 Dec 19, 2020
8eac5a6
Update : README.md - 기능 구현 목록 추가(데이터 분리)
dudtjr913 Dec 19, 2020
e206d19
Feat : 최단거리 구하는 메소드 구현 중
dudtjr913 Dec 19, 2020
f57f915
Feat : 최단시간 구하는 메소드 구현 중
dudtjr913 Dec 19, 2020
d8a348f
Update : README.md - 기능 구현 목록 최신화 및 추가
dudtjr913 Dec 19, 2020
33b93c9
Feat : 유저가 입력한 역을 기준으로 길찾기 시작
dudtjr913 Dec 19, 2020
2f28fac
Feat : 길 찾기 버튼 클릭 시 화면에 결과 랜더링
dudtjr913 Dec 19, 2020
e7de00d
Update : README.md - 기능 구현 목록 최신화
dudtjr913 Dec 19, 2020
00bc4f7
Feat : 결과 화면 삭제 기능 추가
dudtjr913 Dec 19, 2020
e1a09af
Style : 변수 명 변경
dudtjr913 Dec 19, 2020
206a951
Refactor : 필요하지 않은 LINE 삭제
dudtjr913 Dec 19, 2020
106920d
Update : 최단거리/최단시간 구하는 메소드 로직 변경
dudtjr913 Dec 19, 2020
3d6a171
Feat : 총 시간/거리를 구하는 함수 구현 완료
dudtjr913 Dec 19, 2020
1c325aa
Update : README.md - 기능 구현 목록 최신화
dudtjr913 Dec 19, 2020
db85323
Refactor : 상수화 작업
dudtjr913 Dec 19, 2020
97dfe53
Refactor : 상수화 작업 완료
dudtjr913 Dec 19, 2020
1d63470
Update : README.md - 기능 구현 목록 추가
dudtjr913 Dec 19, 2020
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
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
git-commit-template.txt
node_modules
package.json
package-lock.json
.eslintrc.js
147 changes: 146 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,146 @@
# javascript-subway-final
# 🚇 지하철 노선도 경로 조회 미션
- 등록된 지하철 노선도에서 경로를 조회하는 기능을 구현한다.

## 🚀 기능 요구사항
> 프리코스 3주차 미션에서 사용한 코드를 참고해도 무관하다.

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

```
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.jpg" width="100%">

- 출발역과 도착역을 입력받아 경로를 조회한다.
- 경로 조회 시 총 거리, 총 소요 시간을 함께 출력한다.
- 경로 조회 시 `최단 거리` 또는 `최소 시간` 옵션을 선택할 수 있다.

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

<br>

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


## ✅ 프로그래밍 요구사항
### 길찾기 관련 기능
- 출발역을 입력하는 input 태그는 `departure-station-name-input` id 속성값을 가진다.
- 도착역을 입력하는 input 태그는 `arrival-station-name-input` id 속성값을 가진다.
- 최단거리, 최소시간을 선택하는 radio는 `search-type` name 속성값을 가진다.
- **radio option의 default 값은 최단거리이다.**
- 길찾기 버튼은 `search-button` id 속성값을 가진다.
- 📝 결과는 `table`을 이용하여 보여준다.

## ❗️힌트
## 데이터 초기화
자바스크립트에서 데이터를 초기화하는 방법 중에 하나는 아래와 같이 data를 `export`하고, `import`하는 것이다.

```javascript
export const users = [
{
name: 'Alt'
},
{
name: 'Jamie'
},
{
name: 'Sony'
}
]

export const courses = [
{
name: 'frontend',
},
{
name: 'backend',
},
{
name: 'iOS',
},
{
name: 'Android',
}
]

```
위와 같이 데이터를 `export`하면 아래와 같이 데이터를 `import` 하여 사용할 수 있다.
```javascript
import { users, courses } from './data.js'

function App() {
this.users = users
this.courses = courses
}
```

## 최단 경로 라이브러리
- `utils/Dijkstra.js` 라이브러리를 활용하면 간편하게 최단거리를 조회할 수 있다.
- 정점(Vertex)과 간선(Edge), 그리고 가중치 개념을 이용
- 정점: 지하철역
- 간선: 지하철역 연결정보
- 가중치: 거리 or 소요 시간
- 최단 거리 기준 조회 시 가중치를 거리로 설정
- 최소 시간 기준 조회 시 가중치를 시간으로 설정

```javascript
import Dijkstra from "./utils/Dijkstra.js";
const dijkstra = new Dijkstra()

//dijkstra.addEdge("출발역", "도착역", 거리 또는 시간);
dijkstra.addEdge("V1", "V2", 2);
dijkstra.addEdge("V2", "V3", 2);
dijkstra.addEdge("V1", "V3", 100);

const result = dijkstra.findShortestPath("V1", "V3");
// result = ["V1", "V2", "V3"]
```

#### 테스트설명
<img src="/images/dijkstra_example.png" width="400">

- 역 사이의 거리를 고려하지 않는 경우 V1->V3 경로가 최단 경로
- 역 사이의 거리를 고려할 경우 V1->V3 경로의 거리는 100km, V1->V2->V3 경로의 거리는 4km이므로 최단 경로는 V1->V2->V3

<br>

### 요구사항
- 사용자가 잘못된 입력 값을 작성한 경우 `alert`을 이용해 메시지를 보여주고, 재입력할 수 있게 한다.
- 외부 라이브러리(jQuery, Lodash 등)를 사용하지 않고, 순수 Vanilla JS로만 구현한다.
- **자바스크립트 코드 컨벤션을 지키면서 프로그래밍** 한다
- [https://google.github.io/styleguide/jsguide.html](https://google.github.io/styleguide/jsguide.html)
- [https://ui.toast.com/fe-guide/ko_CODING-CONVENSION/](https://ui.toast.com/fe-guide/ko_CODING-CONVENTION)
- **indent(인덴트, 들여쓰기) depth를 3이 넘지 않도록 구현한다. 2까지만 허용**한다.
- 예를 들어 while문 안에 if문이 있으면 들여쓰기는 2이다.
- 힌트: indent(인덴트, 들여쓰기) depth를 줄이는 좋은 방법은 함수(또는 메소드)를 분리하면 된다.
- **함수(또는 메소드)의 길이가 15라인을 넘어가지 않도록 구현한다.**
- 함수(또는 메소드)가 한 가지 일만 잘 하도록 구현한다.
- 변수 선언시 [var](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/var) 를 사용하지 않는다. [const](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/const) 와 [let](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/let) 을 사용한다.
- [import](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Statements/import) 문을 이용해 스크립트를 모듈화하고 불러올 수 있게 만든다.
- [template literal](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals)을 이용해 데이터와 html string을 가독성 좋게 표현한다.

<br/>

## 📝 미션 저장소 및 진행 요구사항

- 미션은 [https://github.com/woowacourse/javascript-subway-path-precourse](https://github.com/woowacourse/javascript-subway-path-precourse) 저장소를 fork/clone해 시작한다.
- **기능을 구현하기 전에 javascript-subway-path-precourse/docs/README.md 파일에 구현할 기능 목록**을 정리해 추가한다.
- **git의 commit 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가**한다.
- [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서 절차를 따라 미션을 제출한다.
30 changes: 30 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
## 기능 구현 목록

- ✔ 초기 화면을 html로 구현한다.

- ✔ 최단거리와 최소시간을 선택할 수 있게 한다. (radio 사용)

- ✔ 지하철 class를 만들어 각종 초기값을 할당한다.

- ✔ 출발역과 도착역에 입력한 input의 유효성을 검사한다.

- 에러사항)
- ✔ 존재하지 않는 역을 입력
- ✔ 빈 칸을 입력
- ✔ 출발과 도착에 같은 역을 입력

- ✔ 최단거리/최소거리 중 어느 값을 선택했는지 확인한다.

- ✔ 초기값으로 들어있는 데이터를 분리해 최단 경로 라이브러리에서 사용할 수 있도록 만든다.

- ✔ 출발역과 도착역을 통해 최단거리를 구한다.

- ✔ 출발역과 도착역을 통해 최소시간을 구한다.

- ✔ 출발역과 도착역을 통해 총 시간과 총 거리를 구한다.

- ✔ 최단거리 및 최소시간을 화면에 랜더링 할 수 있도록 한다.

- ✔ 사용자가 선택한 최단거리/최소시간에 맞춰 화면에 출력해준다.

- 출발역과 도착역이 연결되지 않을 때 경로를 조회할 수 없게 한다.
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.
28 changes: 28 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>지하철 길찾기</title>
<link rel="stylesheet" href="/src/style.css" />
</head>
<body>
<div id="app">
<h1>🚇지하철 길찾기</h1>
<div id="station-wrapper">
<p>출발역 <input id="departure-station-name-input" /></p>
<p>도착역 <input id="arrival-station-name-input" /></p>
<div>
<input type="radio" name="search-type" value="최단거리" checked />
<label>최단거리</label>
<input type="radio" name="search-type" value="최소거리" />
<label>최소거리</label>
</div>
<p>
<button id="search-button">길 찾기</button>
</p>
</div>
<div id="result-wrapper"></div>
</div>
<script src="src/index.js" type="module"></script>
</body>
</html>
28 changes: 28 additions & 0 deletions src/constant/constant.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
export const STATION = [
'교대',
'강남',
'역삼',
'남부터미널',
'양재',
'양재시민의숲',
'매봉',
];

export const SECTION = {
'2호선': '교대 - ( 2km / 3분 ) - 강남 - ( 2km / 3분 ) - 역삼',
'3호선':
'교대 - ( 3km / 2분 ) - 남부터미널 - ( 6km / 5분 ) - 양재 - ( 1km / 1분 ) - 매봉',
'신분당선': '강남 - ( 2km / 8분 ) - 양재 - ( 10km / 3분 ) - 양재시민의숲',
};

export const error_message = {
NOT_STATION: '존재하지 않는 역입니다.',
SAME_STATION: '동일한 역을 입력하셨습니다.',
};

export const TIME = '분';
export const DISTANCE = 'km';
export const SHORT_DISTANCE = '최단거리';
export const RESULT_TEXT = '📑결과';
export const TH_DISTANCE = '총 거리';
export const TH_TIME = '총 소요 시간';
29 changes: 29 additions & 0 deletions src/controller/event.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {$departureName, $arrivalName} from '../view/element.js';
import {renderResultScreen} from '../view/add-screen.js';
import {removeResultScreen} from '../view/remove-screen.js';
import {isInputValid} from './valid.js';
import {SHORT_DISTANCE} from '../constant/constant.js';
import {subway} from '../index.js';

export const onFindRoute = () => {
const departure = $departureName.value;
const arrival = $arrivalName.value;
if (isInputValid(departure, arrival, subway.station)) {
removeResultScreen();
const checkedValue = checkSelectedRadio();
if (checkedValue === SHORT_DISTANCE) {
const shortDistance = subway.findShortDistance(departure, arrival);
return renderResultScreen(checkedValue, shortDistance);
}
const shortTime = subway.findShortTime(departure, arrival);

return renderResultScreen(checkedValue, shortTime);
}
};

const checkSelectedRadio = () => {
const $allRadioInput = document.body.querySelectorAll('[name="search-type"]');
const checkedInput = [...$allRadioInput].find((input) => input.checked);

return checkedInput.value;
};
31 changes: 31 additions & 0 deletions src/controller/valid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import {error_message} from '../constant/constant.js';

export const isInputValid = ($departureName, $arrivalName, stations) => {
if (!isIncluded($departureName, stations)) {
return false;
}
if (!isIncluded($arrivalName, stations)) {
return false;
}
if (!isBothDifferent($departureName, $arrivalName)) {
return false;
}

return true;
};

const isIncluded = ($name, stations) => {
if (!stations.includes($name)) {
return alert(error_message.NOT_STATION);
}

return true;
};

const isBothDifferent = (first, second) => {
if (first === second) {
return alert(error_message.SAME_STATION);
}

return true;
};
8 changes: 8 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Subway from './model/subway.js';
import {onFindRoute} from './controller/event.js';

export const subway = new Subway();

document.body
.querySelector('#search-button')
.addEventListener('click', onFindRoute);
42 changes: 42 additions & 0 deletions src/model/subway.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {STATION, SECTION} from '../constant/constant.js';
import {splitSection} from '../utils/split.js';
import {findTotalTimeOrDistance} from '../utils/total.js';
import Dijkstra from '../utils/Dijkstra.js';

export default class Subway {
constructor() {
this.station = STATION;
this.section = SECTION;
this.splitedSection = splitSection(SECTION);
}

findShortDistance(departure, arrival) {
const dijkstra = new Dijkstra();
this.splitedSection.forEach((station) => {
for (let i = 0; i < station.length; i++) {
const departure = station[i].section[0];
const arrival = station[i].section[1];
dijkstra.addEdge(departure, arrival, station[i].distance);
}
});
const result = dijkstra.findShortestPath(departure, arrival);
const total = findTotalTimeOrDistance(result, this.splitedSection);

return {result, total};
}

findShortTime(departure, arrival) {
const dijkstra = new Dijkstra();
this.splitedSection.forEach((station) => {
for (let i = 0; i < station.length; i++) {
const departure = station[i].section[0];
const arrival = station[i].section[1];
dijkstra.addEdge(departure, arrival, station[i].time);
}
});
const result = dijkstra.findShortestPath(departure, arrival);
const total = findTotalTimeOrDistance(result, this.splitedSection);

return {result, total};
}
}
6 changes: 6 additions & 0 deletions src/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
table,
th,
td {
border: 1px solid black;
text-align: center;
}
Loading