diff --git a/README.md b/README.md index 51abd25..1fa14b5 100644 --- a/README.md +++ b/README.md @@ -1 +1,22 @@ -# javascript-subway-final \ No newline at end of file +# ๐Ÿš‡ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ฒฝ๋กœ ์กฐํšŒ ๋ฏธ์…˜ +- ๋“ฑ๋ก๋œ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„์—์„œ ๊ฒฝ๋กœ๋ฅผ ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค. + +## ๐Ÿš€ ๊ตฌํ˜„ ๊ธฐ๋Šฅ๋ชฉ๋ก + +### ์ดˆ๊ธฐ ์„ค์ • +- ํ”„๋กœ๊ทธ๋žจ ์‹œ์ž‘ ์‹œ ์—ญ, ๋…ธ์„ , ๊ตฌ๊ฐ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ดˆ๊ธฐ ์„ค์ •ํ•œ๋‹ค. + - ๊ฑฐ๋ฆฌ์™€ ์†Œ์š” ์‹œ๊ฐ„์€ ์–‘์˜ ์ •์ˆ˜์ด๋ฉฐ ๋‹จ์œ„๋Š” km์™€ ๋ถ„์„ ์˜๋ฏธํ•œ๋‹ค. + +### ๊ฒฝ๋กœ ์กฐํšŒ ๊ธฐ๋Šฅ +- ์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์„ ์ž…๋ ฅ๋ฐ›์•„ ์ž…๋ ฅ๊ฐ’๋“ค์„ ์ฒ˜๋ฆฌํ•œ๋‹ค. + - ๊ธธ์ฐพ๊ธฐ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ ํ•ด๋‹น ๊ธฐ๋Šฅ์ด ์‹คํ–‰๋œ๋‹ค. + - ์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์€ 2๊ธ€์ž ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค. + - ์กด์žฌํ•˜์ง€ ์•Š๋Š” ์—ญ์„ ์ž…๋ ฅ๋ฐ›์•˜์„ ๊ฒฝ์šฐ alert์ฐฝ์„ ๋„์šด๋‹ค. + - ์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์€ ๋‹ค๋ฅด๊ฒŒ ์ž…๋ ฅํ•ด์•ผ ํ•œ๋‹ค. + - ์ž…๋ ฅ๊ฐ’์ด ์—†์„ ๊ฒฝ์šฐ alert์ฐฝ์„ ๋„์›Œ ๋‹ค์‹œ ์ž…๋ ฅํ•˜๋„๋ก ํ•œ๋‹ค. + - ์ž…๋ ฅ๊ฐ’๋“ค์˜ ๊ณต๋ฐฑ์„ ์ œ๊ฑฐํ•œ๋‹ค. +- ์ž…๋ ฅ๋œ ์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์„ ๋ฐ”ํƒ•์œผ๋กœ ๊ฒฝ๋กœ๋ฅผ ์กฐํšŒํ•œ๋‹ค. + - ์ด ๊ฑฐ๋ฆฌ, ์ด ์†Œ์š” ์‹œ๊ฐ„์„ ํ…Œ์ด๋ธ”์— ๋‹ด์•„ ์ถœ๋ ฅํ•œ๋‹ค. + - ์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์ด ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ๊ฒฝ๋กœ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์—†๋‹ค. + - ๊ฒฝ๋กœ ์กฐํšŒ ์‹œ ์ตœ๋‹จ๊ฑฐ๋ฆฌ ๋˜๋Š” ์ตœ์†Œ ์‹œ๊ฐ„ ์˜ต์…˜์„ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋‹ค. + - ๊ธฐ๋ณธ๊ฐ’์€ ์ตœ๋‹จ๊ฑฐ๋ฆฌ์ด๋‹ค. \ No newline at end of file diff --git a/images/dijkstra_example.png b/images/dijkstra_example.png new file mode 100644 index 0000000..7c75197 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 0000000..ee394bd 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 0000000..40a4bed Binary files /dev/null and b/images/path_result.jpg differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..2b80a95 --- /dev/null +++ b/index.html @@ -0,0 +1,25 @@ + + + + + + ๐Ÿš‡์ง€ํ•˜์ฒ  ๊ธธ์ฐพ๊ธฐ + + +
+

