├── .gitignore ├── AlgoVisualizer ├── AlgoVisualizer.sln ├── AlgoVisualizer.sln.DotSettings ├── Common │ └── AlgoVisualizer.Common │ │ ├── AlgoVisualizer.Common.csproj │ │ ├── AutoMapping │ │ ├── Interfaces │ │ │ ├── IHaveCustomMapping.cs │ │ │ └── IMapWith.cs │ │ └── Profiles │ │ │ └── DefaultProfile.cs │ │ ├── DataStructures │ │ └── MinHeap.cs │ │ ├── GlobalConstants.cs │ │ ├── ModelConstants.cs │ │ ├── NotificationMessages.cs │ │ └── Utils │ │ └── ValidationUtil.cs ├── Services │ ├── AlgoVisualizer.Models │ │ ├── AlgoVisualizer.Models.csproj │ │ ├── Maze │ │ │ ├── MazeNode.cs │ │ │ └── MazeServiceModel.cs │ │ ├── PathFinding │ │ │ ├── AStar │ │ │ │ ├── AStarNode.cs │ │ │ │ └── AStarServiceModel.cs │ │ │ ├── BaseServiceModel.cs │ │ │ ├── Bfs │ │ │ │ ├── BfsNode.cs │ │ │ │ └── BfsServiceModel.cs │ │ │ ├── Dfs │ │ │ │ ├── DfsNode.cs │ │ │ │ └── DfsServiceModel.cs │ │ │ ├── Dijkstra │ │ │ │ ├── DijkstraNode.cs │ │ │ │ └── DijkstraServiceModel.cs │ │ │ ├── Enums │ │ │ │ ├── NodeDirection.cs │ │ │ │ └── NodeType.cs │ │ │ ├── INode.cs │ │ │ └── Result.cs │ │ └── SortingAlgorithms │ │ │ ├── MergeSortConciseModel.cs │ │ │ └── Result.cs │ └── AlgoVisualizer.Services │ │ ├── AlgoVisualizer.Services.csproj │ │ ├── IMazeService.cs │ │ ├── IService.cs │ │ ├── MazeService.cs │ │ ├── PathFindingAlgorithms │ │ ├── Implementations │ │ │ ├── AStarService.cs │ │ │ ├── BaseService.cs │ │ │ ├── BfsService.cs │ │ │ ├── DfsService.cs │ │ │ └── DijkstraService.cs │ │ └── Interfaces │ │ │ ├── IAstarService.cs │ │ │ ├── IBfsService.cs │ │ │ ├── IDfsService.cs │ │ │ └── IDijkstraService.cs │ │ ├── README.md │ │ └── SortingAlgorithms │ │ ├── Implementations │ │ ├── BaseSortingService.cs │ │ ├── BubbleSortService.cs │ │ ├── HeapSortService.cs │ │ ├── MergeSortService.cs │ │ ├── QuickSortService.cs │ │ └── SelectionSortService.cs │ │ └── Interfaces │ │ ├── IBubbleSortService.cs │ │ ├── IHeapSortService.cs │ │ ├── IMergeSortService.cs │ │ ├── IQuickSortService.cs │ │ └── ISelectionSortService.cs ├── Tests │ └── AlgoVisualizer.Services.Tests │ │ ├── AlgoVisualizer.Services.Tests.csproj │ │ ├── BaseTest.cs │ │ └── SortingAlgorithmsTests │ │ ├── BubbleSortServiceTests.cs │ │ ├── HeapSortServiceTests.cs │ │ ├── MergeSortServiceTests.cs │ │ ├── QuickSortServiceTests.cs │ │ └── SelectionSortServiceTests.cs └── Web │ ├── AlgoVisualizer.Api │ ├── AlgoVisualizer.Api.csproj │ ├── Controllers │ │ ├── MazeController.cs │ │ ├── PathFinding │ │ │ ├── AStarController.cs │ │ │ ├── BasePathfindingController.cs │ │ │ ├── BfsController.cs │ │ │ ├── DfsController.cs │ │ │ └── DijkstraController.cs │ │ └── SortingAlgorithms │ │ │ ├── BaseSortingAlgorithmsController.cs │ │ │ ├── BubbleSortController.cs │ │ │ ├── HeapSortController.cs │ │ │ ├── MergeSortController.cs │ │ │ ├── QuickSortController.cs │ │ │ └── SelectionSortController.cs │ ├── Infrastructure │ │ └── ServiceCollectionExtensions.cs │ ├── Models │ │ ├── ErrorModel.cs │ │ ├── MazeRequestModel.cs │ │ ├── NodeDto.cs │ │ ├── PathFindingAlgorithmsRequestModel.cs │ │ ├── SortingAlgorithmsRequestModel.cs │ │ └── SortingAlgorithmsResponseModel.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.Development.json │ └── appsettings.json │ └── ClientApp │ ├── .gitignore │ ├── README.md │ ├── package-lock.json │ ├── package.json │ ├── public │ ├── algorithms-menu.jpg │ ├── dumbbell-solid.svg │ ├── favicon.ico │ ├── index.html │ ├── manifest.json │ ├── navbar-menu.jpg │ ├── point-a-b.jpg │ ├── set-start-end-nodes.gif │ ├── set-weight-and-wall-nodes.gif │ └── visualize-button.jpg │ └── src │ ├── App.jsx │ ├── components │ ├── AppRoute.jsx │ ├── Error │ │ ├── NotFound │ │ │ ├── index.css │ │ │ └── index.jsx │ │ └── index.jsx │ ├── Home │ │ ├── Layout.jsx │ │ ├── NavMenu │ │ │ ├── index.css │ │ │ └── index.jsx │ │ └── index.jsx │ ├── Modal │ │ └── VerticallyCenteredModal.js │ ├── PathFindingAlgorithms │ │ ├── Container.jsx │ │ ├── Grid │ │ │ ├── Node │ │ │ │ ├── index.css │ │ │ │ └── index.jsx │ │ │ ├── index.css │ │ │ └── index.jsx │ │ ├── Layout │ │ │ ├── index.css │ │ │ └── index.jsx │ │ └── Nav │ │ │ ├── index.css │ │ │ └── index.jsx │ └── SortingAlgorithmsVisualizer │ │ ├── Container.jsx │ │ ├── Layout │ │ └── index.jsx │ │ └── NavBar │ │ └── index.jsx │ ├── constants │ ├── apiConstants.js │ ├── errorConstants.js │ ├── gridConstants.js │ ├── pathfindingAlgorithms.js │ └── sortingAlgorithmsConstants.js │ ├── helpers │ ├── fetchData.js │ ├── pathFindingAlgorithms │ │ ├── dataVisualizer.js │ │ └── pathFindingHelper.js │ └── sortingAlgorithmsHelper.js │ ├── index.js │ ├── registerServiceWorker.js │ └── store │ ├── error │ ├── actions │ │ └── index.js │ ├── context │ │ └── index.js │ └── reducers │ │ └── index.js │ ├── pathFindingAlgorithms │ ├── actions │ │ └── index.js │ ├── context │ │ └── index.js │ └── reducers │ │ └── index.js │ └── sortingAlgorithms │ ├── actions │ └── index.js │ ├── context │ └── index.js │ └── reducers │ └── index.js ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | [Ll]ogs/ 33 | 34 | # Visual Studio 2015/2017 cache/options directory 35 | .vs/ 36 | # Uncomment if you have tasks that create the project's static files in wwwroot 37 | #wwwroot/ 38 | 39 | # Visual Studio 2017 auto generated files 40 | Generated\ Files/ 41 | 42 | # MSTest test Results 43 | [Tt]est[Rr]esult*/ 44 | [Bb]uild[Ll]og.* 45 | 46 | # NUnit 47 | *.VisualState.xml 48 | TestResult.xml 49 | nunit-*.xml 50 | 51 | # Build Results of an ATL Project 52 | [Dd]ebugPS/ 53 | [Rr]eleasePS/ 54 | dlldata.c 55 | 56 | # Benchmark Results 57 | BenchmarkDotNet.Artifacts/ 58 | 59 | # .NET Core 60 | project.lock.json 61 | project.fragment.lock.json 62 | artifacts/ 63 | 64 | # StyleCop 65 | StyleCopReport.xml 66 | 67 | # Files built by Visual Studio 68 | *_i.c 69 | *_p.c 70 | *_h.h 71 | *.ilk 72 | *.meta 73 | *.obj 74 | *.iobj 75 | *.pch 76 | *.pdb 77 | *.ipdb 78 | *.pgc 79 | *.pgd 80 | *.rsp 81 | *.sbr 82 | *.tlb 83 | *.tli 84 | *.tlh 85 | *.tmp 86 | *.tmp_proj 87 | *_wpftmp.csproj 88 | *.log 89 | *.vspscc 90 | *.vssscc 91 | .builds 92 | *.pidb 93 | *.svclog 94 | *.scc 95 | 96 | # Chutzpah Test files 97 | _Chutzpah* 98 | 99 | # Visual C++ cache files 100 | ipch/ 101 | *.aps 102 | *.ncb 103 | *.opendb 104 | *.opensdf 105 | *.sdf 106 | *.cachefile 107 | *.VC.db 108 | *.VC.VC.opendb 109 | 110 | # Visual Studio profiler 111 | *.psess 112 | *.vsp 113 | *.vspx 114 | *.sap 115 | 116 | # Visual Studio Trace Files 117 | *.e2e 118 | 119 | # TFS 2012 Local Workspace 120 | $tf/ 121 | 122 | # Guidance Automation Toolkit 123 | *.gpState 124 | 125 | # ReSharper is a .NET coding add-in 126 | _ReSharper*/ 127 | *.[Rr]e[Ss]harper 128 | *.DotSettings.user 129 | 130 | # TeamCity is a build add-in 131 | _TeamCity* 132 | 133 | # DotCover is a Code Coverage Tool 134 | *.dotCover 135 | 136 | # AxoCover is a Code Coverage Tool 137 | .axoCover/* 138 | !.axoCover/settings.json 139 | 140 | # Visual Studio code coverage results 141 | *.coverage 142 | *.coveragexml 143 | 144 | # NCrunch 145 | _NCrunch_* 146 | .*crunch*.local.xml 147 | nCrunchTemp_* 148 | 149 | # MightyMoose 150 | *.mm.* 151 | AutoTest.Net/ 152 | 153 | # Web workbench (sass) 154 | .sass-cache/ 155 | 156 | # Installshield output folder 157 | [Ee]xpress/ 158 | 159 | # DocProject is a documentation generator add-in 160 | DocProject/buildhelp/ 161 | DocProject/Help/*.HxT 162 | DocProject/Help/*.HxC 163 | DocProject/Help/*.hhc 164 | DocProject/Help/*.hhk 165 | DocProject/Help/*.hhp 166 | DocProject/Help/Html2 167 | DocProject/Help/html 168 | 169 | # Click-Once directory 170 | publish/ 171 | 172 | # Publish Web Output 173 | *.[Pp]ublish.xml 174 | *.azurePubxml 175 | # Note: Comment the next line if you want to checkin your web deploy settings, 176 | # but database connection strings (with potential passwords) will be unencrypted 177 | *.pubxml 178 | *.publishproj 179 | 180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 181 | # checkin your Azure Web App publish settings, but sensitive information contained 182 | # in these scripts will be unencrypted 183 | PublishScripts/ 184 | 185 | # NuGet Packages 186 | *.nupkg 187 | # NuGet Symbol Packages 188 | *.snupkg 189 | # The packages folder can be ignored because of Package Restore 190 | **/[Pp]ackages/* 191 | # except build/, which is used as an MSBuild target. 192 | !**/[Pp]ackages/build/ 193 | # Uncomment if necessary however generally it will be regenerated when needed 194 | #!**/[Pp]ackages/repositories.config 195 | # NuGet v3's project.json files produces more ignorable files 196 | *.nuget.props 197 | *.nuget.targets 198 | 199 | # Microsoft Azure Build Output 200 | csx/ 201 | *.build.csdef 202 | 203 | # Microsoft Azure Emulator 204 | ecf/ 205 | rcf/ 206 | 207 | # Windows Store app package directories and files 208 | AppPackages/ 209 | BundleArtifacts/ 210 | Package.StoreAssociation.xml 211 | _pkginfo.txt 212 | *.appx 213 | *.appxbundle 214 | *.appxupload 215 | 216 | # Visual Studio cache files 217 | # files ending in .cache can be ignored 218 | *.[Cc]ache 219 | # but keep track of directories ending in .cache 220 | !?*.[Cc]ache/ 221 | 222 | # Others 223 | ClientBin/ 224 | ~$* 225 | *~ 226 | *.dbmdl 227 | *.dbproj.schemaview 228 | *.jfm 229 | *.pfx 230 | *.publishsettings 231 | orleans.codegen.cs 232 | 233 | # Including strong name files can present a security risk 234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 235 | #*.snk 236 | 237 | # Since there are multiple workflows, uncomment next line to ignore bower_components 238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 239 | #bower_components/ 240 | 241 | # RIA/Silverlight projects 242 | Generated_Code/ 243 | 244 | # Backup & report files from converting an old project file 245 | # to a newer Visual Studio version. Backup files are not needed, 246 | # because we have git ;-) 247 | _UpgradeReport_Files/ 248 | Backup*/ 249 | UpgradeLog*.XML 250 | UpgradeLog*.htm 251 | ServiceFabricBackup/ 252 | *.rptproj.bak 253 | 254 | # SQL Server files 255 | *.mdf 256 | *.ldf 257 | *.ndf 258 | 259 | # Business Intelligence projects 260 | *.rdl.data 261 | *.bim.layout 262 | *.bim_*.settings 263 | *.rptproj.rsuser 264 | *- [Bb]ackup.rdl 265 | *- [Bb]ackup ([0-9]).rdl 266 | *- [Bb]ackup ([0-9][0-9]).rdl 267 | 268 | # Microsoft Fakes 269 | FakesAssemblies/ 270 | 271 | # GhostDoc plugin setting file 272 | *.GhostDoc.xml 273 | 274 | # Node.js Tools for Visual Studio 275 | .ntvs_analysis.dat 276 | node_modules/ 277 | 278 | # Visual Studio 6 build log 279 | *.plg 280 | 281 | # Visual Studio 6 workspace options file 282 | *.opt 283 | 284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 285 | *.vbw 286 | 287 | # Visual Studio LightSwitch build output 288 | **/*.HTMLClient/GeneratedArtifacts 289 | **/*.DesktopClient/GeneratedArtifacts 290 | **/*.DesktopClient/ModelManifest.xml 291 | **/*.Server/GeneratedArtifacts 292 | **/*.Server/ModelManifest.xml 293 | _Pvt_Extensions 294 | 295 | # Paket dependency manager 296 | .paket/paket.exe 297 | paket-files/ 298 | 299 | # FAKE - F# Make 300 | .fake/ 301 | 302 | # CodeRush personal settings 303 | .cr/personal 304 | 305 | # Python Tools for Visual Studio (PTVS) 306 | __pycache__/ 307 | *.pyc 308 | 309 | # Cake - Uncomment if you are using it 310 | # tools/** 311 | # !tools/packages.config 312 | 313 | # Tabs Studio 314 | *.tss 315 | 316 | # Telerik's JustMock configuration file 317 | *.jmconfig 318 | 319 | # BizTalk build output 320 | *.btp.cs 321 | *.btm.cs 322 | *.odx.cs 323 | *.xsd.cs 324 | 325 | # OpenCover UI analysis results 326 | OpenCover/ 327 | 328 | # Azure Stream Analytics local run output 329 | ASALocalRun/ 330 | 331 | # MSBuild Binary and Structured Log 332 | *.binlog 333 | 334 | # NVidia Nsight GPU debugger configuration file 335 | *.nvuser 336 | 337 | # MFractors (Xamarin productivity tool) working folder 338 | .mfractor/ 339 | 340 | # Local History for Visual Studio 341 | .localhistory/ 342 | 343 | # BeatPulse healthcheck temp database 344 | healthchecksdb 345 | 346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 347 | MigrationBackup/ 348 | 349 | # Ionide (cross platform F# VS Code tools) working folder 350 | .ionide/ 351 | -------------------------------------------------------------------------------- /AlgoVisualizer/AlgoVisualizer.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29609.76 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Services", "Services", "{4F5557FA-8B6F-490E-91FB-45CB3A93D896}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{5E45A0B3-5B3C-4362-A4B0-5A405413BBC6}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Web", "Web", "{4F2B08AE-4866-499D-A361-EB3D378BD93B}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlgoVisualizer.Api", "Web\AlgoVisualizer.Api\AlgoVisualizer.Api.csproj", "{F3A7AE41-A974-495A-A884-B6260305264E}" 13 | EndProject 14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlgoVisualizer.Services", "Services\AlgoVisualizer.Services\AlgoVisualizer.Services.csproj", "{C0142771-8181-4EF5-A2A0-14800614D249}" 15 | EndProject 16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlgoVisualizer.Models", "Services\AlgoVisualizer.Models\AlgoVisualizer.Models.csproj", "{97BC9DF5-DA20-42FF-A79A-70E0A373959D}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlgoVisualizer.Common", "Common\AlgoVisualizer.Common\AlgoVisualizer.Common.csproj", "{3B261A51-12A2-4D90-8A80-C265E695D3D7}" 19 | EndProject 20 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{6167BF8C-FD72-4A9A-8FD0-7C030CE8F8F4}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlgoVisualizer.Services.Tests", "Tests\AlgoVisualizer.Services.Tests\AlgoVisualizer.Services.Tests.csproj", "{BD3D5EEA-BE8D-4613-9EED-E76CAD2F5CEF}" 23 | EndProject 24 | Global 25 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 26 | Debug|Any CPU = Debug|Any CPU 27 | Release|Any CPU = Release|Any CPU 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {F3A7AE41-A974-495A-A884-B6260305264E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {F3A7AE41-A974-495A-A884-B6260305264E}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {F3A7AE41-A974-495A-A884-B6260305264E}.Release|Any CPU.ActiveCfg = Release|Any CPU 33 | {F3A7AE41-A974-495A-A884-B6260305264E}.Release|Any CPU.Build.0 = Release|Any CPU 34 | {C0142771-8181-4EF5-A2A0-14800614D249}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 35 | {C0142771-8181-4EF5-A2A0-14800614D249}.Debug|Any CPU.Build.0 = Debug|Any CPU 36 | {C0142771-8181-4EF5-A2A0-14800614D249}.Release|Any CPU.ActiveCfg = Release|Any CPU 37 | {C0142771-8181-4EF5-A2A0-14800614D249}.Release|Any CPU.Build.0 = Release|Any CPU 38 | {97BC9DF5-DA20-42FF-A79A-70E0A373959D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 39 | {97BC9DF5-DA20-42FF-A79A-70E0A373959D}.Debug|Any CPU.Build.0 = Debug|Any CPU 40 | {97BC9DF5-DA20-42FF-A79A-70E0A373959D}.Release|Any CPU.ActiveCfg = Release|Any CPU 41 | {97BC9DF5-DA20-42FF-A79A-70E0A373959D}.Release|Any CPU.Build.0 = Release|Any CPU 42 | {3B261A51-12A2-4D90-8A80-C265E695D3D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 43 | {3B261A51-12A2-4D90-8A80-C265E695D3D7}.Debug|Any CPU.Build.0 = Debug|Any CPU 44 | {3B261A51-12A2-4D90-8A80-C265E695D3D7}.Release|Any CPU.ActiveCfg = Release|Any CPU 45 | {3B261A51-12A2-4D90-8A80-C265E695D3D7}.Release|Any CPU.Build.0 = Release|Any CPU 46 | {BD3D5EEA-BE8D-4613-9EED-E76CAD2F5CEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 47 | {BD3D5EEA-BE8D-4613-9EED-E76CAD2F5CEF}.Debug|Any CPU.Build.0 = Debug|Any CPU 48 | {BD3D5EEA-BE8D-4613-9EED-E76CAD2F5CEF}.Release|Any CPU.ActiveCfg = Release|Any CPU 49 | {BD3D5EEA-BE8D-4613-9EED-E76CAD2F5CEF}.Release|Any CPU.Build.0 = Release|Any CPU 50 | EndGlobalSection 51 | GlobalSection(SolutionProperties) = preSolution 52 | HideSolutionNode = FALSE 53 | EndGlobalSection 54 | GlobalSection(NestedProjects) = preSolution 55 | {F3A7AE41-A974-495A-A884-B6260305264E} = {4F2B08AE-4866-499D-A361-EB3D378BD93B} 56 | {C0142771-8181-4EF5-A2A0-14800614D249} = {4F5557FA-8B6F-490E-91FB-45CB3A93D896} 57 | {97BC9DF5-DA20-42FF-A79A-70E0A373959D} = {4F5557FA-8B6F-490E-91FB-45CB3A93D896} 58 | {3B261A51-12A2-4D90-8A80-C265E695D3D7} = {5E45A0B3-5B3C-4362-A4B0-5A405413BBC6} 59 | {BD3D5EEA-BE8D-4613-9EED-E76CAD2F5CEF} = {6167BF8C-FD72-4A9A-8FD0-7C030CE8F8F4} 60 | EndGlobalSection 61 | GlobalSection(ExtensibilityGlobals) = postSolution 62 | SolutionGuid = {AC8E2AC8-BD30-429B-9BCB-380632449EE8} 63 | EndGlobalSection 64 | EndGlobal 65 | -------------------------------------------------------------------------------- /AlgoVisualizer/AlgoVisualizer.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True -------------------------------------------------------------------------------- /AlgoVisualizer/Common/AlgoVisualizer.Common/AlgoVisualizer.Common.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AlgoVisualizer/Common/AlgoVisualizer.Common/AutoMapping/Interfaces/IHaveCustomMapping.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Common.AutoMapping.Interfaces 2 | { 3 | using AutoMapper; 4 | 5 | public interface IHaveCustomMapping 6 | { 7 | void ConfigureMapping(Profile mapper); 8 | } 9 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Common/AlgoVisualizer.Common/AutoMapping/Interfaces/IMapWith.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Common.AutoMapping.Interfaces 2 | { 3 | // Marker interface 4 | public interface IMapWith 5 | { 6 | } 7 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Common/AlgoVisualizer.Common/AutoMapping/Profiles/DefaultProfile.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Common.AutoMapping.Profiles 2 | { 3 | using System; 4 | using System.Linq; 5 | using AutoMapper; 6 | using Interfaces; 7 | 8 | public class DefaultProfile : Profile 9 | { 10 | public DefaultProfile() 11 | { 12 | this.ConfigureMapping(); 13 | } 14 | 15 | private void ConfigureMapping() 16 | { 17 | var allTypes = AppDomain 18 | .CurrentDomain 19 | .GetAssemblies() 20 | .Where(a => a.GetName().FullName.Contains(nameof(AlgoVisualizer))) 21 | .SelectMany(a => a.GetTypes()) 22 | .ToArray(); 23 | 24 | var withBidirectionalMapping = allTypes 25 | .Where(t => t.IsClass 26 | && !t.IsAbstract 27 | && t.GetInterfaces() 28 | .Where(i => i.IsGenericType) 29 | .Select(i => i.GetGenericTypeDefinition()) 30 | .Contains(typeof(IMapWith<>))) 31 | .SelectMany(t => 32 | t.GetInterfaces() 33 | .Where(i => i.IsGenericType && 34 | i.GetGenericTypeDefinition() == typeof(IMapWith<>)) 35 | .SelectMany(i => i.GetGenericArguments()) 36 | .Select(s => new 37 | { 38 | Type1 = t, 39 | Type2 = s 40 | }) 41 | ) 42 | .ToArray(); 43 | 44 | //Create bidirectional mapping for all types implementing the IMapWith interface 45 | foreach (var mapping in withBidirectionalMapping) 46 | { 47 | this.CreateMap(mapping.Type1, mapping.Type2); 48 | this.CreateMap(mapping.Type2, mapping.Type1); 49 | } 50 | 51 | // Create custom mapping for all types implementing the IHaveCustomMapping interface 52 | var customMappings = allTypes.Where(t => t.IsClass 53 | && !t.IsAbstract 54 | && typeof(IHaveCustomMapping).IsAssignableFrom(t)) 55 | .Select(Activator.CreateInstance) 56 | .Cast() 57 | .ToArray(); 58 | 59 | foreach (var mapping in customMappings) 60 | { 61 | mapping.ConfigureMapping(this); 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Common/AlgoVisualizer.Common/DataStructures/MinHeap.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Common.DataStructures 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | public class MinHeap 7 | { 8 | private readonly IComparer comparer; 9 | private readonly List list = new List { default }; 10 | 11 | public MinHeap() 12 | : this(default(IComparer)) 13 | { 14 | } 15 | 16 | public MinHeap(IComparer comparer) 17 | { 18 | this.comparer = comparer ?? Comparer.Default; 19 | } 20 | 21 | public MinHeap(Comparison comparison) 22 | : this(Comparer.Create(comparison)) 23 | { 24 | } 25 | 26 | public int Count 27 | => this.list.Count - 1; 28 | 29 | public void Add(T element) 30 | { 31 | this.list.Add(element); 32 | this.ShiftUp(this.list.Count - 1); 33 | } 34 | 35 | public T Pop() 36 | { 37 | var result = this.list[1]; 38 | this.list[1] = this.list[^1]; 39 | this.list.RemoveAt(this.list.Count - 1); 40 | this.ShiftDown(1); 41 | return result; 42 | } 43 | 44 | private static int Parent(int i) 45 | => i / 2; 46 | 47 | private static int Left(int i) 48 | => i * 2; 49 | 50 | private static int Right(int i) 51 | => i * 2 + 1; 52 | 53 | private void ShiftUp(int i) 54 | { 55 | while (i > 1) 56 | { 57 | var parent = Parent(i); 58 | if (this.comparer.Compare(this.list[i], this.list[parent]) > 0) 59 | { 60 | return; 61 | } 62 | 63 | (this.list[parent], this.list[i]) = (this.list[i], this.list[parent]); 64 | i = parent; 65 | } 66 | } 67 | 68 | private void ShiftDown(int i) 69 | { 70 | for (var left = Left(i); left < this.list.Count; left = Left(i)) 71 | { 72 | var smallest = this.comparer.Compare(this.list[left], this.list[i]) <= 0 ? left : i; 73 | var right = Right(i); 74 | if (right < this.list.Count 75 | && this.comparer.Compare(this.list[right], this.list[smallest]) <= 0) 76 | { 77 | smallest = right; 78 | } 79 | 80 | if (smallest == i) 81 | { 82 | return; 83 | } 84 | 85 | (this.list[i], this.list[smallest]) = (this.list[smallest], this.list[i]); 86 | i = smallest; 87 | } 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Common/AlgoVisualizer.Common/GlobalConstants.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Common 2 | { 3 | public static class GlobalConstants 4 | { 5 | public const string ClientUrl = "https://localhost:3000"; 6 | } 7 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Common/AlgoVisualizer.Common/ModelConstants.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Common 2 | { 3 | public static class ModelConstants 4 | { 5 | public const string WallNode = "Wall"; 6 | public const string StartNode = "Start"; 7 | public const string EndNode = "End"; 8 | public const string WeightNode = "Weight"; 9 | public const int WeightNodeValue = 10; 10 | public const int DefaultWeightNodeValue = 1; 11 | } 12 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Common/AlgoVisualizer.Common/NotificationMessages.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Common 2 | { 3 | public static class NotificationMessages 4 | { 5 | public static class PathFindingAlgorithms 6 | { 7 | public const string PathNotFound = "There is no possible path!"; 8 | } 9 | 10 | public static class SortingAlgorithms 11 | { 12 | public const string EmptyArrayErrorMessage = "There is nothing to sort!"; 13 | public const string DataAlreadySortedErrorMessage = "Data is already sorted. Please generate new data (array)"; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Common/AlgoVisualizer.Common/Utils/ValidationUtil.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Common.Utils 2 | { 3 | using System.Collections.Generic; 4 | using System.ComponentModel.DataAnnotations; 5 | 6 | public static class ValidationUtil 7 | { 8 | public static bool IsObjectValid(object model) 9 | { 10 | var validationContext = new ValidationContext(model); 11 | var validationResults = new List(); 12 | 13 | return Validator.TryValidateObject(model, validationContext, validationResults, 14 | true); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/AlgoVisualizer.Models.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/Maze/MazeNode.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.Maze 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | using PathFinding; 5 | using PathFinding.Enums; 6 | 7 | public class MazeNode : INode 8 | { 9 | [Required] 10 | public int Row { get; set; } 11 | 12 | [Required] 13 | public int Col { get; set; } 14 | 15 | public bool IsVisited { get; set; } 16 | 17 | public INode PreviousNode { get; set; } 18 | 19 | public NodeType? NodeType { get; set; } 20 | 21 | public int CompareTo(object obj) 22 | => 0; 23 | } 24 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/Maze/MazeServiceModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.Maze 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | public class MazeServiceModel 6 | { 7 | [Required] 8 | public MazeNode[,] Grid { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/AStar/AStarNode.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.AStar 2 | { 3 | using System; 4 | using System.ComponentModel.DataAnnotations; 5 | using Common; 6 | using Enums; 7 | 8 | public class AStarNode : INode 9 | { 10 | public int Weight { get; set; } = ModelConstants.DefaultWeightNodeValue; 11 | 12 | public double GScore { get; set; } = double.PositiveInfinity; 13 | 14 | public double HScore { get; set; } 15 | 16 | public double FScore => this.GScore + this.HScore; 17 | 18 | public NodeDirection? Direction { get; set; } 19 | 20 | [Required] 21 | public int Row { get; set; } 22 | 23 | [Required] 24 | public int Col { get; set; } 25 | 26 | public bool IsVisited { get; set; } 27 | 28 | public INode PreviousNode { get; set; } 29 | 30 | public NodeType? NodeType { get; set; } 31 | 32 | public int CompareTo(object obj) 33 | { 34 | var otherNode = obj as AStarNode; 35 | if (otherNode != null 36 | && Math.Abs(this.FScore - otherNode.FScore) < 1) 37 | { 38 | if (this.HScore > otherNode.HScore) 39 | { 40 | return 1; 41 | } 42 | 43 | if (this.HScore < otherNode.HScore) 44 | { 45 | return -1; 46 | } 47 | } 48 | 49 | return this.FScore.CompareTo(otherNode.FScore); 50 | } 51 | 52 | public override bool Equals(object obj) 53 | => obj is AStarNode other && this.Row == other.Row && this.Col == other.Col; 54 | 55 | public override int GetHashCode() 56 | { 57 | unchecked 58 | { 59 | return (this.Row * 397) ^ this.Col; 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/AStar/AStarServiceModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.AStar 2 | { 3 | public class AStarServiceModel : BaseServiceModel 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/BaseServiceModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | public class BaseServiceModel 6 | { 7 | [Required] 8 | public T StartNode { get; set; } 9 | 10 | [Required] 11 | public T EndNode { get; set; } 12 | 13 | [Required] 14 | public T[,] Grid { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/Bfs/BfsNode.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.Bfs 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | using Enums; 5 | 6 | public class BfsNode : INode 7 | { 8 | public BfsNode(int row, int col, INode previousNode = null, double distance = double.PositiveInfinity) 9 | { 10 | this.Row = row; 11 | this.Col = col; 12 | this.PreviousNode = previousNode; 13 | this.Distance = distance; 14 | } 15 | 16 | public double Distance { get; set; } 17 | 18 | [Required] 19 | public int Row { get; set; } 20 | 21 | [Required] 22 | public int Col { get; set; } 23 | 24 | public bool IsVisited { get; set; } 25 | 26 | public INode PreviousNode { get; set; } 27 | 28 | public NodeType? NodeType { get; set; } 29 | 30 | public int CompareTo(object obj) 31 | => 0; 32 | 33 | public override bool Equals(object obj) 34 | => obj is BfsNode other && this.Row == other.Row && this.Col == other.Col; 35 | 36 | public override int GetHashCode() 37 | { 38 | unchecked 39 | { 40 | return (this.Row * 397) ^ this.Col; 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/Bfs/BfsServiceModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.Bfs 2 | { 3 | public class BfsServiceModel : BaseServiceModel 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/Dfs/DfsNode.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.Dfs 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | using Enums; 5 | 6 | public class DfsNode : INode 7 | { 8 | [Required] 9 | public int Row { get; set; } 10 | 11 | [Required] 12 | public int Col { get; set; } 13 | 14 | public bool IsVisited { get; set; } 15 | 16 | public INode PreviousNode { get; set; } 17 | 18 | public NodeType? NodeType { get; set; } 19 | 20 | public int CompareTo(object obj) 21 | => 0; 22 | 23 | public override bool Equals(object obj) 24 | => obj is DfsNode other && this.Row == other.Row && this.Col == other.Col; 25 | 26 | public override int GetHashCode() 27 | { 28 | unchecked 29 | { 30 | return (this.Row * 397) ^ this.Col; 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/Dfs/DfsServiceModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.Dfs 2 | { 3 | public class DfsServiceModel : BaseServiceModel 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/Dijkstra/DijkstraNode.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.Dijkstra 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | using Common; 5 | using Enums; 6 | 7 | public class DijkstraNode : INode 8 | { 9 | public double Distance { get; set; } = double.PositiveInfinity; 10 | 11 | public int Weight { get; set; } = ModelConstants.DefaultWeightNodeValue; 12 | 13 | [Required] 14 | public int Row { get; set; } 15 | 16 | [Required] 17 | public int Col { get; set; } 18 | 19 | public bool IsVisited { get; set; } 20 | 21 | public INode PreviousNode { get; set; } 22 | 23 | public NodeType? NodeType { get; set; } 24 | 25 | public int CompareTo(object obj) 26 | => obj switch 27 | { 28 | DijkstraNode otherNode => this.Distance.CompareTo(otherNode.Distance), 29 | _ => 0 30 | }; 31 | 32 | public override bool Equals(object obj) 33 | => obj is INode other && this.Row == other.Row && this.Col == other.Col; 34 | 35 | public override int GetHashCode() 36 | { 37 | unchecked 38 | { 39 | return (this.Row * 397) ^ this.Col; 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/Dijkstra/DijkstraServiceModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.Dijkstra 2 | { 3 | public class DijkstraServiceModel : BaseServiceModel 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/Enums/NodeDirection.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.Enums 2 | { 3 | public enum NodeDirection 4 | { 5 | Up, 6 | Right, 7 | Left, 8 | Down 9 | } 10 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/Enums/NodeType.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding.Enums 2 | { 3 | public enum NodeType 4 | { 5 | Start, 6 | End, 7 | Wall, 8 | Weight 9 | } 10 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/INode.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding 2 | { 3 | using System; 4 | using Enums; 5 | 6 | public interface INode : IComparable 7 | { 8 | int Row { get; } 9 | 10 | int Col { get; } 11 | 12 | bool IsVisited { get; set; } 13 | 14 | INode PreviousNode { get; set; } 15 | 16 | NodeType? NodeType { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/PathFinding/Result.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.PathFinding 2 | { 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | public class Result 7 | { 8 | public Result(IEnumerable allVisitedNodesInOrder, IEnumerable allNodesInShortestPathOrder = null) 9 | { 10 | this.AllVisitedNodesInOrder = allVisitedNodesInOrder; 11 | this.AllNodesInShortestPathOrder = allNodesInShortestPathOrder; 12 | } 13 | 14 | public IEnumerable AllVisitedNodesInOrder { get; } 15 | 16 | public IEnumerable AllNodesInShortestPathOrder { get; } 17 | 18 | public int TotalNodesExplored => this.AllVisitedNodesInOrder.Count(); 19 | } 20 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/SortingAlgorithms/MergeSortConciseModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.SortingAlgorithms 2 | { 3 | public class MergeSortConciseModel 4 | { 5 | public MergeSortConciseModel(T value, int currentIndex) 6 | { 7 | this.Value = value; 8 | this.CurrentIndex = currentIndex; 9 | } 10 | 11 | public T Value { get; set; } 12 | 13 | public int CurrentIndex { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Models/SortingAlgorithms/Result.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Models.SortingAlgorithms 2 | { 3 | using System.Collections.Generic; 4 | 5 | public class Result 6 | { 7 | public Result(List usedSwapsToSortArray) 8 | { 9 | this.SwapIndexes = usedSwapsToSortArray; 10 | } 11 | 12 | public Result(string errorMessage) 13 | { 14 | this.ErrorMessage = errorMessage; 15 | } 16 | 17 | public Result(List usedSwapsToSortArray, string errorMessage = null) 18 | { 19 | this.ErrorMessage = errorMessage; 20 | this.SwapIndexes = usedSwapsToSortArray; 21 | } 22 | 23 | public string ErrorMessage { get; set; } 24 | 25 | public List SwapIndexes { get; set; } 26 | 27 | public int TotalSwaps => this.SwapIndexes.Count; 28 | } 29 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/AlgoVisualizer.Services.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/IMazeService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services 2 | { 3 | using System.Collections.Generic; 4 | using Models.Maze; 5 | 6 | public interface IMazeService 7 | { 8 | List GenerateWallMaze(MazeServiceModel model); 9 | 10 | List GenerateWeightMaze(MazeServiceModel model); 11 | } 12 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/IService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services 2 | { 3 | // Marker interface 4 | public interface IService 5 | { 6 | } 7 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/MazeService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using Common.Utils; 6 | using Models.Maze; 7 | using Models.PathFinding.Enums; 8 | using PathFindingAlgorithms.Implementations; 9 | 10 | public class MazeService : BaseService, IMazeService 11 | { 12 | private readonly List elements = new List(); 13 | private readonly Random random = new Random(); 14 | 15 | public List GenerateWallMaze(MazeServiceModel model) 16 | { 17 | if (!ValidationUtil.IsObjectValid(model)) 18 | { 19 | return null; 20 | } 21 | 22 | this.GenerateMaze(model.Grid, 0, 0, NodeType.Wall); 23 | 24 | return this.elements; 25 | } 26 | 27 | public List GenerateWeightMaze(MazeServiceModel model) 28 | { 29 | if (!ValidationUtil.IsObjectValid(model)) 30 | { 31 | return null; 32 | } 33 | 34 | this.GenerateMaze(model.Grid, 0, 0, NodeType.Weight); 35 | 36 | return this.elements; 37 | } 38 | 39 | private void GenerateMaze(MazeNode[,] grid, int startRow, int startCol, NodeType nodeType) 40 | { 41 | this.GenerateMazeFrame(grid, startRow, startCol, nodeType); 42 | this.GenerateNodesVertically(grid, startRow + 1, startCol + 1, nodeType); 43 | } 44 | 45 | private void GenerateNodesVertically(MazeNode[,] grid, int row, int col, NodeType nodeType) 46 | { 47 | if (!CanTraverse(grid, row, col) 48 | || grid[row, col].IsVisited) 49 | { 50 | return; 51 | } 52 | 53 | this.SetNode(grid, row, col, nodeType); 54 | this.GenerateNodesVertically(grid, row + 1, col, nodeType); 55 | this.GenerateNodesVertically(grid, 1, col + 1, nodeType); 56 | } 57 | 58 | private void GenerateMazeFrame(MazeNode[,] grid, int row, int col, NodeType nodeType) 59 | { 60 | if (!CanTraverse(grid, row, col) 61 | || grid[row, col].IsVisited) 62 | { 63 | return; 64 | } 65 | 66 | this.SetNode(grid, row, col, nodeType, false); 67 | if (row == 0) 68 | { 69 | this.GenerateMazeFrame(grid, row, col + 1, nodeType); 70 | } 71 | 72 | if (col == grid.GetLength(1) - 1) 73 | { 74 | this.GenerateMazeFrame(grid, row + 1, col, nodeType); 75 | } 76 | 77 | if (row == grid.GetLength(0) - 1) 78 | { 79 | this.GenerateMazeFrame(grid, row, col - 1, nodeType); 80 | } 81 | 82 | if (col == 0) 83 | { 84 | this.GenerateMazeFrame(grid, row - 1, col, nodeType); 85 | } 86 | } 87 | 88 | private void SetNode(MazeNode[,] grid, int row, int col, NodeType nodeType, bool shouldRandomize = true) 89 | { 90 | var node = grid[row, col]; 91 | if (node.NodeType != NodeType.Start 92 | && node.NodeType != NodeType.End) 93 | { 94 | if (this.random.Next(1, 11) > 7) 95 | { 96 | node.NodeType = nodeType; 97 | this.elements.Add(new[] { row, col }); 98 | } 99 | else if (!shouldRandomize) 100 | { 101 | node.NodeType = nodeType; 102 | this.elements.Add(new[] { row, col }); 103 | } 104 | 105 | node.IsVisited = true; 106 | } 107 | } 108 | 109 | private static bool CanTraverse( 110 | MazeNode[,] grid, 111 | int currentRowDirection, 112 | int currentColDirection) 113 | => currentRowDirection >= 0 && currentColDirection >= 0 && currentRowDirection < grid.GetLength(0) && currentColDirection < grid.GetLength(1); 114 | } 115 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/PathFindingAlgorithms/Implementations/AStarService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.PathFindingAlgorithms.Implementations 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Common.DataStructures; 7 | using Common.Utils; 8 | using Interfaces; 9 | using Models.PathFinding; 10 | using Models.PathFinding.AStar; 11 | using Models.PathFinding.Enums; 12 | 13 | public class AStarService : BaseService, IAStarService 14 | { 15 | public Result FindPath(AStarServiceModel model) 16 | { 17 | if (!ValidationUtil.IsObjectValid(model)) 18 | { 19 | return null; 20 | } 21 | 22 | var heap = new MinHeap(); 23 | var allSteps = new HashSet(); 24 | 25 | var startNode = model.StartNode; 26 | var endNode = model.EndNode; 27 | var grid = model.Grid; 28 | 29 | startNode.GScore = 0; 30 | startNode.HScore = this.ManhattanDistance(startNode, endNode); 31 | startNode.IsVisited = true; 32 | startNode.Direction = NodeDirection.Up; 33 | heap.Add(startNode); 34 | 35 | while (heap.Count != 0) 36 | { 37 | var currentNode = heap.Pop(); 38 | 39 | if (currentNode.NodeType == NodeType.Wall) 40 | { 41 | continue; 42 | } 43 | 44 | if (currentNode.Equals(endNode)) 45 | { 46 | // Remove StartNode 47 | allSteps.Remove(allSteps.ElementAt(0)); 48 | return new Result(allSteps, this.GetAllNodesInShortestPathOrder(currentNode)); 49 | } 50 | 51 | allSteps.Add(currentNode); 52 | 53 | var rowDirection = new[] { -1, +1, 0, 0 }; 54 | var columnDirection = new[] { 0, 0, +1, -1 }; 55 | for (var i = 0; i < 4; i++) 56 | { 57 | var currentRowDirection = currentNode.Row + rowDirection[i]; 58 | var currentColDirection = currentNode.Col + columnDirection[i]; 59 | 60 | if (currentRowDirection < 0 61 | || currentColDirection < 0 62 | || currentRowDirection >= grid.GetLength(0) 63 | || currentColDirection >= grid.GetLength(1)) 64 | { 65 | continue; 66 | } 67 | 68 | var nextNode = grid[currentRowDirection, currentColDirection]; 69 | this.AddNodeToHeap(currentNode, nextNode, endNode, heap); 70 | } 71 | } 72 | 73 | return new Result(allSteps); 74 | } 75 | 76 | private void AddNodeToHeap(AStarNode currentNode, AStarNode nextNode, INode end, MinHeap heap) 77 | { 78 | if (nextNode.IsVisited) 79 | { 80 | return; 81 | } 82 | 83 | var (additionalWeight, direction) = this.ApplyWeightAndDirection(currentNode, nextNode); 84 | var g = currentNode.GScore + nextNode.Weight + additionalWeight; 85 | var h = this.ManhattanDistance(nextNode, end); 86 | 87 | if (g < nextNode.GScore) 88 | { 89 | nextNode.GScore = g; 90 | nextNode.HScore = h; 91 | nextNode.PreviousNode = currentNode; 92 | nextNode.IsVisited = true; 93 | } 94 | 95 | currentNode.Direction = direction; 96 | 97 | heap.Add(nextNode); 98 | } 99 | 100 | private double ManhattanDistance(INode currentNode, INode end) 101 | { 102 | var dx = Math.Abs(end.Row - currentNode.Row); 103 | var dy = Math.Abs(end.Col - currentNode.Col); 104 | return dx + dy; 105 | } 106 | 107 | private (double weight, NodeDirection? Direction) ApplyWeightAndDirection(AStarNode nodeOne, INode nodeTwo) 108 | { 109 | var x1 = nodeOne.Row; 110 | var y1 = nodeOne.Col; 111 | var x2 = nodeTwo.Row; 112 | var y2 = nodeTwo.Col; 113 | 114 | if (x2 < x1 115 | && y1 == y2) 116 | { 117 | switch (nodeOne.Direction) 118 | { 119 | case NodeDirection.Up: 120 | return (1, NodeDirection.Up); 121 | case NodeDirection.Right: 122 | return (2, NodeDirection.Up); 123 | case NodeDirection.Left: 124 | return (2, NodeDirection.Up); 125 | case NodeDirection.Down: 126 | return (3, NodeDirection.Up); 127 | } 128 | } 129 | else if (x2 > x1 130 | && y1 == y2) 131 | { 132 | switch (nodeOne.Direction) 133 | { 134 | case NodeDirection.Up: 135 | return (3, NodeDirection.Down); 136 | case NodeDirection.Right: 137 | return (2, NodeDirection.Down); 138 | case NodeDirection.Left: 139 | return (2, NodeDirection.Down); 140 | case NodeDirection.Down: 141 | return (1, NodeDirection.Down); 142 | } 143 | } 144 | 145 | if (y2 < y1 146 | && x1 == x2) 147 | { 148 | switch (nodeOne.Direction) 149 | { 150 | case NodeDirection.Up: 151 | return (2, NodeDirection.Left); 152 | case NodeDirection.Right: 153 | return (3, NodeDirection.Left); 154 | case NodeDirection.Left: 155 | return (1, NodeDirection.Left); 156 | case NodeDirection.Down: 157 | return (2, NodeDirection.Left); 158 | } 159 | } 160 | else if (y2 > y1 161 | && x1 == x2) 162 | { 163 | switch (nodeOne.Direction) 164 | { 165 | case NodeDirection.Up: 166 | return (2, NodeDirection.Right); 167 | case NodeDirection.Right: 168 | return (1, NodeDirection.Right); 169 | case NodeDirection.Left: 170 | return (3, NodeDirection.Right); 171 | case NodeDirection.Down: 172 | return (2, NodeDirection.Right); 173 | } 174 | } 175 | 176 | return default; 177 | } 178 | } 179 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/PathFindingAlgorithms/Implementations/BaseService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.PathFindingAlgorithms.Implementations 2 | { 3 | using System.Collections.Generic; 4 | using Models.PathFinding; 5 | 6 | public abstract class BaseService 7 | { 8 | private protected IEnumerable GetAllNodesInShortestPathOrder(INode node) 9 | { 10 | var result = new Stack(); 11 | 12 | do 13 | { 14 | result.Push(node.PreviousNode); 15 | node = node.PreviousNode; 16 | } while (node.PreviousNode.PreviousNode != null); 17 | 18 | return result; 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/PathFindingAlgorithms/Implementations/BfsService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.PathFindingAlgorithms.Implementations 2 | { 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using Common.Utils; 6 | using Interfaces; 7 | using Models.PathFinding; 8 | using Models.PathFinding.Bfs; 9 | using Models.PathFinding.Enums; 10 | 11 | public class BfsService : BaseService, IBfsService 12 | { 13 | public Result FindPath(BfsServiceModel model) 14 | { 15 | if (!ValidationUtil.IsObjectValid(model)) 16 | { 17 | return null; 18 | } 19 | 20 | var startNode = model.StartNode; 21 | var endNode = model.EndNode; 22 | var grid = model.Grid; 23 | 24 | var allSteps = new HashSet(); 25 | var queue = new Queue(); 26 | queue.Enqueue(startNode); 27 | 28 | while (queue.Count != 0) 29 | { 30 | var currentNode = queue.Dequeue(); 31 | 32 | if (grid[currentNode.Row, currentNode.Col].NodeType == NodeType.Wall) 33 | { 34 | continue; 35 | } 36 | 37 | // Destination target found 38 | if (currentNode.Equals(endNode)) 39 | { 40 | allSteps.Remove(allSteps.ElementAt(0)); 41 | var shortestPathOrder = this.GetAllNodesInShortestPathOrder(currentNode); 42 | return new Result(allSteps, shortestPathOrder); 43 | } 44 | 45 | allSteps.Add(currentNode); 46 | 47 | // Up 48 | if (currentNode.Row - 1 >= 0 49 | && !grid[currentNode.Row - 1, currentNode.Col].IsVisited) 50 | { 51 | AddNodeToQueue(grid, queue, currentNode, currentNode.Row - 1, currentNode.Col); 52 | } 53 | 54 | // Right 55 | if (currentNode.Col + 1 < grid.GetLength(1) 56 | && !grid[currentNode.Row, currentNode.Col + 1].IsVisited) 57 | { 58 | AddNodeToQueue(grid, queue, currentNode, currentNode.Row, currentNode.Col + 1); 59 | } 60 | 61 | // Down 62 | if (currentNode.Row + 1 < grid.GetLength(0) 63 | && !grid[currentNode.Row + 1, currentNode.Col].IsVisited) 64 | { 65 | AddNodeToQueue(grid, queue, currentNode, currentNode.Row + 1, currentNode.Col); 66 | } 67 | 68 | // Left 69 | if (currentNode.Col - 1 >= 0 70 | && !grid[currentNode.Row, currentNode.Col - 1].IsVisited) 71 | { 72 | AddNodeToQueue(grid, queue, currentNode, currentNode.Row, currentNode.Col - 1); 73 | } 74 | } 75 | 76 | return new Result(allSteps); 77 | } 78 | 79 | private static void AddNodeToQueue( 80 | BfsNode[,] grid, 81 | Queue queue, 82 | BfsNode node, 83 | int nodeRow, 84 | int nodeCol) 85 | { 86 | queue.Enqueue(new BfsNode(nodeRow, nodeCol, node, node.Distance + 1)); 87 | grid[nodeRow, nodeCol].IsVisited = true; 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/PathFindingAlgorithms/Implementations/DfsService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.PathFindingAlgorithms.Implementations 2 | { 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using Common.Utils; 6 | using Interfaces; 7 | using Models.PathFinding; 8 | using Models.PathFinding.Dfs; 9 | using Models.PathFinding.Enums; 10 | 11 | public class DfsService : BaseService, IDfsService 12 | { 13 | public Result FindPath(DfsServiceModel model) 14 | { 15 | if (!ValidationUtil.IsObjectValid(model)) 16 | { 17 | return null; 18 | } 19 | 20 | var path = new List(); 21 | 22 | return this.PathFound(model.Grid, model.StartNode, model.EndNode, path) 23 | ? new Result(path, path) 24 | : new Result(path); 25 | } 26 | 27 | private bool PathFound( 28 | DfsNode[,] grid, 29 | INode node, 30 | INode endNode, 31 | ICollection path) 32 | { 33 | if (node.Equals(endNode)) 34 | { 35 | path.Remove(path.ElementAt(path.Count - 1)); 36 | return true; 37 | } 38 | 39 | var rowDirection = new[] { -1, 0, +1, 0 }; 40 | var columnDirection = new[] { 0, +1, 0, -1 }; 41 | for (var i = 0; i < 4; i++) 42 | { 43 | var currentRowDirection = node.Row + rowDirection[i]; 44 | var currentColDirection = node.Col + columnDirection[i]; 45 | 46 | if (!CanTraverse(grid, currentRowDirection, currentColDirection)) 47 | { 48 | continue; 49 | } 50 | 51 | var nextNode = grid[currentRowDirection, currentColDirection]; 52 | if (nextNode.IsVisited 53 | || nextNode.NodeType == NodeType.Wall) 54 | { 55 | continue; 56 | } 57 | 58 | nextNode.IsVisited = true; 59 | path.Add(nextNode); 60 | 61 | if (this.PathFound(grid, nextNode, endNode, path)) 62 | { 63 | return true; 64 | } 65 | } 66 | 67 | return false; 68 | } 69 | 70 | private static bool CanTraverse( 71 | DfsNode[,] grid, 72 | int currentRowDirection, 73 | int currentColDirection) 74 | => currentRowDirection >= 0 && currentColDirection >= 0 && currentRowDirection < grid.GetLength(0) && currentColDirection < grid.GetLength(1); 75 | } 76 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/PathFindingAlgorithms/Implementations/DijkstraService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.PathFindingAlgorithms.Implementations 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Common.DataStructures; 7 | using Common.Utils; 8 | using Interfaces; 9 | using Models.PathFinding; 10 | using Models.PathFinding.Dijkstra; 11 | using Models.PathFinding.Enums; 12 | 13 | public class DijkstraService : BaseService, IDijkstraService 14 | { 15 | private DijkstraNode endNode; 16 | private DijkstraNode startNode; 17 | 18 | public Result FindPath(DijkstraServiceModel model) 19 | { 20 | if (!ValidationUtil.IsObjectValid(model)) 21 | { 22 | return null; 23 | } 24 | 25 | this.startNode = model.StartNode; 26 | this.endNode = model.EndNode; 27 | var grid = model.Grid; 28 | 29 | var heap = new MinHeap(); 30 | var allSteps = new HashSet(); 31 | 32 | this.startNode.Distance = 0; 33 | this.startNode.IsVisited = true; 34 | heap.Add(this.startNode); 35 | 36 | while (heap.Count != 0) 37 | { 38 | var currentNode = heap.Pop(); 39 | 40 | if (grid[currentNode.Row, currentNode.Col].NodeType == NodeType.Wall) 41 | { 42 | continue; 43 | } 44 | 45 | // Destination target found 46 | if (currentNode.Equals(this.endNode)) 47 | { 48 | allSteps.Remove(allSteps.ElementAt(0)); 49 | return new Result(allSteps, this.GetAllNodesInShortestPathOrder(currentNode)); 50 | } 51 | 52 | allSteps.Add(currentNode); 53 | 54 | var rowDirection = new[] { -1, +1, 0, 0 }; 55 | var columnDirection = new[] { 0, 0, +1, -1 }; 56 | for (var i = 0; i < 4; i++) 57 | { 58 | var currentRowDirection = currentNode.Row + rowDirection[i]; 59 | var currentColDirection = currentNode.Col + columnDirection[i]; 60 | 61 | if (currentRowDirection < 0 62 | || currentColDirection < 0 63 | || currentRowDirection >= grid.GetLength(0) 64 | || currentColDirection >= grid.GetLength(1)) 65 | { 66 | continue; 67 | } 68 | 69 | var targetNode = grid[currentRowDirection, currentColDirection]; 70 | this.AddNodeToHeap(currentNode, targetNode, heap); 71 | } 72 | } 73 | 74 | return new Result(allSteps); 75 | } 76 | 77 | private void AddNodeToHeap( 78 | DijkstraNode currentNode, 79 | DijkstraNode targetNode, 80 | MinHeap heap) 81 | { 82 | if (targetNode.IsVisited 83 | || !(targetNode.Distance > currentNode.Distance)) 84 | { 85 | return; 86 | } 87 | 88 | var newDistance = currentNode.Distance + targetNode.Weight + this.AddAdditionalWeight(currentNode, targetNode); 89 | targetNode.Distance = newDistance < targetNode.Distance ? newDistance : int.MaxValue; 90 | 91 | targetNode.PreviousNode = currentNode; 92 | targetNode.IsVisited = true; 93 | heap.Add(targetNode); 94 | } 95 | 96 | private double AddAdditionalWeight( 97 | INode currentNode, 98 | INode targetNode) 99 | { 100 | /*This code computes the vector cross-product between the start to goal vector and the current point to goal vector. 101 | When these vectors don’t line up, the cross product will be larger. 102 | The result is that this code will give some slight preference to a path that lies along the STRAIGHT LINE 103 | path from the start to the goal.*.*/ 104 | 105 | var dx1 = currentNode.Row - targetNode.Row; 106 | var dy1 = currentNode.Col - targetNode.Col; 107 | var dx2 = this.startNode.Row - this.endNode.Row; 108 | var dy2 = this.startNode.Col - this.endNode.Col; 109 | var cross = Math.Abs(dx1 * dy2 - dx2 * dy1); 110 | return cross * 0.001; 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/PathFindingAlgorithms/Interfaces/IAstarService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.PathFindingAlgorithms.Interfaces 2 | { 3 | using Models.PathFinding; 4 | using Models.PathFinding.AStar; 5 | 6 | public interface IAStarService 7 | { 8 | Result FindPath(AStarServiceModel model); 9 | } 10 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/PathFindingAlgorithms/Interfaces/IBfsService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.PathFindingAlgorithms.Interfaces 2 | { 3 | using Models.PathFinding; 4 | using Models.PathFinding.Bfs; 5 | 6 | public interface IBfsService 7 | { 8 | Result FindPath(BfsServiceModel model); 9 | } 10 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/PathFindingAlgorithms/Interfaces/IDfsService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.PathFindingAlgorithms.Interfaces 2 | { 3 | using Models.PathFinding; 4 | using Models.PathFinding.Dfs; 5 | 6 | public interface IDfsService 7 | { 8 | Result FindPath(DfsServiceModel model); 9 | } 10 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/PathFindingAlgorithms/Interfaces/IDijkstraService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.PathFindingAlgorithms.Interfaces 2 | { 3 | using Models.PathFinding; 4 | using Models.PathFinding.Dijkstra; 5 | 6 | public interface IDijkstraService 7 | { 8 | Result FindPath(DijkstraServiceModel model); 9 | } 10 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/README.md: -------------------------------------------------------------------------------- 1 | # WARNING! 2 | Please keep in mind that the algorithms are adapted for a 2D grid and they are not the ___usual___ pathfinding/sorting algorithms. 3 | -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Implementations/BaseSortingService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Implementations 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Common; 7 | using Models.SortingAlgorithms; 8 | 9 | public class BaseSortingService 10 | { 11 | public Result GenerateResult(IEnumerable data, IEnumerable unsortedData, List swappingIndexes) 12 | where T : struct, 13 | IComparable, 14 | IComparable, 15 | IConvertible, 16 | IEquatable, 17 | IFormattable 18 | => data.SequenceEqual(unsortedData) 19 | ? new Result(NotificationMessages.SortingAlgorithms.DataAlreadySortedErrorMessage) 20 | : new Result(swappingIndexes); 21 | 22 | public void Swap(IList data, int firstIndex, int secondIndex) 23 | where T : struct, 24 | IComparable, 25 | IComparable, 26 | IConvertible, 27 | IEquatable, 28 | IFormattable 29 | { 30 | var firstElement = data[firstIndex]; 31 | data[firstIndex] = data[secondIndex]; 32 | data[secondIndex] = firstElement; 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Implementations/BubbleSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Implementations 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Common; 7 | using Interfaces; 8 | using Models.SortingAlgorithms; 9 | 10 | public class BubbleSortService : BaseSortingService, IBubbleSortService 11 | { 12 | private readonly List swappingIndexes = new List(); 13 | 14 | public Result Sort(T[] data) 15 | where T : struct, 16 | IComparable, 17 | IComparable, 18 | IConvertible, 19 | IEquatable, 20 | IFormattable 21 | { 22 | if (!data.Any()) 23 | { 24 | return new Result(NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 25 | } 26 | 27 | var unsortedData = new List(data); 28 | 29 | this.BubbleSort(data); 30 | 31 | return this.GenerateResult(data, unsortedData, this.swappingIndexes); 32 | } 33 | 34 | private void BubbleSort(IList data) 35 | where T : struct, 36 | IComparable, 37 | IComparable, 38 | IConvertible, 39 | IEquatable, 40 | IFormattable 41 | { 42 | for (var i = 1; i <= data.Count - 1; i++) 43 | { 44 | var isSortingMade = false; 45 | for (var j = 0; j < data.Count - 1; j++) 46 | { 47 | var firstElementIndex = j; 48 | var adjacentElementIndex = j + 1; 49 | if (data[firstElementIndex].CompareTo(data[adjacentElementIndex]) > 0) 50 | { 51 | this.Swap(data, firstElementIndex, adjacentElementIndex); 52 | this.swappingIndexes.Add(new[] { firstElementIndex, adjacentElementIndex }); 53 | 54 | isSortingMade = true; 55 | } 56 | } 57 | 58 | if (!isSortingMade) 59 | { 60 | break; 61 | } 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Implementations/HeapSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Implementations 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Common; 7 | using Interfaces; 8 | using Models.SortingAlgorithms; 9 | 10 | public class HeapSortService : BaseSortingService, IHeapSortService 11 | { 12 | private readonly List swappingIndexes = new List(); 13 | 14 | public Result Sort(T[] data) 15 | where T : struct, 16 | IComparable, 17 | IComparable, 18 | IConvertible, 19 | IEquatable, 20 | IFormattable 21 | { 22 | if (!data.Any()) 23 | { 24 | return new Result(NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 25 | } 26 | 27 | var unsortedArray = new List(data); 28 | 29 | this.HeapSort(data); 30 | 31 | return this.GenerateResult(data, unsortedArray, this.swappingIndexes); 32 | } 33 | 34 | private void HeapSort(IList data) 35 | where T : struct, 36 | IComparable, 37 | IComparable, 38 | IConvertible, 39 | IEquatable, 40 | IFormattable 41 | { 42 | //ALGORITHM: 43 | //1. Build a "max heap" out of the unsorted data (a heap with the largest value as the first node). 44 | //2. Swap the first element of the heap with the final element. That element, now at final position is considered sorted. 45 | // In effect, this makes the largest element, the last one in the considered range. 46 | //3. Decrease the range of considered elements (those still needing to be sorted) by 1. 47 | //4. Continue until the considered range of elements is 1. 48 | 49 | var length = data.Count - 1; 50 | for (var i = length / 2; i >= 0; i--) 51 | { 52 | this.Heapify(data, data.Count, i); 53 | } 54 | 55 | for (var i = length; i >= 0; i--) 56 | { 57 | this.Swap(data, 0, i); 58 | this.swappingIndexes.Add(new[] { 0, i }); 59 | this.Heapify(data, i, 0); 60 | } 61 | } 62 | 63 | private void Heapify(IList array, int length, int index) 64 | where T : struct, 65 | IComparable, 66 | IComparable, 67 | IConvertible, 68 | IEquatable, 69 | IFormattable 70 | { 71 | var largestElementIndex = index; 72 | var left = 2 * index + 1; 73 | var right = 2 * index + 2; 74 | 75 | if (left < length 76 | && array[left].CompareTo(array[largestElementIndex]) > 0) 77 | { 78 | largestElementIndex = left; 79 | } 80 | 81 | if (right < length 82 | && array[right].CompareTo(array[largestElementIndex]) > 0) 83 | { 84 | largestElementIndex = right; 85 | } 86 | 87 | if (largestElementIndex != index) 88 | { 89 | this.Swap(array, index, largestElementIndex); 90 | this.swappingIndexes.Add(new[] { index, largestElementIndex }); 91 | this.Heapify(array, length, largestElementIndex); 92 | } 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Implementations/MergeSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Implementations 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Common; 7 | using Interfaces; 8 | using Models.SortingAlgorithms; 9 | 10 | public class MergeSortService : BaseSortingService, IMergeSortService 11 | { 12 | private readonly List swappingIndexes = new List(); 13 | 14 | public Result Sort(T[] data) 15 | where T : struct, 16 | IComparable, 17 | IComparable, 18 | IConvertible, 19 | IEquatable, 20 | IFormattable 21 | { 22 | if (!data.Any()) 23 | { 24 | return new Result(NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 25 | } 26 | 27 | var unsortedArray = new List(data); 28 | 29 | this.MergeSort(0, data.Length - 1, data); 30 | 31 | return this.GenerateResult(data, unsortedArray, this.swappingIndexes); 32 | } 33 | 34 | private void MergeSort(int start, int end, T[] array) 35 | where T : struct, 36 | IComparable, 37 | IComparable, 38 | IConvertible, 39 | IEquatable, 40 | IFormattable 41 | { 42 | if (start < end) 43 | { 44 | var midPoint = (start + end) / 2; 45 | this.MergeSort(start, midPoint, array); 46 | this.MergeSort(midPoint + 1, end, array); 47 | this.Merge(array, start, midPoint, end); 48 | } 49 | } 50 | 51 | private void Merge(T[] array, int start, int midPoint, int end) 52 | where T : struct, 53 | IComparable, 54 | IComparable, 55 | IConvertible, 56 | IEquatable, 57 | IFormattable 58 | { 59 | var newArray = new MergeSortConciseModel[end - start + 1]; 60 | 61 | var leftSideIndex = start; 62 | var rightSideIndex = midPoint + 1; 63 | var index = 0; 64 | 65 | while (leftSideIndex <= midPoint 66 | && rightSideIndex <= end) 67 | { 68 | if (array[leftSideIndex].CompareTo(array[rightSideIndex]) < 0) 69 | { 70 | newArray[index] = new MergeSortConciseModel(array[leftSideIndex], leftSideIndex); 71 | leftSideIndex++; 72 | } 73 | else 74 | { 75 | newArray[index] = new MergeSortConciseModel(array[rightSideIndex], rightSideIndex); 76 | rightSideIndex++; 77 | } 78 | 79 | index++; 80 | } 81 | 82 | index = CopyRemainingElementsFromTheLeft(array, midPoint, leftSideIndex, newArray, index); 83 | CopyRemainingElementsFromTheRight(array, end, rightSideIndex, newArray, index); 84 | 85 | this.CopyElements(array, start, newArray); 86 | } 87 | 88 | private static void CopyRemainingElementsFromTheRight( 89 | IReadOnlyList array, 90 | int end, 91 | int rightSideIndex, 92 | IList> newArray, 93 | int index) 94 | where T : struct, 95 | IComparable, 96 | IComparable, 97 | IConvertible, 98 | IEquatable, 99 | IFormattable 100 | { 101 | while (rightSideIndex <= end) 102 | { 103 | newArray[index] = new MergeSortConciseModel(array[rightSideIndex], rightSideIndex); 104 | rightSideIndex++; 105 | index++; 106 | } 107 | } 108 | 109 | private static int CopyRemainingElementsFromTheLeft( 110 | IReadOnlyList array, 111 | int midPoint, 112 | int leftSideIndex, 113 | IList> newArray, 114 | int index) 115 | where T : struct, 116 | IComparable, 117 | IComparable, 118 | IConvertible, 119 | IEquatable, 120 | IFormattable 121 | { 122 | while (leftSideIndex <= midPoint) 123 | { 124 | newArray[index] = new MergeSortConciseModel(array[leftSideIndex], leftSideIndex); 125 | leftSideIndex++; 126 | index++; 127 | } 128 | 129 | return index; 130 | } 131 | 132 | private void CopyElements( 133 | IList array, 134 | int start, 135 | IReadOnlyList> newArray) 136 | where T : struct, 137 | IComparable, 138 | IComparable, 139 | IConvertible, 140 | IEquatable, 141 | IFormattable 142 | { 143 | for (var i = 0; i < newArray.Count; i++) 144 | { 145 | var element = newArray[i]; 146 | var swappingIndex = start + i; 147 | if (array[swappingIndex].CompareTo(element.Value) != 0) 148 | { 149 | this.AddSwappingIndexes(array, newArray, swappingIndex, element); 150 | } 151 | } 152 | } 153 | 154 | private void AddSwappingIndexes( 155 | IList array, 156 | IEnumerable> newArray, 157 | int swappingIndex, 158 | MergeSortConciseModel element) 159 | where T : struct, 160 | IComparable, 161 | IComparable, 162 | IConvertible, 163 | IEquatable, 164 | IFormattable 165 | { 166 | var temp = array[swappingIndex]; 167 | array[swappingIndex] = element.Value; 168 | array[element.CurrentIndex] = temp; 169 | 170 | this.swappingIndexes.Add(new[] { swappingIndex, element.CurrentIndex }); 171 | 172 | var elementsToIterateThrough = newArray.Where(x => x.Value.CompareTo(temp) == 0); 173 | foreach (var item in elementsToIterateThrough) 174 | { 175 | item.CurrentIndex = element.CurrentIndex; 176 | if (elementsToIterateThrough.Count() > 1) 177 | { 178 | element.CurrentIndex++; 179 | } 180 | } 181 | 182 | element.CurrentIndex = swappingIndex; 183 | } 184 | } 185 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Implementations/QuickSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Implementations 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Common; 7 | using Interfaces; 8 | using Models.SortingAlgorithms; 9 | 10 | public class QuickSortService : BaseSortingService, IQuickSortService 11 | { 12 | private readonly List result = new List(); 13 | 14 | public Result Sort(T[] data) 15 | where T : struct, 16 | IComparable, 17 | IComparable, 18 | IConvertible, 19 | IEquatable, 20 | IFormattable 21 | { 22 | if (!data.Any()) 23 | { 24 | return new Result(NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 25 | } 26 | 27 | var unsortedData = new List(data); 28 | 29 | this.QuickSort(data, 0, data.Length - 1); 30 | 31 | return this.GenerateResult(data, unsortedData, this.result); 32 | } 33 | 34 | private void QuickSort(IList array, int start, int end) 35 | where T : struct, 36 | IComparable, 37 | IComparable, 38 | IConvertible, 39 | IEquatable, 40 | IFormattable 41 | { 42 | if (start < end) 43 | { 44 | var partitionIndex = this.Partition(array, start, end); 45 | this.QuickSort(array, start, partitionIndex - 1); 46 | this.QuickSort(array, partitionIndex + 1, end); 47 | } 48 | } 49 | 50 | private int Partition(IList array, int start, int end) 51 | where T : struct, 52 | IComparable, 53 | IComparable, 54 | IConvertible, 55 | IEquatable, 56 | IFormattable 57 | { 58 | var pivot = array[end]; 59 | var partitionIndex = start; 60 | 61 | for (var i = start; i < end; i++) 62 | { 63 | if (array[i].CompareTo(pivot) < 0) 64 | { 65 | this.Swap(array, i, partitionIndex); 66 | if (i != partitionIndex) 67 | { 68 | this.result.Add(new[] { i, partitionIndex }); 69 | } 70 | 71 | partitionIndex++; 72 | } 73 | } 74 | 75 | this.Swap(array, partitionIndex, end); 76 | if (partitionIndex != end) 77 | { 78 | this.result.Add(new[] { partitionIndex, end }); 79 | } 80 | 81 | return partitionIndex; 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Implementations/SelectionSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Implementations 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using Common; 7 | using Interfaces; 8 | using Models.SortingAlgorithms; 9 | 10 | public class SelectionSortService : BaseSortingService, ISelectionSortService 11 | { 12 | private readonly List swappingIndexes = new List(); 13 | 14 | public Result Sort(T[] data) 15 | where T : struct, 16 | IComparable, 17 | IComparable, 18 | IConvertible, 19 | IEquatable, 20 | IFormattable 21 | { 22 | if (!data.Any()) 23 | { 24 | return new Result(NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 25 | } 26 | 27 | var unsortedData = new List(data); 28 | 29 | this.SelectionSort(data); 30 | 31 | return this.GenerateResult(data, unsortedData, this.swappingIndexes); 32 | } 33 | 34 | private void SelectionSort(T[] data) 35 | where T : struct, 36 | IComparable, 37 | IComparable, 38 | IConvertible, 39 | IEquatable, 40 | IFormattable 41 | { 42 | for (var i = 0; i < data.Length - 1; i++) 43 | { 44 | var smallestElementIndex = this.GetIndexOfSmallestElement(data, i); 45 | 46 | // If there's no smaller element than the current - continue 47 | if (smallestElementIndex == i) 48 | { 49 | continue; 50 | } 51 | 52 | this.swappingIndexes.Add(new[] { i, smallestElementIndex }); 53 | this.Swap(data, i, smallestElementIndex); 54 | } 55 | } 56 | 57 | private int GetIndexOfSmallestElement(IReadOnlyList data, int currentSmallestElementIndex) 58 | where T : struct, 59 | IComparable, 60 | IComparable, 61 | IConvertible, 62 | IEquatable, 63 | IFormattable 64 | { 65 | for (var i = currentSmallestElementIndex + 1; i < data.Count; i++) 66 | { 67 | if (data[currentSmallestElementIndex].CompareTo(data[i]) > 0) 68 | { 69 | currentSmallestElementIndex = i; 70 | } 71 | } 72 | 73 | return currentSmallestElementIndex; 74 | } 75 | } 76 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Interfaces/IBubbleSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Interfaces 2 | { 3 | using System; 4 | using Models.SortingAlgorithms; 5 | 6 | public interface IBubbleSortService 7 | { 8 | Result Sort(T[] data) 9 | where T : struct, 10 | IComparable, 11 | IComparable, 12 | IConvertible, 13 | IEquatable, 14 | IFormattable; 15 | } 16 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Interfaces/IHeapSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Interfaces 2 | { 3 | using System; 4 | using Models.SortingAlgorithms; 5 | 6 | public interface IHeapSortService 7 | { 8 | Result Sort(T[] data) 9 | where T : struct, 10 | IComparable, 11 | IComparable, 12 | IConvertible, 13 | IEquatable, 14 | IFormattable; 15 | } 16 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Interfaces/IMergeSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Interfaces 2 | { 3 | using System; 4 | using Models.SortingAlgorithms; 5 | 6 | public interface IMergeSortService 7 | { 8 | Result Sort(T[] array) 9 | where T : struct, 10 | IComparable, 11 | IComparable, 12 | IConvertible, 13 | IEquatable, 14 | IFormattable; 15 | } 16 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Interfaces/IQuickSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Interfaces 2 | { 3 | using System; 4 | using Models.SortingAlgorithms; 5 | 6 | public interface IQuickSortService 7 | { 8 | Result Sort(T[] data) 9 | where T : struct, 10 | IComparable, 11 | IComparable, 12 | IConvertible, 13 | IEquatable, 14 | IFormattable; 15 | } 16 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Services/AlgoVisualizer.Services/SortingAlgorithms/Interfaces/ISelectionSortService.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.SortingAlgorithms.Interfaces 2 | { 3 | using System; 4 | using Models.SortingAlgorithms; 5 | 6 | public interface ISelectionSortService 7 | { 8 | Result Sort(T[] data) 9 | where T : struct, 10 | IComparable, 11 | IComparable, 12 | IConvertible, 13 | IEquatable, 14 | IFormattable; 15 | } 16 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Tests/AlgoVisualizer.Services.Tests/AlgoVisualizer.Services.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /AlgoVisualizer/Tests/AlgoVisualizer.Services.Tests/BaseTest.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.Tests 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | 6 | public abstract class BaseTest 7 | { 8 | private readonly Random random = new Random(); 9 | 10 | protected int[] GenerateSortedArray(int count) 11 | { 12 | var data = new int[count]; 13 | 14 | for (var i = 0; i < count; i++) 15 | { 16 | data[i] = i; 17 | } 18 | 19 | return data; 20 | } 21 | 22 | protected int[] GenerateRandomArray(int count) 23 | { 24 | var data = new int[count]; 25 | 26 | for (var i = 0; i < count; i++) 27 | { 28 | data[i] = this.random.Next(1, 1500); 29 | } 30 | 31 | return data; 32 | } 33 | 34 | protected void Swap(IList data, int firstIndex, int secondIndex) 35 | where T : struct, 36 | IComparable, 37 | IComparable, 38 | IConvertible, 39 | IEquatable, 40 | IFormattable 41 | { 42 | var firstElement = data[firstIndex]; 43 | data[firstIndex] = data[secondIndex]; 44 | data[secondIndex] = firstElement; 45 | } 46 | 47 | protected void SortArrayWithGivenIndexes(IEnumerable swapIndexes, IList untouchedData) 48 | { 49 | foreach (var swappingIndexes in swapIndexes) 50 | { 51 | var firstIndex = swappingIndexes[0]; 52 | var secondIndex = swappingIndexes[1]; 53 | this.Swap(untouchedData, firstIndex, secondIndex); 54 | } 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /AlgoVisualizer/Tests/AlgoVisualizer.Services.Tests/SortingAlgorithmsTests/BubbleSortServiceTests.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.Tests.SortingAlgorithmsTests 2 | { 3 | using System.Collections.Generic; 4 | using Common; 5 | using FluentAssertions; 6 | using Models.SortingAlgorithms; 7 | using SortingAlgorithms.Implementations; 8 | using SortingAlgorithms.Interfaces; 9 | using Xunit; 10 | 11 | public class BubbleSortServiceTests : BaseTest 12 | { 13 | private readonly IBubbleSortService bubbleSortService; 14 | 15 | public BubbleSortServiceTests() 16 | { 17 | this.bubbleSortService = new BubbleSortService(); 18 | } 19 | 20 | [Fact] 21 | public void Sort_With_ValidInput_Should_Not_Return_ErrorMessage() 22 | { 23 | // Arrange 24 | const int arrayLength = 50; 25 | var data = this.GenerateRandomArray(arrayLength); 26 | 27 | // Act 28 | var result = this.bubbleSortService.Sort(data); 29 | 30 | // Assert 31 | result 32 | .Should() 33 | .Match(x => x.As().ErrorMessage == null); 34 | } 35 | 36 | [Fact] 37 | public void Sort_With_ValidInput_Should_Return_Correct_SwapIndexes() 38 | { 39 | // Arrange 40 | const int arrayLength = 5; 41 | var data = this.GenerateRandomArray(arrayLength); 42 | var untouchedData = new List(data); 43 | 44 | // Act 45 | var result = this.bubbleSortService.Sort(data); 46 | 47 | // Sort the array with the given indexes 48 | foreach (var swappingIndexes in result.SwapIndexes) 49 | { 50 | var firstIndex = swappingIndexes[0]; 51 | var secondIndex = swappingIndexes[1]; 52 | this.Swap(untouchedData, firstIndex, secondIndex); 53 | } 54 | 55 | // Assert 56 | untouchedData 57 | .Should() 58 | .BeInAscendingOrder(); 59 | } 60 | 61 | [Fact] 62 | public void Sort_With_ValidInput_Should_Return_SortedData() 63 | { 64 | // Arrange 65 | const int arrayLength = 5; 66 | var data = this.GenerateRandomArray(arrayLength); 67 | 68 | // Act 69 | this.bubbleSortService.Sort(data); 70 | 71 | // Assert 72 | data 73 | .Should() 74 | .BeInAscendingOrder(); 75 | } 76 | 77 | [Fact] 78 | public void Sort_With_ValidInput_Should_Return_Correct_TotalSwaps() 79 | { 80 | // Arrange 81 | const int expectedTotalSwaps = 3; 82 | 83 | // We should swap 84 | // 1. Elements 50, 10 with indexes 0 and 1 85 | // 2. Elements 50, 30 with indexes 1 and 2 86 | // 3. Elements 50, 40 with indexes 2 and 3 87 | var data = new int[] { 50, 10, 30, 40, 90 }; 88 | 89 | // Act 90 | var result = this.bubbleSortService.Sort(data); 91 | 92 | // Assert 93 | result 94 | .TotalSwaps 95 | .Should() 96 | .Be(expectedTotalSwaps); 97 | } 98 | 99 | [Fact] 100 | public void Sort_With_AlreadySortedData_Should_Return_DataAlreadySortedErrorMessage() 101 | { 102 | // Arrange 103 | const int arrayLength = 50; 104 | var sortedData = this.GenerateSortedArray(arrayLength); 105 | 106 | // Act 107 | var result = this.bubbleSortService.Sort(sortedData); 108 | 109 | // Assert 110 | result 111 | .Should() 112 | .Match(x => x.As().ErrorMessage != null) 113 | .And 114 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.DataAlreadySortedErrorMessage); 115 | } 116 | 117 | [Fact] 118 | public void Sort_With_NoElements_Should_Return_EmptyArrayErrorMessage() 119 | { 120 | // Act 121 | var result = this.bubbleSortService.Sort(new int[0]); 122 | 123 | // Assert 124 | result 125 | .Should() 126 | .Match(x => x.As().ErrorMessage != null) 127 | .And 128 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 129 | } 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /AlgoVisualizer/Tests/AlgoVisualizer.Services.Tests/SortingAlgorithmsTests/HeapSortServiceTests.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.Tests.SortingAlgorithmsTests 2 | { 3 | using System.Collections.Generic; 4 | using Common; 5 | using FluentAssertions; 6 | using Models.SortingAlgorithms; 7 | using SortingAlgorithms.Implementations; 8 | using SortingAlgorithms.Interfaces; 9 | using Xunit; 10 | 11 | public class HeapSortServiceTests : BaseTest 12 | { 13 | private readonly IHeapSortService heapSortService; 14 | 15 | public HeapSortServiceTests() 16 | { 17 | this.heapSortService = new HeapSortService(); 18 | } 19 | 20 | [Fact] 21 | public void Sort_With_AlreadySortedData_Should_Return_DataAlreadySortedErrorMessage() 22 | { 23 | // Arrange 24 | const int arrayLength = 49; 25 | var sortedData = this.GenerateSortedArray(arrayLength); 26 | 27 | // Act 28 | var result = this.heapSortService.Sort(sortedData); 29 | 30 | // Assert 31 | result 32 | .Should() 33 | .Match(x => x.As().ErrorMessage != null) 34 | .And 35 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.DataAlreadySortedErrorMessage); 36 | } 37 | 38 | [Fact] 39 | public void Sort_With_NoElements_Should_Return_EmptyArrayErrorMessage() 40 | { 41 | // Act 42 | var result = this.heapSortService.Sort(new int[0]); 43 | 44 | // Assert 45 | result 46 | .Should() 47 | .Match(x => x.As().ErrorMessage != null) 48 | .And 49 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 50 | } 51 | 52 | [Fact] 53 | public void Sort_With_ValidInput_Should_Not_Return_ErrorMessage() 54 | { 55 | // Arrange 56 | const int arrayLength = 50; 57 | var data = this.GenerateRandomArray(arrayLength); 58 | 59 | // Act 60 | var result = this.heapSortService.Sort(data); 61 | 62 | // Assert 63 | result 64 | .Should() 65 | .Match(x => x.As().ErrorMessage == null); 66 | } 67 | 68 | [Fact] 69 | public void Sort_With_ValidInput_Should_Return_Correct_SwapIndexes() 70 | { 71 | // Arrange 72 | const int arrayLength = 4; 73 | var data = this.GenerateRandomArray(arrayLength); 74 | var untouchedData = new List(data); 75 | 76 | // Act 77 | var result = this.heapSortService.Sort(data); 78 | 79 | // Sort the array with the given indexes 80 | this.SortArrayWithGivenIndexes(result.SwapIndexes, untouchedData); 81 | 82 | // Assert 83 | untouchedData 84 | .Should() 85 | .BeInAscendingOrder(); 86 | } 87 | 88 | [Fact] 89 | public void Sort_With_ValidInput_Should_Return_Correct_TotalSwaps() 90 | { 91 | // Arrange 92 | const int expectedTotalSwaps = 10; 93 | 94 | // We should swap 95 | // 1. Indexes 1 and 4 96 | // 2. Indexes 0 and 1 97 | // 3. Indexes 0 and 4 98 | // 4. Indexes 0 and 1 99 | // 6. Indexes 1 and 3 100 | // 7. Indexes 0 and 3 101 | // 8. Indexes 0 and 1 102 | // 9. Indexes 0 and 2 103 | // 10. Indexes 0 and 1 104 | // 11. Indexes 0 and 0 105 | var data = new[] { 50, 10, 30, 40, 90 }; 106 | 107 | // Act 108 | var result = this.heapSortService.Sort(data); 109 | 110 | // Assert 111 | result 112 | .TotalSwaps 113 | .Should() 114 | .Be(expectedTotalSwaps); 115 | } 116 | 117 | [Fact] 118 | public void Sort_With_ValidInput_Should_Return_SortedData() 119 | { 120 | // Arrange 121 | const int arrayLength = 40; 122 | var data = this.GenerateRandomArray(arrayLength); 123 | 124 | // Act 125 | this.heapSortService.Sort(data); 126 | 127 | // Assert 128 | data 129 | .Should() 130 | .BeInAscendingOrder(); 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /AlgoVisualizer/Tests/AlgoVisualizer.Services.Tests/SortingAlgorithmsTests/MergeSortServiceTests.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.Tests.SortingAlgorithmsTests 2 | { 3 | using System.Collections.Generic; 4 | using Common; 5 | using FluentAssertions; 6 | using Models.SortingAlgorithms; 7 | using SortingAlgorithms.Implementations; 8 | using SortingAlgorithms.Interfaces; 9 | using Xunit; 10 | 11 | public class MergeSortServiceTests : BaseTest 12 | { 13 | private readonly IMergeSortService mergeSortService; 14 | 15 | public MergeSortServiceTests() 16 | { 17 | this.mergeSortService = new MergeSortService(); 18 | } 19 | 20 | [Fact] 21 | public void Sort_With_AlreadySortedData_Should_Return_DataAlreadySortedErrorMessage() 22 | { 23 | // Arrange 24 | const int arrayLength = 49; 25 | var sortedData = this.GenerateSortedArray(arrayLength); 26 | 27 | // Act 28 | var result = this.mergeSortService.Sort(sortedData); 29 | 30 | // Assert 31 | result 32 | .Should() 33 | .Match(x => x.As().ErrorMessage != null) 34 | .And 35 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.DataAlreadySortedErrorMessage); 36 | } 37 | 38 | [Fact] 39 | public void Sort_With_NoElements_Should_Return_EmptyArrayErrorMessage() 40 | { 41 | // Act 42 | var result = this.mergeSortService.Sort(new int[0]); 43 | 44 | // Assert 45 | result 46 | .Should() 47 | .Match(x => x.As().ErrorMessage != null) 48 | .And 49 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 50 | } 51 | 52 | [Fact] 53 | public void Sort_With_ValidInput_Should_Not_Return_ErrorMessage() 54 | { 55 | // Arrange 56 | const int arrayLength = 50; 57 | var data = this.GenerateRandomArray(arrayLength); 58 | 59 | // Act 60 | var result = this.mergeSortService.Sort(data); 61 | 62 | // Assert 63 | result 64 | .Should() 65 | .Match(x => x.As().ErrorMessage == null); 66 | } 67 | 68 | [Fact] 69 | public void Sort_With_ValidInput_Should_Return_Correct_SwapIndexes() 70 | { 71 | // Arrange 72 | const int arrayLength = 10; 73 | var data = this.GenerateRandomArray(arrayLength); 74 | var untouchedData = new List(data); 75 | 76 | // Act 77 | var result = this.mergeSortService.Sort(data); 78 | 79 | // Sort the array with the given indexes 80 | this.SortArrayWithGivenIndexes(result.SwapIndexes, untouchedData); 81 | 82 | // Assert 83 | untouchedData 84 | .Should() 85 | .BeInAscendingOrder(); 86 | } 87 | 88 | [Fact] 89 | public void Sort_With_ValidInput_Should_Return_Correct_TotalSwaps() 90 | { 91 | // Arrange 92 | const int expectedTotalSwaps = 6; 93 | 94 | // We should swap 95 | // 1. Indexes 3 and 4 96 | // 2. Indexes 4 and 5 97 | // 3. Indexes 0 and 3 98 | // 4. Indexes 1 and 4 99 | // 5. Indexes 2 and 3 100 | // 6. Indexes 3 and 5 101 | var data = new[] { 20, 80, 100, 30, 9, 10 }; 102 | 103 | // Act 104 | var result = this.mergeSortService.Sort(data)?.TotalSwaps; 105 | 106 | // Assert 107 | result 108 | .Should() 109 | .Be(expectedTotalSwaps); 110 | } 111 | 112 | [Fact] 113 | public void Sort_With_ValidInput_Should_Return_SortedData() 114 | { 115 | // Arrange 116 | const int arrayLength = 30; 117 | var data = this.GenerateRandomArray(arrayLength); 118 | 119 | // Act 120 | this.mergeSortService.Sort(data); 121 | 122 | // Assert 123 | data 124 | .Should() 125 | .BeInAscendingOrder(); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /AlgoVisualizer/Tests/AlgoVisualizer.Services.Tests/SortingAlgorithmsTests/QuickSortServiceTests.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.Tests.SortingAlgorithmsTests 2 | { 3 | using System.Collections.Generic; 4 | using Common; 5 | using FluentAssertions; 6 | using Models.SortingAlgorithms; 7 | using SortingAlgorithms.Implementations; 8 | using SortingAlgorithms.Interfaces; 9 | using Xunit; 10 | 11 | public class QuickSortServiceTests : BaseTest 12 | { 13 | private readonly IQuickSortService quickSortService; 14 | 15 | public QuickSortServiceTests() 16 | { 17 | this.quickSortService = new QuickSortService(); 18 | } 19 | 20 | [Fact] 21 | public void Sort_With_AlreadySortedData_Should_Return_DataAlreadySortedErrorMessage() 22 | { 23 | // Arrange 24 | const int arrayLength = 49; 25 | var sortedData = this.GenerateSortedArray(arrayLength); 26 | 27 | // Act 28 | var result = this.quickSortService.Sort(sortedData); 29 | 30 | // Assert 31 | result 32 | .Should() 33 | .Match(x => x.As().ErrorMessage != null) 34 | .And 35 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.DataAlreadySortedErrorMessage); 36 | } 37 | 38 | [Fact] 39 | public void Sort_With_NoElements_Should_Return_EmptyArrayErrorMessage() 40 | { 41 | // Act 42 | var result = this.quickSortService.Sort(new int[0]); 43 | 44 | // Assert 45 | result 46 | .Should() 47 | .Match(x => x.As().ErrorMessage != null) 48 | .And 49 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 50 | } 51 | 52 | [Fact] 53 | public void Sort_With_ValidInput_Should_Not_Return_ErrorMessage() 54 | { 55 | // Arrange 56 | const int arrayLength = 100_000; 57 | var data = this.GenerateRandomArray(arrayLength); 58 | 59 | // Act 60 | var result = this.quickSortService.Sort(data); 61 | 62 | // Assert 63 | result 64 | .Should() 65 | .Match(x => x.As().ErrorMessage == null); 66 | } 67 | 68 | [Fact] 69 | public void Sort_With_ValidInput_Should_Return_Correct_SwapIndexes() 70 | { 71 | // Arrange 72 | const int arrayLength = 100_000; 73 | var data = this.GenerateRandomArray(arrayLength); 74 | var untouchedData = new List(data); 75 | 76 | // Act 77 | var result = this.quickSortService.Sort(data); 78 | 79 | // Sort the array with the given indexes 80 | this.SortArrayWithGivenIndexes(result.SwapIndexes, untouchedData); 81 | 82 | // Assert 83 | untouchedData 84 | .Should() 85 | .BeInAscendingOrder(); 86 | } 87 | 88 | [Fact] 89 | public void Sort_With_ValidInput_Should_Return_Correct_TotalSwaps() 90 | { 91 | // Arrange 92 | const int expectedTotalSwaps = 6; 93 | 94 | // We should swap 95 | // 1. Indexes 4 and 0 96 | // 2. Indexes 1 and 5 97 | // 3. Indexes 3 and 2 98 | // 4. Indexes 4 and 3 99 | // 5. Indexes 4 and 5 100 | // 6. Indexes 2 and 3 101 | var data = new[] { 20, 80, 100, 30, 9, 10 }; 102 | 103 | // Act 104 | var result = this.quickSortService.Sort(data)?.TotalSwaps; 105 | 106 | // Assert 107 | result 108 | .Should() 109 | .Be(expectedTotalSwaps); 110 | } 111 | 112 | [Fact] 113 | public void Sort_With_ValidInput_Should_Return_SortedData() 114 | { 115 | // Arrange 116 | const int arrayLength = 100_000; 117 | var data = this.GenerateRandomArray(arrayLength); 118 | 119 | // Act 120 | this.quickSortService.Sort(data); 121 | 122 | // Assert 123 | data 124 | .Should() 125 | .BeInAscendingOrder(); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /AlgoVisualizer/Tests/AlgoVisualizer.Services.Tests/SortingAlgorithmsTests/SelectionSortServiceTests.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Services.Tests.SortingAlgorithmsTests 2 | { 3 | using System; 4 | using System.Collections.Generic; 5 | using Common; 6 | using FluentAssertions; 7 | using Models.SortingAlgorithms; 8 | using SortingAlgorithms.Implementations; 9 | using SortingAlgorithms.Interfaces; 10 | using Xunit; 11 | 12 | public class SelectionSortServiceTests : BaseTest 13 | { 14 | private readonly ISelectionSortService selectionSortService; 15 | 16 | public SelectionSortServiceTests() 17 | { 18 | this.selectionSortService = new SelectionSortService(); 19 | } 20 | 21 | [Fact] 22 | public void Sort_With_AlreadySortedData_Should_Return_DataAlreadySortedErrorMessage() 23 | { 24 | // Arrange 25 | const int arrayLength = 10000; 26 | var sortedData = this.GenerateSortedArray(arrayLength); 27 | 28 | // Act 29 | var result = this.selectionSortService.Sort(sortedData); 30 | 31 | // Assert 32 | result 33 | .Should() 34 | .Match(x => x.As().ErrorMessage != null) 35 | .And 36 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.DataAlreadySortedErrorMessage); 37 | } 38 | 39 | [Fact] 40 | public void Sort_With_NoElements_Should_Return_EmptyArrayErrorMessage() 41 | { 42 | // Act 43 | var result = this.selectionSortService.Sort(Array.Empty()); 44 | 45 | // Assert 46 | result 47 | .Should() 48 | .Match(x => x.As().ErrorMessage != null) 49 | .And 50 | .Match(x => x.As().ErrorMessage == NotificationMessages.SortingAlgorithms.EmptyArrayErrorMessage); 51 | } 52 | 53 | [Fact] 54 | public void Sort_With_ValidInput_Should_Not_Return_ErrorMessage() 55 | { 56 | // Arrange 57 | const int arrayLength = 1000; 58 | var data = this.GenerateRandomArray(arrayLength); 59 | 60 | // Act 61 | var result = this.selectionSortService.Sort(data); 62 | 63 | // Assert 64 | result 65 | .Should() 66 | .Match(x => x.As().ErrorMessage == null); 67 | } 68 | 69 | [Fact] 70 | public void Sort_With_ValidInput_Should_Return_Correct_SwapIndexes() 71 | { 72 | // Arrange 73 | const int arrayLength = 10000; 74 | var data = this.GenerateRandomArray(arrayLength); 75 | var unmodifiedData = new List(data); 76 | 77 | // Act 78 | var result = this.selectionSortService.Sort(data); 79 | 80 | // Sort the array with the given indexes 81 | this.SortArrayWithGivenIndexes(result.SwapIndexes, unmodifiedData); 82 | 83 | // Assert 84 | unmodifiedData 85 | .Should() 86 | .BeInAscendingOrder(); 87 | } 88 | 89 | [Fact] 90 | public void Sort_With_ValidInput_Should_Return_Correct_TotalSwaps() 91 | { 92 | // Arrange 93 | const int expectedTotalSwaps = 3; 94 | 95 | // We should swap 96 | // 1. Indexes 0 and 1 97 | // 2. Indexes 2 and 5 98 | // 3. Indexes 4 and 5 99 | var data = new[] { 40, 10, 800, 400, 900, 100 }; 100 | 101 | // Act 102 | var result = this.selectionSortService.Sort(data)?.TotalSwaps; 103 | 104 | // Assert 105 | result 106 | .Should() 107 | .Be(expectedTotalSwaps); 108 | } 109 | 110 | [Fact] 111 | public void Sort_With_ValidInput_Should_Return_SortedData() 112 | { 113 | // Arrange 114 | const int arrayLength = 10000; 115 | var data = this.GenerateRandomArray(arrayLength); 116 | 117 | // Act 118 | this.selectionSortService.Sort(data); 119 | 120 | // Assert 121 | data 122 | .Should() 123 | .BeInAscendingOrder(); 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/AlgoVisualizer.Api.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netcoreapp3.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/MazeController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers 2 | { 3 | using AlgoVisualizer.Models.Maze; 4 | using AutoMapper; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Models; 7 | using Services; 8 | 9 | [ApiController] 10 | [Produces("application/json")] 11 | [Route("api/[controller]/[action]")] 12 | public class MazeController : ControllerBase 13 | { 14 | private readonly IMapper mapper; 15 | private readonly IMazeService mazeService; 16 | 17 | public MazeController(IMazeService mazeService, IMapper mapper) 18 | { 19 | this.mazeService = mazeService; 20 | this.mapper = mapper; 21 | } 22 | 23 | [HttpPost] 24 | public IActionResult Wall([FromBody] MazeRequestModel model) 25 | { 26 | var serviceModel = this.mapper.Map(model); 27 | var result = this.mazeService.GenerateWallMaze(serviceModel); 28 | 29 | if (result == null) 30 | { 31 | return this.BadRequest(); 32 | } 33 | 34 | return this.Ok(result); 35 | } 36 | 37 | [HttpPost] 38 | public IActionResult Weight([FromBody] MazeRequestModel model) 39 | { 40 | var serviceModel = this.mapper.Map(model); 41 | var result = this.mazeService.GenerateWeightMaze(serviceModel); 42 | 43 | if (result == null) 44 | { 45 | return this.BadRequest(); 46 | } 47 | 48 | return this.Ok(result); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/PathFinding/AStarController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.PathFinding 2 | { 3 | using AlgoVisualizer.Models.PathFinding.AStar; 4 | using AutoMapper; 5 | using Common; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Models; 8 | using Services.PathFindingAlgorithms.Interfaces; 9 | 10 | public class AStarController : BasePathFindingController 11 | { 12 | private readonly IAStarService aStarService; 13 | private readonly IMapper mapper; 14 | 15 | public AStarController(IMapper mapper, IAStarService aStarService) 16 | { 17 | this.mapper = mapper; 18 | this.aStarService = aStarService; 19 | } 20 | 21 | [HttpPost] 22 | public IActionResult Post([FromBody] PathFindingAlgorithmsRequestModel data) 23 | { 24 | var serviceModel = this.mapper.Map(data); 25 | var result = this.aStarService.FindPath(serviceModel); 26 | if (result?.AllNodesInShortestPathOrder == null) 27 | { 28 | return this.BadRequest(new ErrorModel(NotificationMessages.PathFindingAlgorithms.PathNotFound)); 29 | } 30 | 31 | return this.Ok(result); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/PathFinding/BasePathfindingController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.PathFinding 2 | { 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | [ApiController] 6 | [Produces("application/json")] 7 | [Route("api/pathfinding/[controller]")] 8 | public class BasePathFindingController : ControllerBase 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/PathFinding/BfsController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.PathFinding 2 | { 3 | using AlgoVisualizer.Models.PathFinding.Bfs; 4 | using AutoMapper; 5 | using Common; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Models; 8 | using Services.PathFindingAlgorithms.Interfaces; 9 | 10 | public class BfsController : BasePathFindingController 11 | { 12 | private readonly IBfsService bfsService; 13 | private readonly IMapper mapper; 14 | 15 | public BfsController(IMapper mapper, IBfsService bfsService) 16 | { 17 | this.mapper = mapper; 18 | this.bfsService = bfsService; 19 | } 20 | 21 | [HttpPost] 22 | public IActionResult Post(PathFindingAlgorithmsRequestModel data) 23 | { 24 | var serviceModel = this.mapper.Map(data); 25 | var result = this.bfsService.FindPath(serviceModel); 26 | if (result?.AllNodesInShortestPathOrder == null) 27 | { 28 | return this.BadRequest(new ErrorModel(NotificationMessages.PathFindingAlgorithms.PathNotFound)); 29 | } 30 | 31 | return this.Ok(result); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/PathFinding/DfsController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.PathFinding 2 | { 3 | using AlgoVisualizer.Models.PathFinding.Dfs; 4 | using AutoMapper; 5 | using Common; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Models; 8 | using Services.PathFindingAlgorithms.Interfaces; 9 | 10 | public class DfsController : BasePathFindingController 11 | { 12 | private readonly IDfsService dfsService; 13 | private readonly IMapper mapper; 14 | 15 | public DfsController(IMapper mapper, IDfsService dfsService) 16 | { 17 | this.mapper = mapper; 18 | this.dfsService = dfsService; 19 | } 20 | 21 | [HttpPost] 22 | public IActionResult Post(PathFindingAlgorithmsRequestModel data) 23 | { 24 | var serviceModel = this.mapper.Map(data); 25 | var result = this.dfsService.FindPath(serviceModel); 26 | if (result?.AllNodesInShortestPathOrder == null) 27 | { 28 | return this.BadRequest(new ErrorModel(NotificationMessages.PathFindingAlgorithms.PathNotFound)); 29 | } 30 | 31 | return this.Ok(result); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/PathFinding/DijkstraController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.PathFinding 2 | { 3 | using AlgoVisualizer.Models.PathFinding.Dijkstra; 4 | using AutoMapper; 5 | using Common; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Models; 8 | using Services.PathFindingAlgorithms.Interfaces; 9 | 10 | public class DijkstraController : BasePathFindingController 11 | { 12 | private readonly IDijkstraService dijkstraService; 13 | private readonly IMapper mapper; 14 | 15 | public DijkstraController(IMapper mapper, IDijkstraService dijkstraService) 16 | { 17 | this.mapper = mapper; 18 | this.dijkstraService = dijkstraService; 19 | } 20 | 21 | [HttpPost] 22 | public IActionResult Post(PathFindingAlgorithmsRequestModel data) 23 | { 24 | var serviceModel = this.mapper.Map(data); 25 | var result = this.dijkstraService.FindPath(serviceModel); 26 | if (result?.AllNodesInShortestPathOrder == null) 27 | { 28 | return this.BadRequest(new ErrorModel(NotificationMessages.PathFindingAlgorithms.PathNotFound)); 29 | } 30 | 31 | return this.Ok(result); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/SortingAlgorithms/BaseSortingAlgorithmsController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.SortingAlgorithms 2 | { 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | [ApiController] 6 | [Produces("application/json")] 7 | [Route("api/sortingAlgorithms/[controller]")] 8 | public class BaseSortingAlgorithmsController : ControllerBase 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/SortingAlgorithms/BubbleSortController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.SortingAlgorithms 2 | { 3 | using AutoMapper; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Models; 6 | using Services.SortingAlgorithms.Interfaces; 7 | 8 | public class BubbleSortController : BaseSortingAlgorithmsController 9 | { 10 | private readonly IBubbleSortService bubbleSortService; 11 | private readonly IMapper mapper; 12 | 13 | public BubbleSortController(IMapper mapper, IBubbleSortService bubbleSortService) 14 | { 15 | this.mapper = mapper; 16 | this.bubbleSortService = bubbleSortService; 17 | } 18 | 19 | [HttpPost] 20 | public IActionResult Post([FromBody] SortingAlgorithmsRequestModel data) 21 | { 22 | var serviceModel = this.bubbleSortService.Sort(data.Array); 23 | 24 | if (serviceModel.ErrorMessage != null) 25 | { 26 | return this.BadRequest(new ErrorModel(serviceModel.ErrorMessage)); 27 | } 28 | 29 | var result = this.mapper.Map(serviceModel); 30 | 31 | return this.Ok(result); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/SortingAlgorithms/HeapSortController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.SortingAlgorithms 2 | { 3 | using AutoMapper; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Models; 6 | using Services.SortingAlgorithms.Interfaces; 7 | 8 | public class HeapSortController : BaseSortingAlgorithmsController 9 | { 10 | private readonly IHeapSortService heapSortService; 11 | private readonly IMapper mapper; 12 | 13 | public HeapSortController(IMapper mapper, IHeapSortService heapSortService) 14 | { 15 | this.mapper = mapper; 16 | this.heapSortService = heapSortService; 17 | } 18 | 19 | [HttpPost] 20 | public IActionResult Post([FromBody] SortingAlgorithmsRequestModel data) 21 | { 22 | var serviceModel = this.heapSortService.Sort(data.Array); 23 | 24 | if (serviceModel.ErrorMessage != null) 25 | { 26 | return this.BadRequest(new ErrorModel(serviceModel.ErrorMessage)); 27 | } 28 | 29 | var result = this.mapper.Map(serviceModel); 30 | 31 | return this.Ok(result); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/SortingAlgorithms/MergeSortController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.SortingAlgorithms 2 | { 3 | using AutoMapper; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Models; 6 | using Services.SortingAlgorithms.Interfaces; 7 | 8 | public class MergeSortController : BaseSortingAlgorithmsController 9 | { 10 | private readonly IMapper mapper; 11 | private readonly IMergeSortService mergeSortService; 12 | 13 | public MergeSortController(IMapper mapper, IMergeSortService mergeSortService) 14 | { 15 | this.mapper = mapper; 16 | this.mergeSortService = mergeSortService; 17 | } 18 | 19 | [HttpPost] 20 | public IActionResult Post([FromBody] SortingAlgorithmsRequestModel data) 21 | { 22 | var serviceModel = this.mergeSortService.Sort(data.Array); 23 | if (serviceModel.ErrorMessage != null) 24 | { 25 | return this.BadRequest(new ErrorModel(serviceModel.ErrorMessage)); 26 | } 27 | 28 | var result = this.mapper.Map(serviceModel); 29 | 30 | return this.Ok(result); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/SortingAlgorithms/QuickSortController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.SortingAlgorithms 2 | { 3 | using AutoMapper; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Models; 6 | using Services.SortingAlgorithms.Interfaces; 7 | 8 | public class QuickSortController : BaseSortingAlgorithmsController 9 | { 10 | private readonly IMapper mapper; 11 | private readonly IQuickSortService quickSortService; 12 | 13 | public QuickSortController(IMapper mapper, IQuickSortService quickSortService) 14 | { 15 | this.mapper = mapper; 16 | this.quickSortService = quickSortService; 17 | } 18 | 19 | [HttpPost] 20 | public IActionResult Post([FromBody] SortingAlgorithmsRequestModel data) 21 | { 22 | var serviceModel = this.quickSortService.Sort(data.Array); 23 | if (serviceModel.ErrorMessage != null) 24 | { 25 | return this.BadRequest(new ErrorModel(serviceModel.ErrorMessage)); 26 | } 27 | 28 | var result = this.mapper.Map(serviceModel); 29 | 30 | return this.Ok(result); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Controllers/SortingAlgorithms/SelectionSortController.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Controllers.SortingAlgorithms 2 | { 3 | using AutoMapper; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Models; 6 | using Services.SortingAlgorithms.Interfaces; 7 | 8 | public class SelectionSortController : BaseSortingAlgorithmsController 9 | { 10 | private readonly IMapper mapper; 11 | private readonly ISelectionSortService selectionSortService; 12 | 13 | public SelectionSortController(IMapper mapper, ISelectionSortService selectionSortService) 14 | { 15 | this.mapper = mapper; 16 | this.selectionSortService = selectionSortService; 17 | } 18 | 19 | [HttpPost] 20 | public IActionResult Post([FromBody] SortingAlgorithmsRequestModel data) 21 | { 22 | var serviceModel = this.selectionSortService.Sort(data.Array); 23 | if (serviceModel.ErrorMessage != null) 24 | { 25 | return this.BadRequest(new ErrorModel(serviceModel.ErrorMessage)); 26 | } 27 | 28 | var result = this.mapper.Map(serviceModel); 29 | 30 | return this.Ok(result); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Infrastructure/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Infrastructure 2 | { 3 | using System.Linq; 4 | using System.Reflection; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Services; 7 | 8 | public static class ServiceCollectionExtensions 9 | { 10 | public static IServiceCollection AddDomainServices(this IServiceCollection services) 11 | { 12 | var assembly = Assembly.GetAssembly(typeof(IService)); 13 | 14 | AddAssemblyServices(services, assembly); 15 | 16 | return services; 17 | } 18 | 19 | public static IServiceCollection AddApplicationServices(this IServiceCollection services) 20 | { 21 | var assembly = Assembly.GetExecutingAssembly(); 22 | 23 | AddAssemblyServices(services, assembly); 24 | 25 | return services; 26 | } 27 | 28 | private static void AddAssemblyServices(IServiceCollection services, Assembly assembly) 29 | { 30 | var servicesToRegister = assembly 31 | .GetTypes() 32 | .Where(t => t.IsClass 33 | && !t.IsAbstract 34 | && t.GetInterfaces() 35 | .Any(i => i.Name == $"I{t.Name}")) 36 | .Select(t => new 37 | { 38 | Interface = t.GetInterface($"I{t.Name}"), 39 | Implementation = t 40 | }) 41 | .ToList(); 42 | 43 | servicesToRegister.ForEach(s => services.AddTransient(s.Interface, s.Implementation)); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Models/ErrorModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Models 2 | { 3 | using System.Collections.Generic; 4 | 5 | public class ErrorModel 6 | { 7 | public ErrorModel(List messages) 8 | { 9 | this.Messages = messages ?? new List(); 10 | } 11 | 12 | public ErrorModel(string message) 13 | { 14 | this.Messages = new List(); 15 | 16 | if (!string.IsNullOrWhiteSpace(message)) 17 | { 18 | this.Messages.Add(message); 19 | } 20 | } 21 | 22 | public bool IsSuccess => false; 23 | 24 | public List Messages { get; } 25 | } 26 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Models/MazeRequestModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Models 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | using AlgoVisualizer.Models.Maze; 5 | using Common.AutoMapping.Interfaces; 6 | 7 | public class MazeRequestModel : IMapWith 8 | { 9 | [Required] 10 | public NodeDto[,] Grid { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Models/NodeDto.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Models 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | using AlgoVisualizer.Models.Maze; 5 | using AlgoVisualizer.Models.PathFinding.AStar; 6 | using AlgoVisualizer.Models.PathFinding.Bfs; 7 | using AlgoVisualizer.Models.PathFinding.Dfs; 8 | using AlgoVisualizer.Models.PathFinding.Dijkstra; 9 | using Common; 10 | using Common.AutoMapping.Interfaces; 11 | 12 | public class NodeDto : 13 | IMapWith, 14 | IMapWith, 15 | IMapWith, 16 | IMapWith, 17 | IMapWith 18 | { 19 | [Required] 20 | public int Row { get; set; } 21 | 22 | [Required] 23 | public int Col { get; set; } 24 | 25 | [Required] 26 | public bool IsStart { get; set; } 27 | 28 | [Required] 29 | public bool IsEnd { get; set; } 30 | 31 | [Required] 32 | public bool IsWeight { get; set; } 33 | 34 | [Required] 35 | public bool IsWall { get; set; } 36 | 37 | public string NodeType 38 | => this.IsStart ? ModelConstants.StartNode 39 | : this.IsEnd ? ModelConstants.EndNode 40 | : this.IsWeight ? ModelConstants.WeightNode 41 | : this.IsWall ? ModelConstants.WallNode 42 | : null; 43 | 44 | public int Weight 45 | => this.IsWeight ? ModelConstants.WeightNodeValue : ModelConstants.DefaultWeightNodeValue; 46 | } 47 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Models/PathFindingAlgorithmsRequestModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Models 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | using AlgoVisualizer.Models.PathFinding.AStar; 5 | using AlgoVisualizer.Models.PathFinding.Bfs; 6 | using AlgoVisualizer.Models.PathFinding.Dfs; 7 | using AlgoVisualizer.Models.PathFinding.Dijkstra; 8 | using Common.AutoMapping.Interfaces; 9 | 10 | public class PathFindingAlgorithmsRequestModel : 11 | IMapWith, 12 | IMapWith, 13 | IMapWith, 14 | IMapWith 15 | { 16 | [Required] 17 | public NodeDto StartNode { get; set; } 18 | 19 | [Required] 20 | public NodeDto EndNode { get; set; } 21 | 22 | [Required] 23 | public NodeDto[,] Grid { get; set; } 24 | } 25 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Models/SortingAlgorithmsRequestModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Models 2 | { 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | public class SortingAlgorithmsRequestModel 6 | { 7 | [Required] 8 | public int[] Array { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Models/SortingAlgorithmsResponseModel.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api.Models 2 | { 3 | using System.Collections.Generic; 4 | using AlgoVisualizer.Models.SortingAlgorithms; 5 | using Common.AutoMapping.Interfaces; 6 | 7 | public class SortingAlgorithmsResponseModel : IMapWith 8 | { 9 | public List SwapIndexes { get; set; } 10 | 11 | public int TotalSwaps => this.SwapIndexes.Count; 12 | } 13 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Program.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api 2 | { 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.Hosting; 5 | 6 | public class Program 7 | { 8 | public static void Main(string[] args) 9 | => CreateHostBuilder(args).Build().Run(); 10 | 11 | public static IHostBuilder CreateHostBuilder(string[] args) 12 | => Host.CreateDefaultBuilder(args) 13 | .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup(); }); 14 | } 15 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:49915", 7 | "sslPort": 44370 8 | } 9 | }, 10 | "$schema": "http://json.schemastore.org/launchsettings.json", 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | } 18 | }, 19 | "AlgoVisualizer.Api": { 20 | "commandName": "Project", 21 | "launchBrowser": true, 22 | "environmentVariables": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | }, 25 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/Startup.cs: -------------------------------------------------------------------------------- 1 | namespace AlgoVisualizer.Api 2 | { 3 | using System.Reflection; 4 | using AutoMapper; 5 | using Common; 6 | using Common.AutoMapping.Profiles; 7 | using Infrastructure; 8 | using Microsoft.AspNetCore.Builder; 9 | using Microsoft.AspNetCore.Hosting; 10 | using Microsoft.Extensions.Configuration; 11 | using Microsoft.Extensions.DependencyInjection; 12 | using Microsoft.Extensions.Hosting; 13 | using Microsoft.Net.Http.Headers; 14 | 15 | public class Startup 16 | { 17 | public Startup(IConfiguration configuration) 18 | { 19 | this.Configuration = configuration; 20 | } 21 | 22 | public IConfiguration Configuration { get; } 23 | 24 | public void ConfigureServices(IServiceCollection services) 25 | { 26 | //TODO: Remove this when System.Text.Json supports deserialization for [,] matrices 27 | services 28 | .AddControllers() 29 | .AddNewtonsoftJson(); 30 | 31 | services 32 | .AddApplicationServices() 33 | .AddDomainServices() 34 | .AddAutoMapper(Assembly.GetAssembly(typeof(DefaultProfile))); 35 | 36 | services.AddCors(c => c.AddDefaultPolicy(options => 37 | { 38 | options.WithOrigins(GlobalConstants.ClientUrl); 39 | options.WithHeaders(HeaderNames.ContentType, HeaderNames.Accept); 40 | })); 41 | } 42 | 43 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 44 | { 45 | if (env.IsDevelopment()) 46 | { 47 | app.UseDeveloperExceptionPage(); 48 | } 49 | 50 | app.UseHttpsRedirection(); 51 | 52 | app.UseRouting(); 53 | app.UseCors(); 54 | app.UseAuthorization(); 55 | 56 | app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/AlgoVisualizer.Api/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*" 10 | } 11 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/.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 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/README.md: -------------------------------------------------------------------------------- 1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 2 | 3 | ## Available Scripts 4 | 5 | In the project directory, you can run: 6 | 7 | ### `npm start` 8 | 9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 11 | 12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console. 14 | 15 | ### `npm test` 16 | 17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 19 | 20 | ### `npm run build` 21 | 22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance. 24 | 25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed! 27 | 28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 29 | 30 | ### `npm run eject` 31 | 32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 33 | 34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 35 | 36 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 37 | 38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 39 | 40 | ## Learn More 41 | 42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 43 | 44 | To learn React, check out the [React documentation](https://reactjs.org/). 45 | 46 | ### Code Splitting 47 | 48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting 49 | 50 | ### Analyzing the Bundle Size 51 | 52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size 53 | 54 | ### Making a Progressive Web App 55 | 56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app 57 | 58 | ### Advanced Configuration 59 | 60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration 61 | 62 | ### Deployment 63 | 64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment 65 | 66 | ### `npm run build` fails to minify 67 | 68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify 69 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "algovisualizer", 3 | "version": "0.1.0", 4 | "private": true, 5 | "homepage": "http://melikpehlivanov.github.io/AlgorithmVisualizer", 6 | "dependencies": { 7 | "@testing-library/jest-dom": "^4.2.4", 8 | "@testing-library/react": "^9.4.0", 9 | "@testing-library/user-event": "^7.2.1", 10 | "bootstrap": "^4.4.1", 11 | "chart.js": "^2.9.3", 12 | "react": "^16.12.0", 13 | "react-bootstrap": "^1.0.0-beta.16", 14 | "react-chartjs-2": "^2.9.0", 15 | "react-dom": "^16.12.0", 16 | "react-router": "^5.1.2", 17 | "react-router-dom": "^5.1.2", 18 | "react-scripts": "3.3.0", 19 | "reactstrap": "^8.4.0" 20 | }, 21 | "scripts": { 22 | "predeploy": "npm run build", 23 | "deploy": "gh-pages -b gh-pages -d build", 24 | "start": "set HTTPS=true&&react-scripts start", 25 | "build": "react-scripts build", 26 | "test": "react-scripts test", 27 | "eject": "react-scripts eject" 28 | }, 29 | "eslintConfig": { 30 | "extends": "react-app" 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | }, 44 | "devDependencies": { 45 | "gh-pages": "^2.2.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/algorithms-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melikpehlivanov/AlgorithmVisualizer/b70abd3a07c0e164b2638681c9bd2985724bea01/AlgoVisualizer/Web/ClientApp/public/algorithms-menu.jpg -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/dumbbell-solid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melikpehlivanov/AlgorithmVisualizer/b70abd3a07c0e164b2638681c9bd2985724bea01/AlgoVisualizer/Web/ClientApp/public/favicon.ico -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/index.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 8 | 17 | 18 | 19 | 23 | 24 | 25 | 26 | 27 | AlgoVisualizer 28 | 29 | 30 | 33 |
34 | 35 | 36 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "AlgoVisualizer", 3 | "name": "AlgoVisualizer", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "dumbbell-solid.svg", 12 | "type": "image/x-icon" 13 | }, 14 | { 15 | "src": "algorithms-menu.jpg", 16 | "type": "image/x-icon" 17 | }, 18 | { 19 | "src": "set-start-end-nodes.gif", 20 | "type": "image/x-icon" 21 | }, 22 | { 23 | "src": "set-weight-and-wall-nodes.gif", 24 | "type": "image/x-icon" 25 | }, 26 | { 27 | "src": "point-a-b.jpg", 28 | "type": "image/x-icon" 29 | }, 30 | { 31 | "src": "navbar-menu.jpg", 32 | "type": "image/x-icon" 33 | }, 34 | { 35 | "src": "visualize-button.jpg", 36 | "type": "image/x-icon" 37 | } 38 | ], 39 | "start_url": "./index.html", 40 | "display": "standalone", 41 | "theme_color": "#000000", 42 | "background_color": "#ffffff" 43 | } 44 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/navbar-menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melikpehlivanov/AlgorithmVisualizer/b70abd3a07c0e164b2638681c9bd2985724bea01/AlgoVisualizer/Web/ClientApp/public/navbar-menu.jpg -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/point-a-b.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melikpehlivanov/AlgorithmVisualizer/b70abd3a07c0e164b2638681c9bd2985724bea01/AlgoVisualizer/Web/ClientApp/public/point-a-b.jpg -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/set-start-end-nodes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melikpehlivanov/AlgorithmVisualizer/b70abd3a07c0e164b2638681c9bd2985724bea01/AlgoVisualizer/Web/ClientApp/public/set-start-end-nodes.gif -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/set-weight-and-wall-nodes.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melikpehlivanov/AlgorithmVisualizer/b70abd3a07c0e164b2638681c9bd2985724bea01/AlgoVisualizer/Web/ClientApp/public/set-weight-and-wall-nodes.gif -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/public/visualize-button.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/melikpehlivanov/AlgorithmVisualizer/b70abd3a07c0e164b2638681c9bd2985724bea01/AlgoVisualizer/Web/ClientApp/public/visualize-button.jpg -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/App.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Switch, Redirect } from 'react-router'; 3 | import { Home } from './components/Home'; 4 | import { PathFindingAlgorithmsLayout } from './components/PathFindingAlgorithms/Layout'; 5 | import { SortingAlgorithmsLayout } from './components/SortingAlgorithmsVisualizer/Layout'; 6 | import { SortingAlgorithmsContainer } from './components/SortingAlgorithmsVisualizer/Container'; 7 | 8 | import { AppRoute } from './components/AppRoute'; 9 | import { NotFound } from './components/Error/NotFound'; 10 | import { PathFindingAlgorithmsContainer } from './components/PathFindingAlgorithms/Container'; 11 | 12 | const App = () => { 13 | return ( 14 | 15 | 16 | 21 | 26 | 27 | 28 | 29 | ); 30 | }; 31 | 32 | export default App; 33 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/AppRoute.jsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Route } from 'react-router'; 3 | import { MainLayout } from './Home/Layout'; 4 | 5 | export const AppRoute = ({ 6 | component: Component, 7 | layout: Layout = MainLayout, 8 | ...rest 9 | }) => ( 10 | ( 13 | 14 | {Layout !== null ? ( 15 | 16 | 17 | 18 | ) : ( 19 | 20 | )} 21 | 22 | )} 23 | /> 24 | ); 25 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/Error/NotFound/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-box-sizing: border-box; 3 | box-sizing: border-box; 4 | } 5 | 6 | body { 7 | padding: 0; 8 | margin: 0; 9 | } 10 | 11 | #notfound { 12 | position: relative; 13 | height: 100vh; 14 | background-color: #222; 15 | } 16 | 17 | #notfound .notfound { 18 | position: absolute; 19 | left: 50%; 20 | top: 50%; 21 | -webkit-transform: translate(-50%, -50%); 22 | -ms-transform: translate(-50%, -50%); 23 | transform: translate(-50%, -50%); 24 | } 25 | 26 | .notfound { 27 | max-width: 460px; 28 | width: 100%; 29 | text-align: center; 30 | line-height: 1.4; 31 | } 32 | 33 | .notfound .notfound-404 { 34 | height: 158px; 35 | line-height: 153px; 36 | } 37 | 38 | .notfound .notfound-404 h1 { 39 | font-family: 'Josefin Sans', sans-serif; 40 | color: #222; 41 | font-size: 220px; 42 | letter-spacing: 10px; 43 | margin: 0px; 44 | font-weight: 700; 45 | text-shadow: 2px 2px 0px #c9c9c9, -2px -2px 0px #c9c9c9; 46 | } 47 | 48 | .notfound .notfound-404 h1 > span { 49 | text-shadow: 2px 2px 0px #ffab00, -2px -2px 0px #ffab00, 0px 0px 8px #ff8700; 50 | } 51 | 52 | .notfound p { 53 | font-family: 'Josefin Sans', sans-serif; 54 | color: #c9c9c9; 55 | font-size: 16px; 56 | font-weight: 400; 57 | margin-top: 0px; 58 | margin-bottom: 15px; 59 | } 60 | 61 | .notfound a { 62 | font-family: 'Josefin Sans', sans-serif; 63 | font-size: 14px; 64 | text-decoration: none; 65 | text-transform: uppercase; 66 | background: transparent; 67 | color: #c9c9c9; 68 | border: 2px solid #c9c9c9; 69 | display: inline-block; 70 | padding: 10px 25px; 71 | font-weight: 700; 72 | -webkit-transition: 0.2s all; 73 | transition: 0.2s all; 74 | } 75 | 76 | .notfound a:hover { 77 | color: #ffab00; 78 | border-color: #ffab00; 79 | } 80 | 81 | @media only screen and (max-width: 480px) { 82 | .notfound .notfound-404 { 83 | height: 122px; 84 | line-height: 122px; 85 | } 86 | 87 | .notfound .notfound-404 h1 { 88 | font-size: 122px; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/Error/NotFound/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './index.css'; 3 | import { Link } from 'react-router-dom'; 4 | 5 | export const NotFound = () => { 6 | return ( 7 |
8 |
9 |
10 |

