diff --git a/README.md b/README.md
index 51abd254..49a1dbe0 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,50 @@
-# javascript-subway-final
\ No newline at end of file
+# ๐ ์งํ์ฒ ๋
ธ์ ๋ ๊ฒฝ๋ก ์กฐํ ๋ฏธ์
+- ๋ฑ๋ก๋ ์งํ์ฒ ๋
ธ์ ๋์์ ์ต๋จ ๊ฑฐ๋ฆฌ์ ์ต๋จ ์๊ฐ ๊ฒฝ๋ก๋ฅผ ์กฐํํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค.
+- **ํด๋น ํ๋ก๊ทธ๋จ์ ๋ฐ๋๋ผ ์๋ฐ์คํฌ๋ฆฝํธ๋ก ๊ตฌํํ์์ต๋๋ค.**
+
+## ๐ป ๋น ๋ฅธ ์์
+
+```
+git clone https://github.com/bwyoo1229/javascript-subway-map-precourse.git
+```
+
+
+
+## ๋ฐ์ดํฐ ์ด๊ธฐ ์ค์ ์กฐ๊ฑด
+```
+1. ์งํ์ฒ ์ญ์ผ๋ก ๊ต๋, ๊ฐ๋จ, ์ญ์ผ, ๋จ๋ถํฐ๋ฏธ๋, ์์ฌ, ์์ฌ์๋ฏผ์์ฒ, ๋งค๋ด ์ญ ์ ๋ณด๊ฐ ๋ฑ๋ก๋์ด ์๋ค.
+2. ์งํ์ฒ ๋
ธ์ ์ผ๋ก 2ํธ์ , 3ํธ์ , ์ ๋ถ๋น์ ์ด ๋ฑ๋ก๋์ด ์๋ค.
+3. ๋
ธ์ ์ ์ญ์ด ์๋์ ๊ฐ์ด ๋ฑ๋ก๋์ด ์๋ค.(์ผ์ชฝ ๋์ด ์ํ ์ข
์ )
+ - 2ํธ์ : ๊ต๋ - ( 2km / 3๋ถ ) - ๊ฐ๋จ - ( 2km / 3๋ถ ) - ์ญ์ผ
+ - 3ํธ์ : ๊ต๋ - ( 3km / 2๋ถ ) - ๋จ๋ถํฐ๋ฏธ๋ - ( 6km / 5๋ถ ) - ์์ฌ - ( 1km / 1๋ถ ) - ๋งค๋ด
+ - ์ ๋ถ๋น์ : ๊ฐ๋จ - ( 2km / 8๋ถ ) - ์์ฌ - ( 10km / 3๋ถ ) - ์์ฌ์๋ฏผ์์ฒ
+```
+
+## ๐ป ํ๋ก๊ทธ๋๋ฐ ์คํ ๊ฒฐ๊ณผ
+### ๊ฒฝ๋ก ์กฐํ
+
+
+## ๐ ๊ตฌํํ ๊ธฐ๋ฅ ๋ชฉ๋ก
+#### ์ญ, ๋
ธ์ , ๊ตฌ๊ฐ ๋ฐ์ดํฐ
+- [x] ์ญ, ๋
ธ์ , ๊ตฌ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ง๋ค์ด์ ๊ธฐ๋ณธ ๋ฐ์ดํฐ ์ด๊ธฐํ ํ๋ค.
+ - ๊ตฌ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์๋ฐฉํฅ์ผ๋ก ๊ณ ๋ คํด์ผ ํ๋ค.
+- [x] ์ด๊ธฐํ๋ ์ญ, ๋
ธ์ , ๊ตฌ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํด ์ต๋จ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ ๋
ธ๋์ ๊ฐ์ ๋ค์ ์์ฑํ๋ค.
+- [x] ์ด๊ธฐํ๋ ์ญ, ๋
ธ์ , ๊ตฌ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ด์ฉํด ์ต์์๊ฐ์ ๊ตฌํ ๋
ธ๋์ ๊ฐ์ ๋ค์ ์์ฑํ๋ค.
+#### ์ธํ
+- [x] ์ถ๋ฐ์ญ, ๋์ฐฉ์ญ์ ์
๋ ฅ์ ๋ฐ์์ผํ๋ค
+ - ์์ธ์ฒ๋ฆฌ๋ `alert`๋ก ์๋ ค์ค๋ค.
+ - [x] ์์ธ: ์ถ๋ฐ์ญ๊ณผ ๋์ฐฉ์ญ์ 2๊ธ์ ์ด์์ด๋ค.
+ - [x] ์์ธ: ์ถ๋ฐ์ญ๊ณผ ๋์ฐฉ์ญ์ด ๊ฐ์ ์ ์๋ค.
+ - [x] ์์ธ: ๋
ธ์ ์ ์ด๋ฏธ ๋ฑ๋ก๋ ์ญ๋ง ์
๋ ฅ ๋ฐ์ ์ ์๋ค.
+- [x] ์ต๋จ๊ฑฐ๋ฆฌ, ์ต์๊ฑฐ๋ฆฌ ๋ผ๋์ค ์
๋ ฅ์ ๋ฐ์์ผ ํ๋ค.
+#### ์์ํ
+- [x] ์ด๊ธฐ ์งํ์ฒ ๊ธธ์ฐพ๊ธฐ ํ๋ฉด์ ๋ง๋ค์ด ๋ณด์ฌ์ค์ผ ํ๋ค.
+- [x] ๊ฒฐ๊ณผ ํ
์ด๋ธ์ ๋ง๋ค์ด์ ๋ณด์ฌ์ค์ผ ํ๋ค.
+ - [x] ์๋ก์ด ๊ฐ์ด ์
๋ ฅ๋ ๋ ๋ง๋ค ์๋ก์ด ํ
์ด๋ธ์ ๋ง๋ค์ด์ ์๋กญ๊ฒ ๋ณด์ฌ์ค์ผ ํ๋ค.
+#### ์ต๋จ๊ฑฐ๋ฆฌ
+- [x] ์ต๋จ ๊ฒฝ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด์ ๋
ธ๋์ ๊ฑฐ๋ฆฌ ์ ๋ณด๋ฅผ ๋ฐ์ ํ ์ต๋จ ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ๋ค.
+- [x] ์ต๋จ ๊ฑฐ๋ฆฌ์ ์ด ์๊ฐ์ ๊ตฌํ๋ค.
+#### ์ต์์๊ฐ
+- [x] ์ต๋จ ๊ฒฝ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด์ ๋
ธ๋์ ์๊ฐ ์ ๋ณด๋ฅผ ๋ฐ์ ํ ์ต์ ์๊ฐ์ ๊ตฌํ๋ค.
+- [x] ์ต์ ์๊ฐ์ ์ด ๊ฑฐ๋ฆฌ๋ฅผ ๊ตฌํ๋ค.
+
diff --git a/images/dijkstra_example.png b/images/dijkstra_example.png
new file mode 100644
index 00000000..7c751970
Binary files /dev/null and b/images/dijkstra_example.png differ
diff --git a/images/path_result.gif b/images/path_result.gif
new file mode 100644
index 00000000..ee394bd1
Binary files /dev/null and b/images/path_result.gif differ
diff --git a/images/path_result.jpg b/images/path_result.jpg
new file mode 100644
index 00000000..40a4bedd
Binary files /dev/null and b/images/path_result.jpg differ
diff --git a/index.css b/index.css
new file mode 100644
index 00000000..c5fe5b2d
--- /dev/null
+++ b/index.css
@@ -0,0 +1,8 @@
+body {
+ font-family: sans-serif;
+}
+
+table, th, td {
+ border: 1px solid black;
+ text-align: center;
+}
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..a930e81f
--- /dev/null
+++ b/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+ ์งํ์ฒ ๊ธธ์ฐพ๊ธฐ
+
+
+
+
+
+
+
diff --git a/src/controllers/constants.js b/src/controllers/constants.js
new file mode 100644
index 00000000..149cadeb
--- /dev/null
+++ b/src/controllers/constants.js
@@ -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 = '์ต์์๊ฐ';
diff --git a/src/controllers/subway-path-controller.js b/src/controllers/subway-path-controller.js
new file mode 100644
index 00000000..21fbee54
--- /dev/null
+++ b/src/controllers/subway-path-controller.js
@@ -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);
+ }
+}
\ No newline at end of file
diff --git a/src/data/line-data.js b/src/data/line-data.js
new file mode 100644
index 00000000..f915d91b
--- /dev/null
+++ b/src/data/line-data.js
@@ -0,0 +1,14 @@
+export const lines = [
+ {
+ name: '2ํธ์ ',
+ stations: ['๊ต๋', '๊ฐ๋จ', '์ญ์ผ']
+ },
+ {
+ name: '3ํธ์ ',
+ stations: ['๊ต๋', '๋จ๋ถํฐ๋ฏธ๋', '์์ฌ', '๋งค๋ด']
+ },
+ {
+ name: '์ ๋ถ๋น์ ',
+ stations: ['๊ฐ๋จ', '์์ฌ', '์์ฌ์๋ฏผ์์ฒ']
+ },
+]
\ No newline at end of file
diff --git a/src/data/section-data.js b/src/data/section-data.js
new file mode 100644
index 00000000..088de0af
--- /dev/null
+++ b/src/data/section-data.js
@@ -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
+ },
+]
\ No newline at end of file
diff --git a/src/data/station-data.js b/src/data/station-data.js
new file mode 100644
index 00000000..f170f565
--- /dev/null
+++ b/src/data/station-data.js
@@ -0,0 +1,23 @@
+export const stations = [
+ {
+ name: '๊ต๋'
+ },
+ {
+ name: '๊ฐ๋จ'
+ },
+ {
+ name: '์ญ์ผ'
+ },
+ {
+ name: '๋จ๋ถํฐ๋ฏธ๋'
+ },
+ {
+ name: '์์ฌ'
+ },
+ {
+ name: '๋งค๋ด'
+ },
+ {
+ name: '์์ฌ์๋ฏผ์ ์ฒ'
+ },
+]
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 00000000..9b9f7768
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,9 @@
+import SubwayPathController from './controllers/subway-path-controller.js';
+
+export default class SubwayPathApp {
+ constructor() {
+ this.subwayPathController = new SubwayPathController();
+ }
+}
+
+new SubwayPathApp();
\ No newline at end of file
diff --git a/src/models/subway-distance-map-model.js b/src/models/subway-distance-map-model.js
new file mode 100644
index 00000000..2579fb5a
--- /dev/null
+++ b/src/models/subway-distance-map-model.js
@@ -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;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/models/subway-time-map-model.js b/src/models/subway-time-map-model.js
new file mode 100644
index 00000000..73fe3299
--- /dev/null
+++ b/src/models/subway-time-map-model.js
@@ -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;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/services/constants.js b/src/services/constants.js
new file mode 100644
index 00000000..2012862d
--- /dev/null
+++ b/src/services/constants.js
@@ -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 = '๋ฑ๋ก๋ ์ญ์ด ์๋๋๋ค.';
diff --git a/src/services/validation.js b/src/services/validation.js
new file mode 100644
index 00000000..739f2027
--- /dev/null
+++ b/src/services/validation.js
@@ -0,0 +1,62 @@
+import {
+ MINIMUM_STATION_NAME_LENGTH,
+ MINIMUM_STATION_NAME_LENGTH_ALERT,
+ SAME_STATION_ALERT,
+ NOT_ON_LINE_ALERT,
+} from './constants.js';
+import {stations} from '../data/station-data.js';
+
+const includesBothStations = (connectedStations, startStation, endStation) => {
+ if (connectedStations.includes(startStation) && connectedStations.includes(endStation)) {
+ return true;
+ }
+}
+
+export const isIncludesBothStations = (connectedStations, startStation, endStation) => {
+ return includesBothStations(connectedStations, startStation, endStation);
+}
+
+const isNotInStations = (departureStationName, arrivalStationName) => {
+ for (let station of stations) {
+ if (station.name === departureStationName) {
+ return;
+ }
+ }
+
+ for (let station of stations) {
+ if (station.name === arrivalStationName) {
+ return;
+ }
+ }
+ alert(NOT_ON_LINE_ALERT);
+ return true;
+}
+
+const isSameDepartureNameAndArrivalName = (departureStationName, arrivalStationName) => {
+ if (departureStationName === arrivalStationName) {
+ alert(SAME_STATION_ALERT);
+ return true;
+ }
+}
+
+const isInputLengthTooShort = (departureStationName, arrivalStationName) => {
+ if (departureStationName.length < MINIMUM_STATION_NAME_LENGTH ||
+ arrivalStationName.length < MINIMUM_STATION_NAME_LENGTH) {
+ alert(MINIMUM_STATION_NAME_LENGTH_ALERT);
+ return true;
+ }
+}
+
+const notValidInput = (departureStationName, arrivalStationName) => {
+ if (
+ isInputLengthTooShort(departureStationName, arrivalStationName) ||
+ isSameDepartureNameAndArrivalName(departureStationName, arrivalStationName) ||
+ isNotInStations(departureStationName, arrivalStationName)
+ ) {
+ return true;
+ }
+}
+
+export const isNotValidInput = (departureStationName, arrivalStationName) => {
+ return notValidInput(departureStationName, arrivalStationName);
+}
\ No newline at end of file
diff --git a/src/utils/Dijkstra.js b/src/utils/Dijkstra.js
new file mode 100644
index 00000000..7c6cfd56
--- /dev/null
+++ b/src/utils/Dijkstra.js
@@ -0,0 +1,220 @@
+export default function Dijkstra() {
+ const Node = {
+ init: function (val, priority) {
+ this.val = val;
+ this.priority = priority;
+ },
+ };
+
+ const PriorityQueue = {
+ init: function () {
+ this.values = [];
+ },
+ enqueue: function (val, priority) {
+ const newNode = Object.create(Node);
+ newNode.init(val, priority);
+
+ this.values.push(newNode);
+
+ let idxOfNewNode = this.values.length - 1;
+
+ while (idxOfNewNode > 0) {
+ const idxOfParentNode = Math.floor((idxOfNewNode - 1) / 2);
+
+ const parentNode = this.values[idxOfParentNode];
+
+ if (priority < parentNode.priority) {
+ this.values[idxOfParentNode] = newNode;
+ this.values[idxOfNewNode] = parentNode;
+ idxOfNewNode = idxOfParentNode;
+ continue;
+ }
+ break;
+ }
+ return this.values;
+ },
+ dequeue: function () {
+ if (this.values.length == 0) {
+ return;
+ }
+ const dequeued = this.values.shift();
+ const lastItem = this.values.pop();
+ if (!lastItem) {
+ return dequeued;
+ }
+ this.values.unshift(lastItem);
+
+ let idxOfTarget = 0;
+
+ while (true) {
+ let idxOfLeftChild = idxOfTarget * 2 + 1;
+ let idxOfRightChild = idxOfTarget * 2 + 2;
+ let leftChild = this.values[idxOfLeftChild];
+ let rightChild = this.values[idxOfRightChild];
+
+ function swap(direction) {
+ const idxOfChild =
+ direction == "left" ? idxOfLeftChild : idxOfRightChild;
+ const child = direction == "left" ? leftChild : rightChild;
+ this.values[idxOfChild] = this.values[idxOfTarget];
+ this.values[idxOfTarget] = child;
+ idxOfTarget = idxOfChild;
+ }
+
+ if (!leftChild) {
+ return dequeued;
+ }
+
+ if (!rightChild) {
+ if (leftChild.priority < lastItem.priority) {
+ swap.call(this, "left");
+ continue;
+ }
+ return dequeued;
+ }
+
+ if (leftChild.priority == rightChild.priority) {
+ swap.call(this, "left");
+ continue;
+ }
+
+ if (
+ leftChild.priority < rightChild.priority &&
+ leftChild.priority < lastItem.priority
+ ) {
+ swap.call(this, "left");
+ continue;
+ }
+
+ if (
+ rightChild.priority < leftChild.priority &&
+ rightChild.priority < lastItem.priority
+ ) {
+ swap.call(this, "right");
+ continue;
+ }
+ }
+ },
+ };
+
+ const WeightedGraph = {
+ init: function () {
+ this.adjacencyList = {};
+ this.length = 0;
+ },
+ addVertex: function (vertex) {
+ if (!this.adjacencyList.hasOwnProperty(vertex)) {
+ this.adjacencyList[vertex] = {};
+ this.length++;
+ }
+ },
+ addEdge: function (vertex1, vertex2, weight) {
+ this.addVertex(vertex1);
+ this.addVertex(vertex2);
+ this.adjacencyList[vertex1][vertex2] = weight;
+ this.adjacencyList[vertex2][vertex1] = weight;
+ return this.adjacencyList;
+ },
+ removeEdge: function (vertex1, vertex2) {
+ if (!this.adjacencyList.hasOwnProperty(vertex1)) {
+ return `There's no ${vertex1}`;
+ }
+ if (!this.adjacencyList.hasOwnProperty(vertex2)) {
+ return `There's no ${vertex2}`;
+ }
+
+ function removeHelper(v1, v2) {
+ if (!this.adjacencyList.hasOwnProperty(v1)) {
+ return `There's no edge between ${v1} and ${v2}`;
+ }
+ delete this.adjacencyList[v1][v2];
+ if (Object.keys(this.adjacencyList[v1]).length == 0) {
+ delete this.adjacencyList[v1];
+ }
+ }
+
+ removeHelper.call(this, vertex1, vertex2);
+ removeHelper.call(this, vertex2, vertex1);
+
+ return this.adjacencyList;
+ },
+ removeVertex: function (vertex) {
+ if (!this.adjacencyList.hasOwnProperty(vertex)) {
+ return `There's no ${vertex}`;
+ }
+ const edges = this.adjacencyList[vertex];
+ for (const key in edges) {
+ this.removeEdge(key, vertex);
+ }
+ return this.adjacencyList;
+ },
+ findShortestRoute: function (start, end) {
+ if (!start || !end) {
+ throw Error("์ถ๋ฐ์ง์ ๋์ฐฉ์ง๋ฅผ ๋ชจ๋ ์
๋ ฅํด์ผ ํฉ๋๋ค.");
+ }
+ const distance = {};
+ const previous = {};
+ const pq = Object.create(PriorityQueue);
+ pq.init();
+ pq.enqueue(start, 0);
+ const visited = {};
+
+ const hashOfVertex = this.adjacencyList;
+ for (const vertexName in hashOfVertex) {
+ const priority = vertexName == start ? 0 : Infinity;
+ distance[vertexName] = priority;
+ previous[vertexName] = null;
+ }
+
+ while (true) {
+ let current = pq.dequeue();
+ if (!current?.val) {
+ return;
+ }
+ current = current.val;
+ if (current == end) {
+ break;
+ }
+ const neighbors = hashOfVertex[current];
+
+ for (const vertexName in neighbors) {
+ if (visited.hasOwnProperty(vertexName)) {
+ continue;
+ }
+ const distFromStart = distance[current] + neighbors[vertexName];
+
+ if (distFromStart < distance[vertexName]) {
+ pq.enqueue(vertexName, distFromStart);
+ distance[vertexName] = distFromStart;
+ previous[vertexName] = current;
+ }
+ }
+ visited[current] = true;
+ }
+
+ let node = end;
+
+ const route = [];
+ while (node) {
+ route.unshift(node);
+ node = previous[node];
+ }
+
+ return route;
+ },
+ };
+
+ this.addEdge = (source, target, weight) => {
+ WeightedGraph.addEdge(source, target, weight);
+ };
+
+ this.findShortestPath = (source, target) => {
+ return WeightedGraph.findShortestRoute(source, target);
+ };
+
+ this.addVertex = (vertex) => {
+ WeightedGraph.addVertex(vertex);
+ };
+
+ WeightedGraph.init();
+}
diff --git a/src/views/constants.js b/src/views/constants.js
new file mode 100644
index 00000000..69240623
--- /dev/null
+++ b/src/views/constants.js
@@ -0,0 +1,6 @@
+export const KILOMETER = 'km';
+export const MINUTE = '๋ถ';
+export const ARROW = 'โ';
+
+export const FIRST_RADIO = 0;
+export const SECOND_RADIO = 1;
diff --git a/src/views/subway-path-input.js b/src/views/subway-path-input.js
new file mode 100644
index 00000000..6b063ab9
--- /dev/null
+++ b/src/views/subway-path-input.js
@@ -0,0 +1,41 @@
+import {FIRST_RADIO, SECOND_RADIO} from './constants.js';
+
+export default class SubwayPathInput {
+ bindSearchButton = searchButtonHandler => {
+ const searchButton = document.getElementById('search-button');
+
+ searchButton.addEventListener('click', () => searchButtonHandler(this.getSearchInputs()));
+ }
+
+ getSearchInputs = () => {
+ const departureStationName = this.getDepartureStationName();
+ const arrivalStationName = this.getArrivalStationName();
+ const radioSelect = this.getRadioSelect();
+
+ return [departureStationName, arrivalStationName, radioSelect];
+ }
+
+ getDepartureStationName = () => {
+ const departureStationNameInput = document.getElementById('departure-station-name-input');
+
+ return departureStationNameInput.value;
+ }
+
+ getArrivalStationName = () => {
+ const arrivalStationNameInput = document.getElementById('arrival-station-name-input');
+
+ return arrivalStationNameInput.value;
+ }
+
+ getRadioSelect = () => {
+ const radioSelectInput = document.getElementsByName('search-type');
+ let radioSelect;
+ if (radioSelectInput[FIRST_RADIO].checked) {
+ radioSelect = radioSelectInput[FIRST_RADIO].value;
+ } else if (radioSelectInput[SECOND_RADIO].checked) {
+ radioSelect = radioSelectInput[SECOND_RADIO].value;
+ }
+
+ return radioSelect;
+ }
+}
\ No newline at end of file
diff --git a/src/views/subway-path-output.js b/src/views/subway-path-output.js
new file mode 100644
index 00000000..cc319e54
--- /dev/null
+++ b/src/views/subway-path-output.js
@@ -0,0 +1,90 @@
+import {KILOMETER, MINUTE, ARROW} from './constants.js';
+
+export default class SubwayPathOutput {
+ constructor() {
+ this.subwayPathAppContainer = document.getElementById('app')
+
+ this.renderInputFieldContainer();
+ }
+
+ renderInputFieldContainer = () => {
+ const subwayPathInputContainer = document.createElement('div');
+
+ subwayPathInputContainer.setAttribute('id', 'subway-path-input-container');
+ this.subwayPathAppContainer.appendChild(subwayPathInputContainer);
+
+ this.createInputField(subwayPathInputContainer);
+ }
+
+ createInputField = subwayPathInputContainer => {
+ subwayPathInputContainer.innerHTML =
+ `
+ ๐ ์งํ์ฒ ๊ธธ์ฐพ๊ธฐ
+ ์ถ๋ฐ์ญ
+ ๋์ฐฉ์ญ
+
+ ์ต๋จ๊ฑฐ๋ฆฌ
+
+ ์ต์์๊ฐ
+
+ `;
+ }
+
+ renderResult = resultTableData => {
+ this.clearTableContainer();
+ const resultTableContainer = document.createElement('div');
+ resultTableContainer.setAttribute('id', 'result-table-container');
+ this.subwayPathAppContainer.appendChild(resultTableContainer);
+
+ this.renderResultTable(resultTableContainer, resultTableData);
+ }
+
+ clearTableContainer = () => {
+ const tableContainer = document.getElementById('result-table-container');
+ if (tableContainer !== null) {
+ tableContainer.remove();
+ }
+ }
+
+ renderResultTable = (resultTableContainer, resultTableData) => {
+ let radioSelect;
+ let totalDistance;
+ let totalTime;
+ let totalPath;
+
+ [radioSelect, totalDistance, totalTime, totalPath] = [...resultTableData];
+
+ resultTableContainer.innerHTML = this.createResultType(radioSelect) + this.createResultTable(totalDistance, totalTime, totalPath);
+ }
+
+ createResultType = radioSelect => {
+ const resultType =
+ `
+ ๐ ๊ฒฐ๊ณผ
+ ${radioSelect}
+ `;
+
+ return resultType;
+ }
+
+ createResultTable = (totalDistance, totalTime, totalPath) => {
+ const resultTable =
+ `
+
+
+ | ์ด ๊ฑฐ๋ฆฌ |
+ ์ด ์์ ์๊ฐ |
+
+
+ | ${totalDistance + KILOMETER} |
+ ${totalTime + MINUTE} |
+
+
+ | ${totalPath.join(ARROW)} |
+
+
+ `;
+
+ return resultTable;
+ }
+}
\ No newline at end of file