<!--
MIT License
Copyright (c) 2025 Rob de Roy | Wolfram Consult GmbH & Co. KG
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-->
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Genetischer Algorithmus</title>
<style>
/* Allgemeine Stile */
body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
color: white;
background-color: #121212;
overflow: auto; /* Erlaube Scrollen, wenn der Inhalt zu groß wird */
}
/* Partikelanimation */
canvas {
position: fixed; /* Animation bleibt fixiert im Hintergrund */
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: -1; /* Stelle sicher, dass die Animation hinter dem Content bleibt */
}
/* Hauptcontainer */
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px; /* Füge Padding hinzu, um den Content vom Rand abzurücken */
max-width: 800px; /* Begrenze die Breite des Containers */
margin: 0 auto; /* Zentriere den Container horizontal */
}
h1 {
font-size: 3em;
margin: 0 0 20px;
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5);
}
p.explanation {
font-size: 1.2em;
margin: 0 0 20px;
max-width: 600px;
text-align: center;
line-height: 1.6;
}
input[type="text"], input[type="number"] {
padding: 15px;
width: 400px;
font-size: 18px;
border: none;
border-radius: 5px;
margin-bottom: 20px;
background-color: rgba(255, 255, 255, 0.1);
color: white;
box-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
}
button {
padding: 10px 20px;
font-size: 16px;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
transition: transform 0.3s ease, box-shadow 0.3s ease;
margin: 5px;
}
button.start {
background-color: #4CAF50;
box-shadow: 0 0 10px rgba(76, 175, 80, 0.5);
}
button.reset {
background-color: #f44336;
box-shadow: 0 0 10px rgba(244, 67, 54, 0.5);
}
button.speed {
background-color: #2196F3;
box-shadow: 0 0 10px rgba(33, 150, 243, 0.5);
}
label {
font-size: 16px;
margin-right: 10px;
}
input[type="checkbox"] {
transform: scale(1.5);
margin-right: 10px;
}
button:hover {
transform: scale(1.1);
box-shadow: 0 0 20px rgba(255, 255, 255, 0.8);
}
#output {
margin-top: 20px;
width: 100%; /* Mache das Ausgabefeld responsive */
max-width: 600px; /* Begrenze die maximale Breite */
height: 300px;
overflow-y: auto;
border: 2px solid rgba(255, 255, 255, 0.3);
padding: 10px;
background-color: rgba(0, 0, 0, 0.5);
font-family: Courier, monospace;
font-size: 14px;
color: white;
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.5) transparent;
}
#info {
margin-top: 10px;
font-size: 18px;
color: rgba(255, 255, 255, 0.8);
}
#bestPhrase {
color: #4CAF50; /* Grüne Schriftfarbe für die beste Phrase */
font-weight: bold;
}
#totalYears {
color: #FFC107; /* Gelbe Schriftfarbe für die Gesamtdauer */
font-weight: bold;
}
</style>
</head>
<body>
<!-- Partikelanimation -->
<canvas id="particleCanvas"></canvas>
<!-- Hauptinhalt -->
<div class="container">
<h1>Genetischer Algorithmus</h1>
<p class="explanation">
Willkommen beim <strong>Genetischen Algorithmus-Tool</strong>! Dieses Tool simuliert den Evolutionsprozess, um aus einer zufälligen Phrase dein Ziel zu erreichen. Dabei verwendet es Prinzipien wie Mutation, Selektion und Kreuzung, um nach und nach die richtige Lösung zu finden.
<br>
</p>
<input type="text" id="targetInput" placeholder="Gib dein Ziel ein..." />
<label for="populationSize">Populationgröße (50–500): </label>
<input type="number" id="populationSize" min="50" max="500" value="300" />
<label><input type="checkbox" id="eliteMode" checked> Elite behalten</label>
<div>
<button class="start" onclick="startEvolution()">Start Evolution</button>
<button class="reset" onclick="resetEvolution()">Reset</button>
<button class="speed" onclick="changeSpeed(-1)">Verlangsamen</button>
<button class="speed" onclick="changeSpeed(1)">Beschleunigen</button>
</div>
<div id="info">
Generation: <span id="generation">0</span><br>
Beste Phrase: <span id="bestPhrase"></span><br>
Gesamtdauer: <span id="totalYears">0 Jahre</span>
</div>
<div id="output"></div>
</div>
<script>
// Partikelanimation
const canvas = document.getElementById("particleCanvas");
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
window.addEventListener("resize", () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
});
class Particle {
constructor(x, y) {
this.x = x;
this.y = y;
this.size = Math.random() * 2 + 1;
this.color = `rgba(255, 255, 255, ${Math.random() * 0.5 + 0.1})`;
this.velocity = { x: (Math.random() - 0.5) * 2, y: (Math.random() - 0.5) * 2 };
this.gravity = 0.05;
}
update() {
this.velocity.y += this.gravity;
this.x += this.velocity.x;
this.y += this.velocity.y;
if (this.y + this.size > canvas.height) {
this.velocity.y *= -0.5;
}
if (this.x + this.size > canvas.width || this.x - this.size < 0) {
this.velocity.x *= -1;
}
}
draw() {
ctx.beginPath();
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
ctx.fillStyle = this.color;
ctx.fill();
ctx.closePath();
}
}
let particles = [];
function initParticles() {
for (let i = 0; i < 100; i++) {
particles.push(new Particle(Math.random() * canvas.width, Math.random() * canvas.height));
}
}
function animateParticles() {
requestAnimationFrame(animateParticles);
ctx.clearRect(0, 0, canvas.width, canvas.height);
particles.forEach((particle, index) => {
particle.update();
particle.draw();
// Verbinde Partikel
particles.forEach((otherParticle, otherIndex) => {
if (index !== otherIndex) {
const dx = particle.x - otherParticle.x;
const dy = particle.y - otherParticle.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
ctx.strokeStyle = `rgba(255, 255, 255, ${1 - distance / 100})`;
ctx.lineWidth = 0.5;
ctx.beginPath();
ctx.moveTo(particle.x, particle.y);
ctx.lineTo(otherParticle.x, otherParticle.y);
ctx.stroke();
}
}
});
});
}
initParticles();
animateParticles();
// Genetischer Algorithmus
const charset = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~äöüßÄÖÜ"; // Erweiterter Zeichensatz
let mutationRate = 0.02;
let populationSize = 300; // Standardwert
let population = [];
let target = "";
let generation = 0;
let evolutionInterval = null; // Für Geschwindigkeitssteuerung
let speedFactor = 1; // Standardgeschwindigkeit
let bestPhrase = ""; // Best Phrase global deklarieren
class GeneticDNA {
constructor(numGenes) {
this.genes = [];
this.fitness = 0;
for (let i = 0; i < numGenes; i++) {
this.genes[i] = charset[Math.floor(Math.random() * charset.length)];
}
}
calculateFitness(target) {
let score = 0;
for (let i = 0; i < this.genes.length; i++) {
if (this.genes[i] === target[i]) {
score++;
}
}
this.fitness = score / target.length;
}
crossover(partner) {
let child = new GeneticDNA(this.genes.length);
let midpoint = Math.floor(Math.random() * this.genes.length);
for (let i = 0; i < this.genes.length; i++) {
if (i < midpoint) {
child.genes[i] = this.genes[i];
} else {
child.genes[i] = partner.genes[i];
}
}
return child;
}
mutate(mutationRate) {
for (let i = 0; i < this.genes.length; i++) {
if (Math.random() < mutationRate) {
this.genes[i] = charset[Math.floor(Math.random() * charset.length)];
}
}
}
getPhrase() {
return this.genes.join("");
}
}
function startEvolution() {
if (evolutionInterval) return; // Verhindert mehrere gleichzeitige Evolutionsprozesse
target = document.getElementById("targetInput").value;
if (!target) {
alert("Bitte gib ein Ziel ein!");
return;
}
// Lese die Populationgröße aus dem Eingabefeld
populationSize = parseInt(document.getElementById("populationSize").value, 10);
if (isNaN(populationSize) || populationSize < 50 || populationSize > 500) {
alert("Die Populationgröße muss zwischen 50 und 500 liegen.");
return;
}
population = [];
for (let i = 0; i < populationSize; i++) {
population[i] = new GeneticDNA(target.length);
}
generation = 0;
updateUI();
evolutionInterval = setInterval(evolve, 100 / speedFactor); // Anpassung an Geschwindigkeit
}
function evolve() {
let highestFitness = 0;
for (let phrase of population) {
phrase.calculateFitness(target);
if (phrase.fitness > highestFitness) {
highestFitness = phrase.fitness;
bestPhrase = phrase.getPhrase(); // Aktualisiere die globale Variable
}
}
if (highestFitness === 1) {
clearInterval(evolutionInterval);
evolutionInterval = null;
// Zeige das Ergebnis im Alert-Fenster
const yearsPerGeneration = 30; // Durchschnittliche menschliche Generation
const totalYears = generation * yearsPerGeneration;
alert(`Ziel erreicht: "${target}"\nDie beteiligten Generationen hätten in der Realität ${totalYears} Jahre benötigt, um dieses Ziel zu erreichen.`);
}
let matingPool = [];
for (let phrase of population) {
let n = Math.floor(phrase.fitness * 100);
for (let j = 0; j < n; j++) {
matingPool.push(phrase);
}
}
// Elitism-Option
let eliteMode = document.getElementById("eliteMode").checked;
let elites = [];
if (eliteMode) {
population.sort((a, b) => b.fitness - a.fitness); // Sortiere nach Fitness
elites = population.slice(0, Math.ceil(populationSize * 0.1)); // Behalte die besten 10 % als Elite
}
for (let i = 0; i < population.length - elites.length; i++) {
let partnerA = matingPool[Math.floor(Math.random() * matingPool.length)];
let partnerB = matingPool[Math.floor(Math.random() * matingPool.length)];
let child = partnerA.crossover(partnerB);
child.mutate(mutationRate);
population[i] = child;
}
// Füge die Elite zurück in die Population
if (eliteMode) {
population.splice(population.length - elites.length, 0, ...elites);
}
generation++;
updateUI(); // UI mit bestPhrase und Gesamtdauer aktualisieren
}
function resetEvolution() {
clearInterval(evolutionInterval);
evolutionInterval = null;
population = [];
generation = 0;
document.getElementById("targetInput").value = "";
document.getElementById("populationSize").value = 300; // Setze Standardwert zurück
document.getElementById("info").innerHTML = `
Generation: <span id="generation">0</span><br>
Beste Phrase: <span id="bestPhrase"></span><br>
Gesamtdauer: <span id="totalYears">0 Jahre</span>
`;
document.getElementById("output").textContent = "";
}
function changeSpeed(direction) {
speedFactor += direction * 0.5; // Ändere Geschwindigkeit in Schritten von 0.5
speedFactor = Math.max(0.1, speedFactor); // Mindestgeschwindigkeit 0.1
if (evolutionInterval) {
clearInterval(evolutionInterval);
evolutionInterval = setInterval(evolve, 100 / speedFactor); // Aktualisiere Intervalldauer
}
}
function updateUI() {
// Berechne die Gesamtdauer in Jahren
const yearsPerGeneration = 30; // Durchschnittliche menschliche Generation
const totalYears = generation * yearsPerGeneration;
// Aktualisiere das UI
document.getElementById("info").innerHTML = `
Generation: <span id="generation">${generation}</span><br>
Beste Phrase: <span id="bestPhrase">${bestPhrase || "noch keine Phrase"}</span><br>
Gesamtdauer: <span id="totalYears">${totalYears} Jahre</span>
`;
// Aktualisiere das Ausgabefeld mit der aktuellen Population
let output = document.getElementById("output");
output.textContent = population.map(p => p.getPhrase()).join("\n");
}
</script>
</body>
<br>
<p style="text-align: center;"><span style="color:#FFFFFF">©</span><a href="https://wolfram-consult.com"><span style="color:#FFFFFF">by Wolfram Consult GmbH&Co. KG</span></a></p>
</html>
or
By clicking below, you agree to our terms of service.
New to HackMD? Sign up