Skip to content

Commit d25222f

Browse files
committed
add : Simple Sorting Visualizer
1 parent 85ef4e7 commit d25222f

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
package gsoc
2+
package contributors
3+
4+
import cats.effect.*
5+
import cats.effect.unsafe.implicits.global
6+
import fs2.concurrent.*
7+
import fs2.dom.HtmlElement
8+
import calico.html.io.{*, given}
9+
import calico.syntax.*
10+
import cats.syntax.all.*
11+
import org.scalajs.dom.HTMLSelectElement
12+
13+
import scala.concurrent.duration.*
14+
15+
val Arunanshu655: Contributor = Contributor("Arunanshu655"):
16+
17+
case class State(
18+
input: String,
19+
array: List[Int],
20+
algorithm: String
21+
)
22+
23+
def parseInput(str: String): List[Int] =
24+
str.split(",").toList.flatMap(s => s.trim.toIntOption)
25+
26+
def bubbleAnimated(
27+
arr: List[Int],
28+
state: SignallingRef[IO, State]
29+
): IO[Unit] =
30+
val a = arr.toArray
31+
val n = a.length
32+
def bubblePass(i: Int): IO[Unit] =
33+
if i >= n then IO.unit
34+
else
35+
def swapPass(j: Int): IO[Unit] =
36+
if j >= n - i - 1 then IO.unit
37+
else if a(j) > a(j + 1) then
38+
val t = a(j)
39+
a(j) = a(j + 1)
40+
a(j + 1) = t
41+
for
42+
_ <- state.update(_.copy(array = a.toList))
43+
_ <- IO.sleep(300.millis)
44+
_ <- swapPass(j + 1)
45+
yield ()
46+
else swapPass(j + 1)
47+
for
48+
_ <- swapPass(0)
49+
_ <- bubblePass(i + 1)
50+
yield ()
51+
bubblePass(0)
52+
53+
def insertionAnimated(
54+
arr: List[Int],
55+
state: SignallingRef[IO, State]
56+
): IO[Unit] =
57+
val a = arr.toArray
58+
def insertPass(i: Int): IO[Unit] =
59+
if i >= a.length then IO.unit
60+
else
61+
val key = a(i)
62+
def shiftPass(j: Int): IO[Unit] =
63+
if j < 0 || a(j) <= key then
64+
a(j + 1) = key
65+
for
66+
_ <- state.update(_.copy(array = a.toList))
67+
_ <- IO.sleep(300.millis)
68+
_ <- insertPass(i + 1)
69+
yield ()
70+
else
71+
a(j + 1) = a(j)
72+
for
73+
_ <- state.update(_.copy(array = a.toList))
74+
_ <- IO.sleep(150.millis)
75+
_ <- shiftPass(j - 1)
76+
yield ()
77+
shiftPass(i - 1)
78+
insertPass(1)
79+
80+
def selectionAnimated(
81+
arr: List[Int],
82+
state: SignallingRef[IO, State]
83+
): IO[Unit] =
84+
val a = arr.toArray
85+
def selectPass(i: Int): IO[Unit] =
86+
if i >= a.length then IO.unit
87+
else
88+
def findMin(j: Int, min: Int): Int =
89+
if j >= a.length then min
90+
else findMin(j + 1, if a(j) < a(min) then j else min)
91+
val minIdx = findMin(i + 1, i)
92+
if minIdx == i then selectPass(i + 1)
93+
else
94+
val t = a(i)
95+
a(i) = a(minIdx)
96+
a(minIdx) = t
97+
for
98+
_ <- state.update(_.copy(array = a.toList))
99+
_ <- IO.sleep(300.millis)
100+
_ <- selectPass(i + 1)
101+
yield ()
102+
selectPass(0)
103+
104+
def runSort(state: SignallingRef[IO, State]): IO[Unit] =
105+
for
106+
s <- state.get
107+
arr = parseInput(s.input)
108+
_ <- s.algorithm match
109+
case "Bubble" => bubbleAnimated(arr, state)
110+
case "Insertion" => insertionAnimated(arr, state)
111+
case "Selection" => selectionAnimated(arr, state)
112+
case _ => IO.pure(())
113+
yield ()
114+
115+
val colors =
116+
List("#FF6B6B", "#4ECDC4", "#45B7D1", "#FFA07A", "#98D8C8", "#F7DC6F", "#BB8FCE", "#85C1E2")
117+
118+
SignallingRef[IO].of(State("", List.empty, "Bubble")).toResource.flatMap { state =>
119+
div(
120+
styleAttr := "padding:30px;font-family:system-ui,sans-serif;background:#f5f5f5;border-radius:8px;",
121+
p(
122+
styleAttr := "margin:0 0 20px 0;font-size:1.1em;color:#555;",
123+
"Hola, I'm @Arunanshu655 on GitHub. I agree to follow the Typelevel Code of Conduct and the Typelevel GSoC AI Policy."
124+
),
125+
h3(
126+
styleAttr := "margin:0 0 20px 0;font-size:1.8em;color:#333;",
127+
"Simple Sorting Visualizer"
128+
),
129+
input.withSelf { self =>
130+
(
131+
placeholder := "Enter numbers like 5,3,8,1(more number numbers for better visuals)",
132+
styleAttr := "padding:12px;margin-bottom:15px;width:100%;box-sizing:border-box;font-size:1em;border:2px solid #ddd;border-radius:4px;",
133+
value <-- state.map(_.input),
134+
onInput --> (_.foreach(_ =>
135+
self.value.get.flatMap(v => state.update(s => s.copy(input = v)))))
136+
)
137+
},
138+
div(styleAttr := "height:12px;"),
139+
select.withSelf { self =>
140+
(
141+
styleAttr := "padding:12px;margin-right:12px;margin-bottom:15px;font-size:1.05em;border:2px solid #ddd;border-radius:4px;cursor:pointer;",
142+
option(value := "Bubble", "Bubble Sort"),
143+
option(value := "Insertion", "Insertion Sort"),
144+
option(value := "Selection", "Selection Sort"),
145+
value <-- state.map(_.algorithm),
146+
onChange --> (_.foreach(_ =>
147+
self.value.get.flatMap(v => state.update(s => s.copy(algorithm = v)))))
148+
)
149+
},
150+
button(
151+
styleAttr := "padding:14px 28px;margin-bottom:15px;cursor:pointer;font-size:1.1em;background:#333;color:white;border:none;border-radius:4px;font-weight:bold;",
152+
"Sort",
153+
onClick --> (_.foreach(_ => runSort(state)))
154+
),
155+
div(
156+
styleAttr := "margin-top:30px;display:flex;align-items:flex-end;gap:12px;justify-content:center;flex-wrap:wrap;",
157+
children <-- state.map(_.array.mapWithIndex {
158+
case (n, idx) =>
159+
div(
160+
styleAttr := "display:flex;flex-direction:column;align-items:center;gap:8px;",
161+
div(
162+
styleAttr := s"height:${n * 12}px;width:32px;background:${colors(idx % colors.length)};transition:all 0.15s ease;border-radius:2px;box-shadow:0 2px 4px rgba(0,0,0,0.1);"
163+
),
164+
div(
165+
styleAttr := "font-size:15px;font-weight:bold;color:#333;min-width:32px;text-align:center;",
166+
n.toString
167+
)
168+
)
169+
})
170+
)
171+
)
172+
}

src/main/scala/gsoc/contributors/all.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ val allContributors = NonEmptyList.of(
1616
`typelevel-bot`,
1717
`im-vedant`,
1818
jmesyou,
19+
`Arunanshu655`,
1920
abby_ql,
2021
justaanand50,
2122
codebydeepankar,

0 commit comments

Comments
 (0)