๐Ÿš‡์ง€ํ•˜์ฒ  ๊ธธ์ฐพ๊ธฐ

+

์ถœ๋ฐœ์—ญ

+ +

+

๋„์ฐฉ์—ญ

+ +

+ ์ตœ๋‹จ๊ฑฐ๋ฆฌ + ์ตœ์†Œ์‹œ๊ฐ„ +

+ +

๐Ÿ“๊ฒฐ๊ณผ

+
+ + + diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..7863b52 --- /dev/null +++ b/src/index.js @@ -0,0 +1,34 @@ +import processStationNames from "./process-station-names.js?ver=31"; +import processSubwayDirection from "./process-subway-direction.js?ver=51"; + +export default class Index { + constructor() { + this.processStationNames = new processStationNames(); + this.processSubwayDirection = new processSubwayDirection(); + this.searchButton = document.getElementById("search-button"); + this.searchButton.addEventListener("click", () => {this.printResult()}); + } + + checkRadioButton() { + const radioButton = document.getElementsByName("search-type"); + let radioValue; + radioButton.forEach(button => { + if(button.checked == true) { + radioValue = button.value; + } + }); + return radioValue; + } + + printResult() { + const stationNames = this.processStationNames.getStationNames(); + const radioValue = this.checkRadioButton(); + let result; + if(stationNames !== []) { + result = radioValue === "distance" ? this.processSubwayDirection.getMinDistance(stationNames) : this.processSubwayDirection.getMinTime(stationNames); + } + console.log(result); + } +} + +new Index(); \ No newline at end of file diff --git a/src/process-station-names.js b/src/process-station-names.js new file mode 100644 index 0000000..8ee58e2 --- /dev/null +++ b/src/process-station-names.js @@ -0,0 +1,64 @@ +import {stations} from "./utils/data.js?ver=30"; +import { + removeWhiteSpaceValue, + isEmpty, + isRightLength +} from "./utils/common.js?ver=30"; + +export default class processStationNames { + constructor() { + this.stations = stations; + } + + checkStationInData(name) { + return this.stations.findIndex(station => station.name === name); + } + + getAlertText(stationName, stationType) { + let text = ""; + if(isEmpty(stationName)) { + text = `${stationType}์—ญ์„ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”`; + } + else if(!isRightLength(stationName)) { + text = `${stationType}์—ญ์„ ๋‘๊ธ€์ž ์ด์ƒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”`; + } + else if(this.checkStationInData(stationName) === -1){ + text = `${stationName}์—ญ์€ ๋“ฑ๋ก๋˜์ง€ ์•Š์€ ์—ญ์ž…๋‹ˆ๋‹ค`; + } + return text; + } + + setAlert(departureText, arrivalText, departureStationName, arrivalStationName) { + let isCorrect = false; + if(departureText !== "") { + alert(departureText); + } + else if(arrivalText !== "") { + alert(arrivalText); + } + else if(departureStationName === arrivalStationName){ + alert("์ถœ๋ฐœ์—ญ๊ณผ ๋„์ฐฉ์—ญ์„ ๋‹ค๋ฅด๊ฒŒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”"); + } + else { + isCorrect = true; + } + return isCorrect; + } + + checkStationNames(departureStationName, arrivalStationName) { + const departureText = this.getAlertText(departureStationName, "์ถœ๋ฐœ"); + const arrivalText = this.getAlertText(arrivalStationName, "๋„์ฐฉ"); + return this.setAlert(departureText, arrivalText, departureStationName, arrivalStationName); + } + + getStationNames() { + const departureStationName = removeWhiteSpaceValue(document.getElementById("departure-station-name-input").value); + const arrivalStationName = removeWhiteSpaceValue(document.getElementById("arrival-station-name-input").value); + const isCorrect = this.checkStationNames(departureStationName, arrivalStationName); + let stationNames = []; + if(isCorrect) { + stationNames = [departureStationName, arrivalStationName]; + } + return stationNames; + } +} \ No newline at end of file diff --git a/src/process-subway-direction.js b/src/process-subway-direction.js new file mode 100644 index 0000000..6cf3c82 --- /dev/null +++ b/src/process-subway-direction.js @@ -0,0 +1,46 @@ +import {lines} from "./utils/data.js?ver=30"; + +export default class processSubwayDirection { + constructor() { + this.lines = lines; + this.directions = []; + } + + getLinesInStation(stationName) { + const linesInStation = this.lines.filter(line => line.station.includes(stationName)); + return linesInStation; + } + + checkNextStation(station, index) { + return station.length - 1 ? null : station[index + 1]; + } + + recordDirection(stationList) { + const lineList = this.getLinesInStation(stationList[-1]); + lineList.forEach(line => { + const station = line.station; + this.checkNextStation(station, station.indexOf(stationList[-1])); + }) + } + + getDirection(startLine, stationName) { + const startStation = startLine.station; + const startIndex = startStation.indexOf(stationName); + const nextStation = this.checkNextStation(startStation, startIndex); + if(nextStation !== null) { + this.recordDirection([startStation, nextStation]); + } + } + + getMinDistance(stationNames) { + const startLineList = this.getLinesInStation(stationNames[0]); + startLineList.forEach(line => { + this.getDirection(line, stationNames[0]); + }) + + } + + getMinTime(stationNames) { + + } +} \ No newline at end of file diff --git a/src/style.css b/src/style.css new file mode 100644 index 0000000..63f96de --- /dev/null +++ b/src/style.css @@ -0,0 +1,4 @@ +h3 { + display: inline; +} + 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(); +} diff --git a/src/utils/common.js b/src/utils/common.js new file mode 100644 index 0000000..ac293d1 --- /dev/null +++ b/src/utils/common.js @@ -0,0 +1,12 @@ +export function removeWhiteSpaceValue(value) { + return value.replace(/^\s+|\s+$/gm, ''); +} + +export function isEmpty(value) { + return (value === "" || value === null || value === undefined || (value !== null + && typeof value === "object" && !Object.keys(value).length)); +} + +export function isRightLength(value) { + return value.length >= 2; +} \ No newline at end of file diff --git a/src/utils/data.js b/src/utils/data.js new file mode 100644 index 0000000..9d72b50 --- /dev/null +++ b/src/utils/data.js @@ -0,0 +1,44 @@ +export const stations = [ + { + name: "๊ต๋Œ€" + }, + { + name: "๊ฐ•๋‚จ" + }, + { + name: "์—ญ์‚ผ" + }, + { + name: "๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„" + }, + { + name: "์–‘์žฌ" + }, + { + name: "์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ" + }, + { + name: "๋งค๋ด‰" + } +] + +export const lines = [ + { + name: "2ํ˜ธ์„ ", + station: ["๊ต๋Œ€", "๊ฐ•๋‚จ", "์—ญ์‚ผ"], + distance: [2, 2, 0], + time: [3, 3, 0] + }, + { + name: "3ํ˜ธ์„ ", + station: ["๊ต๋Œ€", "๋‚จ๋ถ€ํ„ฐ๋ฏธ๋„", "์–‘์žฌ", "๋งค๋ด‰"], + distance: [3, 6, 1, 0], + time: [2, 5, 1, 0] + }, + { + name: "์‹ ๋ถ„๋‹น์„ ", + station: ["๊ฐ•๋‚จ", "์–‘์žฌ", "์–‘์žฌ์‹œ๋ฏผ์˜์ˆฒ"], + distance: [2, 10, 0], + time: [8, 3, 0] + } +] \ No newline at end of file