diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..8aa924d --- /dev/null +++ b/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env"] +} \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..54b9a9b --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["airbnb", "prettier"], + "env": { + "browser": true, + "jest/globals": true, + "es2020": true + }, + "parser": "@babel/eslint-parser", + "parserOptions": { + "ecmaVersion": 12, + "sourceType": "module" + }, + "plugins": ["prettier", "jest", "@babel"], + "rules": { + "import/extensions": ["off"], + "lines-between-class-members": ["off"] + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..448cd77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.vscode/ +node_modules/ +package.json +package-lock.json diff --git a/README.md b/README.md deleted file mode 100644 index 51abd25..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -# javascript-subway-final \ No newline at end of file diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..14906bb --- /dev/null +++ b/babel.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: [ + '@babel/plugin-proposal-private-methods', + '@babel/plugin-proposal-class-properties', + ], +}; diff --git a/index.css b/index.css new file mode 100644 index 0000000..d78f42b --- /dev/null +++ b/index.css @@ -0,0 +1,3 @@ +#result { + display: none; +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..d100630 --- /dev/null +++ b/index.html @@ -0,0 +1,49 @@ + + + + + 지하철 길찾기 + + + +
+

지하철 길찾기

+
+
+ + +
+
+ + +
+
+
+ + +
+ + +
+

결과

+

최단거리

