ソースを参照

Add Pathfinder module to intro

tags/v0.1_first_draft
Dejvino 8ヶ月前
コミット
c4314e0c64
11個のファイルの変更1699行の追加2行の削除
  1. +53
    -0
      index.html
  2. +20
    -0
      module/pathfinder/README.md
  3. バイナリ
      module/pathfinder/animation.gif
  4. +109
    -0
      module/pathfinder/grid.css
  5. +74
    -0
      module/pathfinder/index.html
  6. +195
    -0
      module/pathfinder/main.css
  7. +1027
    -0
      module/pathfinder/main.js
  8. +1
    -0
      module/pathfinder/neural.svg
  9. +89
    -0
      module/pathfinder/select.js
  10. +15
    -0
      module/pathfinder/typo.css
  11. +116
    -2
      slides/intro.md

+ 53
- 0
index.html ファイルの表示

@@ -10,6 +10,10 @@
<link rel="stylesheet" href="dist/reset.css">
<link rel="stylesheet" href="dist/reveal.css">
<link rel="stylesheet" href="dist/theme/night.css">
<link rel="stylesheet" href="module/pathfinder/typo.css">
<link rel="stylesheet" href="module/pathfinder/main.css">
<link rel="stylesheet" href="module/pathfinder/grid.css">

<!-- Theme used for syntax highlighted code -->
<link rel="stylesheet" href="plugin/highlight/monokai.css">
@@ -34,6 +38,24 @@
color: #222;
text-shadow: 0px 0px 5px green, 0px 0px 2px white, 2px 2px 1px white;
}
.reveal .hidden {
display: none
}
.reveal .pathfinder-rerun {
z-index: 1000;
position: fixed;
bottom: 10px;
left: 11px;
background-color: rgba(200, 200, 200, 0.3);
border-radius: 10px;
padding: 10px;
cursor: pointer;
}
.reveal .pathfinder-rerun.disabled {
background-color: rgba(139, 106, 106, 0.3);
color: rgba(39, 27, 27, 0.3);
cursor: not-allowed;
}
</style>
</head>

@@ -108,6 +130,37 @@
plugins: [RevealMarkdown, RevealHighlight, RevealNotes]
});
</script>
<script src="module/pathfinder/main.js" async></script>
<script src="module/pathfinder/select.js" async></script>
<script>
const pathfinders = {}
Reveal.on( 'slidetransitionend', event => {
const slide = event.currentSlide
const slideId = event.indexh + ';' + event.indexv
if (slide && slide.classList.contains("pathfinder-page") && !(slideId in pathfinders)) {
pathfinders[slideId] = startPathfinder(slide)
}
});
async function startPathfinder(slide) {
const p = spawnPathfinder(slide)
const rerun = slide.getElementsByClassName("pathfinder-rerun")[0]
if (rerun) {
rerun.onclick = async () => {
if (!rerun.classList.contains("disabled")) {
rerun.classList.add("disabled");
await p.RunMaze()
await p.Run();
rerun.classList.remove("disabled");
}
}
}
await p.RunMaze()
Reveal.layout()
rerun.classList.add("disabled");
await p.Run()
rerun.classList.remove("disabled");
}
</script>
</body>

</html>

+ 20
- 0
module/pathfinder/README.md ファイルの表示

@@ -0,0 +1,20 @@
<p align="center"><img align="center" src="./neural.svg" width=100 height=100>
<h1 align="center">Pathfinding visualizer</h1></p>


<p align="center">
<img alt="GitHub last commit" src="https://img.shields.io/github/last-commit/honzaap/GitHubCity?color=2411ed&style=flat-square">
</p>


