├── .eslintrc
├── .flowconfig
├── .gitignore
├── .prettierrc
├── LICENSE.md
├── README.md
├── flow-typed
└── types.js
├── images
├── flow.jpg
├── react.svg
├── sass.png
└── visualizer.gif
├── jsconfig.json
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── src
├── App.js
├── App.scss
├── Provider.jsx
├── algorithms
│ ├── AStar.js
│ ├── Timer.js
│ ├── bellmanFord.js
│ ├── bfs.js
│ ├── dfs.js
│ ├── dijkstra.js
│ ├── index.js
│ └── pathFinder.js
├── components
│ ├── Board
│ │ ├── Board.jsx
│ │ └── Board.scss
│ ├── Container
│ │ ├── Container.jsx
│ │ └── Container.scss
│ ├── Header
│ │ ├── Header.jsx
│ │ └── Header.scss
│ ├── Item
│ │ ├── Item.jsx
│ │ └── Item.scss
│ ├── ModalError
│ │ ├── ModalError.jsx
│ │ └── ModalError.scss
│ └── ModalInfo
│ │ ├── ModalInfo.jsx
│ │ └── ModalInfo.scss
├── constants.js
├── index.js
└── styles
│ ├── _mixins.scss
│ ├── _placeholders.scss
│ └── _variables.scss
└── yarn.lock
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "extends": ["airbnb", "plugin:prettier/recommended", "plugin:flowtype/recommended"],
4 | "plugins": ["flowtype"],
5 | "rules": {
6 | "prettier/prettier": "error",
7 | "no-unused-vars": "warn",
8 | "no-console": "off",
9 | "func-names": "off",
10 | "no-process-exit": "off",
11 | "object-shorthand": "off",
12 | "class-methods-use-this": "off",
13 | "no-plusplus": "off",
14 | "jsx-a11y/click-events-have-key-events": "off",
15 | "no-continue": "off",
16 | "no-underscore-dangle": "off",
17 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
18 | },
19 | "env": {
20 | "browser": true
21 | },
22 | "settings": {
23 | "import/resolver": {
24 | "node": {
25 | "paths": ["src"],
26 | "extensions": [".js", ".jsx", ".scss"]
27 | }
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/.flowconfig:
--------------------------------------------------------------------------------
1 | [ignore]
2 |
3 | [include]
4 |
5 | [libs]
6 | ./flow-typed/
7 |
8 | [lints]
9 |
10 | [options]
11 | module.system.node.resolve_dirname=node_modules
12 | module.system.node.resolve_dirname=src
13 | ; Extensions
14 | module.file_ext=.js
15 | module.file_ext=.jsx
16 | module.file_ext=.json
17 | module.file_ext=.css
18 | module.file_ext=.scss
19 |
20 | [strict]
21 |
22 | [version]
23 | ^0.117.0
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "semi": true,
4 | "useTabs": false,
5 | "tabWidth": 2,
6 | "trailingComma": "all",
7 | "printWidth": 80
8 | }
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 baeharam
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Pathfinding Visualizer
2 |
3 | ### [LIVE DEMO](https://baeharam.github.io/Pathfinding-Visualizer/)
4 |
5 |
6 |
7 |
8 |
9 | ## Algorithms
10 |
11 | * Dijkstra
12 | * Bellman-Ford
13 | * DFS
14 | * 0-1 BFS
15 | * A* with manhatten distance heuristic
16 |
17 |
18 |
19 | ## Technical Stack
20 |
21 | | UI Library | Styling | Typing |
22 | | :-------------------------------------------: | :------------------------------------------: | :------------------------------------------: |
23 | |
|
|
|
24 |
25 |
26 |
27 | ## Build Guide
28 |
29 | ```bash
30 | git clone https://github.com/baeharam/Pathfinding-Visualizer
31 | cd Pathfinding-Visualizer
32 | yarn install
33 | yarn start
34 | ```
35 |
36 |
37 |
38 | ## LICENSE
39 |
40 | [MIT]('./LICENSE.md')
--------------------------------------------------------------------------------
/flow-typed/types.js:
--------------------------------------------------------------------------------
1 | declare type ElementEvent = {
2 | target: E,
3 | } & Event;
4 |
--------------------------------------------------------------------------------
/images/flow.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baeharam/Pathfinding-Visualizer/925b588902381054ee3a9a908d34831cc41cf068/images/flow.jpg
--------------------------------------------------------------------------------
/images/react.svg:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/images/sass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baeharam/Pathfinding-Visualizer/925b588902381054ee3a9a908d34831cc41cf068/images/sass.png
--------------------------------------------------------------------------------
/images/visualizer.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baeharam/Pathfinding-Visualizer/925b588902381054ee3a9a908d34831cc41cf068/images/visualizer.gif
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "src"
4 | },
5 | "include": ["src"]
6 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pathfinding-visualizer",
3 | "homepage": "http://baeharam.github.io/Pathfinding-Visualizer",
4 | "version": "0.1.0",
5 | "license": "MIT",
6 | "private": true,
7 | "dependencies": {
8 | "@testing-library/jest-dom": "^4.2.4",
9 | "@testing-library/react": "^9.3.2",
10 | "@testing-library/user-event": "^7.1.2",
11 | "flow-bin": "^0.117.0",
12 | "js-priority-queue": "^0.1.5",
13 | "node-sass": "^4.13.1",
14 | "open-color": "^1.7.0",
15 | "queue-fifo": "^0.2.6",
16 | "react": "^16.12.0",
17 | "react-dom": "^16.12.0",
18 | "react-helmet": "5.2.1",
19 | "react-icons": "^3.9.0",
20 | "react-modal": "^3.11.1",
21 | "react-scripts": "3.3.0",
22 | "reset-css": "^5.0.1",
23 | "uuid": "^3.4.0"
24 | },
25 | "scripts": {
26 | "start": "react-scripts start",
27 | "build": "react-scripts build",
28 | "test": "react-scripts test",
29 | "eject": "react-scripts eject",
30 | "flow": "flow",
31 | "predeploy": "yarn build",
32 | "deploy": "gh-pages -d build"
33 | },
34 | "eslintConfig": {
35 | "extends": "react-app"
36 | },
37 | "browserslist": {
38 | "production": [
39 | ">0.2%",
40 | "not dead",
41 | "not op_mini all"
42 | ],
43 | "development": [
44 | "last 1 chrome version",
45 | "last 1 firefox version",
46 | "last 1 safari version"
47 | ]
48 | },
49 | "devDependencies": {
50 | "babel-eslint": "^10.0.3",
51 | "eslint": "^6.8.0",
52 | "eslint-config-airbnb": "^18.0.1",
53 | "eslint-config-prettier": "^6.10.0",
54 | "eslint-plugin-flowtype": "^4.6.0",
55 | "eslint-plugin-import": "^2.20.0",
56 | "eslint-plugin-jsx-a11y": "^6.2.3",
57 | "eslint-plugin-prettier": "^3.1.2",
58 | "eslint-plugin-react": "^7.18.0",
59 | "gh-pages": "^2.2.0",
60 | "prettier": "^1.19.1",
61 | "serialize-javascript": "^2.1.2"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baeharam/Pathfinding-Visualizer/925b588902381054ee3a9a908d34831cc41cf068/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baeharam/Pathfinding-Visualizer/925b588902381054ee3a9a908d34831cc41cf068/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/baeharam/Pathfinding-Visualizer/925b588902381054ee3a9a908d34831cc41cf068/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Provider } from 'Provider';
3 | import Container from 'components/Container/Container';
4 | import 'reset-css';
5 | import './App.scss';
6 |
7 | const App = () => {
8 | return (
9 |
10 |
11 |
12 | );
13 | };
14 |
15 | export default App;
16 |
--------------------------------------------------------------------------------
/src/App.scss:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Julius+Sans+One&display=swap');
2 |
3 | body,html {
4 | height: 100%;
5 | }
6 |
7 | body {
8 | font-family: 'Julius Sans One', sans-serif;
9 | user-select: none;
10 | -webkit-user-select: none;
11 | -moz-user-select: none;
12 | }
--------------------------------------------------------------------------------
/src/Provider.jsx:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import React, { createContext, useRef, useState, type Node } from 'react';
4 | import Timer from 'algorithms/Timer';
5 | import {
6 | BOARD,
7 | KEYS,
8 | DELAY_NORMAL,
9 | ITEM_INITIAL,
10 | ITEM_FIXED,
11 | ITEM_CLICKED,
12 | BOARD_ROW,
13 | BOARD_COL,
14 | } from './constants';
15 |
16 | type PositionType = {| x: number, y: number |};
17 | type SetItemCacheType = { [key: string]: (string) => void };
18 |
19 | export type ContextType = {|
20 | isPathExist: boolean,
21 | isVisualized: boolean,
22 | isHelped: boolean,
23 |
24 | begin: { current: PositionType },
25 | end: { current: PositionType },
26 | board: { current: Array> },
27 | setItemCache: { current: SetItemCacheType },
28 | pathFinder: { current: any },
29 | delay: { current: number },
30 |
31 | clear: void => void,
32 | clearPath: void => void,
33 | updateItem: (number, number, string, number) => void,
34 |
35 | setIsPathExist: boolean => void,
36 | setIsVisualized: boolean => void,
37 | setIsHelped: boolean => void,
38 | |};
39 |
40 | const Context = createContext();
41 |
42 | const Provider = ({ children }: Node) => {
43 | const [isPathExist, setIsPathExist] = useState(true);
44 | const [isVisualized, setIsVisualized] = useState(false);
45 | const [isHelped, setIsHelped] = useState(false);
46 |
47 | const begin = useRef({ x: Math.round(BOARD_ROW / 2), y: 2 });
48 | const end = useRef({
49 | x: Math.round(BOARD_ROW / 2),
50 | y: BOARD_COL - 3,
51 | });
52 | const board = useRef>>(JSON.parse(JSON.stringify(BOARD)));
53 | const setItemCache = useRef({});
54 | const pathFinder = useRef(null);
55 | const delay = useRef(DELAY_NORMAL);
56 |
57 | const updateItem = (
58 | ridx,
59 | cidx,
60 | type: string = ITEM_FIXED,
61 | timeFactor: number = 0,
62 | ) => {
63 | board.current[ridx][cidx] = type;
64 | const setItem = setItemCache.current[KEYS[ridx][cidx]];
65 |
66 | if (timeFactor) {
67 | const timer = new Timer({
68 | callback: () => setItem(type),
69 | delay: timeFactor * delay.current,
70 | });
71 | pathFinder.current.timers.push(timer);
72 | } else {
73 | setItem(type);
74 | }
75 | };
76 |
77 | const clear = () => {
78 | if (!isPathExist) setIsPathExist(true);
79 | if (isVisualized) setIsVisualized(false);
80 | const currentBoard = board.current;
81 | currentBoard.forEach((row, ridx) => {
82 | row.forEach((item, cidx) => {
83 | updateItem(ridx, cidx, ITEM_INITIAL);
84 | });
85 | });
86 | };
87 |
88 | const clearPath = () => {
89 | board.current.forEach((row, ridx) => {
90 | row.forEach((item, cidx) => {
91 | if (board.current[ridx][cidx] !== ITEM_CLICKED) {
92 | updateItem(ridx, cidx, ITEM_INITIAL);
93 | }
94 | });
95 | });
96 | };
97 |
98 | return (
99 |
123 | {children}
124 |
125 | );
126 | };
127 |
128 | export { Context, Provider };
129 |
--------------------------------------------------------------------------------
/src/algorithms/AStar.js:
--------------------------------------------------------------------------------
1 | // @flow
2 |
3 | import PriorityQueue from 'js-priority-queue';
4 | import { BOARD_ROW, BOARD_COL, ITEM_CLICKED, ITEM_VISITED } from 'constants.js';
5 | import PathFinder, { type ConstructorType } from './pathFinder';
6 |
7 | export default class AStar extends PathFinder {
8 | opened: Array>;
9 |
10 | constructor(args: ConstructorType) {
11 | super(args);
12 | this.opened = new Array(BOARD_ROW);
13 | for (let i = 0; i < BOARD_ROW; i++) {
14 | this.opened[i] = new Array(BOARD_COL).fill(false);
15 | }
16 | this.pq = new PriorityQueue
49 |
50 |
51 |
1. You can make wall by clicking any block
52 |
53 |
54 |
2. You can move
55 |
56 | by dragging
57 |
58 |
59 |
3. You can choose algorithm and speed from select box
60 |
61 |
62 |
65 |
66 | );
67 | };
68 |
69 | export default ModalInfo;
70 |
--------------------------------------------------------------------------------
/src/components/ModalInfo/ModalInfo.scss:
--------------------------------------------------------------------------------
1 | @import 'open-color/open-color';
2 | @import 'styles/_mixins';
3 | @import 'styles/_placeholders';
4 | @import 'styles/_variables';
5 |
6 | .modal-info {
7 | $self: &;
8 | @include modal($oc-indigo-7);
9 | width: 700px;
10 | height: 350px;
11 | padding: 20px;
12 | align-items: center;
13 |
14 | &__title {
15 | @include modal-title($oc-indigo-7);
16 | }
17 |
18 | &__color {
19 | margin-bottom: 20px;
20 | }
21 |
22 | &__usage {
23 | #{$self}__row {
24 | margin-bottom: 20px;
25 | }
26 |
27 | #{$self}__square {
28 | margin-right: 10px;
29 | }
30 |
31 | h2 {
32 | margin-right: 10px;
33 | font-size: 20px;
34 | }
35 | }
36 |
37 | &__row {
38 | display: flex;
39 | align-items: center;
40 | }
41 |
42 | &__content {
43 | @extend %modal-content;
44 | width: 150px;
45 | display: flex;
46 | flex-direction: row;
47 | align-items: center;
48 | margin-bottom: 20px;
49 | }
50 |
51 | &__square {
52 | display: block;
53 | width: 24px;
54 | height: 24px;
55 | margin-right: 20px;
56 |
57 | &--initial {
58 | @extend #{$self}__square;
59 | background-color: $initial-color;
60 | }
61 |
62 | &--visited {
63 | @extend #{$self}__square;
64 | background-color: $visited-color;
65 | }
66 |
67 | &--clicked {
68 | @extend #{$self}__square;
69 | background-color: $clicked-color;
70 | }
71 |
72 | &--fixed {
73 | @extend #{$self}__square;
74 | background-color: $fixed-color;
75 | }
76 |
77 | &--shortest {
78 | @extend #{$self}__square;
79 | background-color: $shortest-color;
80 | }
81 | }
82 |
83 | &__close {
84 | @include modal-close($oc-indigo-7);
85 | }
86 | }
--------------------------------------------------------------------------------
/src/constants.js:
--------------------------------------------------------------------------------
1 | import uuidv4 from 'uuid/v4';
2 | import Styles from 'styles/_variables.scss';
3 |
4 | // Board Size
5 | export const BOARD_ROW = Number(Styles.boardRow);
6 | export const BOARD_COL = Number(Styles.boardCol);
7 |
8 | // Color
9 | export const INITIAL_COLOR = Styles.initialColor;
10 | export const VISITED_COLOR = Styles.visitedColor;
11 | export const CLICKED_COLOR = Styles.clickedColor;
12 | export const FIXED_COLOR = Styles.fixedColor;
13 | export const SHORTEST_COLOR = Styles.shortestColor;
14 | export const COLOR_TYPES = [
15 | 'initial',
16 | 'visited',
17 | 'clicked',
18 | 'fixed',
19 | 'shortest',
20 | ];
21 |
22 | // algorithm
23 | export const DIJKSTRA = 'dijkstra';
24 | export const BELLMAN_FORD = 'bellman-ford';
25 | export const A_STAR = 'A-star';
26 | export const DFS = 'DFS';
27 | export const BFS = 'BFS';
28 |
29 | // uuid
30 | export const KEYS = [];
31 | for (let i = 0; i < BOARD_ROW; i++) {
32 | KEYS[i] = [];
33 | for (let j = 0; j < BOARD_COL; j++) {
34 | KEYS[i][j] = uuidv4();
35 | }
36 | }
37 |
38 | // Item state
39 | export const ITEM_FIXED = 'ITEM_FIXED';
40 | export const ITEM_INITIAL = 'ITEM_INITIAL';
41 | export const ITEM_VISITED = 'ITEM_VISITED';
42 | export const ITEM_CLICKED = 'ITEM_CLICKED';
43 | export const ITEM_SHORTEST = 'ITEM_SHORTEST';
44 |
45 | // Delay
46 | export const DELAY_SLOWEST = 550;
47 | export const DELAY_SLOW = 450;
48 | export const DELAY_NORMAL = 300;
49 | export const DELAY_FAST = 150;
50 | export const DELAY_FASTEST = 50;
51 |
52 | // Board
53 | export const BOARD = [];
54 | for (let i = 0; i < BOARD_ROW; i++) {
55 | BOARD[i] = [];
56 | for (let j = 0; j < BOARD_COL; j++) {
57 | BOARD[i][j] = {
58 | color: INITIAL_COLOR,
59 | visit: false,
60 | };
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(, document.getElementById('root'));
6 |
--------------------------------------------------------------------------------
/src/styles/_mixins.scss:
--------------------------------------------------------------------------------
1 | @mixin modal($color) {
2 | position: absolute;
3 | top: 50%;
4 | left: 50%;
5 | transform: translate(-50%, -50%);
6 | width: 400px;
7 | height: 200px;
8 | background-color: white;
9 | border-radius: 5px;
10 | outline: none;
11 | box-shadow: 0 3px 0 0 rgba(0,0,0,0.4);
12 | text-align: center;
13 | display: flex;
14 | flex-direction: column;
15 | justify-content: center;
16 | font-weight: bold;
17 | border-top: 7px solid $color;
18 | }
19 |
20 | @mixin modal-title($color) {
21 | font-family: inherit;
22 | font-size: 36px;
23 | margin-bottom: 20px;
24 | color: $color;
25 | }
26 |
27 | @mixin modal-close($color) {
28 | position: absolute;
29 | right: 10px;
30 | top: 10px;
31 | border-radius: 50%;
32 | width: 25px;
33 | height: 25px;
34 | border: none;
35 | background-color: $color;
36 | color: white;
37 | cursor: pointer;
38 | transition: opacity 0.3s linear;
39 | opacity: 0.5;
40 | outline: none;
41 |
42 | &:hover {
43 | opacity: 1;
44 | }
45 | }
--------------------------------------------------------------------------------
/src/styles/_placeholders.scss:
--------------------------------------------------------------------------------
1 | %modal-content {
2 | font-size: 20px;
3 | }
4 |
5 | %disabled {
6 | background-color: $oc-gray-5;
7 | box-shadow: none;
8 | }
--------------------------------------------------------------------------------
/src/styles/_variables.scss:
--------------------------------------------------------------------------------
1 | $visited-color: #75e1ff;
2 | $shortest-color: #cf2541;
3 | $fixed-color: #000000;
4 | $clicked-color: #fcba03;
5 | $initial-color: #a1a6a3;
6 |
7 | $header-height: 10vh;
8 | $content-header-height: 9vh;
9 | $footer-height: 10vh;
10 | $board-height: calc(100vh - (#{$header-height} + #{$content-header-height} + #{$footer-height}));
11 |
12 | $board-row: 16;
13 | $board-col: 30;
14 |
15 | $border-item-size: calc(calc(#{$board-height} / #{$board-row}) - 5px);
16 |
17 | :export {
18 | visitedColor: $visited-color;
19 | shortestColor: $shortest-color;
20 | fixedColor: $fixed-color;
21 | clickedColor: $clicked-color;
22 | initialColor: $initial-color;
23 |
24 | boardRow: $board-row;
25 | boardCol: $board-col;
26 | }
--------------------------------------------------------------------------------