+ + + + + + + + +
총 거리총 소요 시간
+
+
+ + + diff --git a/src/classes/station/station.js b/src/classes/station/station.js new file mode 100644 index 0000000..95d917d --- /dev/null +++ b/src/classes/station/station.js @@ -0,0 +1,11 @@ +import { MIN_STATION_NAME_LENGTH } from '../../constants/constants.js'; + +export default class Station { + static isStationNameTooShort(stationName) { + return stationName.length < MIN_STATION_NAME_LENGTH; + } + + static isStationNamesSame(startStationName, endStationName) { + return startStationName === endStationName; + } +} diff --git a/src/classes/subwayMap/subwayMap.js b/src/classes/subwayMap/subwayMap.js new file mode 100644 index 0000000..4387cba --- /dev/null +++ b/src/classes/subwayMap/subwayMap.js @@ -0,0 +1,90 @@ +import { initalLineData, initalStationData } from '../../data/data.js'; + +export default class SubwayMap { + #allLines; + #allStations; + #pathInfo = { totalDistance: 0, totalTime: 0 }; + #path; constructor() { + this.#allStations = initalStationData; + this.#allLines = initalLineData; + } + + get allLines() { + return this.#allLines; + } + + get allStations() { + return this.#allStations; + } + + setPath(path) { + this.#path = path; + } + + getTotalDistanceAndTimeFromPath() { + this.#pathInfo.totalDistance = 0; + this.#pathInfo.totalTime = 0; + const initialIndex = 0; + const initialDistance = 0; + const initialTime = 0; + + this.#traverseSubwayMap(initialIndex, initialDistance, initialTime); + return this.#pathInfo; + } + + // 첫번째 노드를 바탕으로 역들을 순회 + // 순회하다가 발견하면 연결된 노드들 중에 index + 1에 해당하는 값이 있는지 확인 + // 있다면 info 를 더함 + + #traverseSubwayMap(index, distance, time) { + if (index >= this.#path.length - 1) { + this.#pathInfo.totalDistance = distance; + this.#pathInfo.totalTime = time; + } + const stationName = this.#path[index]; + const newIndex = index + 1; + let addedDistance = distance; + let addedTime = time; + + const station = this.#allStations[stationName]; + station.connected.forEach((connectedStation) => { + const nextPathStation = this.#path[newIndex]; + if (connectedStation.station === nextPathStation) { + addedDistance += connectedStation.distance; + addedTime += connectedStation.time; + this.#traverseSubwayMap(newIndex, addedDistance, addedTime); + } + }); + } + + isStationNotExist(stationName) { + let isExist = true; + const allLineNames = Object.keys(this.#allLines); + allLineNames.forEach((lineName) => { + const line = this.#allLines[lineName]; + line.forEach((section) => { + if (section.station === stationName) { + isExist = false; + } + }); + }); + + return isExist; + } + + isStationsConnected(fromStationName, toStationName) { + let isConnected = false; + const allLineNames = Object.keys(this.#allLines); + allLineNames.forEach((lineName) => { + const line = this.#allLines[lineName]; + const fileterdLine = line.filter( + (section) => section.station === fromStationName || toStationName + ); + if (fileterdLine.length === 2) { + isConnected = true; + } + }); + + return isConnected; + } +} diff --git a/src/classes/subwayPath/subwayPath.js b/src/classes/subwayPath/subwayPath.js new file mode 100644 index 0000000..f5faa96 --- /dev/null +++ b/src/classes/subwayPath/subwayPath.js @@ -0,0 +1,13 @@ +import DijstraStore from '../../store/dijkstra.js'; + +const { distanceDijkstra, timeDijkstra } = DijstraStore; + +export default class subwayPath { + static getMinDistancePath(startStationName, endStationName) { + return distanceDijkstra.findShortestPath(startStationName, endStationName); + } + + static getMinTimePath(startStationName, endStationName) { + return timeDijkstra.findShortestPath(startStationName, endStationName); + } +} diff --git a/src/classes/subwayPath/subwayPathUI.js b/src/classes/subwayPath/subwayPathUI.js new file mode 100644 index 0000000..34bb36f --- /dev/null +++ b/src/classes/subwayPath/subwayPathUI.js @@ -0,0 +1,121 @@ +import { + MIN_DISTANCE_CHECK_OPTION_NAME, + MIN_TIME_CHECK_OPTION_NAME, + TOO_SHORT_STATION_NAME_MESSAGE, + NOT_CONNECTED_STATIONS_MESSAGE, + SAME_STATIONS_MESSAGE, + STATION_NOT_EXIST_MESSAGE, +} from '../../constants/constants.js'; +import { + resultElement, + resultTableBodyElement, + arrivalStationNameInputElement, + departureStationNameInputElement, + minDistancePathSearchRadioElement, + minTimePathSearchRadioElement, +} from '../../elements/subwayPath.js'; +import SubwayPath from './subwayPath.js'; +import Station from '../station/station.js'; +import { subwayMap } from '../../store/subway.js'; +import { getResultTableBodyTemplate } from '../../templates/table.js'; + +export default class SubwayPathUI { + static getCheckedOptionName() { + let checkedOptionName = ''; + if (minDistancePathSearchRadioElement.checked === true) { + checkedOptionName = MIN_DISTANCE_CHECK_OPTION_NAME; + } else if (minTimePathSearchRadioElement.checked === true) { + checkedOptionName = MIN_TIME_CHECK_OPTION_NAME; + } + + return checkedOptionName; + } + + static getInvalidInputAlertMessage(startStationName, endStationName) { + let alertMessage = ''; + if ( + Station.isStationNameTooShort(startStationName) || + Station.isStationNameTooShort(endStationName) + ) { + alertMessage += TOO_SHORT_STATION_NAME_MESSAGE; + } + if (Station.isStationNamesSame(startStationName, endStationName)) { + alertMessage += SAME_STATIONS_MESSAGE; + } + + return alertMessage; + } + + static getInvalidSearchAlertMessage(startStationName, endStationName) { + let alertMessage = ''; + if ( + subwayMap.isStationNotExist(startStationName) || + subwayMap.isStationNotExist(endStationName) + ) { + alertMessage += STATION_NOT_EXIST_MESSAGE; + } + if (subwayMap.isStationsConnected(startStationName, endStationName)) { + alertMessage += NOT_CONNECTED_STATIONS_MESSAGE; + } + + return alertMessage; + } + + static showResultToTable({ + checkedOptionName, + departureStationName, + arrivalStationName, + }) { + let resultPath; + if (checkedOptionName === MIN_DISTANCE_CHECK_OPTION_NAME) { + resultPath = SubwayPath.getMinDistancePath( + departureStationName, + arrivalStationName + ); + } else if (checkedOptionName === MIN_TIME_CHECK_OPTION_NAME) { + resultPath = SubwayPath.getMinTimePath( + departureStationName, + arrivalStationName + ); + } + subwayMap.setPath(resultPath); + const { + totalDistance, + totalTime, + } = subwayMap.getTotalDistanceAndTimeFromPath(); + const resultTableBodyTemplate = getResultTableBodyTemplate( + totalDistance, + totalTime, + resultPath + ); + resultElement.setAttribute('style', 'display: block;'); + resultTableBodyElement.innerHTML = resultTableBodyTemplate; + } + + static showPath() { + const departureStationName = departureStationNameInputElement.value; + const arrivalStationName = arrivalStationNameInputElement.value; + const checkedOptionName = SubwayPathUI.getCheckedOptionName(); + const invalidInputAlertMessage = SubwayPathUI.getInvalidInputAlertMessage( + departureStationName, + arrivalStationName + ); + if (invalidInputAlertMessage !== '') { + alert(invalidInputAlertMessage); + return; + } + const invalidSearchAlertMessage = SubwayPathUI.getInvalidSearchAlertMessage( + departureStationName, + arrivalStationName + ); + if (invalidSearchAlertMessage !== '') { + alert(invalidSearchAlertMessage); + } else { + SubwayPathUI.showResultToTable({ + checkedOptionName, + departureStationName, + arrivalStationName, + }); + } + } +} diff --git a/src/constants/constants.js b/src/constants/constants.js new file mode 100644 index 0000000..f10d98b --- /dev/null +++ b/src/constants/constants.js @@ -0,0 +1,18 @@ +export const MIN_STATION_NAME_LENGTH = 2; +export const MIN_DISTANCE_CHECK_OPTION_NAME = '최단거리'; +export const MIN_TIME_CHECK_OPTION_NAME = '최소시간'; +export const TOO_SHORT_STATION_NAME_MESSAGE = + '입력하신 역들 중 이름이 너무 짧은 역이 있습니다'; +export const SAME_STATIONS_MESSAGE = '출발역과 도착역의 이름이 동일합니다'; +export const NOT_CONNECTED_STATIONS_MESSAGE = + '출발역으로부터 도착역에 도달할 수 없습니다'; +export const STATION_NOT_EXIST_MESSAGE = '존재하지 않는 역을 입력하셨습니다' + +export default { + MIN_STATION_NAME_LENGTH, + MIN_DISTANCE_CHECK_OPTION_NAME, + MIN_TIME_CHECK_OPTION_NAME, + TOO_SHORT_STATION_NAME_MESSAGE, + SAME_STATIONS_MESSAGE, + NOT_CONNECTED_STATIONS_MESSAGE +}; diff --git a/src/data/data.js b/src/data/data.js new file mode 100644 index 0000000..1ad4904 --- /dev/null +++ b/src/data/data.js @@ -0,0 +1,62 @@ +export const initalStationData = { + 교대: { + connected: [ + { station: '강남', distance: 2, time: 3 }, + { station: '남부터미널', distance: 3, time: 2 }, + ], + }, + 강남: { + connected: [ + { station: '교대', distance: 2, time: 3 }, + { station: '역삼', distance: 2, time: 3 }, + { station: '양재', distance: 2, time: 8 }, + ], + }, + 역삼: { + connected: [{ station: '강남', distance: 2, time: 3 }], + }, + 남부터미널: { + connected: [ + { station: '교대', distance: 3, time: 2 }, + { station: '양재', distance: 6, time: 5 }, + ], + }, + 양재: { + connected: [ + { station: '남부터미널', distance: 3, time: 2 }, + { station: '매봉', distance: 1, time: 1 }, + { station: '강남', distance: 2, time: 8 }, + { station: '양재시민의 숲', distance: 10, time: 3 }, + ], + }, + 매봉: { + connected: [{ station: '양재', distance: 1, time: 1 }], + }, + '양재시민의 숲': { + connected: [{ station: '양재', distance: 10, time: 3 }], + }, +}; + +export const initalLineData = { + '2호선': [ + { station: '교대', distance: 0, time: 0 }, + { station: '강남', distance: 2, time: 3 }, + { station: '역삼', distance: 2, time: 3 }, + ], + '3호선': [ + { station: '교대', distance: 0, time: 0 }, + { station: '남부터미널', distance: 3, time: 2 }, + { station: '양재', distance: 6, time: 5 }, + { station: '매봉', distance: 1, time: 1 }, + ], + 신분당선: [ + { station: '강남', distance: 0, time: 0 }, + { station: '양재', distance: 2, time: 8 }, + { station: '양재시민의 숲', distance: 10, time: 3 }, + ], +}; + +export default { + initalLineData, + initalStationData, +}; diff --git a/src/docs/README.md b/src/docs/README.md new file mode 100644 index 0000000..940c615 --- /dev/null +++ b/src/docs/README.md @@ -0,0 +1,29 @@ +# 🚇 지하철 노선도 경로 조회 프로그램 + +- 등록된 지하철 노선도에서 경로를 조회할 수 있는 프로그램입니다. + +## 🚀 기능 목록 + +### 초기 설정 + +- 역, 노선, 구간 데이터와 인터페이스를 초기 설정 + +### 경로 조회 기능 + + + +- 출발역과 도착역이 2글자 이상인지 검사 +- 존재하지 않는 역을 출발역 또는 도착역으로 입력했는지 검사 +- 경로 조회 시 출발역과 도착역이 같은지 검사 +- 경로 조회 시 출발역과 도착역이 연결되어 있지 않은지 검사 +- 출발역과 도착역을 입력받아 최단 경로를 조회 +- 출발역과 도착역을 입력받아 최소시간 경로를 조회 +- 최단 거리 또는 최소 시간 옵션을 바탕으로 경로의 총 거리, 총 소요 시간 출력 + +
+ +## 💻 프로그램 실행 결과 + +### 경로 조회 + + diff --git a/src/elements/subwayPath.js b/src/elements/subwayPath.js new file mode 100644 index 0000000..e592898 --- /dev/null +++ b/src/elements/subwayPath.js @@ -0,0 +1,25 @@ +export const departureStationNameInputElement = document.getElementById( + 'departure-station-name-input' +); +export const arrivalStationNameInputElement = document.getElementById( + 'arrival-station-name-input' +); +const searchOptionRadioElements = document.querySelectorAll( + 'input[name="search-type"]' +); +export const minDistancePathSearchRadioElement = searchOptionRadioElements[0]; +export const minTimePathSearchRadioElement = searchOptionRadioElements[1]; +export const resultTableBodyElement = document.getElementById( + 'result-table-body' +); +export const resultElement = document.getElementById('result'); +export const searchButtonElement = document.getElementById('search-button'); + +export default { + departureStationNameInputElement, + minDistancePathSearchRadioElement, + minTimePathSearchRadioElement, + searchButtonElement, + resultTableBodyElement, + resultElement, +}; diff --git a/src/handlers/subwayPath.js b/src/handlers/subwayPath.js new file mode 100644 index 0000000..924f2ef --- /dev/null +++ b/src/handlers/subwayPath.js @@ -0,0 +1,9 @@ +import SubwayPathUI from '../classes/subwayPath/subwayPathUI.js'; + +export const onSearchPath = () => { + SubwayPathUI.showPath(); +}; + +export default { + onSearchPath, +}; diff --git a/src/images/dijkstra_example.png b/src/images/dijkstra_example.png new file mode 100644 index 0000000..7c75197 Binary files /dev/null and b/src/images/dijkstra_example.png differ diff --git a/src/images/path_result.gif b/src/images/path_result.gif new file mode 100644 index 0000000..ee394bd Binary files /dev/null and b/src/images/path_result.gif differ diff --git a/src/images/path_result.jpg b/src/images/path_result.jpg new file mode 100644 index 0000000..40a4bed Binary files /dev/null and b/src/images/path_result.jpg differ diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..bb5bc8b --- /dev/null +++ b/src/index.js @@ -0,0 +1,3 @@ +import { setSubwayPathEventListener } from './listeners/subwayPath.js'; + +setSubwayPathEventListener(); diff --git a/src/listeners/subwayPath.js b/src/listeners/subwayPath.js new file mode 100644 index 0000000..432b781 --- /dev/null +++ b/src/listeners/subwayPath.js @@ -0,0 +1,10 @@ +import { searchButtonElement } from '../elements/subwayPath.js'; +import { onSearchPath } from '../handlers/subwayPath.js'; + +export const setSubwayPathEventListener = () => { + searchButtonElement.addEventListener('click', onSearchPath); +}; + +export default { + setSubwayPathEventListener, +}; diff --git a/src/store/dijkstra.js b/src/store/dijkstra.js new file mode 100644 index 0000000..1889493 --- /dev/null +++ b/src/store/dijkstra.js @@ -0,0 +1,29 @@ +import Dijkstra from '../utils/Dijkstra.js'; + +const distanceDijkstra = new Dijkstra(); +const timeDijkstra = new Dijkstra(); + +distanceDijkstra.addEdge('교대', '강남', 2); +distanceDijkstra.addEdge('강남', '역삼', 2); + +distanceDijkstra.addEdge('교대', '남부터미널', 3); +distanceDijkstra.addEdge('남부터미널', '양재', 6); +distanceDijkstra.addEdge('양재', '매봉', 1); + +distanceDijkstra.addEdge('강남', '양재', 2); +distanceDijkstra.addEdge('양재', '양재시민의', 10); + +timeDijkstra.addEdge('교대', '강남', 3); +timeDijkstra.addEdge('강남', '역삼', 3); + +timeDijkstra.addEdge('교대', '남부터미널', 2); +timeDijkstra.addEdge('남부터미널', '양재', 5); +timeDijkstra.addEdge('양재', '매봉', 1); + +timeDijkstra.addEdge('강남', '양재', 8); +timeDijkstra.addEdge('양재', '양재시민의', 3); + +export default { + distanceDijkstra, + timeDijkstra, +}; diff --git a/src/store/subway.js b/src/store/subway.js new file mode 100644 index 0000000..5c0a0be --- /dev/null +++ b/src/store/subway.js @@ -0,0 +1,10 @@ +import SubwayPath from '../classes/subwayPath/subwayPath.js'; +import SubwayMap from '../classes/subwayMap/subwayMap.js'; + +export const subwayPath = new SubwayPath(); +export const subwayMap = new SubwayMap(); + +export default { + subwayPath, + subwayMap, +}; diff --git a/src/templates/table.js b/src/templates/table.js new file mode 100644 index 0000000..b506cc8 --- /dev/null +++ b/src/templates/table.js @@ -0,0 +1,30 @@ +const getPathRowTemplate = (nodes) => { + let nodesTemplate = ''; + nodes.forEach((node, index) => { + nodesTemplate += node; + if (index !== nodes.length - 1) { + nodesTemplate += '🡆'; + } + }); + return ` + ${nodesTemplate} + `; +}; + +export const getResultTableBodyTemplate = (distance, time, path) => { + const pathRowTemplate = getPathRowTemplate(path); + + return ` + + ${distance}km + ${time}분 + + + ${pathRowTemplate} + + `; +}; + +export default { + getResultTableBodyTemplate, +}; diff --git a/src/utils/Dijkstra.js b/src/utils/Dijkstra.js new file mode 100644 index 0000000..7c6cfd5 --- /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(); +}