![Gif of Pathfinding](https://honzaap.github.io/Pathfinding/animation.gif)

### Available algorithms:
* A*
* Djikstra's
* BFS
* DFS
* Greedy

### Installation
Just clone the repository and open index.html, no compilation is needed.

バイナリ
module/pathfinder/animation.gif ファイルの表示

変更前 変更後
幅: 1238  |  高さ: 710  |  サイズ: 915 KiB

+ 109
- 0
module/pathfinder/grid.css ファイルの表示

@@ -0,0 +1,109 @@
.main-grid-container{
height: 100%;
display: flex;
flex-flow: row nowrap;
justify-content: center;
align-items: center;
}
.grid-container{
display: inline-block;
}
.grid{
display: flex;
flex-flow: column nowrap;
justify-content: center;
align-items: center;
background: #1e1f29;
border: 2px solid var(--closed-path);
overflow: hidden;
}
.row{
display: flex;
flex-flow: row nowrap;
height: 31px;
}
.row.odd{
margin-left: 37px;
}
.cell{
margin: 0 1px 0 0;
width: 36px;
height: 40px;
overflow: visible;
position: relative;
}
.cell::after{
content: "";
display: block;
position: absolute;
background-color: transparent;
width: 40px;
height: 40px;
transition: background-color 0.15s linear;
clip-path: polygon(20px 0, 38px 10px, 38px 30px, 20px 40px, 2px 30px, 2px 10px);;
top: 0;
left: 0;
}
.cell::before{
content: "";
display: block;
position: absolute;
background-color: rgba(255, 255, 255, 0.03);
width: 40px;
height: 40px;
clip-path: polygon(20px 0, 38px 10px, 38px 30px, 20px 40px, 2px 30px, 2px 10px);;
top: 0px;
left: 0px;
}
/* Cell States */
.cell.start::after{
background-color: var(--start);
}
.cell.end::after{
background-color: var(--end);
}
.cell.null::after{
background-color: transparent;
}
.cell.null::before{
/*transform: scale(1.05);*/
}
.cell.open::after{
background-color: var(--open-path);
}
.cell.closed::after{
background-color: var(--closed-path);
}
.cell.path::after{
background-color: var(--path);
}
.cell.wall::after{
background: linear-gradient(var(--wall) 0px, var(--open-path) 1400px);
background-attachment: fixed;
}
.cell.wall::before{
background: linear-gradient(var(--wall) 0px, var(--open-path) 1400px);
background-attachment: fixed;
}
.cell.animate{
animation-name: cell-anim;
animation-duration: 0.4s;
}
@keyframes cell-anim {
0%{
transform: scale(1.0);
z-index: 2;
}
50%{
transform: scale(1.25);
}
100%{
transform: scale(1.0);
z-index: 1;
}
}

+ 74
- 0
module/pathfinder/index.html ファイルの表示

@@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" crossorigin="anonymous" />
<title>Pathfinding Visualizer</title>
<meta name="description" content="Pathfinding algorithms visualizer. Visualize algorithms like A*, Djikstra's and more!">
<meta name="keywords" content="pathfinding, visualization, a*, djikstra's algorithm, prim's algorithm">
<link rel="stylesheet" href="typo.css">
<link rel="stylesheet" href="main.css">
<link rel="stylesheet" href="grid.css">
<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>
<link rel="icon" href="neural.svg">
</head>
<body>
<div class="pathfinder-page">
<header>
<nav class="navbar" id="navbar">
<div class="navbar-item">
<div class="custom-select">
<select id="algo-select">
<option value="AStar">A* Algorithm</option>
<option value="Dijkstra">Dijkstra's Algorithm</option>
<option value="BFS">Breadth First Search</option>
<option value="DFS">Depth First Search</option>
<option value="Greedy">Greedy Algorithm</option>
</select>
</div>
</div>
<div class="navbar-item">
<div class="custom-select">
<select id="maze-algo-select">
<option value="DFS">Random DFS Maze</option>
<option value="Prim">Prim's Algorithm</option>
<option value="Random">Random Maze</option>
</select>
</div>
</div>
<div class="navbar-item">
<button class="general-button start-button" onclick="Run()">Visualize</button>
</div>
<div class="navbar-item">
<div class="speed-container slidecontainer">
<span class="range-caption">Speed</span>
<input type="range" class="slider" id="range-speed" min="0" max="200" value="200">
</div>
</div>
<div class="navbar-item">
<button class="general-button options-button" onclick="ResetPath();">Reset Path</button>
</div>
<div class="navbar-item">
<button class="general-button options-button" onclick="ClearWalls();">Remove Walls</button>
</div>
<div class="navbar-item">
<button class="general-button options-button" onclick="ClearGrid();">Clear Board</button>
</div>
</nav>
</header>
<div class="main-grid-container">
<div class="grid-container">
<div class="grid" id="grid">
</div>
</div>
</div>
</div>
<script src="main.js" async></script>
<script src="select.js" async></script>
</body>
</html>

+ 195
- 0
module/pathfinder/main.css ファイルの表示

@@ -0,0 +1,195 @@
*{
margin: 0;
padding: 0;
outline: none;
border: none;
text-decoration: none;
box-sizing: border-box;
}
:root{
--start: #9faf20;
--end: #207094;
--open-path: #885771;
--closed-path: #a6819b;
--path: #ff6be6;
--wall: #001834;
}
.pathfinder-page{
width: 100%;
height: 100%;
display: flex;
flex-flow:column nowrap;
justify-content: flex-start;
align-items: stretch;
}
.navbar{
width: 100%;
display: flex;
flex-flow: row wrap;
justify-content: center;
align-items: stretch;
font-size: 16px;
font-weight: bold;
padding: 15px 0;
}
.navbar-item{
text-align: center;
display: flex;
align-items: center;
margin: 0 10px;
}
.navbar-item-caption{
text-align: center;
background-color: var(--closed-path);
}
.general-button{
color: #fff;
font-weight: inherit;
font-size: inherit;
padding: 0.5em 1em;
background-color: transparent;
transition: background-color 0.3s linear, transform 0.15s ease-out;
}
.general-button:hover{
cursor: pointer;
}
.general-button:active{
transform: scale(1.1);
}
.options-button:hover{
color: var(--path);
}
.start-button{
background-color: var(--start);
border-radius: 50px;
color: #fff;
padding: 20px 40px;
}
.start-button:hover{
background-color: var(--end);
}
.speed-container{
margin-top: 0.2em;
padding: 0.2em 0.5em;
}
.range-caption{
font-size: 1em;
display: block;
text-align: center;
}
.custom-select {
position: relative;
font-size: 1em;
background-color: transparent;
height: 100%;
}
.custom-select:hover{
}
.custom-select select {
font-size: inherit;
}
.select-selected:after {
position: absolute;
content: "";
top: 40%;
right: 5px;
width: 0;
height: 0;
border: 6px solid transparent;
border-color: #fff transparent transparent transparent;
}
.select-selected.select-arrow-active:after {
border-color: transparent transparent #fff transparent;
top: 30%;
}
.select-items div,.select-selected {
padding: 0.5em 0 0.5em 0.3em;
border: none;
cursor: pointer;
}
/* Style items (options): */
.select-items {
position: absolute;
top: 100%;
left: 0;
right: 0;
z-index: 99;
text-align:left;
border-radius: 8px;
overflow: hidden;
width: 220px;
}
.select-items div{
background-color: var(--open-path);
transition: background-color 0.3s linear;
padding: 12px 20px;
}
/* Hide the items when the select box is closed: */
.select-hide {
display: none;
}
.select-items div:hover, .same-as-selected {
background-color: var(--closed-path);
}
.select-selected {
background-color: transparent;
border: none;
height: 100%;
padding: 1em 1em 1em 0.3em;
}
.slidecontainer {
width: 100%;
}
.slider {
-webkit-appearance: none;
overflow: hidden;
appearance: none;
width: 100%;
height: 18px;
margin-top: 5px;
outline: none;
border-radius: 15px;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
border-radius: 15px;
cursor: pointer;
background: var(--wall);
box-shadow: -85px 0 0 80px var(--path);
}
.slider::-moz-range-thumb {
width: 1em;
height: 1em;
background: #000;
cursor: pointer;
}
/** FF*/
input[type="range"]::-moz-range-progress {
background-color: var(--start);
}
input[type="range"]::-moz-range-track {
background-color: #fff;
}
/* IE*/
input[type="range"]::-ms-fill-lower {
background-color: var(--start);
}
input[type="range"]::-ms-fill-upper {
background-color: #fff;
}

+ 1027
- 0
module/pathfinder/main.js
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 1
- 0
module/pathfinder/neural.svg ファイルの表示

@@ -0,0 +1 @@
<svg id="Layer_1_1_" enable-background="new 0 0 64 64" height="512" viewBox="0 0 64 64" width="512" xmlns="http://www.w3.org/2000/svg"><g fill="#68607c"><path d="m13.55 13h14.9v2h-14.9z" transform="matrix(.94 -.342 .342 .94 -3.524 8.035)"/><path d="m42 9.686h2v22.627h-2z" transform="matrix(.707 -.707 .707 .707 -2.255 36.556)"/><path d="m42 24.444h1.999v12.113h-1.999z" transform="matrix(.136 -.991 .991 .136 6.926 68.943)"/><path d="m20 14.556h2v17.889h-2z" transform="matrix(.447 -.894 .894 .447 -9.41 31.775)"/><path d="m19.825 41.406h2.001v16.018h-2.001z" transform="matrix(.448 -.894 .894 .448 -32.685 45.919)"/><path d="m31 33h2v17h-2z"/><path d="m5.513 26h30.974v2h-30.974z" transform="matrix(.544 -.839 .839 .544 -13.08 29.93)"/><path d="m31.824 42.25h22.832v2h-22.832z" transform="matrix(.691 -.723 .723 .691 -17.903 44.594)"/><path d="m19.785 20.006h2v32.257h-2z" transform="matrix(.86 -.511 .511 .86 -15.542 15.688)"/></g><path d="m17 44c0 1.13-.26 2.19-.74 3.13-1.14 2.3-3.52 3.87-6.26 3.87-3.87 0-7-3.13-7-7s3.13-7 7-7c1.41 0 2.71.41 3.8 1.12 1.93 1.25 3.2 3.41 3.2 5.88z" fill="#4e9bb9"/><path d="m37.31 49.45c1.06 1.22 1.69 2.81 1.69 4.55 0 3.87-3.13 7-7 7s-7-3.13-7-7c0-.81.14-1.58.39-2.3.48-1.41 1.4-2.6 2.6-3.44 1.13-.8 2.51-1.26 4.01-1.26 2.13 0 4.04.95 5.31 2.45z" fill="#91cbd7"/><path d="m54 25c3.87 0 7 3.13 7 7s-3.13 7-7 7c-1.88 0-3.58-.73-4.83-1.95-1.34-1.26-2.17-3.06-2.17-5.05 0-.32.02-.63.07-.94.2-1.56.92-2.95 1.98-4.01 1.27-1.27 3.01-2.05 4.95-2.05z" fill="#ffd086"/><path d="m38.93 29.94c-.45 3.42-3.38 6.06-6.93 6.06-3.87 0-7-3.13-7-7 0-1.13.26-2.19.74-3.13 1.14-2.3 3.52-3.87 6.26-3.87 3.87 0 7 3.13 7 7 0 .32-.02.63-.07.94z" fill="#ed6571"/><path d="m32 3c3.87 0 7 3.13 7 7 0 1.94-.78 3.68-2.05 4.95s-3.01 2.05-4.95 2.05c-1.41 0-2.71-.41-3.8-1.12-1.27-.82-2.26-2.04-2.78-3.49-.27-.74-.42-1.55-.42-2.39 0-3.87 3.13-7 7-7z" fill="#f69489"/><path d="m16.58 15.61c.27.74.42 1.55.42 2.39 0 1.13-.26 2.19-.74 3.13-.6 1.2-1.53 2.2-2.68 2.88-1.04.63-2.27.99-3.58.99-3.87 0-7-3.13-7-7s3.13-7 7-7c3.03 0 5.6 1.92 6.58 4.61z" fill="#91cbd7"/></svg>

+ 89
- 0
module/pathfinder/select.js ファイルの表示

@@ -0,0 +1,89 @@
var x, i, j, l, ll, selElmnt, a, b, c;
/* Look for any elements with the class "custom-select": */
x = document.getElementsByClassName("custom-select");
for(let c of x)
{
c.style.width = (c.children[0].scrollWidth + 35).toString() + "px";
c.children[0].style.display = "none";
}
l = x.length;
for (i = 0; i < l; i++) {
selElmnt = x[i].getElementsByTagName("select")[0];
ll = selElmnt.length;
/* For each element, create a new DIV that will act as the selected item: */
a = document.createElement("DIV");
a.setAttribute("class", "select-selected");
a.innerHTML = selElmnt.options[selElmnt.selectedIndex].innerHTML;
x[i].appendChild(a);
/* For each element, create a new DIV that will contain the option list: */
b = document.createElement("DIV");
b.setAttribute("class", "select-items select-hide");
for (j = 0; j < ll; j++) {
/* For each option in the original select element,
create a new DIV that will act as an option item: */
c = document.createElement("DIV");
c.innerHTML = selElmnt.options[j].innerHTML;
c.addEventListener("click", function(e) {
/* When an item is clicked, update the original select box,
and the selected item: */
var y, i, k, s, h, sl, yl;
s = this.parentNode.parentNode.getElementsByTagName("select")[0];
sl = s.length;
h = this.parentNode.previousSibling;
for (i = 0; i < sl; i++) {
if (s.options[i].innerHTML == this.innerHTML) {
s.selectedIndex = i;
h.innerHTML = this.innerHTML;
y = this.parentNode.getElementsByClassName("same-as-selected");
yl = y.length;
for (k = 0; k < yl; k++) {
y[k].removeAttribute("class");
}
this.setAttribute("class", "same-as-selected");
break;
}
}
SelectChange(s.id);
h.click();
});
b.appendChild(c);
}
x[i].appendChild(b);
a.addEventListener("click", function(e) {
/* When the select box is clicked, close any other select boxes,
and open/close the current select box: */
e.stopPropagation();
closeAllSelect(this);
this.nextSibling.classList.toggle("select-hide");
this.classList.toggle("select-arrow-active");
});
}
function closeAllSelect(elmnt) {
/* A function that will close all select boxes in the document,
except the current select box: */
var x, y, i, xl, yl, arrNo = [];
x = document.getElementsByClassName("select-items");
y = document.getElementsByClassName("select-selected");
xl = x.length;
yl = y.length;
for (i = 0; i < yl; i++) {
if (elmnt == y[i]) {
arrNo.push(i)
} else {
y[i].classList.remove("select-arrow-active");
}
}
for (i = 0; i < xl; i++) {
if (arrNo.indexOf(i)) {
x[i].classList.add("select-hide");
}
}
}
/* If the user clicks anywhere outside the select box,
then close all select boxes: */
document.addEventListener("click", closeAllSelect);

+ 15
- 0
module/pathfinder/typo.css ファイルの表示

@@ -0,0 +1,15 @@
html{
font-family: "Roboto";
font-size: 1.3em;
}
a,p,span,h1,h2,h3,h4,h5,button,select,option{
font-family: "Roboto";
}
a{
text-decoration: none;
color: inherit;
}
select,option,select::after,select::before{
border: none;
outline: none;
}

+ 116
- 2
slides/intro.md ファイルの表示

@@ -13,9 +13,123 @@
- you feel miserable and tired. <!-- .element: class="fragment" -->

---
<!-- .slide: data-transition="slide-in fade-out" -->
### ...but why?

---
<!-- .slide: data-transition="fade-in slide-out" -->
I don't feel like it.

I'm too tired now. <!-- .element: class="fragment" -->

I don't know how to do it. <!-- .element: class="fragment" -->

I'm too busy now. <!-- .element: class="fragment" -->

I'll do it, but first [☕]. <!-- .element: class="fragment" -->

---
<!-- .slide: class="pathfinder-page" -->
#### Trying it all

<header class="navbar hidden">
<nav class="navbar">
<div class="navbar-item">
<div class="custom-select">
<select class="algo-select">
<option value="BFS" selected>Breadth First Search</option>
</select>
</div>
</div>
<div class="navbar-item">
<div class="custom-select">
<select class="maze-algo-select">
<option value="Random" selected>Random Maze</option>
</select>
</div>
</div>
<div class="navbar-item">
<div class="speed-container slidecontainer">
<span class="range-caption">Speed</span>
<input type="range" class="slider range-speed" min="0" max="200" value="100">
</div>
</div>
</nav>
</header>
<div class="main-grid-container">
<div class="grid-container"><div class="grid" id="grid"></div></div>
</div>

<div class="pathfinder-rerun">Restart</div>

-V-
<!-- .slide: class="pathfinder-page" -->
#### Wandering around

<header class="navbar hidden">
<nav class="navbar">
<div class="navbar-item">
<div class="custom-select">
<select class="algo-select">
<option value="DFS" selected>Depth First Search</option>
</select>
</div>
</div>
<div class="navbar-item">
<div class="custom-select">
<select class="maze-algo-select">
<option value="Random" selected>Random Maze</option>
</select>
</div>
</div>
<div class="navbar-item">
<div class="speed-container slidecontainer">
<span class="range-caption">Speed</span>
<input type="range" class="slider range-speed" min="0" max="200" value="100">
</div>
</div>
</nav>
</header>
<div class="main-grid-container">
<div class="grid-container"><div class="grid"></div></div>
</div>

<div class="pathfinder-rerun">Restart</div>

-V-
<!-- .slide: class="pathfinder-page" -->
#### Having a goal

<header class="navbar hidden">
<nav class="navbar">
<div class="navbar-item">
<div class="custom-select">
<select class="algo-select">
<option value="Greedy" selected>Greedy Algorithm</option>
</select>
</div>
</div>
<div class="navbar-item">
<div class="custom-select">
<select class="maze-algo-select">
<option value="Random" selected>Random Maze</option>
</select>
</div>
</div>
<div class="navbar-item">
<div class="speed-container slidecontainer">
<span class="range-caption">Speed</span>
<input type="range" class="slider range-speed" min="0" max="200" value="100">
</div>
</div>
</nav>
</header>
<div class="main-grid-container">
<div class="grid-container"><div class="grid"></div></div>
</div>

<div class="pathfinder-rerun">Restart</div>

---

#### Decision Paralysis
@@ -24,7 +138,7 @@
- What if I choose the wrong one? <!-- .element: class="fragment" -->
- Should I try the other one? <!-- .element: class="fragment" -->

Deciding on anything hurts. Let's not do it *right now*.
Deciding on anything hurts. Let's not do it *now*.
<!-- .element: class="fragment r-fit-text" -->

---


読み込み中…
キャンセル
保存