Closed VatsalPandya47 closed 9 months ago
// Include necessary headers
using namespace std;
// Define constants for the maze dimensions const int MAZE_SIZE = 20; const int POPULATION_SIZE = 100; const int NUM_GENERATIONS = 1000; const double MUTATION_RATE = 0.1; const double CROSSOVER_RATE = 0.8;
// Define directions for movement in the maze enum class Direction { UP, DOWN, LEFT, RIGHT, STAND };
// Define a structure for representing an individual in the population
struct Individual {
vector
// Mutex and condition variables for thread synchronization mutex mtx; condition_variable cv; bool ready = false;
// Define a thread-safe queue for the work items
queue
// Function to generate random directions for an individual's genome
vector
for (int i = 0; i < MAZE_SIZE * MAZE_SIZE; ++i) {
genome.push_back(static_cast<Direction>(dis(gen)));
}
return genome;
}
// Function to evaluate the fitness of an individual
int evaluateFitness(const vector
// Function to perform crossover between two individuals
Individual crossover(const Individual& parent1, const Individual& parent2) {
Individual child;
child.genome.reserve(parent1.genome.size());
static random_device rd;
static mt19937 gen(rd());
uniform_real_distribution
for (size_t i = 0; i < parent1.genome.size(); ++i) {
if (dis(gen) < CROSSOVER_RATE) {
child.genome.push_back(parent1.genome[i]);
} else {
child.genome.push_back(parent2.genome[i]);
}
}
return child;
}
// Function to perform mutation on an individual's genome
void mutate(Individual& individual) {
static random_device rd;
static mt19937 gen(rd());
uniform_real_distribution
for (auto& gene : individual.genome) {
if (dis(gen) < MUTATION_RATE) {
gene = static_cast<Direction>((gene + 1) % 5); // Mutate the gene
}
}
}
// Function for the worker thread
void workerThread(vector
// Perform work for the individual at the given index
population[index].fitness = evaluateFitness(population[index].genome);
}
}
// Function to visualize the maze and path
void visualizeMaze(const vector
int main() {
// Create a pool of worker threads
vector
for (int i = 0; i < thread::hardware_concurrency(); ++i) {
threads.emplace_back(workerThread, ref(population));
}
// Main loop for genetic algorithm
for (int generation = 0; generation < NUM_GENERATIONS; ++generation) {
// Create and evaluate initial population
for (int i = 0; i < POPULATION_SIZE; ++i) {
population[i] = {generateGenome(), 0};
workQueue.push(i);
}
// Notify worker threads to start processing
{
lock_guard<mutex> lck(mtx);
ready = true;
cv.notify_all();
}
// Wait for all work to be finished
{
unique_lock<mutex> lck(mtx);
cv.wait(lck, []{ return workQueue.empty(); });
}
// Sort population based on fitness
sort(population.begin(), population.end(), [](const Individual& a, const Individual& b) {
return a.fitness > b.fitness;
});
// Perform selection, crossover, and mutation
vector<Individual> newPopulation;
newPopulation.reserve(POPULATION_SIZE);
for (int i = 0; i < POPULATION_SIZE; ++i) {
Individual parent1 = population[i];
Individual parent2 = population[i < POPULATION_SIZE - 1 ? i + 1 : i - 1]; // Cyclic crossover
Individual child = crossover(parent1, parent2);
mutate(child);
newPopulation.push_back(child);
}
// Replace the old population with the new one
population = move(newPopulation);
// Output the best individual of the current generation
cout << "Generation " << generation << ": Best fitness = " << population[0].fitness << endl;
// Visualize the best path
visualizeMaze(population[0].genome);
}
// Join worker threads
for (auto& t : threads) {
t.join();
}
return 0;
}
Project Overview: MazeFinder is an advanced C++ application that utilizes genetic algorithms and parallel processing to find optimal solutions for mazes of size 20x20. The project incorporates dynamic maze generation, sophisticated fitness evaluation, advanced selection, crossover, and mutation techniques, as well as multi-threading for improved performance.
Features and Components: Dynamic Maze Generation:
Randomly generates mazes of size 20x20 for each individual in the population. Uses algorithms such as randomized depth-first search (DFS) or Prim's algorithm for maze generation. Genetic Algorithm:
Implements a genetic algorithm to evolve solutions for maze traversal. Population size: 100 individuals. Number of generations: 1000. Individual Representation:
Each individual is represented by a genome, which consists of a sequence of movements (UP, DOWN, LEFT, RIGHT, STAND) to navigate the maze. Genome size: 400 (20x20 maze). Fitness Evaluation:
Evaluates the fitness of each individual based on maze traversal. Fitness function considers factors such as path length, dead ends, loops, and path completeness. Uses maze simulation to determine the fitness score of individuals. Selection Strategies:
Incorporates elitism to preserve the best individuals from each generation. Utilizes advanced selection methods such as roulette wheel selection, tournament selection, or rank-based selection to choose parents for crossover. Crossover and Mutation Operators:
Implements advanced crossover techniques including uniform crossover, arithmetic crossover, or simulated binary crossover. Mutation operators randomly insert, delete, or modify genes in the genome to maintain genetic diversity. Parallel Processing:
Utilizes multi-threading to parallelize fitness evaluation and other computationally intensive tasks. Implements dynamic thread pool management to adjust the number of worker threads based on system resources and workload. Thread Safety and Synchronization:
Ensures thread safety using mutexes and condition variables to prevent data races and ensure proper synchronization among threads. Visualization:
Provides visualization capabilities to display maze generation, path exploration, and algorithm progress in real-time using OpenGL or SDL libraries. Parameter Tuning:
Allows for experimentation with parameters such as population size, mutation rate, crossover rate, and selection pressure to optimize algorithm performance. Conclusion: The MazeFinder project offers a comprehensive solution for solving complex mazes using genetic algorithms and parallel processing techniques. By incorporating dynamic maze generation, advanced fitness evaluation, selection, crossover, and mutation strategies, as well as parallel processing, the project achieves efficient maze traversal and finds optimal solutions for mazes of size 20x20. Additionally, the project provides flexibility for parameter tuning and visualization, making it a versatile tool for maze-solving applications.