11 | 404 12 |

13 |
14 |

15 | The page you are looking for might have been removed, had its name 16 | changed or is temporarily unavailable. 17 |

18 | Home Page 19 |
20 |
21 | // 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/Error/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react'; 2 | import { Alert } from 'react-bootstrap'; 3 | import { ErrorContext } from '../../store/error/context'; 4 | import { clearErrors } from '../../store/error/actions'; 5 | 6 | export const Error = () => { 7 | const { state, dispatchError } = useContext(ErrorContext); 8 | 9 | return state.showError ? ( 10 | dispatchError(clearErrors())} 14 | dismissible 15 | > 16 | Oh snap! 17 | {state.messages.length === 1 ? ( 18 |

{state.messages[0]}

19 | ) : ( 20 | state.messages.map((element, i) =>

{element}

) 21 | )} 22 |
23 | ) : null; 24 | }; 25 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/Home/Layout.jsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Container } from 'reactstrap'; 3 | import { NavMenu } from './NavMenu'; 4 | 5 | export const MainLayout = props => { 6 | return ( 7 | 8 | 9 | {props.children} 10 | 11 | ); 12 | }; 13 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/Home/NavMenu/index.css: -------------------------------------------------------------------------------- 1 | a.navbar-brand { 2 | white-space: normal; 3 | text-align: center; 4 | word-break: break-all; 5 | } 6 | 7 | html { 8 | font-size: 14px; 9 | } 10 | @media (min-width: 768px) { 11 | html { 12 | font-size: 16px; 13 | } 14 | } 15 | 16 | .box-shadow { 17 | box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05); 18 | } 19 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/Home/NavMenu/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import { 3 | Collapse, 4 | Container, 5 | Navbar, 6 | NavbarBrand, 7 | NavbarToggler, 8 | NavItem, 9 | NavLink 10 | } from 'reactstrap'; 11 | import { Link } from 'react-router-dom'; 12 | import './index.css'; 13 | 14 | export const NavMenu = () => { 15 | const [collapsed, setCollapsed] = useState(true); 16 | 17 | const toggleNavbar = () => { 18 | setCollapsed(!collapsed); 19 | }; 20 | 21 | return ( 22 |
23 | 27 | 28 | 29 | AlgoVisualizer 30 | 31 | toggleNavbar()} className="mr-2" /> 32 | 37 |
    38 | 39 | 40 | Home 41 | 42 | 43 | 44 | 49 | Pathfinding algorithms 50 | 51 | 52 | 53 | 58 | Sorting algorithms 59 | 60 | 61 |
62 |
63 |
64 |
65 |
66 | ); 67 | }; 68 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/Home/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { Link } from 'react-router-dom'; 3 | 4 | export const Home = () => { 5 | return ( 6 | 7 |
8 |

Welcome to AlgoVisualizer!

9 |

Please choose one of the following algorithms visualizer

10 |
    11 |
  1. 12 | 13 | Pathfinding algorithms visualizer 14 | 15 |
  2. 16 |
  3. 17 |
    18 | Sorting algorithms visualizer 19 |   - Currently in beta version! 20 |
    21 |
  4. 22 |
23 |
24 |
25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/Modal/VerticallyCenteredModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Modal, Button } from 'react-bootstrap'; 3 | 4 | export const VerticallyCenteredModal = props => { 5 | return ( 6 | 13 | 14 | 15 | {props.title} 16 | 17 | 18 |
19 | {props.currentPage}/{props.totalPages} 20 |
21 |
22 | 23 | 24 |
25 | 26 |
27 | 28 | {props.currentPage === props.totalPages ? ( 29 | 32 | ) : ( 33 | 34 | )} 35 |
36 |
37 | ); 38 | }; 39 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/PathFindingAlgorithms/Container.jsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useState, useEffect } from 'react'; 2 | import { VerticallyCenteredModal } from '../Modal/VerticallyCenteredModal'; 3 | import { modalTutorialContent } from '../../constants/gridConstants'; 4 | import { Grid } from './Grid'; 5 | 6 | export const PathFindingAlgorithmsContainer = () => { 7 | const [modalShow, setModalShow] = useState(false); 8 | const [pageNumber, setPageNumber] = useState(1); 9 | 10 | useEffect(() => { 11 | setModalShow(true); 12 | }, []); 13 | 14 | return ( 15 | 16 | {modalShow ? ( 17 | setModalShow(false)} 22 | previousPage={() => 23 | pageNumber > 1 ? setPageNumber(pageNumber - 1) : null 24 | } 25 | nextPage={() => 26 | pageNumber <= modalTutorialContent.length - 1 27 | ? setPageNumber(pageNumber + 1) 28 | : null 29 | } 30 | currentPage={pageNumber} 31 | totalPages={modalTutorialContent.length} 32 | /> 33 | ) : ( 34 | '' 35 | )} 36 |
37 |
    38 |
  • 39 |
    40 | Start Node 41 |
  • 42 |
  • 43 |
    44 | End Node 45 |
  • 46 |
  • 47 |
    48 | Wall Node 49 |
  • 50 |
  • 51 | weight-node 56 | Weight Node 57 |
  • 58 |
  • 59 |
    60 | Unvisited Node 61 |
  • 62 |
  • 63 |
    64 | Visited Node 65 |
  • 66 |
  • 67 |
    68 | Shortest Path Node 69 |
  • 70 |
71 |
72 | 73 |
74 | ); 75 | }; 76 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/PathFindingAlgorithms/Grid/Node/index.css: -------------------------------------------------------------------------------- 1 | .node { 2 | width: 1.65%; 3 | float: left; 4 | height: 25px; 5 | outline: 1px solid rgb(27, 98, 153); 6 | display: inline-block; 7 | } 8 | 9 | .node-start { 10 | background-color: green !important; 11 | } 12 | 13 | .node-end { 14 | background-color: red; 15 | } 16 | 17 | .node-wall { 18 | background-color: grey; 19 | } 20 | .node-weight { 21 | background-color: purple; 22 | } 23 | 24 | .node-dumbbell { 25 | width: 74%; 26 | height: 60%; 27 | background-image: url(/dumbbell-solid.svg); 28 | display: inline-block; 29 | margin-left: 3px; 30 | } 31 | 32 | .node-visited { 33 | animation-name: visitedAnimation; 34 | animation-duration: 1.5s; 35 | animation-timing-function: ease-out; 36 | animation-delay: 0; 37 | animation-direction: alternate; 38 | animation-iteration-count: 1; 39 | animation-fill-mode: forwards; 40 | animation-play-state: running; 41 | } 42 | 43 | .node-shortest-path { 44 | animation-name: shortestPathAnimation; 45 | animation-duration: 1.5s; 46 | animation-timing-function: ease-out; 47 | animation-delay: 0; 48 | animation-direction: alternate; 49 | animation-iteration-count: 1; 50 | animation-fill-mode: forwards; 51 | animation-play-state: running; 52 | } 53 | 54 | @keyframes shortestPathAnimation { 55 | 0% { 56 | transform: scale(0.3); 57 | background-color: rgb(30, 63, 32); 58 | border-radius: 100%; 59 | } 60 | 61 | 50% { 62 | background-color: rgb(52, 88, 48); 63 | } 64 | 65 | 75% { 66 | transform: scale(1.2); 67 | background-color: rgb(74, 120, 86); 68 | } 69 | 70 | 100% { 71 | transform: scale(1); 72 | background-color: rgb(148, 236, 190); 73 | } 74 | } 75 | 76 | @keyframes visitedAnimation { 77 | 0% { 78 | transform: scale(0.3); 79 | background-color: rgba(0, 0, 66, 0.75); 80 | border-radius: 100%; 81 | } 82 | 83 | 50% { 84 | background-color: rgba(17, 104, 217, 0.75); 85 | } 86 | 87 | 75% { 88 | transform: scale(1.2); 89 | background-color: rgba(0, 217, 159, 0.75); 90 | } 91 | 92 | 100% { 93 | transform: scale(1); 94 | background-color: rgba(0, 190, 218, 0.75); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/PathFindingAlgorithms/Grid/Node/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import './index.css'; 4 | 5 | export const Node = props => { 6 | const { row, col, isStart, isEnd, isWall, isWeight } = props.node; 7 | const extraClassName = isStart 8 | ? 'node-start' 9 | : isEnd 10 | ? 'node-end' 11 | : isWall 12 | ? 'node-wall' 13 | : ''; 14 | 15 | return ( 16 |
props.onClick(event, row, col)} 20 | onMouseOver={event => props.onMouseOver(event, row, col)} 21 | onMouseDown={props.onMouseDown} 22 | onMouseUp={props.onMouseUp} 23 | > 24 | {isWeight ? : ''} 25 |
26 | ); 27 | }; 28 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/PathFindingAlgorithms/Grid/index.css: -------------------------------------------------------------------------------- 1 | .grid { 2 | margin: 15px 0 0 !important; 3 | } -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/PathFindingAlgorithms/Grid/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useState, useContext } from 'react'; 2 | import { Node } from './Node'; 3 | import { 4 | initializeGrid, 5 | setStartNode, 6 | setEndNode, 7 | setWeightNode, 8 | setWallNode, 9 | removeWeightNodes 10 | } from '../../../store/pathFindingAlgorithms/actions'; 11 | 12 | import './index.css'; 13 | import { PathFindingAlgorithmsContext } from '../../../store/pathFindingAlgorithms/context'; 14 | import { useEffect } from 'react'; 15 | import { TOTAL_NODES_EXPLORED_DEFAULT_VALUE } from '../../../constants/gridConstants'; 16 | 17 | const ShiftKeyCode = 16; 18 | const KeyDownEvent = 'keydown'; 19 | const KeyUpEvent = 'keyup'; 20 | 21 | export const Grid = () => { 22 | const { state, dispatch } = useContext(PathFindingAlgorithmsContext); 23 | const [isMouseStillClicked, setIsMouseStillClicked] = useState(false); 24 | const [isShiftStillPressed, setIsShiftStillPressed] = useState(false); 25 | const { 26 | grid, 27 | algorithmDescription, 28 | isLoading, 29 | isWeightNodeAllowed, 30 | isNavbarClickable 31 | } = state; 32 | 33 | useEffect(() => { 34 | document.addEventListener(KeyDownEvent, handleKeyPress); 35 | document.addEventListener(KeyUpEvent, handleKeyUp); 36 | dispatch(initializeGrid()); 37 | return () => { 38 | document.removeEventListener(KeyDownEvent, handleKeyPress); 39 | document.removeEventListener(KeyUpEvent, handleKeyUp); 40 | }; 41 | }, [dispatch]); 42 | 43 | useEffect(() => { 44 | if (!isWeightNodeAllowed) { 45 | dispatch(removeWeightNodes()); 46 | } 47 | }, [isWeightNodeAllowed]); 48 | 49 | const handleKeyPress = e => { 50 | if (e.keyCode === ShiftKeyCode) { 51 | setIsShiftStillPressed(true); 52 | } 53 | }; 54 | 55 | const handleKeyUp = e => { 56 | if (e.keyCode === ShiftKeyCode) { 57 | setIsShiftStillPressed(false); 58 | } 59 | }; 60 | 61 | const handleMouseDown = () => { 62 | setIsMouseStillClicked(true); 63 | }; 64 | 65 | const handleMouseUp = () => { 66 | setIsMouseStillClicked(false); 67 | }; 68 | 69 | const handleOnClick = (event, row, col) => { 70 | if (isNavbarClickable) { 71 | if (event) { 72 | if (event.ctrlKey) { 73 | dispatch(setStartNode(row, col)); 74 | } 75 | if (event.altKey) { 76 | dispatch(setEndNode(row, col)); 77 | } 78 | if (isWeightNodeAllowed && event.shiftKey) { 79 | dispatch(setWeightNode(row, col)); 80 | } 81 | } 82 | if (!event.shiftKey && !event.ctrlKey && !event.altKey) { 83 | dispatch(setWallNode(row, col)); 84 | } 85 | } 86 | }; 87 | 88 | const handleMouseOver = (event, row, col) => { 89 | if (!isMouseStillClicked || !isNavbarClickable) return; 90 | if (event && isWeightNodeAllowed && isShiftStillPressed) { 91 | dispatch(setWeightNode(row, col)); 92 | } else { 93 | dispatch(setWallNode(row, col)); 94 | } 95 | }; 96 | 97 | return ( 98 | 99 |
100 | {state.totalNodesExplored !== TOTAL_NODES_EXPLORED_DEFAULT_VALUE ? ( 101 |

102 | Total nodes explored: {state.totalNodesExplored} 103 |

104 | ) : ( 105 |

{algorithmDescription}

106 | )} 107 |
108 | 109 | {isLoading ? ( 110 |

Loading...

111 | ) : ( 112 |
113 | {grid.map((row, rowIndex) => { 114 | return ( 115 |
116 | {row.map((node, nodeIndex) => { 117 | return ( 118 | 122 | handleOnClick(event, row, col) 123 | } 124 | onMouseOver={(event, row, col) => 125 | handleMouseOver(event, row, col) 126 | } 127 | onMouseDown={() => handleMouseDown()} 128 | onMouseUp={() => handleMouseUp()} 129 | > 130 | ); 131 | })} 132 |
133 | ); 134 | })} 135 |
136 | )} 137 |
138 | ); 139 | }; 140 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/PathFindingAlgorithms/Layout/index.css: -------------------------------------------------------------------------------- 1 | .main-grid { 2 | padding-left: 1rem !important; 3 | } 4 | 5 | #algo-legend > ul li { 6 | display: inline-block; 7 | list-style: none; 8 | padding: 0 28px 0 0; 9 | margin-bottom: 0.5em; 10 | } 11 | 12 | #algo-legend div { 13 | border: 1px solid rgb(12, 53, 71); 14 | width: 25px; 15 | height: 25px; 16 | display: inline-block; 17 | top: 0.35em; 18 | margin: 0 1em 0 2.5em; 19 | } 20 | 21 | .dumbbell { 22 | width: 30px; 23 | height: 25px; 24 | margin: 0 1em 0 2.5em; 25 | float: left; 26 | } 27 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/PathFindingAlgorithms/Layout/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import './index.css'; 3 | import { PathfindingAlgorithmsNavbar } from '../Nav'; 4 | import { Error } from '../../Error'; 5 | import { PathFindingAlgorithmsProvider } from '../../../store/pathFindingAlgorithms/context'; 6 | import { ErrorProvider } from '../../../store/error/context'; 7 | 8 | export const PathFindingAlgorithmsLayout = props => { 9 | return ( 10 | 11 | 12 | 13 | 14 | 15 |
{props.children}
16 |
17 |
18 |
19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/PathFindingAlgorithms/Nav/index.css: -------------------------------------------------------------------------------- 1 | .disabled { 2 | cursor: not-allowed !important; 3 | } 4 | .disabled > a { 5 | display: inline-block; /* For IE11/ MS Edge bug */ 6 | pointer-events: none; 7 | text-decoration: none; 8 | } 9 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/SortingAlgorithmsVisualizer/Container.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, Fragment } from 'react'; 2 | import { Bar } from 'react-chartjs-2'; 3 | import { SortingAlgorithmsContext } from '../../store/sortingAlgorithms/context'; 4 | import { initializeChartData } from '../../store/sortingAlgorithms/actions'; 5 | import { Spinner } from 'react-bootstrap'; 6 | 7 | export const SortingAlgorithmsContainer = () => { 8 | const { state, dispatch } = useContext(SortingAlgorithmsContext); 9 | useEffect(() => { 10 | dispatch(initializeChartData()); 11 | }, [dispatch]); 12 | 13 | return ( 14 | 15 | {state.totalSwaps !== 0 ? ( 16 |
17 |

Total swaps:

18 |

{state.totalSwaps}

19 |
20 | ) : ( 21 | '' 22 | )} 23 | {state.isLoading ? ( 24 |
25 | 26 | Loading... 27 | 28 |
29 | ) : ( 30 | 31 | )} 32 |
33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/SortingAlgorithmsVisualizer/Layout/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment } from 'react'; 2 | import { SortingAlgorithmsProvider } from '../../../store/sortingAlgorithms/context'; 3 | import { ErrorProvider } from '../../../store/error/context'; 4 | import { Error } from '../../Error'; 5 | import { SortingAlgorithmsNavbar } from '../NavBar'; 6 | 7 | export const SortingAlgorithmsLayout = props => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 |
{props.children}
15 |
16 |
17 |
18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/components/SortingAlgorithmsVisualizer/NavBar/index.jsx: -------------------------------------------------------------------------------- 1 | import React, { Fragment, useState, useContext } from 'react'; 2 | import { 3 | Navbar, 4 | Nav, 5 | NavItem, 6 | Button, 7 | NavDropdown, 8 | ButtonToolbar, 9 | Spinner 10 | } from 'react-bootstrap'; 11 | import { NavLink } from 'reactstrap'; 12 | import { Link } from 'react-router-dom'; 13 | import { SortingAlgorithmsContext } from '../../../store/sortingAlgorithms/context'; 14 | import { 15 | generateNewArray, 16 | setIsNavbarClickable, 17 | setTotalSwaps 18 | } from '../../../store/sortingAlgorithms/actions'; 19 | import { ErrorContext } from '../../../store/error/context'; 20 | import { clearErrors, showError } from '../../../store/error/actions'; 21 | import { makePostApiCallAsync } from '../../../helpers/fetchData'; 22 | import { visualizeArrayElementsSwapping } from '../../../helpers/sortingAlgorithmsHelper'; 23 | import { TOTAL_SWAPS_DEFAULT_VALUE } from '../../../constants/sortingAlgorithmsConstants'; 24 | import { SORTING_ALGORITHMS_API_URL } from '../../../constants/apiConstants'; 25 | 26 | export const SortingAlgorithmsNavbar = () => { 27 | const [algorithm, setAlgorithm] = useState(''); 28 | const { state, dispatch } = useContext(SortingAlgorithmsContext); 29 | const { dispatchError } = useContext(ErrorContext); 30 | const [showAlgorithmsMenu, setShowAlgorithmsMenu] = useState(false); 31 | 32 | const fetchData = async () => { 33 | dispatchError(clearErrors()); 34 | dispatch(setTotalSwaps(TOTAL_SWAPS_DEFAULT_VALUE)); 35 | 36 | const url = `${SORTING_ALGORITHMS_API_URL}/${algorithm.value}`; 37 | dispatch(setIsNavbarClickable(false)); 38 | 39 | const data = JSON.stringify({ 40 | Array: state.barChart.labels 41 | }); 42 | 43 | const result = await makePostApiCallAsync(url, data, dispatchError); 44 | dispatch(setIsNavbarClickable(true)); 45 | 46 | if (result) { 47 | if (result.isSuccess !== undefined && !result.isSuccess) { 48 | dispatchError(showError(result.messages)); 49 | return; 50 | } 51 | 52 | await visualizeArrayElementsSwapping( 53 | dispatch, 54 | state.barChart, 55 | result.swapIndexes 56 | ); 57 | dispatch(setTotalSwaps(result.totalSwaps)); 58 | } 59 | }; 60 | 61 | const isClickable = () => (!state.isNavbarClickable ? 'disabled' : ''); 62 | 63 | const handleNewArrayGeneration = () => { 64 | if (state.isNavbarClickable) { 65 | dispatch(generateNewArray()); 66 | } 67 | }; 68 | 69 | return ( 70 | 71 | 76 | 77 | 78 | AlgoVisualizer 79 | 80 | 81 | 82 | 83 | 109 | 110 | {algorithm !== '' ? ( 111 | 112 | 132 | 133 | ) : ( 134 | '' 135 | )} 136 | 137 | 150 | 151 | 152 | 153 | ); 154 | }; 155 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/constants/apiConstants.js: -------------------------------------------------------------------------------- 1 | export const PATHFINDING_ALGORITHMS_API_URL = 2 | 'https://localhost:44370/api/pathfinding'; 3 | 4 | export const SORTING_ALGORITHMS_API_URL = 5 | 'https://localhost:44370/api/sortingAlgorithms'; 6 | 7 | export const MAZE_API_URL = 'https://localhost:44370/api/maze'; 8 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/constants/errorConstants.js: -------------------------------------------------------------------------------- 1 | export const SHOW_ERROR_WITH_MESSAGE = 'SHOW_ERROR_WITH_MESSAGE'; 2 | export const CLEAR_ERRORS = 'CLEAR_ERRORS'; 3 | export const DEFAULT_ERROR_MESSAGE = 4 | 'Something terribly went wrong! Please try again later.'; 5 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/constants/gridConstants.js: -------------------------------------------------------------------------------- 1 | export const ROWS = 21; 2 | export const COLS = 60; 3 | 4 | export const START_NODE_ROW = 5; 5 | export const START_NODE_COL = 15; 6 | export const END_NODE_ROW = 10; 7 | export const END_NODE_COL = 35; 8 | 9 | export const TOTAL_NODES_EXPLORED_DEFAULT_VALUE = 0; 10 | 11 | export const INITIALIZE_GRID = 'INITIALIZE_GRID'; 12 | export const SET_START_NODE = 'SET_START_NODE'; 13 | export const SET_END_NODE = 'SET_END_NODE'; 14 | 15 | export const SET_IS_NAVBAR_CLICKABLE = 'SET_IS_NAVBAR_CLICKABLE'; 16 | 17 | export const SET_WEIGHT_NODE = 'SET_WEIGHT_NODE'; 18 | export const SET_WALL_NODE = 'SET_WALL_NODE'; 19 | 20 | export const SET_TOTAL_NODES_EXPLORED = 'SET_TOTAL_NODES_EXPLORED'; 21 | 22 | export const SET_ALGORITHM = 'SET_ALGORITHM'; 23 | export const SET_ALGORITHM_DESCRIPTION = 'SET_ALGORITHM_DESCRIPTION'; 24 | 25 | export const REMOVE_WEIGHT_NODES = 'REMOVE_WEIGHT_NODES'; 26 | 27 | export const CLEAR_STATE = 'CLEAR_STATE'; 28 | export const CLEAR_GRID = 'CLEAR_GRID'; 29 | 30 | export const SHORTEST_PATH_CLASSNAME = 'node node-shortest-path'; 31 | export const VISITED_NODE_CLASSNAME = 'node node-visited'; 32 | 33 | export const modalTutorialContent = [ 34 | { 35 | title: 'Welcome to Algorithm Visualizer!', 36 | body: { 37 | __html: 38 | '

This short tutorial will walk you through the basic features of the application and will show you how to use them.

If you want to wade right in, feel free to press the "Skip Tutorial" button below. Otherwise, press "Next"!

P.S Even though that this project is responsive it is not recommended to use it on phones.

', 39 | }, 40 | }, 41 | { 42 | title: 'What is a pathfinding algorithm ?', 43 | body: { 44 | __html: 45 | '

At its core, a pathfinding algorithm searches a graph/grid by starting at one vertex/node and exploring adjacent nodes until the destination node is reached, generally with the intent of finding the cheapest route.

All the algorithms for this application are adapted for a 2D grid, where movements from node to node have cost of 1.

', 46 | }, 47 | }, 48 | { 49 | title: 'How to pick an algorithm', 50 | body: { 51 | __html: 52 | '

Choose an algorithm from the "Algorithms" drop-down menu.

Note that some algorithms are unweighted, while others are weighted. Unweighted algorithms do not take weight nodes into account, whereas weighted ones do. Furthermore, not all algorithms guarantee the shortest path.

', 53 | }, 54 | }, 55 | { 56 | title: 'Meet the algorithms', 57 | body: { 58 | __html: 59 | "

Not all algorithms are equal. Please read the notes down below!

  • A* Search is weighted and it is arguably the best pathfinding algorithm out there. It uses heuristics to guarantee the shortest path and is much faster than Dijkstra's Algorithm
  • Dijkstra's Algorithm is also weighted. Dijkstra's algorithm is the father of pathfinding algorithms and it guarantees the shortest path
  • Breath-first Search is unweighted and it's a good algorithm which guarantees the shortest path
  • Depth-first Search is unweighted and it's a very bad algorithm for pathfinding. Moreover, it does not guarantee the shortest path

P.S Many new algorithms are going to come out with the next version of this app!

", 60 | }, 61 | }, 62 | { 63 | title: 'How to move start and end point nodes', 64 | body: { 65 | __html: 66 | '

1. How to set a new start point.

1.1 In order to set new start point you simply need to hold down "Ctrl" key while clicking on the desired node.

2. How to set a new end point.

2.1 Setting an end node is the same as setting start node but instead of holding down "Ctrl" key you must hold down "Alt" key.

', 67 | }, 68 | }, 69 | { 70 | title: 'How to add and remove weight and wall nodes', 71 | body: { 72 | __html: 73 | '

1. How to add wall node.

1.1 In order to add wall node you need to click on the desired node. Additionaly, you can hold down your left mouse button while moving over the nodes and this will also set wall nodes.

2. How to add weight node.

2.1 Adding a wall node is the same as adding weight node except we have to keep the "Shift" key pressed.

3. Removing wall and weight nodes

In order to remove wall or weight node, simply click onto the node with the same key combination you have used to add them or use the "Clear board" button.

Walls are impassable meaning that a path cannot cross through. Weights, however, are not impassable. They simply cost more to move through. If you are wondering what does that mean, imagine the following situation: It is time to go home after a long day at work and you turn on your GPS, put in your home address and the GPS will calculate the route for you. But in the meantime, there could be a traffic jam so the GPS would say: "Hey, there is a traffic jam, would you like me to take a roundabout route which will save you a lot of time by avoiding the traffic jams and you will get home much faster". In this application, moving through a weight node has a "cost" of 15.

', 74 | }, 75 | }, 76 | { 77 | title: 'How to generate mazes/labyrinths', 78 | body: { 79 | __html: 80 | '

Use the navbar menu "Mazes" to generate different mazes/labyrinths!

', 81 | }, 82 | }, 83 | { 84 | title: 'How to pick visualization speed', 85 | body: { 86 | __html: 87 | '

Use the navbar dropdown menu "Animation speed" to choose the desired animation speed.!

', 88 | }, 89 | }, 90 | { 91 | title: 'How to visualize an algorithm', 92 | body: { 93 | __html: 94 | '

Use the navbar buttons to visualize algorithms and clear grid!

Click on the "Visualize" button after you have chosen an algorithm in order to visualize it. Also, you can clear the current path, walls and weights from the "Clear Board" button positioned in the top right corner. Moreover, you do not need to clear the board manually after you have visualized given algorithm, simply choose the new algorithm which you want to visualize and the grid will clear itself automatically when "Visualize" button is clicked.

', 95 | }, 96 | }, 97 | { 98 | title: 'Thank you for coming to this stage of the tutorial.', 99 | body: { 100 | __html: 101 | '

I believe that you are ready to go on your own now and explore the different algorithms.

If for some reason you want to get back to this tutorial simply refresh the page.

By the way, if you are interested in the source code of this project you can check it out in my github account. Giving the project a star is highly appreciated!

', 102 | }, 103 | }, 104 | ]; 105 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/constants/pathfindingAlgorithms.js: -------------------------------------------------------------------------------- 1 | export const availablePathFindingAlgorithms = [ 2 | { 3 | value: 'astar', 4 | label: 'A* Search', 5 | description: 'A* Search is 𝐰𝐞𝐢𝐠𝐡𝐭𝐞𝐝 and 𝐠𝐮𝐚𝐫𝐚𝐧𝐭𝐞𝐞𝐬 the shortest path!', 6 | isWeight: true, 7 | }, 8 | { 9 | value: 'dijkstra', 10 | label: "Dijkstra's Search", 11 | description: 12 | "Dijkstra's Algorithm is 𝐰𝐞𝐢𝐠𝐡𝐭𝐞𝐝 and 𝐠𝐮𝐚𝐫𝐚𝐧𝐭𝐞𝐞𝐬 the shortest path!", 13 | isWeight: true, 14 | }, 15 | { 16 | value: 'bfs', 17 | label: 'Breadth-first Search', 18 | description: 19 | 'Breath-first Search is 𝐮𝐧𝐰𝐞𝐢𝐠𝐡𝐭𝐞𝐝 and 𝐠𝐮𝐚𝐫𝐚𝐧𝐭𝐞𝐞𝐬 the shortest path!', 20 | isWeight: false, 21 | }, 22 | { 23 | value: 'dfs', 24 | label: 'Depth-first Search', 25 | description: 26 | 'Depth-first Search is 𝐮𝐧𝐰𝐞𝐢𝐠𝐡𝐭𝐞𝐝 and 𝐝𝐨𝐞𝐬 𝐧𝐨𝐭 𝐠𝐮𝐚𝐫𝐚𝐧𝐭𝐞𝐞 the shortest path!', 27 | isWeight: false, 28 | }, 29 | ]; 30 | 31 | export const MAZE_TYPES = [ 32 | { 33 | label: 'Generate wall maze', 34 | value: 'wall', 35 | }, 36 | { 37 | label: 'Generate weight maze', 38 | value: 'weight', 39 | }, 40 | ]; 41 | 42 | export const DEFAULT_ANIMATION = { 43 | label: 'Average', 44 | value: 20, 45 | }; 46 | 47 | export const ANIMATION_SPEEDS = [ 48 | { 49 | label: 'Slow', 50 | value: 120, 51 | }, 52 | DEFAULT_ANIMATION, 53 | { 54 | label: 'Fast', 55 | value: 10, 56 | }, 57 | ]; 58 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/constants/sortingAlgorithmsConstants.js: -------------------------------------------------------------------------------- 1 | export const INITIALIZE_CHART_DATA = 'INITIALIZE_CHART_DATA'; 2 | export const GENERATE_NEW_ARRAY = 'GENERATE_NEW_ARRAY'; 3 | export const SET_IS_NAVBAR_CLICKABLE = 'SET_IS_NAVBAR_CLICKABLE'; 4 | 5 | export const BAR_CHART_DEFAULT_BACKGROUND_COLOR = 'rgba(255,99,132,0.2)'; 6 | export const MARKED_ELEMENT_BACKGROUND_COLOR = 'yellow'; 7 | 8 | export const SET_BAR_CHART_ELEMENT_BACKGROUND_COLOR = 9 | 'SET_BAR_CHART_ELEMENT_BACKGROUND_COLOR'; 10 | 11 | export const SET_TOTAL_SWAPS = 'SET_TOTAL_SWAPS'; 12 | export const TOTAL_SWAPS_DEFAULT_VALUE = 0; 13 | 14 | export const availableSortingAlgorithms = [ 15 | { 16 | value: 'mergesort', 17 | label: 'Merge sort' 18 | }, 19 | { 20 | value: 'bubblesort', 21 | label: 'Bubble Sort' 22 | }, 23 | { 24 | value: 'heapsort', 25 | label: 'Heap Sort' 26 | }, 27 | { 28 | value: 'quicksort', 29 | label: 'Quick Sort' 30 | }, 31 | { 32 | value: 'selectionsort', 33 | label: 'Selection Sort' 34 | } 35 | ]; 36 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/helpers/fetchData.js: -------------------------------------------------------------------------------- 1 | import { showError } from '../store/error/actions'; 2 | import { DEFAULT_ERROR_MESSAGE } from '../constants/errorConstants'; 3 | 4 | export const makePostApiCallAsync = async (url, data, dispatchError) => { 5 | try { 6 | const response = await fetch(url, { 7 | method: 'POST', 8 | headers: { 9 | 'content-type': 'application/json' 10 | }, 11 | body: data 12 | }); 13 | 14 | const result = response.json(); 15 | if (response.status <= 400) { 16 | return result; 17 | } else { 18 | dispatchError(showError([DEFAULT_ERROR_MESSAGE])); 19 | } 20 | } catch (error) { 21 | dispatchError(showError([DEFAULT_ERROR_MESSAGE])); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/helpers/pathFindingAlgorithms/dataVisualizer.js: -------------------------------------------------------------------------------- 1 | import { 2 | SHORTEST_PATH_CLASSNAME, 3 | VISITED_NODE_CLASSNAME, 4 | } from '../../constants/gridConstants'; 5 | import { 6 | setIsNavbarClickable, 7 | setWallNode, 8 | setWeightNode, 9 | setTotalNodesExplored, 10 | } from '../../store/pathFindingAlgorithms/actions'; 11 | 12 | const nodeName = 'node'; 13 | const mazeGenerationAnimationSpeed = 20; 14 | 15 | export const visualizeResult = ( 16 | dispatch, 17 | visitedNodesInOrder, 18 | nodesInShortestPathOrder, 19 | totalNodesExplored, 20 | animationSpeed 21 | ) => { 22 | const allVisitedNodesInOrder = visitedNodesInOrder; 23 | const allNodesInShortestPathOrder = nodesInShortestPathOrder; 24 | dispatch(setIsNavbarClickable(false)); 25 | animateResult( 26 | dispatch, 27 | allVisitedNodesInOrder, 28 | allNodesInShortestPathOrder, 29 | totalNodesExplored, 30 | animationSpeed 31 | ); 32 | }; 33 | 34 | export const visualizeMazeGeneration = (dispatch, nodes, mazeType) => { 35 | dispatch(setIsNavbarClickable(false)); 36 | animateMazeGeneration(dispatch, nodes, mazeType); 37 | }; 38 | 39 | const animateMazeGeneration = (dispatch, nodes, mazeType) => { 40 | for (let i = 0; i < nodes.length; i++) { 41 | const node = nodes[i]; 42 | const row = node[0]; 43 | const col = node[1]; 44 | 45 | setTimeout(() => { 46 | if (mazeType === 'wall') { 47 | dispatch(setWallNode(row, col)); 48 | } 49 | if (mazeType === 'weight') { 50 | dispatch(setWeightNode(row, col)); 51 | } 52 | 53 | if (i === nodes.length - 1) { 54 | dispatch(setIsNavbarClickable(true)); 55 | clearTimeout(); 56 | } 57 | }, mazeGenerationAnimationSpeed * i); 58 | } 59 | }; 60 | 61 | const animateResult = ( 62 | dispatch, 63 | allVisitedNodesInOrder, 64 | allNodesInShortestPathOrder, 65 | totalNodesExplored, 66 | animationSpeed 67 | ) => { 68 | for (let i = 0; i <= allVisitedNodesInOrder.length; i++) { 69 | if (i === allVisitedNodesInOrder.length) { 70 | setTimeout(() => { 71 | animateShortestPath( 72 | dispatch, 73 | allNodesInShortestPathOrder, 74 | totalNodesExplored 75 | ); 76 | }, animationSpeed * i); 77 | return; 78 | } 79 | 80 | setTimeout(() => { 81 | const node = allVisitedNodesInOrder[i]; 82 | if (node) { 83 | const element = getElement(nodeName, node.row, node.col); 84 | if (element === null) return; 85 | element.className = VISITED_NODE_CLASSNAME; 86 | } 87 | 88 | return; 89 | }, animationSpeed * i); 90 | } 91 | }; 92 | 93 | const animateShortestPath = (dispatch, nodes, totalNodesExplored) => { 94 | for (let i = 0; i <= nodes.length; i++) { 95 | setTimeout(() => { 96 | const node = nodes[i]; 97 | if (node) { 98 | const element = getElement(nodeName, node.row, node.col); 99 | if (element === null) return; 100 | element.className = SHORTEST_PATH_CLASSNAME; 101 | } 102 | 103 | if (i === nodes.length - 1) { 104 | dispatch(setIsNavbarClickable(true)); 105 | dispatch(setTotalNodesExplored(totalNodesExplored)); 106 | clearTimeout(); 107 | } 108 | }, 50 * i * 2); 109 | } 110 | }; 111 | 112 | const getElement = (nodeName, row, col) => 113 | document.getElementById(`${nodeName}-${row}-${col}`); 114 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/helpers/pathFindingAlgorithms/pathFindingHelper.js: -------------------------------------------------------------------------------- 1 | import { 2 | ROWS, 3 | COLS, 4 | START_NODE_ROW, 5 | START_NODE_COL, 6 | END_NODE_ROW, 7 | END_NODE_COL, 8 | SHORTEST_PATH_CLASSNAME, 9 | VISITED_NODE_CLASSNAME 10 | } from '../../constants/gridConstants'; 11 | 12 | // Modifiable 13 | let StartNodeRow; 14 | let StartNodeCol; 15 | let EndNodeRow; 16 | let EndNodeCol; 17 | 18 | export function getInitialGrid() { 19 | const grid = [[], []]; 20 | for (let row = 0; row < ROWS; row++) { 21 | grid[row] = []; 22 | for (let col = 0; col < COLS; col++) { 23 | grid[row][col] = createNode(row, col); 24 | } 25 | } 26 | 27 | StartNodeRow = START_NODE_ROW; 28 | StartNodeCol = START_NODE_COL; 29 | EndNodeRow = END_NODE_ROW; 30 | EndNodeCol = END_NODE_COL; 31 | 32 | return grid; 33 | } 34 | 35 | export const removeAllWeightNodes = grid => { 36 | if (!grid) return; 37 | for (let row = 0; row < ROWS; row++) { 38 | for (let col = 0; col < COLS; col++) { 39 | if (grid[row][col].isWeight) { 40 | grid[row][col].isWeight = false; 41 | } 42 | } 43 | } 44 | return grid; 45 | }; 46 | 47 | export const clearGrid = () => { 48 | const nodeClassName = 'node'; 49 | for (let row = 0; row < ROWS; row++) { 50 | for (let col = 0; col < COLS; col++) { 51 | const element = document.getElementById(`${nodeClassName}-${row}-${col}`); 52 | if ( 53 | element && 54 | (element.className === SHORTEST_PATH_CLASSNAME || 55 | element.className === VISITED_NODE_CLASSNAME) 56 | ) { 57 | element.className = nodeClassName; 58 | } 59 | } 60 | } 61 | }; 62 | 63 | const createNode = (row, col) => { 64 | return { 65 | row, 66 | col, 67 | isStart: row === START_NODE_ROW && col === START_NODE_COL, 68 | isEnd: row === END_NODE_ROW && col === END_NODE_COL, 69 | isWall: false, 70 | isWeight: false 71 | }; 72 | }; 73 | 74 | export const setWallNode = (grid, row, col) => { 75 | if (!isPlaceable(row, col)) return grid; 76 | 77 | const newGrid = grid.slice(); 78 | const node = newGrid[row][col]; 79 | const newNode = { 80 | ...node, 81 | isWall: !node.isWall, 82 | isWeight: false 83 | }; 84 | newGrid[row][col] = newNode; 85 | return newGrid; 86 | }; 87 | 88 | export const setWeightNode = (grid, row, col) => { 89 | if (!isPlaceable(row, col)) return grid; 90 | 91 | const newGrid = grid.slice(); 92 | const node = newGrid[row][col]; 93 | const newNode = { 94 | ...node, 95 | isWeight: !node.isWeight, 96 | isWall: false 97 | }; 98 | newGrid[row][col] = newNode; 99 | return newGrid; 100 | }; 101 | 102 | export const setStartNode = (grid, row, col) => { 103 | if (!isPlaceable(row, col)) { 104 | return grid; 105 | } 106 | 107 | const newGrid = grid.slice(); 108 | newGrid[StartNodeRow][StartNodeCol].isStart = false; 109 | newGrid[row][col].isStart = true; 110 | newGrid[row][col].isWall = false; 111 | newGrid[row][col].isWeight = false; 112 | 113 | StartNodeRow = row; 114 | StartNodeCol = col; 115 | 116 | return newGrid; 117 | }; 118 | 119 | export const setEndNode = (grid, row, col) => { 120 | if (!isPlaceable(row, col)) { 121 | return grid; 122 | } 123 | 124 | const newGrid = grid.slice(); 125 | newGrid[EndNodeRow][EndNodeCol].isEnd = false; 126 | newGrid[row][col].isEnd = true; 127 | newGrid[row][col].isWall = false; 128 | newGrid[row][col].isWeight = false; 129 | 130 | EndNodeRow = row; 131 | EndNodeCol = col; 132 | 133 | return newGrid; 134 | }; 135 | 136 | const isPlaceable = (row, col) => { 137 | if ( 138 | (row === StartNodeRow && col === StartNodeCol) || 139 | (row === EndNodeRow && col === EndNodeCol) 140 | ) { 141 | return false; 142 | } 143 | 144 | return true; 145 | }; 146 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/helpers/sortingAlgorithmsHelper.js: -------------------------------------------------------------------------------- 1 | import { 2 | BAR_CHART_DEFAULT_BACKGROUND_COLOR, 3 | MARKED_ELEMENT_BACKGROUND_COLOR 4 | } from '../constants/sortingAlgorithmsConstants'; 5 | import { 6 | setBarChartElementBackgroundColor, 7 | setIsNavbarClickable 8 | } from '../store/sortingAlgorithms/actions'; 9 | 10 | const arraySize = 20; 11 | const randomMultiplyingFactor = 300; 12 | 13 | export const getInitialChart = () => { 14 | const barChart = { 15 | labels: [], 16 | dataset: { 17 | backgroundColor: [], 18 | data: [] 19 | } 20 | }; 21 | 22 | const dataSet = barChart.dataset; 23 | for (let i = 0; i <= arraySize; i++) { 24 | const number = Math.floor(Math.random() * randomMultiplyingFactor); 25 | dataSet.backgroundColor.push(BAR_CHART_DEFAULT_BACKGROUND_COLOR); 26 | barChart.labels.push(number); 27 | dataSet.data.push(number); 28 | } 29 | 30 | return barChart; 31 | }; 32 | 33 | export const generateNewChart = data => { 34 | const dataSet = data.datasets[0]; 35 | for (let i = 0; i <= arraySize; i++) { 36 | const number = Math.floor(Math.random() * randomMultiplyingFactor); 37 | data.labels[i] = number; 38 | dataSet.data[i] = number; 39 | } 40 | 41 | return data; 42 | }; 43 | 44 | export const setBackgroundColorToChartElements = ( 45 | barChart, 46 | elements, 47 | color 48 | ) => { 49 | const dataSet = barChart.datasets[0]; 50 | for (let i = 0; i < elements.length; i++) { 51 | dataSet.backgroundColor[elements[i]] = color; 52 | } 53 | return barChart.backgroundColor; 54 | }; 55 | 56 | export const visualizeArrayElementsSwapping = async ( 57 | dispatch, 58 | barChart, 59 | swappingIndexes 60 | ) => { 61 | const timeOutMs = 500; 62 | 63 | dispatch(setIsNavbarClickable(false)); 64 | 65 | for (let i = 0; i < swappingIndexes.length; i++) { 66 | const element = swappingIndexes[i]; 67 | const firstIndex = element[0]; 68 | const secondIndex = element[1]; 69 | 70 | await Promise.all([ 71 | dispatch( 72 | setBarChartElementBackgroundColor( 73 | [firstIndex, secondIndex], 74 | MARKED_ELEMENT_BACKGROUND_COLOR 75 | ) 76 | ), 77 | timeout(timeOutMs) 78 | ]); 79 | 80 | await Promise.all([ 81 | swapElements(barChart, firstIndex, secondIndex), 82 | timeout(250) 83 | ]); 84 | 85 | await Promise.all([ 86 | dispatch( 87 | setBarChartElementBackgroundColor( 88 | [firstIndex, secondIndex], 89 | BAR_CHART_DEFAULT_BACKGROUND_COLOR 90 | ) 91 | ), 92 | timeout(timeOutMs) 93 | ]); 94 | 95 | if (i === swappingIndexes.length - 1) { 96 | dispatch(setIsNavbarClickable(true)); 97 | } 98 | } 99 | }; 100 | 101 | const timeout = ms => { 102 | return new Promise(resolve => setTimeout(resolve, ms)); 103 | }; 104 | 105 | const swapElements = (barChart, firstIndex, secondIndex) => { 106 | const dataSet = barChart.datasets[0]; 107 | 108 | const temp = barChart.labels[firstIndex]; 109 | 110 | const secondElement = barChart.labels[secondIndex]; 111 | barChart.labels[firstIndex] = secondElement; 112 | dataSet.data[firstIndex] = secondElement; 113 | 114 | barChart.labels[secondIndex] = temp; 115 | dataSet.data[secondIndex] = temp; 116 | }; 117 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/index.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap/dist/css/bootstrap.css'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import { BrowserRouter } from 'react-router-dom'; 5 | import App from './App'; 6 | import registerServiceWorker from './registerServiceWorker'; 7 | 8 | const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href'); 9 | const rootElement = document.getElementById('root'); 10 | 11 | ReactDOM.render( 12 | 13 | 14 | , 15 | rootElement 16 | ); 17 | 18 | registerServiceWorker(); 19 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/registerServiceWorker.js: -------------------------------------------------------------------------------- 1 | // In production, we register a service worker to serve assets from local cache. 2 | 3 | // This lets the app load faster on subsequent visits in production, and gives 4 | // it offline capabilities. However, it also means that developers (and users) 5 | // will only see deployed updates on the "N+1" visit to a page, since previously 6 | // cached resources are updated in the background. 7 | 8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy. 9 | // This link also includes instructions on opting out of this behavior. 10 | 11 | const isLocalhost = Boolean( 12 | window.location.hostname === 'localhost' || 13 | // [::1] is the IPv6 localhost address. 14 | window.location.hostname === '[::1]' || 15 | // 127.0.0.1/8 is considered localhost for IPv4. 16 | window.location.hostname.match( 17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ 18 | ) 19 | ); 20 | 21 | export default function register () { 22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { 23 | // The URL constructor is available in all browsers that support SW. 24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location); 25 | if (publicUrl.origin !== window.location.origin) { 26 | // Our service worker won't work if PUBLIC_URL is on a different origin 27 | // from what our page is served on. This might happen if a CDN is used to 28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 29 | return; 30 | } 31 | 32 | window.addEventListener('load', () => { 33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; 34 | 35 | if (isLocalhost) { 36 | // This is running on localhost. Lets check if a service worker still exists or not. 37 | checkValidServiceWorker(swUrl); 38 | } else { 39 | // Is not local host. Just register service worker 40 | registerValidSW(swUrl); 41 | } 42 | }); 43 | } 44 | } 45 | 46 | function registerValidSW (swUrl) { 47 | navigator.serviceWorker 48 | .register(swUrl) 49 | .then(registration => { 50 | registration.onupdatefound = () => { 51 | const installingWorker = registration.installing; 52 | installingWorker.onstatechange = () => { 53 | if (installingWorker.state === 'installed') { 54 | if (navigator.serviceWorker.controller) { 55 | // At this point, the old content will have been purged and 56 | // the fresh content will have been added to the cache. 57 | // It's the perfect time to display a "New content is 58 | // available; please refresh." message in your web app. 59 | console.log('New content is available; please refresh.'); 60 | } else { 61 | // At this point, everything has been precached. 62 | // It's the perfect time to display a 63 | // "Content is cached for offline use." message. 64 | console.log('Content is cached for offline use.'); 65 | } 66 | } 67 | }; 68 | }; 69 | }) 70 | .catch(error => { 71 | console.error('Error during service worker registration:', error); 72 | }); 73 | } 74 | 75 | function checkValidServiceWorker (swUrl) { 76 | // Check if the service worker can be found. If it can't reload the page. 77 | fetch(swUrl) 78 | .then(response => { 79 | // Ensure service worker exists, and that we really are getting a JS file. 80 | if ( 81 | response.status === 404 || 82 | response.headers.get('content-type').indexOf('javascript') === -1 83 | ) { 84 | // No service worker found. Probably a different app. Reload the page. 85 | navigator.serviceWorker.ready.then(registration => { 86 | registration.unregister().then(() => { 87 | window.location.reload(); 88 | }); 89 | }); 90 | } else { 91 | // Service worker found. Proceed as normal. 92 | registerValidSW(swUrl); 93 | } 94 | }) 95 | .catch(() => { 96 | console.log( 97 | 'No internet connection found. App is running in offline mode.' 98 | ); 99 | }); 100 | } 101 | 102 | export function unregister () { 103 | if ('serviceWorker' in navigator) { 104 | navigator.serviceWorker.ready.then(registration => { 105 | registration.unregister(); 106 | }); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/store/error/actions/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | SHOW_ERROR_WITH_MESSAGE, 3 | CLEAR_ERRORS 4 | } from '../../../constants/errorConstants'; 5 | 6 | export const showError = messages => { 7 | return { 8 | type: SHOW_ERROR_WITH_MESSAGE, 9 | payload: messages 10 | }; 11 | }; 12 | 13 | export const clearErrors = () => { 14 | return { 15 | type: CLEAR_ERRORS 16 | }; 17 | }; 18 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/store/error/context/index.js: -------------------------------------------------------------------------------- 1 | import React, { createContext, useReducer } from 'react'; 2 | import errorReducer from '../reducers'; 3 | 4 | export const initialState = { 5 | messages: [], 6 | showError: false 7 | }; 8 | 9 | export const ErrorContext = createContext(); 10 | 11 | export const ErrorProvider = props => { 12 | const [state, dispatchError] = useReducer(errorReducer, initialState); 13 | return ( 14 | 15 | {props.children} 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/store/error/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | SHOW_ERROR_WITH_MESSAGE, 3 | CLEAR_ERRORS 4 | } from '../../../constants/errorConstants'; 5 | import { initialState } from '../context'; 6 | 7 | const errorReducer = (state = initialState, action) => { 8 | switch (action.type) { 9 | case SHOW_ERROR_WITH_MESSAGE: 10 | return { 11 | ...state, 12 | showError: true, 13 | messages: action.payload 14 | }; 15 | case CLEAR_ERRORS: 16 | state = initialState; 17 | return state; 18 | default: 19 | return state; 20 | } 21 | }; 22 | 23 | export default errorReducer; 24 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/store/pathFindingAlgorithms/actions/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | INITIALIZE_GRID, 3 | SET_IS_NAVBAR_CLICKABLE, 4 | SET_START_NODE, 5 | SET_END_NODE, 6 | SET_WEIGHT_NODE, 7 | SET_WALL_NODE, 8 | SET_ALGORITHM, 9 | SET_ALGORITHM_DESCRIPTION, 10 | CLEAR_STATE, 11 | REMOVE_WEIGHT_NODES, 12 | CLEAR_GRID, 13 | SET_TOTAL_NODES_EXPLORED 14 | } from '../../../constants/gridConstants'; 15 | 16 | export const initializeGrid = () => { 17 | return { 18 | type: INITIALIZE_GRID 19 | }; 20 | }; 21 | 22 | export const setIsNavbarClickable = isClickable => { 23 | return { 24 | type: SET_IS_NAVBAR_CLICKABLE, 25 | payload: isClickable 26 | }; 27 | }; 28 | 29 | export const setStartNode = (row, col) => { 30 | return { 31 | type: SET_START_NODE, 32 | payload: { row, col } 33 | }; 34 | }; 35 | 36 | export const setEndNode = (row, col) => { 37 | return { 38 | type: SET_END_NODE, 39 | payload: { row, col } 40 | }; 41 | }; 42 | 43 | export const setWeightNode = (row, col) => { 44 | return { 45 | type: SET_WEIGHT_NODE, 46 | payload: { row, col } 47 | }; 48 | }; 49 | 50 | export const setWallNode = (row, col) => { 51 | return { 52 | type: SET_WALL_NODE, 53 | payload: { row, col } 54 | }; 55 | }; 56 | 57 | export const setTotalNodesExplored = value => { 58 | return { 59 | type: SET_TOTAL_NODES_EXPLORED, 60 | payload: value 61 | }; 62 | }; 63 | 64 | export const setAlgorithm = algorithm => { 65 | return { 66 | type: SET_ALGORITHM, 67 | payload: algorithm 68 | }; 69 | }; 70 | 71 | export const setAlgorithmDescription = description => { 72 | return { 73 | type: SET_ALGORITHM_DESCRIPTION, 74 | payload: description 75 | }; 76 | }; 77 | 78 | export const clearState = () => { 79 | return { 80 | type: CLEAR_STATE 81 | }; 82 | }; 83 | 84 | export const clearGrid = () => { 85 | return { 86 | type: CLEAR_GRID 87 | }; 88 | }; 89 | 90 | export const removeWeightNodes = () => { 91 | return { 92 | type: REMOVE_WEIGHT_NODES 93 | }; 94 | }; 95 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/store/pathFindingAlgorithms/context/index.js: -------------------------------------------------------------------------------- 1 | import React, { createContext, useReducer } from 'react'; 2 | import pathFindingAlgorithmsReducer from '../reducers'; 3 | import { 4 | START_NODE_ROW, 5 | START_NODE_COL, 6 | END_NODE_ROW, 7 | END_NODE_COL, 8 | TOTAL_NODES_EXPLORED_DEFAULT_VALUE 9 | } from '../../../constants/gridConstants'; 10 | import { availablePathFindingAlgorithms } from '../../../constants/pathfindingAlgorithms'; 11 | 12 | export const initialState = { 13 | isLoading: true, 14 | isNavbarClickable: true, 15 | grid: [], 16 | totalNodesExplored: TOTAL_NODES_EXPLORED_DEFAULT_VALUE, 17 | algorithms: availablePathFindingAlgorithms, 18 | algorithm: '', 19 | algorithmDescription: '', 20 | isWeightNodeAllowed: true, 21 | startNode: { row: START_NODE_ROW, col: START_NODE_COL, isStart: true }, 22 | endNode: { row: END_NODE_ROW, col: END_NODE_COL, isEnd: true } 23 | }; 24 | 25 | export const PathFindingAlgorithmsContext = createContext(); 26 | 27 | export const PathFindingAlgorithmsProvider = props => { 28 | const [state, dispatch] = useReducer( 29 | pathFindingAlgorithmsReducer, 30 | initialState 31 | ); 32 | return ( 33 | 34 | {props.children} 35 | 36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/store/pathFindingAlgorithms/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | INITIALIZE_GRID, 3 | SET_START_NODE, 4 | SET_END_NODE, 5 | SET_WEIGHT_NODE, 6 | SET_WALL_NODE, 7 | SET_ALGORITHM, 8 | SET_ALGORITHM_DESCRIPTION, 9 | CLEAR_STATE, 10 | CLEAR_GRID, 11 | REMOVE_WEIGHT_NODES, 12 | SET_IS_NAVBAR_CLICKABLE, 13 | SET_TOTAL_NODES_EXPLORED 14 | } from '../../../constants/gridConstants'; 15 | 16 | import { 17 | getInitialGrid, 18 | setStartNode, 19 | setEndNode, 20 | setWeightNode, 21 | setWallNode, 22 | removeAllWeightNodes, 23 | clearGrid 24 | } from '../../../helpers/pathFindingAlgorithms/pathFindingHelper'; 25 | import { initialState } from '../context'; 26 | 27 | let isGridChanged = false; 28 | 29 | const pathFindingAlgorithmsReducer = (state = initialState, action) => { 30 | switch (action.type) { 31 | case INITIALIZE_GRID: 32 | return { ...state, grid: getInitialGrid(), isLoading: false }; 33 | case SET_IS_NAVBAR_CLICKABLE: 34 | return { ...state, isNavbarClickable: action.payload }; 35 | case SET_START_NODE: 36 | MarkGridAsChanged(); 37 | 38 | return { 39 | ...state, 40 | grid: setStartNode(state.grid, action.payload.row, action.payload.col), 41 | startNode: { 42 | row: action.payload.row, 43 | col: action.payload.col, 44 | isStart: true 45 | } 46 | }; 47 | case SET_END_NODE: 48 | MarkGridAsChanged(); 49 | 50 | return { 51 | ...state, 52 | grid: setEndNode(state.grid, action.payload.row, action.payload.col), 53 | endNode: { 54 | row: action.payload.row, 55 | col: action.payload.col, 56 | isEnd: false 57 | } 58 | }; 59 | case SET_WEIGHT_NODE: 60 | MarkGridAsChanged(); 61 | 62 | return { 63 | ...state, 64 | grid: setWeightNode(state.grid, action.payload.row, action.payload.col) 65 | }; 66 | case SET_WALL_NODE: 67 | MarkGridAsChanged(); 68 | 69 | return { 70 | ...state, 71 | grid: setWallNode(state.grid, action.payload.row, action.payload.col) 72 | }; 73 | case SET_TOTAL_NODES_EXPLORED: 74 | return { 75 | ...state, 76 | totalNodesExplored: action.payload 77 | }; 78 | case SET_ALGORITHM: 79 | const algorithm = state.algorithms.find( 80 | el => el.value === action.payload 81 | ); 82 | if (!algorithm || state.algorithm === action.payload) return state; 83 | 84 | return { 85 | ...state, 86 | algorithm: action.payload, 87 | isWeightNodeAllowed: algorithm.isWeight 88 | }; 89 | case SET_ALGORITHM_DESCRIPTION: 90 | if (!action.payload || state.algorithm === action.payload) return state; 91 | return { ...state, algorithmDescription: action.payload }; 92 | case CLEAR_STATE: 93 | if (!isGridChanged) return state; 94 | 95 | state = initialState; 96 | isGridChanged = false; 97 | clearGrid(); 98 | 99 | return { 100 | ...state, 101 | grid: getInitialGrid(), 102 | isLoading: false 103 | }; 104 | case CLEAR_GRID: 105 | if (state.grid.length === 0) return state; 106 | MarkGridAsChanged(); 107 | clearGrid(); 108 | return state; 109 | case REMOVE_WEIGHT_NODES: 110 | let newGrid = removeAllWeightNodes(state.grid); 111 | return { 112 | ...state, 113 | grid: newGrid 114 | }; 115 | default: 116 | return state; 117 | } 118 | 119 | function MarkGridAsChanged() { 120 | if (!isGridChanged) { 121 | isGridChanged = true; 122 | } 123 | } 124 | }; 125 | 126 | export default pathFindingAlgorithmsReducer; 127 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/store/sortingAlgorithms/actions/index.js: -------------------------------------------------------------------------------- 1 | import { 2 | INITIALIZE_CHART_DATA, 3 | GENERATE_NEW_ARRAY, 4 | SET_IS_NAVBAR_CLICKABLE, 5 | SET_BAR_CHART_ELEMENT_BACKGROUND_COLOR, 6 | SET_TOTAL_SWAPS 7 | } from '../../../constants/sortingAlgorithmsConstants'; 8 | 9 | export const initializeChartData = () => { 10 | return { 11 | type: INITIALIZE_CHART_DATA 12 | }; 13 | }; 14 | 15 | export const generateNewArray = () => { 16 | return { 17 | type: GENERATE_NEW_ARRAY 18 | }; 19 | }; 20 | 21 | export const setIsNavbarClickable = isClickable => { 22 | return { 23 | type: SET_IS_NAVBAR_CLICKABLE, 24 | payload: isClickable 25 | }; 26 | }; 27 | 28 | export const setTotalSwaps = value => { 29 | return { 30 | type: SET_TOTAL_SWAPS, 31 | payload: value 32 | }; 33 | }; 34 | 35 | export const setBarChartElementBackgroundColor = (elementsIndexes, color) => { 36 | return { 37 | type: SET_BAR_CHART_ELEMENT_BACKGROUND_COLOR, 38 | payload: { elementsIndexes, color } 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/store/sortingAlgorithms/context/index.js: -------------------------------------------------------------------------------- 1 | import React, { createContext, useReducer } from 'react'; 2 | import sortingAlgorithmsReducer from '../reducers'; 3 | import { 4 | TOTAL_SWAPS_DEFAULT_VALUE, 5 | availableSortingAlgorithms 6 | } from '../../../constants/sortingAlgorithmsConstants'; 7 | 8 | export const initialState = { 9 | isLoading: true, 10 | isNavbarClickable: true, 11 | algorithms: availableSortingAlgorithms, 12 | totalSwaps: TOTAL_SWAPS_DEFAULT_VALUE, 13 | barChart: { 14 | labels: [], 15 | datasets: [ 16 | { 17 | label: 'Value', 18 | backgroundColor: [], 19 | borderColor: 'rgba(255,99,132,1)', 20 | borderWidth: 1, 21 | hoverBackgroundColor: 'rgba(255,99,132,0.4)', 22 | hoverBorderColor: 'rgba(255,99,132,1)', 23 | data: [] 24 | } 25 | ] 26 | } 27 | }; 28 | 29 | export const SortingAlgorithmsContext = createContext(); 30 | 31 | export const SortingAlgorithmsProvider = props => { 32 | const [state, dispatch] = useReducer(sortingAlgorithmsReducer, initialState); 33 | return ( 34 | 35 | {props.children} 36 | 37 | ); 38 | }; 39 | -------------------------------------------------------------------------------- /AlgoVisualizer/Web/ClientApp/src/store/sortingAlgorithms/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { initialState } from '../context'; 2 | import { 3 | INITIALIZE_CHART_DATA, 4 | GENERATE_NEW_ARRAY, 5 | SET_IS_NAVBAR_CLICKABLE, 6 | SET_BAR_CHART_ELEMENT_BACKGROUND_COLOR, 7 | SET_TOTAL_SWAPS 8 | } from '../../../constants/sortingAlgorithmsConstants'; 9 | import { 10 | getInitialChart, 11 | generateNewChart, 12 | setBackgroundColorToChartElements 13 | } from '../../../helpers/sortingAlgorithmsHelper'; 14 | 15 | const sortingAlgorithmsReducer = (state = initialState, action) => { 16 | switch (action.type) { 17 | case INITIALIZE_CHART_DATA: 18 | const newChart = getInitialChart(); 19 | const oldDataSet = state.barChart.datasets[0]; 20 | return { 21 | ...state, 22 | barChart: { 23 | ...state.barChart, 24 | labels: newChart.labels, 25 | datasets: [ 26 | { 27 | ...oldDataSet, 28 | data: newChart.dataset.data, 29 | backgroundColor: newChart.dataset.backgroundColor 30 | } 31 | ] 32 | }, 33 | isLoading: false 34 | }; 35 | case GENERATE_NEW_ARRAY: 36 | const data = state.barChart; 37 | return { 38 | ...state, 39 | barChart: Object.assign({}, data, { 40 | data: generateNewChart(data) 41 | }) 42 | }; 43 | case SET_IS_NAVBAR_CLICKABLE: 44 | return { 45 | ...state, 46 | isNavbarClickable: action.payload 47 | }; 48 | case SET_TOTAL_SWAPS: 49 | return { ...state, totalSwaps: action.payload }; 50 | case SET_BAR_CHART_ELEMENT_BACKGROUND_COLOR: 51 | const barChart = state.barChart; 52 | return { 53 | ...state, 54 | barChart: Object.assign({}, barChart, { 55 | backgroundColor: Object.assign({}, barChart.backgroundColor, { 56 | backgroundColor: setBackgroundColorToChartElements( 57 | barChart, 58 | action.payload.elementsIndexes, 59 | action.payload.color 60 | ) 61 | }) 62 | }) 63 | }; 64 | default: 65 | return state; 66 | } 67 | }; 68 | 69 | export default sortingAlgorithmsReducer; 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Melik Pehlivanov 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 | # AlgorithmVisualizer 2 | 3 | **AlgorithmVisualizer** is an open-source web project which visualizes different pathfinding and sorting algorithms. I hope that you will enjoy this project just as much as I enjoyed building it. If you find any bugs, feel free to open an issue or make a pull request. https://melikpehlivanov.github.io/AlgorithmVisualizer/ 4 | 5 | >**My initial idea was to learn algorithms and react in the meantime so I decided to build this project. Firstly, I used react-redux and then switched to react-hooks in order to practice React. If you're interested to see the two different approaches, check the repository branches. By the way, the algorithmic part could have been implemented on the front end in order to eliminate the 2x more work but I wanted the algorithms to be written in C#. I also could use event sourcing but it would've been overengineering for such a small project.** 6 | 7 | [![Build status](https://dev.azure.com/melikpehlivanov/AlgoVisualizer/_apis/build/status/AlgoVisualizer)](https://dev.azure.com/melikpehlivanov/AlgoVisualizer/_build/latest?definitionId=7) 8 | 9 | ## Avalailable algorithms 10 | 11 | *** 12 | 13 | **Pathfinding algorithms:** 14 | * ___A* Search___ is weighted and it is arguably the best pathfinding algorithm out there. It uses heuristics to guarantee the shortest path and is much faster than Dijkstra's Algorithm 15 | * **Dijkstra's** Algorithm is also weighted. Dijkstra's algorithm is the father of pathfinding algorithms and it guarantees the shortest path 16 | * **Breath-first Search** is unweighted and it's a good algorithm which guarantees the shortest path 17 | * **Depth-first Search** is unweighted and it's a very bad algorithm for pathfinding. Moreover, it does not guarantee the shortest path 18 | *** 19 | 20 | **Sorting algorithms:** 21 | * Merge sort 22 | * Buble sort 23 | * Heap sort 24 | * Quick sort 25 | 26 | P.S Many more algorithms are going to come out with the next version of this application. By the way, if you like the project feel free to give it a star. 27 | --------------------------------------------------------------------------------