sorting and PLF example 2 with modern form.
a lot of C# to be real!
This commit is contained in:
33
PLF/plf/bsp2.py
Normal file
33
PLF/plf/bsp2.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
print("Berge Österreich")
|
||||||
|
b = ["Großglockner","Wildspitze","Weißkugel","Großvenediger"]
|
||||||
|
h = [3798,3768,3738,3657]
|
||||||
|
|
||||||
|
while True:
|
||||||
|
ein=str(input("Neue Eingabe (j/n)? "))
|
||||||
|
if ein == "j":
|
||||||
|
nb = str(input("Name des Berges: "))
|
||||||
|
nh = int(input("Höhe: "))
|
||||||
|
|
||||||
|
if nb in b:
|
||||||
|
print("Schon vorhanden")
|
||||||
|
else:
|
||||||
|
b.append(nb)
|
||||||
|
h.append(nh)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
for x,y in zip(b,h):
|
||||||
|
print(x,":",y)
|
||||||
|
|
||||||
|
ma = max(h)
|
||||||
|
i = h.index(ma)
|
||||||
|
print("Der höchste Berg der Liste ist der",b[i],"mit einer Höhe von",ma,"m")
|
||||||
|
|
||||||
|
d = sum(h)/len(h)
|
||||||
|
print("Die durchschnittliche Höhe aller Berge beträgt",d,"m.")
|
||||||
|
|
||||||
|
z = 0
|
||||||
|
for x in h:
|
||||||
|
if x >= 3000:
|
||||||
|
z+=1
|
||||||
|
print("In der Liste sind",z,"3000er gespeichert.")
|
||||||
91
PLF/plf/bsp2_modern.cpp
Normal file
91
PLF/plf/bsp2_modern.cpp
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <numeric>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
void add_mountain(vector<string>& names, vector<int>& heights) {
|
||||||
|
cout << "Name des Berges: ";
|
||||||
|
string name;
|
||||||
|
getline(cin >> ws, name);
|
||||||
|
|
||||||
|
// Check if already exists
|
||||||
|
if (find(names.begin(), names.end(), name) != names.end()) {
|
||||||
|
cout << "Schon vorhanden." << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cout << "Höhe: ";
|
||||||
|
int height;
|
||||||
|
if (!(cin >> height)) {
|
||||||
|
cout << "Ungültige Eingabe! Bitte eine Zahl angeben." << endl;
|
||||||
|
cin.clear();
|
||||||
|
cin.ignore(numeric_limits<streamsize>::max(), '\n');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
names.push_back(name);
|
||||||
|
heights.push_back(height);
|
||||||
|
cout << "'" << name << "' mit " << height << " m wurde hinzugefügt." << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void display_mountains(const vector<string>& names, const vector<int>& heights) {
|
||||||
|
cout << "\nBergliste:\n";
|
||||||
|
for (size_t i = 0; i < names.size(); ++i) {
|
||||||
|
cout << " • " << names[i] << ": " << heights[i] << " m\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pair<string, int> get_highest_mountain(const vector<string>& names, const vector<int>& heights) {
|
||||||
|
auto it = max_element(heights.begin(), heights.end());
|
||||||
|
size_t index = distance(heights.begin(), it);
|
||||||
|
return { names[index], *it };
|
||||||
|
}
|
||||||
|
|
||||||
|
double calculate_average_height(const vector<int>& heights) {
|
||||||
|
double sum = accumulate(heights.begin(), heights.end(), 0);
|
||||||
|
return sum / heights.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
int count_3000ers(const vector<int>& heights) {
|
||||||
|
return count_if(heights.begin(), heights.end(), [](int h) { return h >= 3000; });
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
cout << "Berge Österreich" << endl;
|
||||||
|
|
||||||
|
vector<string> mountain_names = { "Großglockner", "Wildspitze", "Weißkugel", "Großvenediger" };
|
||||||
|
vector<int> mountain_heights = { 3798, 3768, 3738, 3657 };
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
cout << "Neue Eingabe (j/n)? ";
|
||||||
|
string choice;
|
||||||
|
cin >> choice;
|
||||||
|
|
||||||
|
if (choice == "j" || choice == "J") {
|
||||||
|
add_mountain(mountain_names, mountain_heights);
|
||||||
|
} else if (choice == "n" || choice == "N") {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
cout << "Bitte nur 'j' oder 'n' eingeben." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
display_mountains(mountain_names, mountain_heights);
|
||||||
|
|
||||||
|
auto [highest_name, highest_height] = get_highest_mountain(mountain_names, mountain_heights);
|
||||||
|
cout << "\nDer höchste Berg ist der " << highest_name
|
||||||
|
<< " mit " << highest_height << " m.\n";
|
||||||
|
|
||||||
|
cout << fixed << setprecision(1);
|
||||||
|
double avg_height = calculate_average_height(mountain_heights);
|
||||||
|
cout << "Die durchschnittliche Höhe beträgt " << avg_height << " m.\n";
|
||||||
|
|
||||||
|
int count = count_3000ers(mountain_heights);
|
||||||
|
cout << "In der Liste sind " << count << " 3000er gespeichert.\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
74
PLF/plf/bsp2_modern.py
Normal file
74
PLF/plf/bsp2_modern.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
from typing import List
|
||||||
|
|
||||||
|
def add_mountain(names: List[str], heights: List[int]) -> None:
|
||||||
|
"""Add a new mountain entry if it doesn't already exist."""
|
||||||
|
name = input("Name des Berges: ").strip()
|
||||||
|
if name in names:
|
||||||
|
print("Schon vorhanden.")
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
height = int(input("Höhe: ").strip())
|
||||||
|
except ValueError:
|
||||||
|
print("Ungültige Eingabe! Bitte eine Zahl angeben.")
|
||||||
|
return
|
||||||
|
|
||||||
|
names.append(name)
|
||||||
|
heights.append(height)
|
||||||
|
print(f"'{name}' mit {height} m wurde hinzugefügt.")
|
||||||
|
|
||||||
|
|
||||||
|
def display_mountains(names: List[str], heights: List[int]) -> None:
|
||||||
|
"""Print the list of all mountains and their heights."""
|
||||||
|
print("\nBergliste:")
|
||||||
|
for name, height in zip(names, heights):
|
||||||
|
print(f" • {name}: {height} m")
|
||||||
|
|
||||||
|
|
||||||
|
def get_highest_mountain(names: List[str], heights: List[int]) -> tuple[str, int]:
|
||||||
|
"""Return the highest mountain as (name, height)."""
|
||||||
|
max_height = max(heights)
|
||||||
|
index = heights.index(max_height)
|
||||||
|
return names[index], max_height
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_average_height(heights: List[int]) -> float:
|
||||||
|
"""Return the average height of all mountains."""
|
||||||
|
return sum(heights) / len(heights)
|
||||||
|
|
||||||
|
|
||||||
|
def count_3000ers(heights: List[int]) -> int:
|
||||||
|
"""Return how many mountains are 3000 meters or higher."""
|
||||||
|
return sum(h >= 3000 for h in heights)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""Main program loop."""
|
||||||
|
print("Berge Österreich")
|
||||||
|
|
||||||
|
mountain_names = ["Großglockner", "Wildspitze", "Weißkugel", "Großvenediger"]
|
||||||
|
mountain_heights = [3798, 3768, 3738, 3657]
|
||||||
|
|
||||||
|
while True:
|
||||||
|
choice = input("Neue Eingabe (j/n)? ").strip().lower()
|
||||||
|
if choice == "j":
|
||||||
|
add_mountain(mountain_names, mountain_heights)
|
||||||
|
elif choice == "n":
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
print("Bitte nur 'j' oder 'n' eingeben.")
|
||||||
|
|
||||||
|
display_mountains(mountain_names, mountain_heights)
|
||||||
|
|
||||||
|
highest_name, highest_height = get_highest_mountain(mountain_names, mountain_heights)
|
||||||
|
print(f"\nDer höchste Berg ist der {highest_name} mit {highest_height} m.")
|
||||||
|
|
||||||
|
avg_height = calculate_average_height(mountain_heights)
|
||||||
|
print(f"Die durchschnittliche Höhe beträgt {avg_height:.1f} m.")
|
||||||
|
|
||||||
|
count = count_3000ers(mountain_heights)
|
||||||
|
print(f"In der Liste sind {count} 3000er gespeichert.")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -283,7 +283,7 @@ namespace CubeCollisionSimulator
|
|||||||
// Instructions
|
// Instructions
|
||||||
Label instructionsLabel = new Label
|
Label instructionsLabel = new Label
|
||||||
{
|
{
|
||||||
Text = "Instructions:\n\n<> Click and drag cubes\n<> Throw them by dragging\n<> Watch them collide!\n<> Adjust physics sliders\n<> Add more cubes\n<> Toggle sound on/off",
|
Text = "Instructions:\n\n<> Click and drag cubes\n<> Throw them by dragging\n<> Watch them collide!\n<> Adjust physics sliders\n<> Add more cubes\n<> Toggle sound on/off",
|
||||||
Location = new Point(10, yPos + 20),
|
Location = new Point(10, yPos + 20),
|
||||||
Size = new Size(230, 200),
|
Size = new Size(230, 200),
|
||||||
ForeColor = Color.LightGray
|
ForeColor = Color.LightGray
|
||||||
@@ -547,4 +547,5 @@ namespace CubeCollisionSimulator
|
|||||||
Application.Run(new SimulatorForm());
|
Application.Run(new SimulatorForm());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
50
simulations/SortVisualizer/Algorithms/BogoSort.cs
Normal file
50
simulations/SortVisualizer/Algorithms/BogoSort.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public class BogoSort : ISortAlgorithm
|
||||||
|
{
|
||||||
|
public string Name => "Bogo Sort";
|
||||||
|
|
||||||
|
private static readonly Random rand = new();
|
||||||
|
public static BogoSort Instance { get; } = new BogoSort();
|
||||||
|
public BogoSort() { }
|
||||||
|
|
||||||
|
public async Task Sort(int[] array, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (!IsSorted(array))
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
// Shuffle array
|
||||||
|
for (int i = 0; i < array.Length; i++)
|
||||||
|
{
|
||||||
|
int j = rand.Next(array.Length);
|
||||||
|
(array[i], array[j]) = (array[j], array[i]);
|
||||||
|
|
||||||
|
playSound?.Invoke(array[i]);
|
||||||
|
refresh?.Invoke();
|
||||||
|
|
||||||
|
// small delay for live updates
|
||||||
|
await Task.Delay(delay, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
// Sorting was stopped; exit gracefully
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsSorted(int[] array)
|
||||||
|
{
|
||||||
|
for (int i = 1; i < array.Length; i++)
|
||||||
|
if (array[i - 1] > array[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
29
simulations/SortVisualizer/Algorithms/BubbleSort.cs
Normal file
29
simulations/SortVisualizer/Algorithms/BubbleSort.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public class BubbleSort : ISortAlgorithm
|
||||||
|
{
|
||||||
|
public string Name => "Bubble Sort";
|
||||||
|
|
||||||
|
public async Task Sort(int[] array, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < array.Length - 1; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < array.Length - i - 1; j++)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested) return;
|
||||||
|
|
||||||
|
playSound(array[j]);
|
||||||
|
if (array[j] > array[j + 1])
|
||||||
|
{
|
||||||
|
(array[j], array[j + 1]) = (array[j + 1], array[j]);
|
||||||
|
refresh();
|
||||||
|
await Task.Delay(delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
simulations/SortVisualizer/Algorithms/ISortAlgorithm.cs
Normal file
18
simulations/SortVisualizer/Algorithms/ISortAlgorithm.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public interface ISortAlgorithm
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
Task Sort(
|
||||||
|
int[] array,
|
||||||
|
Action refresh,
|
||||||
|
int delay,
|
||||||
|
Action<int> playSound,
|
||||||
|
CancellationToken token
|
||||||
|
);
|
||||||
|
}
|
||||||
33
simulations/SortVisualizer/Algorithms/InsertionSort.cs
Normal file
33
simulations/SortVisualizer/Algorithms/InsertionSort.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public class InsertionSort : ISortAlgorithm
|
||||||
|
{
|
||||||
|
public string Name => "Insertion Sort";
|
||||||
|
|
||||||
|
public async Task Sort(int[] array, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
for (int i = 1; i < array.Length; i++)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested) return;
|
||||||
|
|
||||||
|
int key = array[i];
|
||||||
|
int j = i - 1;
|
||||||
|
|
||||||
|
while (j >= 0 && array[j] > key)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested) return;
|
||||||
|
|
||||||
|
playSound(array[j]);
|
||||||
|
array[j + 1] = array[j];
|
||||||
|
j--;
|
||||||
|
refresh();
|
||||||
|
await Task.Delay(delay);
|
||||||
|
}
|
||||||
|
array[j + 1] = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
83
simulations/SortVisualizer/Algorithms/MergeSort.cs
Normal file
83
simulations/SortVisualizer/Algorithms/MergeSort.cs
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public class MergeSort : ISortAlgorithm
|
||||||
|
{
|
||||||
|
public string Name => "Merge Sort";
|
||||||
|
public MergeSort() { }
|
||||||
|
public async Task Sort(int[] array, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
await MergeSortRecursive(array, 0, array.Length - 1, refresh, delay, playSound, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task MergeSortRecursive(int[] array, int left, int right, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (left >= right) return;
|
||||||
|
|
||||||
|
int mid = (left + right) / 2;
|
||||||
|
await MergeSortRecursive(array, left, mid, refresh, delay, playSound, token);
|
||||||
|
await MergeSortRecursive(array, mid + 1, right, refresh, delay, playSound, token);
|
||||||
|
await Merge(array, left, mid, right, refresh, delay, playSound, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Merge(int[] array, int left, int mid, int right, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
int n1 = mid - left + 1;
|
||||||
|
int n2 = right - mid;
|
||||||
|
|
||||||
|
int[] L = new int[n1];
|
||||||
|
int[] R = new int[n2];
|
||||||
|
|
||||||
|
Array.Copy(array, left, L, 0, n1);
|
||||||
|
Array.Copy(array, mid + 1, R, 0, n2);
|
||||||
|
|
||||||
|
int i = 0, j = 0, k = left;
|
||||||
|
|
||||||
|
while (i < n1 && j < n2)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
if (L[i] <= R[j])
|
||||||
|
{
|
||||||
|
array[k] = L[i];
|
||||||
|
playSound?.Invoke(L[i]);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
array[k] = R[j];
|
||||||
|
playSound?.Invoke(R[j]);
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh?.Invoke();
|
||||||
|
await Task.Delay(delay, token);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (i < n1)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
array[k] = L[i];
|
||||||
|
playSound?.Invoke(L[i]);
|
||||||
|
i++; k++;
|
||||||
|
refresh?.Invoke();
|
||||||
|
await Task.Delay(delay, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (j < n2)
|
||||||
|
{
|
||||||
|
token.ThrowIfCancellationRequested();
|
||||||
|
array[k] = R[j];
|
||||||
|
playSound?.Invoke(R[j]);
|
||||||
|
j++; k++;
|
||||||
|
refresh?.Invoke();
|
||||||
|
await Task.Delay(delay, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
simulations/SortVisualizer/Algorithms/StoogeSort.cs
Normal file
58
simulations/SortVisualizer/Algorithms/StoogeSort.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public class StoogeSort : ISortAlgorithm
|
||||||
|
{
|
||||||
|
public string Name => "Stooge Sort";
|
||||||
|
public StoogeSort() { }
|
||||||
|
|
||||||
|
public async Task Sort(int[] array, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await StoogeSortRecursive(array, 0, array.Length - 1, refresh, delay, playSound, token);
|
||||||
|
}
|
||||||
|
catch (TaskCanceledException)
|
||||||
|
{
|
||||||
|
// Sorting was cancelled <20> handle gracefully
|
||||||
|
// Optionally, reset UI or log here
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
// Unexpected exception <20> optional logging
|
||||||
|
Console.WriteLine($"StoogeSort error: {ex}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task StoogeSortRecursive(int[] array, int i, int j, Action refresh, int delay, Action<int> playSound, CancellationToken token)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested) return; // graceful early exit
|
||||||
|
|
||||||
|
// Swap if first element is greater than last
|
||||||
|
if (array[i] > array[j])
|
||||||
|
{
|
||||||
|
int temp = array[i];
|
||||||
|
array[i] = array[j];
|
||||||
|
array[j] = temp;
|
||||||
|
|
||||||
|
playSound?.Invoke(array[i]);
|
||||||
|
playSound?.Invoke(array[j]);
|
||||||
|
refresh?.Invoke();
|
||||||
|
|
||||||
|
try { await Task.Delay(delay, token); }
|
||||||
|
catch (TaskCanceledException) { return; } // exit silently if cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j - i + 1 > 2)
|
||||||
|
{
|
||||||
|
int t = (j - i + 1) / 3;
|
||||||
|
|
||||||
|
await StoogeSortRecursive(array, i, j - t, refresh, delay, playSound, token);
|
||||||
|
await StoogeSortRecursive(array, i + t, j, refresh, delay, playSound, token);
|
||||||
|
await StoogeSortRecursive(array, i, j - t, refresh, delay, playSound, token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
simulations/SortVisualizer/Form1.Designer.cs
generated
Normal file
38
simulations/SortVisualizer/Form1.Designer.cs
generated
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
partial class Form1
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Required designer variable.
|
||||||
|
/// </summary>
|
||||||
|
private System.ComponentModel.IContainer components = null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Clean up any resources being used.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing && (components != null))
|
||||||
|
{
|
||||||
|
components.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Windows Form Designer generated code
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Required method for Designer support - do not modify
|
||||||
|
/// the contents of this method with the code editor.
|
||||||
|
/// </summary>
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
this.components = new System.ComponentModel.Container();
|
||||||
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
this.ClientSize = new System.Drawing.Size(800, 450);
|
||||||
|
this.Text = "Form1";
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
9
simulations/SortVisualizer/Form1.cs
Normal file
9
simulations/SortVisualizer/Form1.cs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public partial class Form1 : Form
|
||||||
|
{
|
||||||
|
public Form1()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
14
simulations/SortVisualizer/Program.cs
Normal file
14
simulations/SortVisualizer/Program.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
internal static class Program
|
||||||
|
{
|
||||||
|
[STAThread]
|
||||||
|
static void Main()
|
||||||
|
{
|
||||||
|
ApplicationConfiguration.Initialize();
|
||||||
|
Application.Run(new VisualizerForm());
|
||||||
|
}
|
||||||
|
}
|
||||||
11
simulations/SortVisualizer/SortVisualizer.csproj
Normal file
11
simulations/SortVisualizer/SortVisualizer.csproj
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net9.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<UseWindowsForms>true</UseWindowsForms>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
289
simulations/SortVisualizer/VisualizerForm.cs
Normal file
289
simulations/SortVisualizer/VisualizerForm.cs
Normal file
@@ -0,0 +1,289 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Media;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace SortVisualizer;
|
||||||
|
|
||||||
|
public class VisualizerForm : Form
|
||||||
|
{
|
||||||
|
int[] array = Array.Empty<int>();
|
||||||
|
Random rand = new();
|
||||||
|
int delay = 10;
|
||||||
|
bool sorting = false;
|
||||||
|
|
||||||
|
ComboBox algoSelector;
|
||||||
|
Button startButton, stopButton, shuffleButton;
|
||||||
|
TrackBar speedSlider;
|
||||||
|
CheckBox soundToggle;
|
||||||
|
Label speedLabel, statusLabel;
|
||||||
|
|
||||||
|
List<ISortAlgorithm> algorithms;
|
||||||
|
CancellationTokenSource? cts;
|
||||||
|
|
||||||
|
Dictionary<int, byte[]> toneCache = new();
|
||||||
|
SemaphoreSlim soundSemaphore = new(1, 1); // prevent sound overlap
|
||||||
|
|
||||||
|
int highlightedIndex1 = -1;
|
||||||
|
int highlightedIndex2 = -1;
|
||||||
|
|
||||||
|
public VisualizerForm()
|
||||||
|
{
|
||||||
|
Text = "C# Sorting";
|
||||||
|
DoubleBuffered = true;
|
||||||
|
MinimumSize = new Size(800, 500);
|
||||||
|
Width = 1000;
|
||||||
|
Height = 600;
|
||||||
|
|
||||||
|
algorithms = new() { new BubbleSort(), new InsertionSort(), new BogoSort(),
|
||||||
|
new MergeSort() , new StoogeSort()
|
||||||
|
};
|
||||||
|
|
||||||
|
// --- Top Control Panel ---
|
||||||
|
var topPanel = new FlowLayoutPanel
|
||||||
|
{
|
||||||
|
Dock = DockStyle.Top,
|
||||||
|
AutoSize = true,
|
||||||
|
WrapContents = true,
|
||||||
|
FlowDirection = FlowDirection.LeftToRight,
|
||||||
|
Padding = new Padding(5),
|
||||||
|
AutoScroll = true
|
||||||
|
};
|
||||||
|
|
||||||
|
algoSelector = new ComboBox { Width = 160, DropDownStyle = ComboBoxStyle.DropDownList };
|
||||||
|
algoSelector.DataSource = algorithms;
|
||||||
|
algoSelector.DisplayMember = "Name";
|
||||||
|
|
||||||
|
int buttonHeight = algoSelector.Height;
|
||||||
|
|
||||||
|
startButton = new Button { Width = 100, Height = buttonHeight, Text = "Start" };
|
||||||
|
stopButton = new Button { Width = 100, Height = buttonHeight, Text = "Stop" };
|
||||||
|
shuffleButton = new Button { Width = 100, Height = buttonHeight, Text = "Shuffle" };
|
||||||
|
|
||||||
|
soundToggle = new CheckBox { Width = 100, Height = buttonHeight, Text = "Sound On", Checked = true };
|
||||||
|
|
||||||
|
speedLabel = new Label { Width = 60, Height = buttonHeight, Text = "Speed: 10", TextAlign = ContentAlignment.MiddleCenter };
|
||||||
|
speedSlider = new TrackBar
|
||||||
|
{
|
||||||
|
Width = 250,
|
||||||
|
Minimum = 1,
|
||||||
|
Maximum = 100,
|
||||||
|
Value = 10,
|
||||||
|
TickFrequency = 10,
|
||||||
|
SmallChange = 1,
|
||||||
|
LargeChange = 10,
|
||||||
|
Height = buttonHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
statusLabel = new Label { Width = 150, Height = buttonHeight, Text = "Idle", TextAlign = ContentAlignment.MiddleRight };
|
||||||
|
|
||||||
|
topPanel.Controls.AddRange(new Control[]
|
||||||
|
{
|
||||||
|
algoSelector, startButton, stopButton, shuffleButton,
|
||||||
|
soundToggle, speedLabel, speedSlider, statusLabel
|
||||||
|
});
|
||||||
|
|
||||||
|
Controls.Add(topPanel);
|
||||||
|
|
||||||
|
speedSlider.ValueChanged += (s, e) =>
|
||||||
|
{
|
||||||
|
delay = 101 - speedSlider.Value;
|
||||||
|
speedLabel.Text = $"Speed: {speedSlider.Value}";
|
||||||
|
};
|
||||||
|
|
||||||
|
startButton.Click += async (s, e) => await StartSort();
|
||||||
|
stopButton.Click += (s, e) => StopSort();
|
||||||
|
shuffleButton.Click += (s, e) => Shuffle();
|
||||||
|
|
||||||
|
this.Resize += (s, e) => Invalidate();
|
||||||
|
|
||||||
|
Shuffle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shuffle()
|
||||||
|
{
|
||||||
|
if (sorting) return;
|
||||||
|
array = Enumerable.Range(1, 100).OrderBy(_ => rand.Next()).ToArray();
|
||||||
|
highlightedIndex1 = highlightedIndex2 = -1;
|
||||||
|
Invalidate();
|
||||||
|
statusLabel.Text = "Shuffled!";
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task StartSort()
|
||||||
|
{
|
||||||
|
if (sorting) return;
|
||||||
|
sorting = true;
|
||||||
|
cts = new CancellationTokenSource();
|
||||||
|
|
||||||
|
var algo = (ISortAlgorithm)algoSelector.SelectedItem!;
|
||||||
|
statusLabel.Text = $"Sorting ( {algo.Name} )...";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await algo.Sort(
|
||||||
|
array,
|
||||||
|
() => Invalidate(), // keep original signature
|
||||||
|
delay,
|
||||||
|
value => { if (soundToggle.Checked) _ = PlaySoundAsync(value); },
|
||||||
|
cts.Token
|
||||||
|
);
|
||||||
|
|
||||||
|
highlightedIndex1 = highlightedIndex2 = -1;
|
||||||
|
Invalidate();
|
||||||
|
|
||||||
|
if (!cts.Token.IsCancellationRequested)
|
||||||
|
statusLabel.Text = "Done!";
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
sorting = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StopSort()
|
||||||
|
{
|
||||||
|
if (!sorting) return;
|
||||||
|
cts?.Cancel();
|
||||||
|
sorting = false;
|
||||||
|
highlightedIndex1 = highlightedIndex2 = -1;
|
||||||
|
Invalidate();
|
||||||
|
statusLabel.Text = "Stopped.";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPaint(PaintEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnPaint(e);
|
||||||
|
var g = e.Graphics;
|
||||||
|
|
||||||
|
int offsetY = 50;
|
||||||
|
int marginX = 20;
|
||||||
|
|
||||||
|
if (array.Length == 0) return;
|
||||||
|
|
||||||
|
int barWidth = (ClientSize.Width - 2 * marginX) / array.Length;
|
||||||
|
int availableHeight = ClientSize.Height - offsetY;
|
||||||
|
|
||||||
|
for (int i = 0; i < array.Length; i++)
|
||||||
|
{
|
||||||
|
int height = (int)(array[i] * (availableHeight / (float)array.Length));
|
||||||
|
Brush brush = Brushes.LightGreen;
|
||||||
|
|
||||||
|
if (sorting)
|
||||||
|
{
|
||||||
|
if (i == highlightedIndex1) brush = Brushes.Red;
|
||||||
|
else if (i == highlightedIndex2) brush = Brushes.Orange;
|
||||||
|
else brush = Brushes.DeepSkyBlue;
|
||||||
|
}
|
||||||
|
|
||||||
|
g.FillRectangle(brush, marginX + i * barWidth, ClientSize.Height - height, barWidth - 1, height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task PlaySoundAsync(int value)
|
||||||
|
{
|
||||||
|
// Use semaphore to prevent overlapping sounds
|
||||||
|
if (!await soundSemaphore.WaitAsync(0))
|
||||||
|
return; // skip if already playing
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int freq = 220 + (int)(value * 12.0);
|
||||||
|
int durationMs = 10;
|
||||||
|
|
||||||
|
if (!toneCache.TryGetValue(freq, out var wav))
|
||||||
|
{
|
||||||
|
wav = GenerateToneWav(freq, durationMs, 44100);
|
||||||
|
|
||||||
|
// Limit cache size
|
||||||
|
if (toneCache.Count > 200)
|
||||||
|
toneCache.Clear();
|
||||||
|
|
||||||
|
toneCache[freq] = wav;
|
||||||
|
}
|
||||||
|
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var ms = new MemoryStream(wav);
|
||||||
|
using var player = new SoundPlayer(ms);
|
||||||
|
player.PlaySync(); // blocks on background thread
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||||
|
Console.Beep(freq, durationMs);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
soundSemaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
cts?.Dispose();
|
||||||
|
soundSemaphore?.Dispose();
|
||||||
|
}
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Tone Generation
|
||||||
|
|
||||||
|
public static byte[] GenerateToneWav(int frequency, int durationMs, int sampleRate = 44100, double amplitude = 0.25)
|
||||||
|
{
|
||||||
|
int samples = (int)((durationMs / 1000.0) * sampleRate);
|
||||||
|
using var ms = new MemoryStream();
|
||||||
|
using var bw = new BinaryWriter(ms);
|
||||||
|
|
||||||
|
short numChannels = 1;
|
||||||
|
short bitsPerSample = 16;
|
||||||
|
int byteRate = sampleRate * numChannels * bitsPerSample / 8;
|
||||||
|
short blockAlign = (short)(numChannels * bitsPerSample / 8);
|
||||||
|
int dataSize = samples * numChannels * (bitsPerSample / 8);
|
||||||
|
|
||||||
|
bw.Write(System.Text.Encoding.ASCII.GetBytes("RIFF"));
|
||||||
|
bw.Write(36 + dataSize);
|
||||||
|
bw.Write(System.Text.Encoding.ASCII.GetBytes("WAVE"));
|
||||||
|
|
||||||
|
bw.Write(System.Text.Encoding.ASCII.GetBytes("fmt "));
|
||||||
|
bw.Write(16);
|
||||||
|
bw.Write((short)1);
|
||||||
|
bw.Write(numChannels);
|
||||||
|
bw.Write(sampleRate);
|
||||||
|
bw.Write(byteRate);
|
||||||
|
bw.Write(blockAlign);
|
||||||
|
bw.Write(bitsPerSample);
|
||||||
|
|
||||||
|
bw.Write(System.Text.Encoding.ASCII.GetBytes("data"));
|
||||||
|
bw.Write(dataSize);
|
||||||
|
|
||||||
|
double twoPiF = 2 * Math.PI * frequency;
|
||||||
|
for (int n = 0; n < samples; n++)
|
||||||
|
{
|
||||||
|
double t = n / (double)sampleRate;
|
||||||
|
double sample = amplitude * Math.Sin(twoPiF * t);
|
||||||
|
short s = (short)Math.Max(short.MinValue, Math.Min(short.MaxValue, sample * short.MaxValue));
|
||||||
|
bw.Write(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
bw.Flush();
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ pygame.init()
|
|||||||
# Screen setup
|
# Screen setup
|
||||||
WIDTH, HEIGHT = 800, 600
|
WIDTH, HEIGHT = 800, 600
|
||||||
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
||||||
pygame.display.set_caption("Enhanced Physics Bouncing Balls")
|
pygame.display.set_caption("balls")
|
||||||
|
|
||||||
# Colors
|
# Colors
|
||||||
BLACK = (0, 0, 0)
|
BLACK = (0, 0, 0)
|
||||||
@@ -259,15 +259,15 @@ while running:
|
|||||||
|
|
||||||
# Physics info
|
# Physics info
|
||||||
font = pygame.font.SysFont(None, 22)
|
font = pygame.font.SysFont(None, 22)
|
||||||
info = [
|
# info = [
|
||||||
f"Gravity: {gravity:.2f} (↑↓) Elasticity: {elasticity:.2f} (←→)",
|
# f"Gravity: {gravity:.2f} Elasticity: {elasticity:.2f} (←→)",
|
||||||
f"Air Resistance: {air_resistance:.3f} (WS) Balls: {len(balls)}",
|
# f"Air Resistance: {air_resistance:.3f} (WS) Balls: {len(balls)}",
|
||||||
f"SPACE: Add ball C: Clear Drag to throw!"
|
# f"SPACE: Add ball C: Clear Drag to throw!"
|
||||||
]
|
# ]
|
||||||
|
|
||||||
for i, text in enumerate(info):
|
# for i, text in enumerate(info):
|
||||||
surface = font.render(text, True, WHITE)
|
# surface = font.render(text, True, WHITE)
|
||||||
screen.blit(surface, (10, 10 + i * 25))
|
# screen.blit(surface, (10, 10 + i * 25))
|
||||||
|
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
clock.tick(FPS)
|
clock.tick(FPS)
|
||||||
|
|||||||
Reference in New Issue
Block a user