diff --git a/README.md b/README.md
index 51abd25..d74c447 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,74 @@
-# javascript-subway-final
\ No newline at end of file
+# ๐ ์งํ์ฒ ๋
ธ์ ๋ ๊ฒฝ๋ก ์กฐํ ๋ฏธ์
+- ๋ฑ๋ก๋ ์งํ์ฒ ๋
ธ์ ๋์์ ๊ฒฝ๋ก๋ฅผ ์กฐํํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค.
+
+## ๐ ๊ธฐ๋ฅ ์๊ตฌ์ฌํญ
+> ํ๋ฆฌ์ฝ์ค 3์ฃผ์ฐจ ๋ฏธ์
์์ ์ฌ์ฉํ ์ฝ๋๋ฅผ ์ฐธ๊ณ ํด๋ ๋ฌด๊ดํ๋ค.
+### UI
+- [x] index.html ์์ฑ
+- [x] '๊ธธ์ฐพ๊ธฐ'๋ฒํผ ๋๋ ์ ๋ ๊ฒฐ๊ณผ์ฐฝ visible
+- [x] ์ต๋จ๊ฑฐ๋ฆฌ, ์ต์์๊ฐ ๋ผ๋์ค๋ฒํผ
+- [x] ๊ฒฐ๊ณผ์ฐฝ ๊ตฌ์ฑ
+
+### ๊ธฐ๋ฅ
+- [x] ์ต๋จ๊ฑฐ๋ฆฌ ๊ตฌํ๊ธฐ
+- [x] ์ต์์๊ฐ ๊ตฌํ๊ธฐ
+ - [x] ๋ฐ์ดํฐ๋ฅผ import๋ก ๋ถ๋ฌ์์ ์ ๋ถ edge์ ์ถ๊ฐํ๋ค.
+ - [x] ๋ค์ต์คํธ๋ผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด์ฉํด **type์ ๋ฐ๋ผ** ์ต๋จ๊ฑฐ๋ฆฌ๋ฅผ ๋ฆฌํด
+- [x] ํ๋ก๊ทธ๋จ ์์ ์ App๊ฐ์ฒด ์์ฑ
+ - [x] ์์ฑํ ๋ data.js ๋ฅผ ๊ฐ์ฒด์ ์์ฑ์ผ๋ก ์ง์
+ - [x] '๊ธธ์ฐพ๊ธฐ' ๋ฒํผ ๋๋ฅผ ๋๋ง๋ค ๊ฒฝ๋ก๋ฅผ ๊ฐ์ฒด์ ์์ฑ์ผ๋ก ์ง์
+
+------------
+
+### ๊ฒฝ๋ก ์กฐํ ๊ธฐ๋ฅ
+
+
+- [x]]์ถ๋ฐ์ญ๊ณผ ๋์ฐฉ์ญ์ ์
๋ ฅ๋ฐ์ ๊ฒฝ๋ก๋ฅผ ์กฐํํ๋ค.
+- [x]๊ฒฝ๋ก ์กฐํ ์ ์ด ๊ฑฐ๋ฆฌ, ์ด ์์ ์๊ฐ์ ํจ๊ป ์ถ๋ ฅํ๋ค.
+- [x]๊ฒฝ๋ก ์กฐํ ์ `์ต๋จ ๊ฑฐ๋ฆฌ` ๋๋ `์ต์ ์๊ฐ` ์ต์
์ ์ ํํ ์ ์๋ค.
+
+### ์์ธ ์ฒ๋ฆฌ
+- [x]์ถ๋ฐ์ญ๊ณผ ๋์ฐฉ์ญ์ 2๊ธ์ ์ด์์ด์ด์ผ ํ๋ค. - '์ด๋ฆ๊ด๋ จ'
+- [x]์กด์ฌํ์ง ์๋ ์ญ์ ์ถ๋ฐ์ญ ๋๋ ๋์ฐฉ์ญ์ผ๋ก ์
๋ ฅํ ์ ์๋ค. - '์ด๋ฆ๊ด๋ จ'
+- [x]๊ฒฝ๋ก ์กฐํ ์ ์ถ๋ฐ์ญ๊ณผ ๋์ฐฉ์ญ์ด ๊ฐ์ ์ ์๋ค. - '๋ ์ญ ๊ด๋ จ'
+- [x]๊ฒฝ๋ก ์กฐํ ์ ์ถ๋ฐ์ญ๊ณผ ๋์ฐฉ์ญ์ด ์ฐ๊ฒฐ๋์ง ์์ผ๋ฉด ๊ฒฝ๋ก๋ฅผ ์กฐํํ ์ ์๋ค. - '๋ ์ญ ๊ด๋ จ'
+- [x]๊ทธ ์ธ ์ ์์ ์ผ๋ก ํ๋ก๊ทธ๋จ์ด ์ํ๋์ง ์์ ๊ฒฝ์ฐ `alert`์ผ๋ก ์๋ฌ๋ฅผ ์ถ๋ ฅํ๋ค.
+
+### ์ด๊ธฐ ์ค์
+- [x]ํ๋ก๊ทธ๋จ ์์ ์ ์ญ, ๋
ธ์ , ๊ตฌ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์ด๊ธฐ ์ค์ ํด์ผ ํ๋ค.
+- [x]๊ฑฐ๋ฆฌ์ ์์ ์๊ฐ์ ์์ ์ ์์ด๋ฉฐ ๋จ์๋ km์ ๋ถ์ ์๋ฏธํ๋ค.
+- [x]์๋์ ์ฌ์ ๋ฑ๋ก ์ ๋ณด๋ก ๋ฐ๋์ ์ด๊ธฐ ์ค์ ์ ํ๋ค.
+
+```
+1. ์งํ์ฒ ์ญ์ผ๋ก ๊ต๋, ๊ฐ๋จ, ์ญ์ผ, ๋จ๋ถํฐ๋ฏธ๋, ์์ฌ, ์์ฌ์๋ฏผ์์ฒ, ๋งค๋ด ์ญ ์ ๋ณด๊ฐ ๋ฑ๋ก๋์ด ์๋ค.
+2. ์งํ์ฒ ๋
ธ์ ์ผ๋ก 2ํธ์ , 3ํธ์ , ์ ๋ถ๋น์ ์ด ๋ฑ๋ก๋์ด ์๋ค.
+3. ๋
ธ์ ์ ์ญ์ด ์๋์ ๊ฐ์ด ๋ฑ๋ก๋์ด ์๋ค.(์ผ์ชฝ ๋์ด ์ํ ์ข
์ )
+ - 2ํธ์ : ๊ต๋ - ( 2km / 3๋ถ ) - ๊ฐ๋จ - ( 2km / 3๋ถ ) - ์ญ์ผ
+ - 3ํธ์ : ๊ต๋ - ( 3km / 2๋ถ ) - ๋จ๋ถํฐ๋ฏธ๋ - ( 6km / 5๋ถ ) - ์์ฌ - ( 1km / 1๋ถ ) - ๋งค๋ด
+ - ์ ๋ถ๋น์ : ๊ฐ๋จ - ( 2km / 8๋ถ ) - ์์ฌ - ( 10km / 3๋ถ ) - ์์ฌ์๋ฏผ์์ฒ
+```
+
+
+
+## โ
ํ๋ก๊ทธ๋๋ฐ ์๊ตฌ์ฌํญ
+### ๊ธธ์ฐพ๊ธฐ ๊ด๋ จ ๊ธฐ๋ฅ
+- [x]์ถ๋ฐ์ญ์ ์
๋ ฅํ๋ input ํ๊ทธ๋ `departure-station-name-input` id ์์ฑ๊ฐ์ ๊ฐ์ง๋ค.
+- [x]๋์ฐฉ์ญ์ ์
๋ ฅํ๋ input ํ๊ทธ๋ `arrival-station-name-input` id ์์ฑ๊ฐ์ ๊ฐ์ง๋ค.
+- [x]์ต๋จ๊ฑฐ๋ฆฌ, ์ต์์๊ฐ์ ์ ํํ๋ radio๋ `search-type` name ์์ฑ๊ฐ์ ๊ฐ์ง๋ค.
+ - **radio option์ default ๊ฐ์ ์ต๋จ๊ฑฐ๋ฆฌ์ด๋ค.**
+- [x]๊ธธ์ฐพ๊ธฐ ๋ฒํผ์ `search-button` id ์์ฑ๊ฐ์ ๊ฐ์ง๋ค.
+- [x]๐ ๊ฒฐ๊ณผ๋ `table`์ ์ด์ฉํ์ฌ ๋ณด์ฌ์ค๋ค.
+
+## โ๏ธํํธ
+## ๋ฐ์ดํฐ ์ด๊ธฐํ
+- [x] ์ด๊ธฐํ ๋ฐ์ดํฐ DB ๋ง๋ค์ด์ ์ฐ๊ฒฐ
+
+## ์ต๋จ ๊ฒฝ๋ก ๋ผ์ด๋ธ๋ฌ๋ฆฌ
+- [x] dijkstra ์ฌ์ฉํ์ฌ ๊ตฌํ
+
+#### ํ
์คํธ์ค๋ช
+
+
+- ์ญ ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ์ง ์๋ ๊ฒฝ์ฐ V1->V3 ๊ฒฝ๋ก๊ฐ ์ต๋จ ๊ฒฝ๋ก
+- ์ญ ์ฌ์ด์ ๊ฑฐ๋ฆฌ๋ฅผ ๊ณ ๋ คํ ๊ฒฝ์ฐ V1->V3 ๊ฒฝ๋ก์ ๊ฑฐ๋ฆฌ๋ 100km, V1->V2->V3 ๊ฒฝ๋ก์ ๊ฑฐ๋ฆฌ๋ 4km์ด๋ฏ๋ก ์ต๋จ ๊ฒฝ๋ก๋ V1->V2->V3
+
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..b8bf847
--- /dev/null
+++ b/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+ ์งํ์ฒ ๊ธธ์ฐพ๊ธฐ
+
+
+
+
+
๐์งํ์ฒ ๊ธธ์ฐพ๊ธฐ
+ ์ถ๋ฐ์ญ
+ ๋์ฐฉ์ญ
+
์ต๋จ๊ฑฐ๋ฆฌ
+
์ต์์๊ฐ
+
+
+
๊ฒฐ๊ณผ
+
+
+
+ | ์ด ๊ฑฐ๋ฆฌ |
+ ์ด ์์ ์๊ฐ |
+
+
+ |
+ |
+
+
+ |
+
+
+
+
+
+
diff --git a/src/constants.js b/src/constants.js
new file mode 100644
index 0000000..1e53feb
--- /dev/null
+++ b/src/constants.js
@@ -0,0 +1,22 @@
+export const SEARCH = {
+ BUTTON: document.getElementById('search-button'),
+ TYPE: document.getElementsByName('search-type'),
+};
+
+export const INPUT = {
+ DEPARTURE: document.getElementById('departure-station-name-input'),
+ ARRIVAL: document.getElementById('arrival-station-name-input'),
+};
+
+export const SEARCH_TYPE = {
+ PATH: '์ต๋จ๊ฑฐ๋ฆฌ',
+ TIME: '์ต์์๊ฐ',
+};
+
+export const RESULT = {
+ DISPLAY: document.getElementById('result'),
+ TYPE: document.getElementById('result-type'),
+ DISTANCE: document.getElementById('total-distance'),
+ TIME: document.getElementById('total-time'),
+ PATH: document.getElementById('result-path'),
+};
diff --git a/src/createMessages.js b/src/createMessages.js
new file mode 100644
index 0000000..b592eca
--- /dev/null
+++ b/src/createMessages.js
@@ -0,0 +1,11 @@
+export function createResultPathMessage(pathArray) {
+ return pathArray.join('->');
+}
+
+export function createDistanceMessage(distance) {
+ return `${distance}km`;
+}
+
+export function createTimeMessage(time) {
+ return `${time}๋ถ`;
+}
diff --git a/src/data.js b/src/data.js
new file mode 100644
index 0000000..7204bbe
--- /dev/null
+++ b/src/data.js
@@ -0,0 +1,34 @@
+export const lines = [
+ {
+ name: '2ํธ์ ',
+ stations: [
+ '๊ต๋',
+ {distance: 2, time: 3},
+ '๊ฐ๋จ',
+ {distance: 2, time: 3},
+ '์ญ์ผ',
+ ],
+ },
+ {
+ name: '3ํธ์ ',
+ stations: [
+ '๊ต๋',
+ {distance: 3, time: 2},
+ '๋จ๋ถํฐ๋ฏธ๋',
+ {distance: 6, time: 5},
+ '์์ฌ',
+ {distance: 1, time: 1},
+ '๋งค๋ด',
+ ],
+ },
+ {
+ name: '์ ๋ถ๋น์ ',
+ stations: [
+ '๊ฐ๋จ',
+ {distance: 2, time: 8},
+ '์์ฌ',
+ {distance: 10, time: 3},
+ '์์ฌ์๋ฏผ์์ฒ',
+ ],
+ },
+];
diff --git a/src/display.js b/src/display.js
new file mode 100644
index 0000000..f52fbcd
--- /dev/null
+++ b/src/display.js
@@ -0,0 +1,27 @@
+import {RESULT} from './constants.js';
+
+export function appendDistanceToTable(distance) {
+ RESULT.DISTANCE.innerText = distance;
+}
+
+export function appendTimeToTable(time) {
+ RESULT.TIME.innerText = time;
+}
+
+export function appendPathToTable(path) {
+ RESULT.PATH.innerText = path;
+}
+
+export function changeTypeTitle(type) {
+ if (type==='distance') {
+ RESULT.TYPE.innerText = '์ต๋จ๊ฑฐ๋ฆฌ';
+ }
+ if (type==='time') {
+ RESULT.TYPE.innerText = '์ต์์๊ฐ';
+ }
+}
+
+export function display(object) {
+ changeTypeTitle(object.type);
+ RESULT.DISPLAY.style.display = 'block';
+}
diff --git a/src/getMinimum.js b/src/getMinimum.js
new file mode 100644
index 0000000..9cd4aba
--- /dev/null
+++ b/src/getMinimum.js
@@ -0,0 +1,17 @@
+import Dijkstra from './utils/Dijkstra.js';
+
+export function minPath(data, departure, arrival, type) {
+ const dijkstra = new Dijkstra();
+ importDataToDijkstra(data, dijkstra, type);
+
+ const result = dijkstra.findShortestPath(departure, arrival);
+ return result;
+}
+function importDataToDijkstra(data, dijkstra, type) {
+ for (let i=0; i {
+ display(this);
+ this.type = changeType();
+ isValid(this);
+ this.path = minPath(this.data, INPUT.DEPARTURE.value, INPUT.ARRIVAL.value, this.type.value,);
+ if (!areStationsLinked(this.path)) {
+ window.alert('์ฐ๊ฒฐ๋ ์ญ์ ์
๋ ฅํด์ฃผ์ธ์!');
+ return;
+ }
+ appendDistanceToTable(createDistanceMessage(totalBetweenStations(this.data, this.path, 'distance')));
+ appendTimeToTable(createTimeMessage(totalBetweenStations(this.data, this.path, 'time')));
+ appendPathToTable(createResultPathMessage(this.path));
+ });
+}
+
+function changeType() {
+ let type;
+ if (SEARCH.TYPE[0].checked == true) {
+ type = SEARCH.TYPE[0];
+ }
+ if (SEARCH.TYPE[1].checked == true) {
+ type = SEARCH.TYPE[1];
+ }
+ return type;
+}
+
+function isValid(object) {
+ if (isNameShort(INPUT.DEPARTURE.value) || isNameShort(INPUT.ARRIVAL.value)) {
+ window.alert('์ญ ์ด๋ฆ์ 2๊ธ์ ์ด์์ด์ด์ผ ํฉ๋๋ค!');
+ return;
+ } else if (!isStationAvaliable(INPUT.DEPARTURE.value, object.data) || !isStationAvaliable(INPUT.DEPARTURE.value, object.data)) {
+ window.alert('์กด์ฌํ์ง ์๋ ์ญ์
๋๋ค!');
+ return;
+ } else if (!areStationsDifferent(INPUT.DEPARTURE.value, INPUT.ARRIVAL.value)) {
+ window.alert('์๋ก ๋ค๋ฅธ ์ญ์ ์
๋ ฅํด์ฃผ์ธ์!');
+ return;
+ }
+}
+
+new App();
diff --git a/src/inputValid.js b/src/inputValid.js
new file mode 100644
index 0000000..13582dd
--- /dev/null
+++ b/src/inputValid.js
@@ -0,0 +1,22 @@
+export function isNameShort(name) {
+ return (name.length<2);
+}
+
+export function isStationAvaliable(name, data) {
+ let result = false;
+ for (let i=0; i 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();
+}