Add comments

This commit is contained in:
emil
2024-11-27 19:12:19 +03:00
parent c1939b27ac
commit 65b3f31ba6
2 changed files with 112 additions and 93 deletions
+81 -71
View File
@@ -4,67 +4,77 @@ import java.util.List;
import java.util.Random; import java.util.Random;
public class Main { public class Main {
List<Chromosome> population = new ArrayList<>(); // Список хромосом // List to store the population of chromosomes
List<Chromosome> population = new ArrayList<>();
Random random = new Random(); Random random = new Random();
public static void main(String[] args) { public static void main(String[] args) {
// Чтение входной матрицы из консоли // Base Sudoku matrix (input matrix)
int[][] baseSudoku = new int[9][9]; int[][] baseSudoku = new int[9][9];
// List to track positions in Sudoku that are mutable
List<int[]> mutablePositions = new ArrayList<>(); List<int[]> mutablePositions = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try { try {
// Reading the Sudoku matrix from the console input
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
// Split the input by space
String[] tokens = reader.readLine().split(" "); String[] tokens = reader.readLine().split(" ");
for (int j = 0; j < 9; j++) { for (int j = 0; j < 9; j++) {
if (tokens[j].equals("-")) { if (tokens[j].equals("-")) {
// Empty cells are marked as 0
baseSudoku[i][j] = 0; baseSudoku[i][j] = 0;
// Add mutable positions (i, j) to the list
mutablePositions.add(new int[]{i, j}); mutablePositions.add(new int[]{i, j});
} else { } else {
// Set fixed value from the input
baseSudoku[i][j] = Integer.parseInt(tokens[j]); baseSudoku[i][j] = Integer.parseInt(tokens[j]);
} }
} }
} }
} catch (IOException e) { } catch (IOException e) {
// If an error occurs during input reading, print the error and stop the program
System.err.println("Error reading input: " + e.getMessage()); System.err.println("Error reading input: " + e.getMessage());
return; return;
} }
// Создаем экземпляр класса Main Main mainInstance = new Main(); // Create instance of Main class
Main mainInstance = new Main(); // Generate initial population of 100 chromosomes
mainInstance.generateInitialChromosomes(100, baseSudoku, mutablePositions); // Генерация 100 хромосом mainInstance.generateInitialChromosomes(100, baseSudoku, mutablePositions);
// Убираем ограничение на количество поколений double mutationRate = 0.05; // Mutation rate for genetic algorithm
double mutationRate = 0.05; // Вероятность мутации
Chromosome bestSolution = null; Chromosome bestSolution = null;
int generation = 0; int generation = 0; // Track the number of generations
while (true) { while (true) {
// Оценка текущего поколения // Evaluate the fitness of each chromosome in the population
mainInstance.evaluatePopulation(); mainInstance.evaluatePopulation();
// Отбор родителей и создание новых потомков
List<Chromosome> newPopulation = new ArrayList<>(); List<Chromosome> newPopulation = new ArrayList<>();
for (int i = 0; i < mainInstance.population.size() / 2; i++) { for (int i = 0; i < mainInstance.population.size() / 2; i++) {
// Select parents using tournament selection
List<Chromosome> parents = mainInstance.tournamentSelection(5); List<Chromosome> parents = mainInstance.tournamentSelection(5);
// Perform crossover to create two children from the selected parents
Chromosome child1 = mainInstance.crossoverBySubgrids(parents.get(0), parents.get(1)); Chromosome child1 = mainInstance.crossoverBySubgrids(parents.get(0), parents.get(1));
Chromosome child2 = mainInstance.crossoverBySubgrids(parents.get(1), parents.get(0)); Chromosome child2 = mainInstance.crossoverBySubgrids(parents.get(1), parents.get(0));
// Мутация потомков // Apply mutation to both children
mainInstance.mutateChromosome(child1, mutationRate); mainInstance.mutateChromosome(child1, mutationRate);
mainInstance.mutateChromosome(child2, mutationRate); mainInstance.mutateChromosome(child2, mutationRate);
// Add both children to the new population
newPopulation.add(child1); newPopulation.add(child1);
newPopulation.add(child2); newPopulation.add(child2);
} }
// Замена старой популяции на новую // Replace the old population with the new population
mainInstance.population = newPopulation; mainInstance.population = newPopulation;
// Логирование лучшего решения текущего поколения // Get the best chromosome from the current population
bestSolution = mainInstance.getBestChromosome(); bestSolution = mainInstance.getBestChromosome();
generation++; generation++;
// Критерий завершения (если найдено идеальное решение) // If the best solution found has a fitness of 0, print it and end the program
if (bestSolution.getFitness() == 0) { if (bestSolution.getFitness() == 0) {
bestSolution.printChromosome(false); bestSolution.printChromosome(false);
return; return;
@@ -72,25 +82,25 @@ public class Main {
} }
} }
// Генерация начальной популяции хромосом // Generate initial population of chromosomes
public void generateInitialChromosomes(int numberOfChromosomes, int[][] baseSudoku, List<int[]> mutablePositions) { public void generateInitialChromosomes(int numberOfChromosomes, int[][] baseSudoku, List<int[]> mutablePositions) {
// Создаем заданное количество хромосом
for (int i = 0; i < numberOfChromosomes; i++) { for (int i = 0; i < numberOfChromosomes; i++) {
int[][] sudoku = copyMatrix(baseSudoku); // Копируем базовый Судоку // Create a copy of the base Sudoku
// Заполняем изменяемые позиции случайными числами (1-9) int[][] sudoku = copyMatrix(baseSudoku);
// Randomly fill mutable positions
for (int[] pos : mutablePositions) { for (int[] pos : mutablePositions) {
int row = pos[0]; int row = pos[0];
int col = pos[1]; int col = pos[1];
sudoku[row][col] = random.nextInt(9) + 1; sudoku[row][col] = random.nextInt(9) + 1;
} }
// Добавляем хромосому в популяцию // Create a new chromosome with the generated Sudoku and mutable positions
Chromosome chromosome = new Chromosome(sudoku, new ArrayList<>(mutablePositions)); Chromosome chromosome = new Chromosome(sudoku, new ArrayList<>(mutablePositions));
chromosome.evaluateFitness(); // Оценка фитнеса хромосомы chromosome.evaluateFitness(); // Evaluate its fitness
population.add(chromosome); population.add(chromosome); // Add to the population
} }
} }
// Копирование матрицы // Create a deep copy of a matrix
private int[][] copyMatrix(int[][] original) { private int[][] copyMatrix(int[][] original) {
int[][] copy = new int[original.length][original[0].length]; int[][] copy = new int[original.length][original[0].length];
for (int i = 0; i < original.length; i++) { for (int i = 0; i < original.length; i++) {
@@ -99,37 +109,39 @@ public class Main {
return copy; return copy;
} }
// Турнирная селекция
public List<Chromosome> tournamentSelection(int tournamentSize) { public List<Chromosome> tournamentSelection(int tournamentSize) {
List<Chromosome> selectedParents = new ArrayList<>(); List<Chromosome> selectedParents = new ArrayList<>();
for (int i = 0; i < 2; i++) { // Выбираем двух родителей for (int i = 0; i < 2; i++) {
List<Chromosome> tournament = new ArrayList<>(); List<Chromosome> tournament = new ArrayList<>();
// Randomly select chromosomes for the tournament
for (int j = 0; j < tournamentSize; j++) { for (int j = 0; j < tournamentSize; j++) {
Chromosome randomChromosome = population.get(random.nextInt(population.size())); Chromosome randomChromosome = population.get(random.nextInt(population.size()));
tournament.add(randomChromosome); tournament.add(randomChromosome);
} }
// Determine the best chromosome in the tournament based on fitness
Chromosome best = tournament.get(0); Chromosome best = tournament.get(0);
for (Chromosome chromosome : tournament) { for (Chromosome chromosome : tournament) {
if (chromosome.getFitness() < best.getFitness()) { if (chromosome.getFitness() < best.getFitness()) {
best = chromosome; best = chromosome;
} }
} }
// Add the best chromosome to the list of selected parents
selectedParents.add(best); selectedParents.add(best);
} }
return selectedParents; return selectedParents;
} }
// Кроссовер по подрешеткам
public Chromosome crossoverBySubgrids(Chromosome parent1, Chromosome parent2) { public Chromosome crossoverBySubgrids(Chromosome parent1, Chromosome parent2) {
int[][] childSudoku = new int[9][9]; int[][] childSudoku = new int[9][9];
// Сначала копируем матрицу от первого родителя // Copy the entire Sudoku grid from parent1 to the child
for (int row = 0; row < 9; row++) { for (int row = 0; row < 9; row++) {
System.arraycopy(parent1.getSudoku()[row], 0, childSudoku[row], 0, 9); System.arraycopy(parent1.getSudoku()[row], 0, childSudoku[row], 0, 9);
} }
// Выбираем случайные подрешётки для обмена (например, 4 подрешётка) // Determine the number of subgrids to swap from parent2 to child (1-5)
int numSubgridsToSwap = random.nextInt(5) + 1; // Выбираем от 1 до 5 подрешеток для обмена int numSubgridsToSwap = random.nextInt(5) + 1;
List<Integer> selectedSubgrids = new ArrayList<>(); List<Integer> selectedSubgrids = new ArrayList<>();
while (selectedSubgrids.size() < numSubgridsToSwap) { while (selectedSubgrids.size() < numSubgridsToSwap) {
int subgridIndex = random.nextInt(9); int subgridIndex = random.nextInt(9);
@@ -138,7 +150,7 @@ public class Main {
} }
} }
// Выполняем обмен выбранных подрешётков // Swap the selected subgrids from parent2 into the child
for (int subgrid : selectedSubgrids) { for (int subgrid : selectedSubgrids) {
int rowStart = (subgrid / 3) * 3; int rowStart = (subgrid / 3) * 3;
int colStart = (subgrid % 3) * 3; int colStart = (subgrid % 3) * 3;
@@ -149,16 +161,16 @@ public class Main {
} }
} }
// Создаем и возвращаем нового потомка // Create a new chromosome with the resulting child Sudoku and evaluate its fitness
Chromosome child = new Chromosome(childSudoku, parent1.getMutablePositions()); Chromosome child = new Chromosome(childSudoku, parent1.getMutablePositions());
child.evaluateFitness(); child.evaluateFitness();
return child; return child;
} }
// Вывод содержимого популяции для проверки
public void printPopulation(boolean printMutPos) { public void printPopulation(boolean printMutPos) {
System.out.println("Generated Population:"); System.out.println("Generated Population:");
int count = 1; int count = 1;
// Print each chromosome's Sudoku and fitness value
for (Chromosome chromosome : population) { for (Chromosome chromosome : population) {
System.out.println("Chromosome " + count + ":"); System.out.println("Chromosome " + count + ":");
chromosome.printChromosome(printMutPos); chromosome.printChromosome(printMutPos);
@@ -168,36 +180,34 @@ public class Main {
} }
} }
// Мутация хромосомы
public void mutateChromosome(Chromosome chromosome, double mutationRate) { public void mutateChromosome(Chromosome chromosome, double mutationRate) {
int[][] sudoku = chromosome.getSudoku(); int[][] sudoku = chromosome.getSudoku();
List<int[]> mutablePositions = chromosome.getMutablePositions(); List<int[]> mutablePositions = chromosome.getMutablePositions();
// Проходим по всем изменяемым позициям // Mutate each mutable position with a probability defined by mutationRate
for (int[] pos : mutablePositions) { for (int[] pos : mutablePositions) {
if (random.nextDouble() < mutationRate) { if (random.nextDouble() < mutationRate) {
int row = pos[0]; int row = pos[0];
int col = pos[1]; int col = pos[1];
int newValue = random.nextInt(9) + 1; // Генерируем новое значение от 1 до 9 int newValue = random.nextInt(9) + 1; // Assign a new value between 1 and 9
sudoku[row][col] = newValue; // Изменяем значение в выбранной позиции sudoku[row][col] = newValue;
} }
} }
// Обновляем матрицу и оцениваем фитнес // Update the chromosome's Sudoku and recalculate its fitness
chromosome.setSudoku(sudoku); chromosome.setSudoku(sudoku);
chromosome.evaluateFitness(); chromosome.evaluateFitness();
} }
// Метод для оценки всей популяции
public void evaluatePopulation() { public void evaluatePopulation() {
// Evaluate the fitness of each chromosome in the population
for (Chromosome chromosome : population) { for (Chromosome chromosome : population) {
chromosome.evaluateFitness(); chromosome.evaluateFitness();
} }
} }
// Метод для получения лучшей хромосомы в популяции
public Chromosome getBestChromosome() { public Chromosome getBestChromosome() {
// Find and return the chromosome with the best (lowest) fitness in the population
Chromosome best = population.get(0); Chromosome best = population.get(0);
for (Chromosome chromosome : population) { for (Chromosome chromosome : population) {
if (chromosome.getFitness() < best.getFitness()) { if (chromosome.getFitness() < best.getFitness()) {
@@ -207,80 +217,70 @@ public class Main {
return best; return best;
} }
// Класс хромосомы // Chromosome class representing an individual solution
public class Chromosome { public class Chromosome {
private int[][] sudoku; // Матрица Судоку private int[][] sudoku; // Sudoku grid representing the chromosome
private List<int[]> mutablePositions; // Список координат изменяемых позиций private List<int[]> mutablePositions; // Positions that can be changed (mutable)
private int fitness; // Значение фитнеса private int fitness; // Fitness value representing the number of conflicts
// Конструктор для инициализации хромосомы // Constructor for initializing a Chromosome with a Sudoku grid and mutable positions
public Chromosome(int[][] sudoku, List<int[]> mutablePositions) { public Chromosome(int[][] sudoku, List<int[]> mutablePositions) {
this.sudoku = sudoku; this.sudoku = sudoku;
this.mutablePositions = mutablePositions; this.mutablePositions = mutablePositions;
} }
// Геттер для матрицы Судоку
public int[][] getSudoku() { public int[][] getSudoku() {
return sudoku; return sudoku;
} }
// Сеттер для матрицы Судоку
public void setSudoku(int[][] sudoku) { public void setSudoku(int[][] sudoku) {
this.sudoku = sudoku; this.sudoku = sudoku;
} }
// Геттер для изменяемых позиций
public List<int[]> getMutablePositions() { public List<int[]> getMutablePositions() {
return mutablePositions; return mutablePositions;
} }
// Сеттер для изменяемых позиций
public void setMutablePositions(List<int[]> mutablePositions) {
this.mutablePositions = mutablePositions;
}
// Геттер для фитнеса
public int getFitness() { public int getFitness() {
return fitness; return fitness;
} }
// Метод для оценки фитнеса хромосомы // Evaluate the fitness of the Sudoku by counting the number of row, column, and subgrid violations
public void evaluateFitness() { public void evaluateFitness() {
fitness = countRowViolations() + countColumnViolations() + countSubgridViolations(); fitness = countRowViolations() + countColumnViolations() + countSubgridViolations();
} }
// Подсчет нарушений в строках
// Подсчет нарушений в строках
private int countRowViolations() { private int countRowViolations() {
int violations = 0; int violations = 0;
// Iterate through each row to count conflicts
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
boolean[] present = new boolean[10]; // Используем индекс от 1 до 9 boolean[] present = new boolean[10];
for (int j = 0; j < 9; j++) { for (int j = 0; j < 9; j++) {
int value = sudoku[i][j]; int value = sudoku[i][j];
if (value != 0) { if (value != 0) {
if (present[value]) { if (present[value]) {
violations++; violations++; // Increment violations if the value is already seen
} else { } else {
present[value] = true; present[value] = true; // Mark the value as seen
} }
} }
} }
} }
return violations; return violations;
} }
// Подсчет нарушений в колонках
private int countColumnViolations() { private int countColumnViolations() {
int violations = 0; int violations = 0;
// Loop through each column
for (int j = 0; j < 9; j++) { for (int j = 0; j < 9; j++) {
boolean[] present = new boolean[10]; // Используем индекс от 1 до 9 boolean[] present = new boolean[10]; // Track numbers present in the column
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
int value = sudoku[i][j]; int value = sudoku[i][j];
if (value != 0) { if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) { if (present[value]) {
violations++; violations++;
} else { } else {
// Mark the number as present
present[value] = true; present[value] = true;
} }
} }
@@ -289,19 +289,22 @@ public class Main {
return violations; return violations;
} }
// Подсчет нарушений в подрешетках
private int countSubgridViolations() { private int countSubgridViolations() {
int violations = 0; int violations = 0;
// Loop through each 3x3 subgrid
for (int gridRow = 0; gridRow < 3; gridRow++) { for (int gridRow = 0; gridRow < 3; gridRow++) {
for (int gridCol = 0; gridCol < 3; gridCol++) { for (int gridCol = 0; gridCol < 3; gridCol++) {
boolean[] present = new boolean[10]; // Используем индекс от 1 до 9 boolean[] present = new boolean[10]; // Track numbers present in the subgrid
// Loop through cells in the 3x3 subgrid
for (int row = gridRow * 3; row < gridRow * 3 + 3; row++) { for (int row = gridRow * 3; row < gridRow * 3 + 3; row++) {
for (int col = gridCol * 3; col < gridCol * 3 + 3; col++) { for (int col = gridCol * 3; col < gridCol * 3 + 3; col++) {
int value = sudoku[row][col]; int value = sudoku[row][col];
if (value != 0) { if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) { if (present[value]) {
violations++; violations++;
} else { } else {
// Mark the number as present
present[value] = true; present[value] = true;
} }
} }
@@ -312,19 +315,26 @@ public class Main {
return violations; return violations;
} }
// Метод для отображения состояния хромосомы
public void printChromosome(boolean printMutPos) { public void printChromosome(boolean printMutPos) {
//System.out.println("Sudoku Matrix:"); // Print the Sudoku matrix
for (int[] row : sudoku) { for (int[] row : sudoku) {
for (int num : row) { for (int j = 0; j < row.length; j++) {
System.out.print(num + " "); System.out.print(row[j]);
if (j < row.length - 1) {
System.out.print(" ");
}
} }
System.out.println(); System.out.println();
} }
// If requested, print mutable positions
if (printMutPos) { if (printMutPos) {
System.out.println("Mutable Positions:"); System.out.println("Mutable Positions:");
for (int[] pos : mutablePositions) { for (int i = 0; i < mutablePositions.size(); i++) {
System.out.print("(" + pos[0] + ", " + pos[1] + ") "); int[] pos = mutablePositions.get(i);
System.out.print("(" + pos[0] + ", " + pos[1] + ")");
if (i < mutablePositions.size() - 1) {
System.out.print(" ");
}
} }
System.out.println(); System.out.println();
} }
+9
View File
@@ -7,3 +7,12 @@
8 - - 1 - 4 - - 9 8 - - 1 - 4 - - 9
- - 1 9 - 3 6 - - - - 1 9 - 3 6 - -
- 4 - - - - - 2 - - 4 - - - - - 2 -
1 8 5 4 3 6 2 9 7
4 3 7 5 9 2 8 1 6
6 9 2 8 1 7 3 4 5
3 7 6 2 8 9 4 5 1
2 1 4 3 7 5 9 6 8
9 5 8 6 4 1 7 3 2
8 6 3 1 2 4 5 7 9
7 2 1 9 5 3 6 8 4
5 4 9 7 6 8 1 2 3