Compare commits

..
10 Commits
Author SHA1 Message Date
emil aaa4a2a490 final commit 2024-12-01 22:42:57 +03:00
emil 1562f775af Commit before some experiments with smart argument changing 2024-12-01 19:57:30 +03:00
emil 26d454c976 Selected some arguments for new method 2024-12-01 18:04:27 +03:00
emil 39736e90fd Updated with guaranteed subrid method. Statistial version update required. 2024-11-28 14:28:17 +03:00
emil b1615d03b1 37.5 points commit 2024-11-27 23:48:19 +03:00
emil b3ec87c1c3 Add analitical version of algorithm with plotting 2024-11-27 21:45:27 +03:00
emil 681cd729bb Some version 2024-11-27 21:14:04 +03:00
emil 65b3f31ba6 Add comments 2024-11-27 19:12:19 +03:00
emil c1939b27ac Finished I\O 2024-11-27 16:33:20 +03:00
emil 5ff0c89688 Correct I/O. switch to manual I\O needed 2024-11-27 16:21:09 +03:00
23 changed files with 2856 additions and 187 deletions
+224 -178
View File
@@ -1,127 +1,155 @@
import java.io.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Main {
List<Chromosome> population = new ArrayList<>(); // Список хромосом
// Initalizing variables
public static int POPULATIONSIZE = 0;
public static int TOURNAMENTSIZE = 0;
public static double MUTATIONRATE = 0;
// Threshold of number of mutable positions for easy level sudoku
public static int EASYTHRESHOLD = 60;
public static int HARDTHRESHOLD = 70;
// List to store the population of chromosomes
List<Chromosome> population = new ArrayList<>();
Random random = new Random();
public static void main(String[] args) {
// Создаем экземпляр класса Main
Main mainInstance = new Main();
mainInstance.generateInitialChromosomes(100); // Генерация 100 хромосом
// Base Sudoku matrix (input matrix)
int[][] baseSudoku = new int[9][9];
// List to track positions in Sudoku that are mutable
List<int[]> mutablePositions = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
// Reading the Sudoku matrix from the console input
for (int i = 0; i < 9; i++) {
// Split the input by space
String[] tokens = reader.readLine().split(" ");
for (int j = 0; j < 9; j++) {
if (tokens[j].equals("-")) {
// Empty cells are marked as 0
baseSudoku[i][j] = 0;
// Add mutable positions (i, j) to the list
mutablePositions.add(new int[]{i, j});
} else {
// Set fixed value from the input
baseSudoku[i][j] = Integer.parseInt(tokens[j]);
}
}
}
} 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());
return;
}
Main mainInstance = new Main(); // Create instance of Main class
// Choosing variables for different sudoku difficulties
if (mutablePositions.size() < EASYTHRESHOLD) { // Easy sudoku
POPULATIONSIZE = 100000;
TOURNAMENTSIZE = 8;
MUTATIONRATE = 0.34;
} else if (mutablePositions.size() < HARDTHRESHOLD) { // Hard sudoku
POPULATIONSIZE = 100000;
TOURNAMENTSIZE = 8;
MUTATIONRATE = 0.34;
}
else { // Ultra-hard sudoku
POPULATIONSIZE = 500000;
TOURNAMENTSIZE = 3;
MUTATIONRATE = 0.15;
}
// Generate initial population of 100 chromosomes
mainInstance.generateInitialChromosomes(POPULATIONSIZE, baseSudoku, mutablePositions);
// Убираем ограничение на количество поколений
double mutationRate = 0.05; // Вероятность мутации
Chromosome bestSolution = null;
int generation = 0;
int generation = 0; // Track the number of generations
while (true) {
// Оценка текущего поколения
// Evaluate the fitness of each chromosome in the population
mainInstance.evaluatePopulation();
// Отбор родителей и создание новых потомков
List<Chromosome> newPopulation = new ArrayList<>();
for (int i = 0; i < mainInstance.population.size() / 2; i++) {
List<Chromosome> parents = mainInstance.tournamentSelection(5);
// Select parents using tournament selection
List<Chromosome> parents = mainInstance.tournamentSelection(TOURNAMENTSIZE);
// Perform crossover to create two children from the selected parents
Chromosome child1 = mainInstance.crossoverBySubgrids(parents.get(0), parents.get(1));
Chromosome child2 = mainInstance.crossoverBySubgrids(parents.get(1), parents.get(0));
// Мутация потомков
mainInstance.mutateChromosome(child1, mutationRate);
mainInstance.mutateChromosome(child2, mutationRate);
// Apply mutation to both children
mainInstance.mutateChromosome(child1, MUTATIONRATE);
mainInstance.mutateChromosome(child2, MUTATIONRATE);
// Add both children to the new population
newPopulation.add(child1);
newPopulation.add(child2);
}
// Замена старой популяции на новую
// Replace the old population with the new population
mainInstance.population = newPopulation;
// Логирование лучшего решения текущего поколения
// Get the best chromosome from the current population
bestSolution = mainInstance.getBestChromosome();
System.out.println("Generation " + generation + ": Best Fitness = " + bestSolution.getFitness());
generation++;
// Критерий завершения (если найдено идеальное решение)
// If the best solution found has a fitness of 0, print it and end the program
if (bestSolution.getFitness() == 0) {
System.out.println("Optimal solution found in generation " + generation);
break;
bestSolution.printChromosome(false);
return;
}
}
// Вывод финального решения
if (bestSolution != null) {
System.out.println("Final Solution:");
bestSolution.printChromosome(false);
System.out.println("Fitness: " + bestSolution.getFitness());
}
// Пример использования турнирной селекции
List<Chromosome> parents = mainInstance.tournamentSelection(5);
System.out.println("Selected Parents:");
for (Chromosome parent : parents) {
parent.printChromosome(false);
System.out.println("Fitness: " + parent.getFitness());
}
// Пример использования кроссовера по подрешеткам
Chromosome child = mainInstance.crossoverBySubgrids(parents.get(0), parents.get(1));
// Пример мутации
mainInstance.mutateChromosome(child, 0.05); // Мутация с вероятностью 5%
System.out.println("Child Chromosome:");
child.printChromosome(false);
System.out.println("Fitness: " + child.getFitness());
System.out.println("Fitness: " + child.getFitness());
}
// Генерация начальной популяции хромосом
public void generateInitialChromosomes(int numberOfChromosomes) {
String inputFileName = "input.txt";
try (BufferedReader br = new BufferedReader(new FileReader(inputFileName))) {
String line;
int[][] baseSudoku = new int[9][9]; // Матрица Судоку для шаблона
List<int[]> mutablePositions = new ArrayList<>(); // Список координат изменяемых позиций
int rowIndex = 0;
while ((line = br.readLine()) != null) {
String[] tokens = line.split(" "); // Разделяем строку по пробелам
for (int colIndex = 0; colIndex < tokens.length; colIndex++) {
if (tokens[colIndex].equals("-")) {
baseSudoku[rowIndex][colIndex] = 0; // Пустые ячейки заполняются 0
mutablePositions.add(new int[]{rowIndex, colIndex}); // Добавляем координаты изменяемой позиции
} else {
baseSudoku[rowIndex][colIndex] = Integer.parseInt(tokens[colIndex]); // Конвертируем строку в число
// Generate initial population of chromosomes
public void generateInitialChromosomes(int numberOfChromosomes, int[][] baseSudoku, List<int[]> mutablePositions) {
for (int i = 0; i < numberOfChromosomes; i++) {
// Create a copy of the base Sudoku
int[][] sudoku = copyMatrix(baseSudoku);
// Randomly fill mutable positions while ensuring no duplicates in subgrids
for (int gridRow = 0; gridRow < 3; gridRow++) {
for (int gridCol = 0; gridCol < 3; gridCol++) {
boolean[] present = new boolean[10];
List<int[]> subgridPositions = new ArrayList<>();
// Collect all positions in the current 3x3 subgrid
for (int row = gridRow * 3; row < gridRow * 3 + 3; row++) {
for (int col = gridCol * 3; col < gridCol * 3 + 3; col++) {
int value = sudoku[row][col];
if (value != 0) {
present[value] = true;
} else {
subgridPositions.add(new int[]{row, col});
}
}
}
// Randomly fill the subgrid ensuring no duplicates
for (int[] pos : subgridPositions) {
int newValue;
do {
newValue = random.nextInt(9) + 1;
} while (present[newValue]);
sudoku[pos[0]][pos[1]] = newValue;
present[newValue] = true;
}
}
rowIndex++;
}
// Создаем заданное количество хромосом
for (int i = 0; i < numberOfChromosomes; i++) {
int[][] sudoku = copyMatrix(baseSudoku); // Копируем базовый Судоку
// Заполняем изменяемые позиции случайными числами (1-9)
for (int[] pos : mutablePositions) {
int row = pos[0];
int col = pos[1];
sudoku[row][col] = random.nextInt(9) + 1;
}
// Добавляем хромосому в популяцию
Chromosome chromosome = new Chromosome(sudoku, new ArrayList<>(mutablePositions));
chromosome.evaluateFitness(); // Оценка фитнеса хромосомы
population.add(chromosome);
}
} catch (IOException e) {
System.err.println("Error reading the file: " + e.getMessage());
// Create a new chromosome with the generated Sudoku and mutable positions
Chromosome chromosome = new Chromosome(sudoku, new ArrayList<>(mutablePositions));
chromosome.evaluateFitness(); // Evaluate its fitness
population.add(chromosome); // Add to the population
}
}
// Копирование матрицы
// Create a deep copy of a matrix
private int[][] copyMatrix(int[][] original) {
int[][] copy = new int[original.length][original[0].length];
for (int i = 0; i < original.length; i++) {
@@ -130,37 +158,39 @@ public class Main {
return copy;
}
// Турнирная селекция
public List<Chromosome> tournamentSelection(int tournamentSize) {
List<Chromosome> selectedParents = new ArrayList<>();
for (int i = 0; i < 2; i++) { // Выбираем двух родителей
for (int i = 0; i < 2; i++) {
List<Chromosome> tournament = new ArrayList<>();
// Randomly select chromosomes for the tournament
for (int j = 0; j < tournamentSize; j++) {
Chromosome randomChromosome = population.get(random.nextInt(population.size()));
tournament.add(randomChromosome);
}
// Determine the best chromosome in the tournament based on fitness
Chromosome best = tournament.get(0);
for (Chromosome chromosome : tournament) {
if (chromosome.getFitness() < best.getFitness()) {
best = chromosome;
}
}
// Add the best chromosome to the list of selected parents
selectedParents.add(best);
}
return selectedParents;
}
// Кроссовер по подрешеткам
public Chromosome crossoverBySubgrids(Chromosome parent1, Chromosome parent2) {
int[][] childSudoku = new int[9][9];
// Сначала копируем матрицу от первого родителя
// Copy the entire Sudoku grid from parent1 to the child
for (int row = 0; row < 9; row++) {
System.arraycopy(parent1.getSudoku()[row], 0, childSudoku[row], 0, 9);
}
// Выбираем случайные подрешётки для обмена (например, 4 подрешётка)
int numSubgridsToSwap = random.nextInt(5) + 1; // Выбираем от 1 до 5 подрешеток для обмена
// Determine the number of subgrids to swap from parent2 to child (1-5)
int numSubgridsToSwap = random.nextInt(5) + 1;
List<Integer> selectedSubgrids = new ArrayList<>();
while (selectedSubgrids.size() < numSubgridsToSwap) {
int subgridIndex = random.nextInt(9);
@@ -168,8 +198,8 @@ public class Main {
selectedSubgrids.add(subgridIndex);
}
}
// Выполняем обмен выбранных подрешётков
// Swap the selected subgrids from parent2 into the child
for (int subgrid : selectedSubgrids) {
int rowStart = (subgrid / 3) * 3;
int colStart = (subgrid % 3) * 3;
@@ -179,19 +209,17 @@ public class Main {
}
}
}
// Создаем и возвращаем нового потомка
// Create a new chromosome with the resulting child Sudoku and evaluate its fitness
Chromosome child = new Chromosome(childSudoku, parent1.getMutablePositions());
child.evaluateFitness();
child.evaluateFitness();
return child;
}
// Вывод содержимого популяции для проверки
public void printPopulation(boolean printMutPos) {
System.out.println("Generated Population:");
int count = 1;
// Print each chromosome's Sudoku and fitness value
for (Chromosome chromosome : population) {
System.out.println("Chromosome " + count + ":");
chromosome.printChromosome(printMutPos);
@@ -200,36 +228,50 @@ public class Main {
count++;
}
}
// Мутация хромосомы
public void mutateChromosome(Chromosome chromosome, double mutationRate) {
int[][] sudoku = chromosome.getSudoku();
List<int[]> mutablePositions = chromosome.getMutablePositions();
// Проходим по всем изменяемым позициям
for (int[] pos : mutablePositions) {
if (random.nextDouble() < mutationRate) {
int row = pos[0];
int col = pos[1];
int newValue = random.nextInt(9) + 1; // Генерируем новое значение от 1 до 9
sudoku[row][col] = newValue; // Изменяем значение в выбранной позиции
// With a probability defined by mutationRate, perform a mutation by swapping subgrids
if (random.nextDouble() < mutationRate) {
// Randomly select two different subgrids to swap
int subgrid1, subgrid2;
do {
subgrid1 = random.nextInt(9);
subgrid2 = random.nextInt(9);
} while (subgrid1 == subgrid2);
// Get the starting coordinates for both subgrids
int rowStart1 = (subgrid1 / 3) * 3;
int colStart1 = (subgrid1 % 3) * 3;
int rowStart2 = (subgrid2 / 3) * 3;
int colStart2 = (subgrid2 % 3) * 3;
// Swap the values in the two selected subgrids
for (int rowOffset = 0; rowOffset < 3; rowOffset++) {
for (int colOffset = 0; colOffset < 3; colOffset++) {
int temp = sudoku[rowStart1 + rowOffset][colStart1 + colOffset];
sudoku[rowStart1 + rowOffset][colStart1 + colOffset] = sudoku[rowStart2 + rowOffset][colStart2 + colOffset];
sudoku[rowStart2 + rowOffset][colStart2 + colOffset] = temp;
}
}
}
// Обновляем матрицу и оцениваем фитнес
// Update the chromosome's Sudoku and recalculate its fitness
chromosome.setSudoku(sudoku);
chromosome.evaluateFitness();
}
// Метод для оценки всей популяции
public void evaluatePopulation() {
// Evaluate the fitness of each chromosome in the population
for (Chromosome chromosome : population) {
chromosome.evaluateFitness();
}
}
// Метод для получения лучшей хромосомы в популяции
public Chromosome getBestChromosome() {
// Find and return the chromosome with the best (lowest) fitness in the population
Chromosome best = population.get(0);
for (Chromosome chromosome : population) {
if (chromosome.getFitness() < best.getFitness()) {
@@ -238,100 +280,96 @@ public class Main {
}
return best;
}
// Класс хромосомы
// Chromosome class representing an individual solution
public class Chromosome {
private int[][] sudoku; // Матрица Судоку
private List<int[]> mutablePositions; // Список координат изменяемых позиций
private int fitness; // Значение фитнеса
// Конструктор для инициализации хромосомы
private int[][] sudoku; // Sudoku grid representing the chromosome
private List<int[]> mutablePositions; // Positions that can be changed (mutable)
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) {
this.sudoku = sudoku;
this.mutablePositions = mutablePositions;
}
// Геттер для матрицы Судоку
public int[][] getSudoku() {
return sudoku;
}
// Сеттер для матрицы Судоку
public void setSudoku(int[][] sudoku) {
this.sudoku = sudoku;
}
// Геттер для изменяемых позиций
public List<int[]> getMutablePositions() {
return mutablePositions;
}
// Сеттер для изменяемых позиций
public void setMutablePositions(List<int[]> mutablePositions) {
this.mutablePositions = mutablePositions;
}
// Геттер для фитнеса
public int getFitness() {
return fitness;
}
// Метод для оценки фитнеса хромосомы
// Evaluate the fitness of the Sudoku by counting the number of row, column, and subgrid violations
public void evaluateFitness() {
fitness = countRowViolations() + countColumnViolations() + countSubgridViolations();
fitness = countRowViolations() + countColumnViolations();
}
// Подсчет нарушений в строках
private int countRowViolations() {
int violations = 0;
for (int[] row : sudoku) {
boolean[] seen = new boolean[10];
for (int num : row) {
if (num != 0) {
if (seen[num]) {
violations++;
// Iterate through each row to count conflicts
for (int i = 0; i < 9; i++) {
boolean[] present = new boolean[10];
for (int j = 0; j < 9; j++) {
int value = sudoku[i][j];
if (value != 0) {
if (present[value]) {
violations++; // Increment violations if the value is already seen
} else {
seen[num] = true;
present[value] = true; // Mark the value as seen
}
}
}
}
return violations;
}
// Подсчет нарушений в столбцах
private int countColumnViolations() {
int violations = 0;
for (int col = 0; col < 9; col++) {
boolean[] seen = new boolean[10];
for (int row = 0; row < 9; row++) {
int num = sudoku[row][col];
if (num != 0) {
if (seen[num]) {
// Loop through each column
for (int j = 0; j < 9; j++) {
boolean[] present = new boolean[10]; // Track numbers present in the column
for (int i = 0; i < 9; i++) {
int value = sudoku[i][j];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
seen[num] = true;
// Mark the number as present
present[value] = true;
}
}
}
}
return violations;
}
// Подсчет нарушений в подрешетках 3x3
private int countSubgridViolations() {
int violations = 0;
for (int rowStart = 0; rowStart < 9; rowStart += 3) {
for (int colStart = 0; colStart < 9; colStart += 3) {
boolean[] seen = new boolean[10];
for (int row = rowStart; row < rowStart + 3; row++) {
for (int col = colStart; col < colStart + 3; col++) {
int num = sudoku[row][col];
if (num != 0) {
if (seen[num]) {
// Loop through each 3x3 subgrid
for (int gridRow = 0; gridRow < 3; gridRow++) {
for (int gridCol = 0; gridCol < 3; gridCol++) {
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 col = gridCol * 3; col < gridCol * 3 + 3; col++) {
int value = sudoku[row][col];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
seen[num] = true;
// Mark the number as present
present[value] = true;
}
}
}
@@ -340,22 +378,30 @@ public class Main {
}
return violations;
}
// Метод для отображения состояния хромосомы
public void printChromosome(boolean printMutPos) {
System.out.println("Sudoku Matrix:");
// Print the Sudoku matrix
for (int[] row : sudoku) {
for (int num : row) {
System.out.print(num + " ");
for (int j = 0; j < row.length; j++) {
System.out.print(row[j]);
if (j < row.length - 1) {
System.out.print(" ");
}
}
System.out.println();
}
// If requested, print mutable positions
if (printMutPos) {
System.out.println("Mutable Positions (Coordinates):");
for (int[] pos : mutablePositions) {
System.out.println("Row: " + pos[0] + ", Col: " + pos[1]);
System.out.println("Mutable Positions:");
for (int i = 0; i < mutablePositions.size(); i++) {
int[] pos = mutablePositions.get(i);
System.out.print("(" + pos[0] + ", " + pos[1] + ")");
if (i < mutablePositions.size() - 1) {
System.out.print(" ");
}
}
System.out.println();
}
}
}
}
}
+368
View File
@@ -0,0 +1,368 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Main {
// Initalizing variables
public static int POPULATIONSIZE = 0;
public static int TOURNAMENTSIZE = 0;
public static double MUTATIONRATE = 0;
// Threshold of number of mutable positions for easy level sudoku
public static int EASYTHRESHOLD = 60;
public static int HARDTHRESHOLD = 70;
// List to store the population of chromosomes
List<Chromosome> population = new ArrayList<>();
Random random = new Random();
public static void main(String[] args) {
// Base Sudoku matrix (input matrix)
int[][] baseSudoku = new int[9][9];
// List to track positions in Sudoku that are mutable
List<int[]> mutablePositions = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
// Reading the Sudoku matrix from the console input
for (int i = 0; i < 9; i++) {
// Split the input by space
String[] tokens = reader.readLine().split(" ");
for (int j = 0; j < 9; j++) {
if (tokens[j].equals("-")) {
// Empty cells are marked as 0
baseSudoku[i][j] = 0;
// Add mutable positions (i, j) to the list
mutablePositions.add(new int[]{i, j});
} else {
// Set fixed value from the input
baseSudoku[i][j] = Integer.parseInt(tokens[j]);
}
}
}
} 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());
return;
}
Main mainInstance = new Main(); // Create instance of Main class
// Choosing variables for different sudoku difficulties
if (mutablePositions.size() < EASYTHRESHOLD) { // Easy sudoku
POPULATIONSIZE = 100;
TOURNAMENTSIZE = 5;
MUTATIONRATE = 0.05;
} else if (mutablePositions.size() < HARDTHRESHOLD) { // Hard sudoku
POPULATIONSIZE = 100;
TOURNAMENTSIZE = 5;
MUTATIONRATE = 0.057;
}
else { // Ultra-hard sudoku
POPULATIONSIZE = 20000;
TOURNAMENTSIZE = 4;
MUTATIONRATE = 0.032;
}
// Generate initial population of 100 chromosomes
mainInstance.generateInitialChromosomes(POPULATIONSIZE, baseSudoku, mutablePositions);
Chromosome bestSolution = null;
int generation = 0; // Track the number of generations
while (true) {
// Evaluate the fitness of each chromosome in the population
mainInstance.evaluatePopulation();
List<Chromosome> newPopulation = new ArrayList<>();
for (int i = 0; i < mainInstance.population.size() / 2; i++) {
// Select parents using tournament selection
List<Chromosome> parents = mainInstance.tournamentSelection(TOURNAMENTSIZE);
// Perform crossover to create two children from the selected parents
Chromosome child1 = mainInstance.crossoverBySubgrids(parents.get(0), parents.get(1));
Chromosome child2 = mainInstance.crossoverBySubgrids(parents.get(1), parents.get(0));
// Apply mutation to both children
mainInstance.mutateChromosome(child1, MUTATIONRATE);
mainInstance.mutateChromosome(child2, MUTATIONRATE);
// Add both children to the new population
newPopulation.add(child1);
newPopulation.add(child2);
}
// Replace the old population with the new population
mainInstance.population = newPopulation;
// Get the best chromosome from the current population
bestSolution = mainInstance.getBestChromosome();
generation++;
// If the best solution found has a fitness of 0, print it and end the program
if (bestSolution.getFitness() == 0) {
bestSolution.printChromosome(false);
return;
}
}
}
// Generate initial population of chromosomes
public void generateInitialChromosomes(int numberOfChromosomes, int[][] baseSudoku, List<int[]> mutablePositions) {
for (int i = 0; i < numberOfChromosomes; i++) {
// Create a copy of the base Sudoku
int[][] sudoku = copyMatrix(baseSudoku);
// Randomly fill mutable positions
for (int[] pos : mutablePositions) {
int row = pos[0];
int col = pos[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.evaluateFitness(); // Evaluate its fitness
population.add(chromosome); // Add to the population
}
}
// Create a deep copy of a matrix
private int[][] copyMatrix(int[][] original) {
int[][] copy = new int[original.length][original[0].length];
for (int i = 0; i < original.length; i++) {
System.arraycopy(original[i], 0, copy[i], 0, original[i].length);
}
return copy;
}
public List<Chromosome> tournamentSelection(int tournamentSize) {
List<Chromosome> selectedParents = new ArrayList<>();
for (int i = 0; i < 2; i++) {
List<Chromosome> tournament = new ArrayList<>();
// Randomly select chromosomes for the tournament
for (int j = 0; j < tournamentSize; j++) {
Chromosome randomChromosome = population.get(random.nextInt(population.size()));
tournament.add(randomChromosome);
}
// Determine the best chromosome in the tournament based on fitness
Chromosome best = tournament.get(0);
for (Chromosome chromosome : tournament) {
if (chromosome.getFitness() < best.getFitness()) {
best = chromosome;
}
}
// Add the best chromosome to the list of selected parents
selectedParents.add(best);
}
return selectedParents;
}
public Chromosome crossoverBySubgrids(Chromosome parent1, Chromosome parent2) {
int[][] childSudoku = new int[9][9];
// Copy the entire Sudoku grid from parent1 to the child
for (int row = 0; row < 9; row++) {
System.arraycopy(parent1.getSudoku()[row], 0, childSudoku[row], 0, 9);
}
// Determine the number of subgrids to swap from parent2 to child (1-5)
int numSubgridsToSwap = random.nextInt(5) + 1;
List<Integer> selectedSubgrids = new ArrayList<>();
while (selectedSubgrids.size() < numSubgridsToSwap) {
int subgridIndex = random.nextInt(9);
if (!selectedSubgrids.contains(subgridIndex)) {
selectedSubgrids.add(subgridIndex);
}
}
// Swap the selected subgrids from parent2 into the child
for (int subgrid : selectedSubgrids) {
int rowStart = (subgrid / 3) * 3;
int colStart = (subgrid % 3) * 3;
for (int row = rowStart; row < rowStart + 3; row++) {
for (int col = colStart; col < colStart + 3; col++) {
childSudoku[row][col] = parent2.getSudoku()[row][col];
}
}
}
// Create a new chromosome with the resulting child Sudoku and evaluate its fitness
Chromosome child = new Chromosome(childSudoku, parent1.getMutablePositions());
child.evaluateFitness();
return child;
}
public void printPopulation(boolean printMutPos) {
System.out.println("Generated Population:");
int count = 1;
// Print each chromosome's Sudoku and fitness value
for (Chromosome chromosome : population) {
System.out.println("Chromosome " + count + ":");
chromosome.printChromosome(printMutPos);
System.out.println("Fitness: " + chromosome.getFitness());
System.out.println();
count++;
}
}
public void mutateChromosome(Chromosome chromosome, double mutationRate) {
int[][] sudoku = chromosome.getSudoku();
List<int[]> mutablePositions = chromosome.getMutablePositions();
// Mutate each mutable position with a probability defined by mutationRate
for (int[] pos : mutablePositions) {
if (random.nextDouble() < mutationRate) {
int row = pos[0];
int col = pos[1];
int newValue = random.nextInt(9) + 1; // Assign a new value between 1 and 9
sudoku[row][col] = newValue;
}
}
// Update the chromosome's Sudoku and recalculate its fitness
chromosome.setSudoku(sudoku);
chromosome.evaluateFitness();
}
public void evaluatePopulation() {
// Evaluate the fitness of each chromosome in the population
for (Chromosome chromosome : population) {
chromosome.evaluateFitness();
}
}
public Chromosome getBestChromosome() {
// Find and return the chromosome with the best (lowest) fitness in the population
Chromosome best = population.get(0);
for (Chromosome chromosome : population) {
if (chromosome.getFitness() < best.getFitness()) {
best = chromosome;
}
}
return best;
}
// Chromosome class representing an individual solution
public class Chromosome {
private int[][] sudoku; // Sudoku grid representing the chromosome
private List<int[]> mutablePositions; // Positions that can be changed (mutable)
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) {
this.sudoku = sudoku;
this.mutablePositions = mutablePositions;
}
public int[][] getSudoku() {
return sudoku;
}
public void setSudoku(int[][] sudoku) {
this.sudoku = sudoku;
}
public List<int[]> getMutablePositions() {
return mutablePositions;
}
public int getFitness() {
return fitness;
}
// Evaluate the fitness of the Sudoku by counting the number of row, column, and subgrid violations
public void evaluateFitness() {
fitness = countRowViolations() + countColumnViolations() + countSubgridViolations();
}
private int countRowViolations() {
int violations = 0;
// Iterate through each row to count conflicts
for (int i = 0; i < 9; i++) {
boolean[] present = new boolean[10];
for (int j = 0; j < 9; j++) {
int value = sudoku[i][j];
if (value != 0) {
if (present[value]) {
violations++; // Increment violations if the value is already seen
} else {
present[value] = true; // Mark the value as seen
}
}
}
}
return violations;
}
private int countColumnViolations() {
int violations = 0;
// Loop through each column
for (int j = 0; j < 9; j++) {
boolean[] present = new boolean[10]; // Track numbers present in the column
for (int i = 0; i < 9; i++) {
int value = sudoku[i][j];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
// Mark the number as present
present[value] = true;
}
}
}
}
return violations;
}
private int countSubgridViolations() {
int violations = 0;
// Loop through each 3x3 subgrid
for (int gridRow = 0; gridRow < 3; gridRow++) {
for (int gridCol = 0; gridCol < 3; gridCol++) {
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 col = gridCol * 3; col < gridCol * 3 + 3; col++) {
int value = sudoku[row][col];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
// Mark the number as present
present[value] = true;
}
}
}
}
}
}
return violations;
}
public void printChromosome(boolean printMutPos) {
// Print the Sudoku matrix
for (int[] row : sudoku) {
for (int j = 0; j < row.length; j++) {
System.out.print(row[j]);
if (j < row.length - 1) {
System.out.print(" ");
}
}
System.out.println();
}
// If requested, print mutable positions
if (printMutPos) {
System.out.println("Mutable Positions:");
for (int i = 0; i < mutablePositions.size(); i++) {
int[] pos = mutablePositions.get(i);
System.out.print("(" + pos[0] + ", " + pos[1] + ")");
if (i < mutablePositions.size() - 1) {
System.out.print(" ");
}
}
System.out.println();
}
}
}
}
+115
View File
@@ -0,0 +1,115 @@
import subprocess
from time import sleep
process = subprocess.Popen(['java', './Main.java'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
info = []
for i in range(9):
info.append([""] * 9)
def check(x, y):
a = 0
res = []
if info[x][y] != "":
a += 1
res.append(info[x][y])
for dx in range(-1, 2):
for dy in range(-1, 2):
if (0 <= x+dx <= 8 and 0 <= y+dy <= 8 and (dy != 0 or dx != 0) and info[x+dx][y+dy] == 'A'):
a += 1
res.append("P")
return [a, res]
if (0 <= x-1 <= 8 and info[x-1][y] == 'S' or 0 <= x+1 <= 8 and info[x+1][y] == 'S' or 0 <= y-1 <= 8 and info[x][y-1] == 'S' or 0 <= y+1 <= 8 and info[x][y+1] == 'S'):
a += 1
res.append("P")
return [a, res]
return [a, res]
def show(neo_x, neo_y):
with open('close.txt', encoding='utf-8', mode='w') as f1:
a = list(map)
a[map.find('𖨆')] = ' '
a[map.find(str(neo_x) + " |") + 4 + neo_y * 4] = '𖨆'
f1.write(''.join(a))
map = ''
keymaker_x = 0
keymaker_y = 0
key_x = 99
key_y = 99
with open('field.txt', encoding='utf-8') as initial:
i = 1
for line in initial:
map += line
if (3 <= i and i <= 19 and i % 2 == 1):
line = line.split('|')[1:-1]
for j in range(len(line)):
if (line[j] == ' ■ '):
info[i // 2 - 1][j] = 'A'
elif (line[j] == ' □ '):
info[i // 2 - 1][j] = 'S'
elif (line[j] == ' ⚷ '):
info[i // 2 - 1][j] = 'B'
key_x = i // 2 - 1
key_y = j
elif (line[j] == ' K '):
info[i // 2 - 1][j] = 'K'
keymaker_x = i // 2 - 1
keymaker_y = j
i += 1
# show(0, 0)
mode = 1
process.stdin.write((str(mode) + "\n" +
str(keymaker_x) + " " +
str(keymaker_y) + "\n"))
process.stdin.flush()
print(str(mode) + "\n" + str(keymaker_x) + " " + str(keymaker_y))
now_x = 0
now_y = 0
while True:
move = process.stdout.readline().replace('\n', '')
print(move)
if 'e' in move:
break
move = move.split()
temp_x = int(move[1])
temp_y = int(move[2])
# show(temp_x, temp_y)
if not(temp_x + 1 == now_x and temp_y == now_y or temp_x - 1 == now_x and temp_y == now_y or temp_x == now_x and temp_y + 1 == now_y or temp_x == now_x and temp_y - 1 == now_y or temp_x == now_x and temp_y == now_y):
print("Error: Teleport")
break
now_x = int(move[1])
now_y = int(move[2])
# sleep(0.5)
res = ''
num = 0
if mode == 1:
left = -1
right = 2
else:
left = -2
right = 3
for dx in range(left, right):
for dy in range(left, right):
new_x = now_x + dx
new_y = now_y + dy
if 0 <= new_x <= 8 and 0 <= new_y <= 8:
a = check(new_x, new_y)
num += a[0]
for elem in a[1]:
res += str(new_x) + " " + str(new_y) + " " + elem + "\n"
# Кодируем результат перед записью
send = str(num) + '\n' + res
process.stdin.write(send)
print(send[:-1])
process.stdin.flush()
+180
View File
@@ -0,0 +1,180 @@
import pandas as pd
from statistics import multimode, mean, median, stdev
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
def calculate_statistics(execution_times):
"""Calculate mean, median, mode, and standard deviation."""
mean_time = mean(execution_times)
median_time = median(execution_times)
modes = multimode(execution_times)
std_dev = stdev(execution_times)
# Handle multiple modes
if len(modes) == 1:
mode_time = modes[0]
else:
mode_time = modes # List of modes
return mean_time, median_time, mode_time, std_dev
def plot_histogram(execution_times, mean_time, median_time, mode_time, std_dev):
"""Plot a histogram of execution times with mean, median, mode, and standard deviation."""
plt.figure(figsize=(10, 6))
# Define bin range to focus between 25 and 35 ms
bin_start = 25
bin_end = 35
bins = list(range(bin_start, bin_end + 1)) # Bins from 25 to 35
# Plot the main histogram
plt.hist(execution_times, bins=bins, edgecolor='black', alpha=0.7, label='Execution Times (25-35 ms)')
# Plot outliers (below 25 or above 35 ms)
outliers = [x for x in execution_times if x < bin_start or x > bin_end]
if outliers:
# Determine appropriate bins for outliers
outlier_min = min(outliers)
outlier_max = max(outliers)
outlier_bins = list(range(outlier_min, outlier_max + 2))
plt.hist(outliers, bins=outlier_bins, edgecolor='black', alpha=0.7, color='red', label='Outliers (<25 or >35 ms)')
plt.title('Histogram of Execution Times')
plt.xlabel('Execution Time (ms)')
plt.ylabel('Frequency')
# Plot mean
plt.axvline(mean_time, color='blue', linestyle='dashed', linewidth=1.5, label=f'Mean: {mean_time:.2f} ms')
# Plot median
plt.axvline(median_time, color='green', linestyle='dashed', linewidth=1.5, label=f'Median: {median_time} ms')
# Plot mode(s)
if isinstance(mode_time, list):
for m in mode_time:
plt.axvline(m, color='purple', linestyle='dashed', linewidth=1.5, label=f'Mode: {m} ms')
else:
plt.axvline(mode_time, color='purple', linestyle='dashed', linewidth=1.5, label=f'Mode: {mode_time} ms')
# Shade the area within one standard deviation from the mean
plt.axvspan(mean_time - std_dev, mean_time + std_dev, color='yellow', alpha=0.2, label='±1 Standard Deviation')
# Set x-axis limits to focus on 25-35 ms with some padding for outliers
plt.xlim(bin_start - 5, bin_end + 5) # Extending a bit to show outliers
plt.legend()
plt.tight_layout()
return plt.gcf() # Return the current figure
def plot_boxplot(execution_times):
"""Plot a box plot of execution times."""
plt.figure(figsize=(10, 6))
plt.boxplot(execution_times, vert=False, patch_artist=True, boxprops=dict(facecolor='lightblue'))
plt.title('Box Plot of Execution Times')
plt.xlabel('Execution Time (ms)')
plt.tight_layout()
return plt.gcf()
def generate_pdf_report(csv_file, output_pdf):
"""Generate a PDF report containing statistics and visualizations."""
# Read the CSV file with error handling
try:
data = pd.read_csv(csv_file)
except FileNotFoundError:
print(f"Error: The file '{csv_file}' was not found.")
return
except pd.errors.EmptyDataError:
print(f"Error: The file '{csv_file}' is empty.")
return
except pd.errors.ParserError:
print(f"Error: The file '{csv_file}' does not appear to be in CSV format.")
return
# Check if 'ExecutionTime_ms' column exists
if 'ExecutionTime_ms' not in data.columns:
print("Error: 'ExecutionTime_ms' column not found in the CSV file.")
return
# Extract execution times
execution_times = data['ExecutionTime_ms'].tolist()
# Validate execution times
if not execution_times:
print("Error: No execution time data found.")
return
# Check for non-numeric values
non_numeric = [x for x in execution_times if not isinstance(x, (int, float))]
if non_numeric:
print("Error: Non-numeric values found in 'ExecutionTime_ms' column.")
print(non_numeric)
return
# Check if there are enough data points for standard deviation
if len(execution_times) < 2:
print("Error: At least two execution time data points are required to calculate standard deviation.")
return
# Calculate statistics
mean_time, median_time, mode_time, std_dev = calculate_statistics(execution_times)
# Debug print statements
print(f"Mean: {mean_time:.2f} ms")
print(f"Median: {median_time} ms")
print(f"Mode: {mode_time if isinstance(mode_time, list) else [mode_time]} ms")
print(f"Standard Deviation: {std_dev:.2f} ms")
# Create histogram plot with standard deviation shaded
fig_hist = plot_histogram(execution_times, mean_time, median_time, mode_time, std_dev)
# Create box plot
fig_box = plot_boxplot(execution_times)
# Prepare statistics text
if isinstance(mode_time, list):
mode_str = ', '.join(map(str, mode_time))
else:
mode_str = str(mode_time)
stats_text = f"""
Execution Time Statistics
=========================
Total Runs: {len(execution_times)}
Mean: {mean_time:.2f} ms
Median: {median_time} ms
Mode: {mode_str} ms
Standard Deviation: {std_dev:.2f} ms
"""
# Create PDF
with PdfPages(output_pdf) as pdf:
# Page 1: Histogram
pdf.savefig(fig_hist)
plt.close(fig_hist)
# Page 2: Box Plot
pdf.savefig(fig_box)
plt.close(fig_box)
# Page 3: Statistics Summary
plt.figure(figsize=(8.5, 11))
plt.axis('off') # Hide axes
# Add text to the figure
plt.text(0.5, 0.5, stats_text, horizontalalignment='center', verticalalignment='center', fontsize=12, wrap=True)
# Add the statistics page to the PDF
pdf.savefig()
plt.close()
print(f"PDF report '{output_pdf}' has been generated successfully.")
if __name__ == "__main__":
# Define input and output files
csv_file = 'execution_times.csv'
output_pdf = 'execution_time_report.pdf'
# Generate the PDF report
generate_pdf_report(csv_file, output_pdf)
+238
View File
@@ -0,0 +1,238 @@
import subprocess
from random import randint
import timeit
import statistics
# astar = ['python', './astar.py']
# backtracking = ['python', './bt.exe']
astar = ['./code.exe']
backtracking = ['./bt.exe']
process1 = subprocess.Popen(astar, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
process2 = subprocess.Popen(astar, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
process3 = subprocess.Popen(backtracking, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
wins_Astar = 0
losses_Astar = 0
wins_bt = 0
losses_bt = 0
def check(x, y):
a = 0
res = []
if info[x][y] != "":
a += 1
res.append(info[x][y])
for dx in range(-1, 2):
for dy in range(-1, 2):
if (0 <= x+dx <= 8 and 0 <= y+dy <= 8 and info[x+dx][y+dy] == 'A'):
a += 1
res.append("P")
return [a, res]
if (0 <= x-1 <= 8 and info[x-1][y] == 'S' or 0 <= x+1 <= 8 and info[x+1][y] == 'S' or 0 <= y-1 <= 8 and info[x][y-1] == 'S' or 0 <= y+1 <= 8 and info[x][y+1] == 'S'):
a += 1
res.append("P")
return [a, res]
return [a, res]
def Astar_mode_1():
global info, process1, wins_Astar, losses_Astar, keymaker_x, keymaker_y, key_x, key_y
mode = 1
process1.stdin.write(str(mode) + "\n" + str(keymaker_x) + " " + str(keymaker_y) + "\n")
process1.stdin.flush()
now_x = 0
now_y = 0
while True:
move = process1.stdout.readline().strip()
if 'e' in move:
if (move[-2:] == '-1'):
losses_Astar += 1
else:
wins_Astar += 1
break
move = move.split()
now_x = int(move[1])
now_y = int(move[2])
res = ''
num = 0
if mode == 1:
left = -1
right = 2
else:
left = -2
right = 3
for dx in range(left, right):
for dy in range(left, right):
new_x = now_x + dx
new_y = now_y + dy
if 0 <= new_x <= 8 and 0 <= new_y <= 8:
a = check(new_x, new_y)
num += a[0]
for elem in a[1]:
res += str(new_x) + " " + str(new_y) + " " + elem + "\n"
process1.stdin.write(str(num) + '\n' + res)
process1.stdin.flush()
def Astar_mode_2():
global info, process2, keymaker_x, keymaker_y, key_x, key_y
mode = 2
process2.stdin.write(str(mode) + "\n" + str(keymaker_x) + " " + str(keymaker_y) + "\n")
process2.stdin.flush()
now_x = 0
now_y = 0
while True:
move = process2.stdout.readline().strip()
if 'e' in move:
break
move = move.split()
now_x = int(move[1])
now_y = int(move[2])
res = ''
num = 0
if mode == 1:
left = -1
right = 2
else:
left = -2
right = 3
for dx in range(left, right):
for dy in range(left, right):
new_x = now_x + dx
new_y = now_y + dy
if 0 <= new_x <= 8 and 0 <= new_y <= 8:
a = check(new_x, new_y)
num += a[0]
for elem in a[1]:
res += str(new_x) + " " + str(new_y) + " " + elem + "\n"
process2.stdin.write(str(num) + '\n' + res)
process2.stdin.flush()
def back():
global info, process3, wins_bt, losses_bt, keymaker_x, keymaker_y, key_x, key_y
mode = randint(1, 2)
process3.stdin.write(str(mode) + "\n" + str(keymaker_x) + " " + str(keymaker_y) + "\n")
process3.stdin.flush()
now_x = 0
now_y = 0
while True:
move = process3.stdout.readline().strip()
if 'e' in move:
if (move[-2:] == '-1'):
losses_bt += 1
else:
wins_bt += 1
break
move = move.split()
now_x = int(move[1])
now_y = int(move[2])
res = ''
num = 0
if mode == 1:
left = -1
right = 2
else:
left = -2
right = 3
for dx in range(left, right):
for dy in range(left, right):
new_x = now_x + dx
new_y = now_y + dy
if 0 <= new_x <= 8 and 0 <= new_y <= 8:
a = check(new_x, new_y)
num += a[0]
for elem in a[1]:
res += str(new_x) + " " + str(new_y) + " " + elem + "\n"
process3.stdin.write(str(num) + '\n' + res)
process3.stdin.flush()
def mapgen():
global info, keymaker_x, keymaker_y, key_x, key_y, process1, process2, process3, astar, backtracking
info = []
for i in range(9):
info.append([""] * 9)
info[0][0] = 'N'
keymaker_x = randint(0, 8)
keymaker_y = randint(0, 8)
while (info[keymaker_x][keymaker_y] != ''):
keymaker_x = randint(0, 8)
keymaker_y = randint(0, 8)
info[keymaker_x][keymaker_y] = 'K'
key_x = randint(0, 8)
key_y = randint(0, 8)
while (info[key_x][key_y] != ""):
key_x = randint(0, 8)
key_y = randint(0, 8)
info[key_x][key_y] = 'B'
for smith in range(randint(0, 3)):
x = randint(0, 8)
y = randint(0, 8)
while (x == 0 and y == 0 or x == 0 and y == 1 or x == 1 and y == 0 or x == 1 and y == 1 or info[x][y] != '' or (x-1 >= 0 and y-1 >=0 and (info[x-1][y-1] == 'K' or info[x-1][y-1] == "B")) or (x-1 >= 0 and (info[x-1][y] == 'K' or info[x-1][y] == 'B')) or (x-1 >= 0 and y+1 <= 8 and (info[x-1][y+1] == 'K' or info[x-1][y+1] == 'B')) or (y-1 >= 0 and (info[x][y-1] == 'K' or info[x][y-1] == 'B')) or (y+1 <= 8 and (info[x][y+1] == 'K' or info[x][y+1] == 'B')) or (x+1 <= 8 and y-1 >= 0 and (info[x+1][y-1] == 'K' or info[x+1][y-1] == 'B')) or (x+1 <= 8 and (info[x+1][y] == 'K' or info[x+1][y] == 'B')) or (x+1 <= 8 and y+1 <= 8 and (info[x+1][y+1] == 'K' or info[x+1][y+1] == 'B'))):
x = randint(0, 8)
y = randint(0, 8)
info[x][y] = 'A'
for sentiel in range(randint(0, 1)):
x = randint(0, 8)
y = randint(0, 8)
while (x == 0 and y == 0 or x == 0 and y == 1 or x == 1 and y == 0 or info[x][y] != '' or (x-1 >= 0 and (info[x-1][y] == 'K' or info[x-1][y] == 'B')) or (x+1 <= 8 and (info[x+1][y] == 'K' or info[x+1][y] == 'B')) or (y-1 >= 0 and (info[x][y-1] == 'K' or info[x][y-1] == 'B')) or (y+1 <= 8 and (info[x][y+1] == 'K' or info[x][y+1] == 'B'))):
x = randint(0, 8)
y = randint(0, 8)
info[x][y] = 'S'
info[0][0] = ''
process1 = subprocess.Popen(astar, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
process2 = subprocess.Popen(astar, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
process3 = subprocess.Popen(backtracking, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
execution_time_1 = []
execution_time_2 = []
execution_time_3 = []
for i in range(1, 1001):
mapgen()
execution_time_1.append(timeit.timeit(Astar_mode_1, number=1) * 1000000)
execution_time_2.append(timeit.timeit(Astar_mode_2, number=1) * 1000000)
execution_time_3.append(timeit.timeit(back, number=1) * 1000000)
if (i % 100 == 0):
print('Запущено карт', i)
print("Execution time (A* mode 1)")
print("Mean:", statistics.mean(execution_time_1))
print("Mode:", statistics.mode(execution_time_1))
print("Median:", statistics.median(execution_time_1))
print("Standart deviation:", statistics.stdev(execution_time_1))
print()
print("Execution time (A* mode 2)")
print("Mean:", statistics.mean(execution_time_2))
print("Mode:", statistics.mode(execution_time_2))
print("Median:", statistics.median(execution_time_2))
print("Standart deviation:", statistics.stdev(execution_time_2))
print()
print("Execution time (Backtrack)")
print("Mean:", statistics.mean(execution_time_3))
print("Mode:", statistics.mode(execution_time_3))
print("Median:", statistics.median(execution_time_3))
print("Standart deviation:", statistics.stdev(execution_time_3))
print()
print("Wins A*:", wins_Astar)
print("Losses A*:", losses_Astar)
print("Wins bt:", wins_bt)
print("Losses bt:", losses_bt)
+52
View File
@@ -0,0 +1,52 @@
#!/bin/bash
# Initialize the CSV file and write the header
echo "Run,ExecutionTime_ms,Result" > execution_times.csv
FILE_NAME=Main.java
for i in {1..1000}
do
# Record the start time in milliseconds
start_time=$(perl -MTime::HiRes=time -e 'printf("%.0f\n", time()*1000)')
# Execute the Python script and capture its output
# Use `stdout` and `stderr` to capture all outputs
output=$(python "$FILE_NAME" 2>&1)
# Record the end time in milliseconds
end_time=$(perl -MTime::HiRes=time -e 'printf("%.0f\n", time()*1000)')
# Calculate the elapsed time
elapsed_time=$((end_time - start_time))
# Extract the result from the Python script's output
# Assumes the output is in the format "e <number>"
result_line=$(echo "$output" | grep '^e ')
if [ -n "$result_line" ]; then
# Extract the number after 'e '
number=$(echo "$result_line" | awk '{print $2}')
# Determine Result as 1 or 0 based on the number
if [ "$number" -gt 0 ]; then
result=1
elif [ "$number" -eq -1 ]; then
result=0
else
# Handle unexpected numbers
result="Unexpected_$number"
echo "Run $i: $elapsed_time ms, Result: $result (Unexpected number)"
fi
else
# If the expected line is not found
result="N/A"
echo "Run $i: $elapsed_time ms, Result: $result (Missing 'e ' in output)"
fi
# Log the execution time and result
echo "Run $i: $elapsed_time ms, Result: $result"
# Append the run number, elapsed time, and result to the CSV file
echo "$i,$elapsed_time,$result" >> execution_times.csv
done
+17
View File
@@ -0,0 +1,17 @@
#!/bin/bash
# Initialize the CSV file and write the header
echo "Run,ExecutionTime_ms" > execution_times.csv
FILE_NAME=save_neo.py
for i in {1..1000}
do
start_time=$(perl -MTime::HiRes=time -e 'printf("%.0f\n", time()*1000)')
python $FILE_NAME
end_time=$(perl -MTime::HiRes=time -e 'printf("%.0f\n", time()*1000)')
elapsed_time=$(($end_time - $start_time))
echo "Run $i: $elapsed_time ms"
# Append the result to the CSV file
echo "$i,$elapsed_time" >> execution_times.csv
done
+186
View File
@@ -0,0 +1,186 @@
import subprocess
from time import time
import matplotlib.pyplot as plt
import random
from dokusan import generators
# C++ коды
#code = ["./build/sudoku"]
# Java коды
code = ["java", "./Main.java"]
# Python коды
# code = ["python", "./submit.py"]
N_TESTS = 30
def read_sudoku(file):
sudoku = []
i = 0
for line in file:
i += 1
if (i == 10):
break
row = list(map(int, line.split()))
sudoku.append(row)
return sudoku
def is_valid_sudoku(sudoku, input_file):
# Проверка строк
for row in sudoku:
if len(set(row)) != 9 or any(num < 1 or num > 9 for num in row):
print('строка', row)
return False
# Проверка столбцов
for col in range(9):
column = [sudoku[row][col] for row in range(9)]
if len(set(column)) != 9:
print('столбец', col)
return False
# Проверка 3x3 квадратов
for box_row in range(0, 9, 3):
for box_col in range(0, 9, 3):
square = []
for i in range(3):
for j in range(3):
square.append(sudoku[box_row + i][box_col + j])
if len(set(square)) != 9:
print('квадрат')
return False
# Проверка совпадения с input
row = 0
for line in input_file:
a = line.split()
for column in range(9):
if a[column] != '-' and int(a[column]) != sudoku[row][column]:
print('строка', row)
return False
row += 1
return True
def mapgen(numbers, input_file):
# Сгенерировать полный решённый Судоку
full_sudoku = list(map(int, str(generators.random_sudoku(avg_rank=0))))
grid = [full_sudoku[i:i+9] for i in range(0, 81, 9)]
# Составить список всех координат
coords = [(i, j) for i in range(9) for j in range(9)]
random.shuffle(coords)
# Удаление чисел с проверкой на уникальность решения
while sum(row.count(0) for row in grid) < (81 - numbers) and coords:
x, y = coords.pop()
grid[x][y] = 0
# Записать результат в файл
for row in grid:
input_file.write(" ".join(map(str, row)).replace('0', '-') + "\n")
def main():
exec_time_avg_easy = []
avg_fitness_avg_easy = []
max_fitness_avg_easy = []
exec_time_avg_medium = []
avg_fitness_avg_medium = []
max_fitness_avg_medium = []
exec_time_avg_hard = []
avg_fitness_avg_hard = []
max_fitness_avg_hard = []
exec_time_avg = []
avg_fitness_avg = []
max_fitness_avg = []
number_of_cells = []
a = 21
b = 41
for cells in range(a, b):
exec_time = []
avg_fitness = []
max_fitness = []
for maps in range(N_TESTS):
number_of_cells.append(cells)
# генерация карты
with open("input.txt", "w") as input_file:
mapgen(cells, input_file)
# запуск алгоритма
with open("input.txt", "r") as input_file, open("output.txt", "w") as output_file:
start = time()
process1 = subprocess.Popen(code, stdin=input_file, stdout=output_file, stderr=subprocess.PIPE, text=True)
process1.wait()
exec_time.append(round(time() - start, 2))
print('Тест', cells, maps, 'пройден за', exec_time[-1])
# проверка на корректность решения
with open("input.txt", "r") as input_file, open("output.txt", "r") as output_file:
read = output_file.readlines()
avg_fitness.append(float(read[1]))
max_fitness.append(float(read[0]))
read.pop(1)
read.pop(0)
sudoku = read_sudoku(read)
if not is_valid_sudoku(sudoku, input_file):
print("Решение судоку некорректное.")
exit()
if (30 <= cells <= 40):
exec_time_avg_easy += exec_time
avg_fitness_avg_easy += avg_fitness
max_fitness_avg_easy += max_fitness
elif (26 <= cells <= 29):
exec_time_avg_medium += exec_time
avg_fitness_avg_medium += avg_fitness
max_fitness_avg_medium += max_fitness
else:
exec_time_avg_hard += exec_time
avg_fitness_avg_hard += avg_fitness
max_fitness_avg_hard += max_fitness
exec_time_avg.append(sum(exec_time) / len(exec_time))
avg_fitness_avg.append(sum(avg_fitness) / len(avg_fitness))
max_fitness_avg.append(sum(max_fitness) / len(max_fitness))
print('EASY')
print('average time', sum(exec_time_avg_easy) / len(exec_time_avg_easy))
print('maximum fitness', sum(max_fitness_avg_easy) / len(max_fitness_avg_easy))
print('average fitness', sum(avg_fitness_avg_easy) / len(avg_fitness_avg_easy))
print()
print('MEDIUM')
print('average time', sum(exec_time_avg_medium) / len(exec_time_avg_medium))
print('maximum fitness', sum(max_fitness_avg_medium) / len(max_fitness_avg_medium))
print('average fitness', sum(avg_fitness_avg_medium) / len(avg_fitness_avg_medium))
print()
print('HARD')
print('average time', sum(exec_time_avg_hard) / len(exec_time_avg_hard))
print('maximum fitness', sum(max_fitness_avg_hard) / len(max_fitness_avg_hard))
print('average fitness', sum(avg_fitness_avg_hard) / len(avg_fitness_avg_hard))
plt.figure(1)
plt.plot([i for i in range(a, b)], avg_fitness_avg, linestyle='-', color='b')
plt.title(f'Average avg fitness on last generation among {N_TESTS} tests per each N')
plt.xlabel('Numbers provided (N)')
plt.ylabel('Average avg fitness on last generation')
plt.grid()
plt.savefig(f"avgfit{N_TESTS}.png", dpi=400)
plt.figure(2)
plt.plot([i for i in range(a, b)], exec_time_avg, linestyle='-', color='b')
plt.title(f'Average execution time among {N_TESTS} tests per each N')
plt.xlabel('Numbers provided (N)')
plt.ylabel('Average execution time, sec')
plt.grid()
plt.savefig(f"exec{N_TESTS}.png", dpi=400)
plt.figure(3)
plt.plot([i for i in range(a, b)], max_fitness_avg, linestyle='-', color='b')
plt.title(f'Average max fitness on last generation among {N_TESTS} tests per each N')
plt.xlabel('Numbers provided (N)')
plt.ylabel('Average max fitness on last generation')
plt.grid()
plt.savefig(f"maxfit{N_TESTS}.png", dpi=400)
plt.show()
if __name__ == "__main__":
main()
+187
View File
@@ -0,0 +1,187 @@
# POSSIBLE USAGE KEYS
# map, keymaker_position = Utils.generate_random_map()
# proceed with map actions...
import random
from typing import (
List,
Tuple,
Optional,
Set,
)
class Utils:
@staticmethod
def generate_random_map() -> Tuple[List[List[str]], Optional[Tuple[int, int]]]:
"""
Generates a random 9x9 game map with placements of 'A', 'S', and 'P'.
'P' placements depend on the positions of 'A' and 'S'.
Returns:
A tuple containing the game map and one unoccupied square (or None if all occupied).
"""
# Initialize a 9x9 grid with empty strings
game_map: List[List[str]] = [[[] for _ in range(9)] for _ in range(9)]
all_coordinates: List[Tuple[int, int]] = [(x, y) for x in range(9) for y in range(9)]
def place_letter(
letter: str,
count: int,
available: List[Tuple[int, int]],
) -> List[Tuple[int, int]]:
"""
Places a specified letter on the game map a certain number of times.
Args:
letter: The letter to place ('A' or 'S').
count: Number of times to place the letter.
available: List of available coordinates.
Returns:
A list of coordinates where the letter was placed.
"""
placed: List[Tuple[int, int]] = []
for _ in range(count):
if not available:
break
x, y = random.choice(available)
game_map[x][y] = [letter]
placed.append((x, y))
available.remove((x, y))
return placed
# Place "A" 0 to 3 times
num_A: int = random.randint(0, 3)
A_positions: List[Tuple[int, int]] = place_letter("A", num_A, all_coordinates)
# Place "S" 0 to 1 times
num_S: int = random.randint(0, 1)
S_positions: List[Tuple[int, int]] = place_letter("S", num_S, all_coordinates)
def get_moore_neighbors(x: int, y: int) -> List[Tuple[int, int]]:
"""
Retrieves all Moore neighbors (8 surrounding cells) for a given position.
Args:
x: X-coordinate.
y: Y-coordinate.
Returns:
A list of neighboring coordinates within bounds.
"""
neighbors: List[Tuple[int, int]] = []
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if dx == 0 and dy == 0:
continue
nx, ny = x + dx, y + dy
if 0 <= nx < 9 and 0 <= ny < 9:
neighbors.append((nx, ny))
return neighbors
def get_von_neumann_neighbors(x: int, y: int) -> List[Tuple[int, int]]:
"""
Retrieves all von Neumann neighbors (4 adjacent cells) for a given position.
Args:
x: X-coordinate.
y: Y-coordinate.
Returns:
A list of neighboring coordinates within bounds.
"""
neighbors: List[Tuple[int, int]] = []
for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]:
nx, ny = x + dx, y + dy
if 0 <= nx < 9 and 0 <= ny < 9:
neighbors.append((nx, ny))
return neighbors
# Collect all possible P placement positions
possible_P_positions: Set[Tuple[int, int]] = set()
for x, y in A_positions:
neighbors = get_moore_neighbors(x, y)
possible_P_positions.update(neighbors)
for x, y in S_positions:
neighbors = get_von_neumann_neighbors(x, y)
possible_P_positions.update(neighbors)
# Remove positions already occupied by "A" or "S"
occupied_positions: Set[Tuple[int, int]] = set(A_positions + S_positions)
possible_P_positions = [
pos
for pos in possible_P_positions
if pos not in occupied_positions and game_map[pos[0]][pos[1]] == []
]
# Place "P" in all possible positions derived from "A" and "S"
for x, y in possible_P_positions:
game_map[x][y] = ["P"]
if (x, y) in all_coordinates:
all_coordinates.remove((x, y))
# Select one unoccupied square
chosen_unoccupied: Optional[Tuple[int, int]] = (
random.choice(all_coordinates) if all_coordinates else None
)
return game_map, chosen_unoccupied
@staticmethod
def heuristic(pos: Tuple[int, int], goal: Tuple[int, int]) -> int:
"""
Calculates the Manhattan distance between two positions.
Args:
pos: Current position as (x, y).
goal: Goal position as (x, y).
Returns:
The Manhattan distance as an integer.
"""
return abs(pos[0] - goal[0]) + abs(pos[1] - goal[1])
@staticmethod
def get_directions(pos: Tuple[int, int]) -> List[Tuple[int, int]]:
"""
Returns possible moves (Up, Down, Left, Right) from the current position within bounds.
Args:
pos: Current position as (x, y).
Returns:
A list of valid adjacent positions.
"""
moves: List[Tuple[int, int]] = [
(pos[0] + 1, pos[1]), # Down
(pos[0] - 1, pos[1]), # Up
(pos[0], pos[1] + 1), # Right
(pos[0], pos[1] - 1), # Left
]
return [move for move in moves if 0 <= move[0] <= 8 and 0 <= move[1] <= 8]
@staticmethod
def get_directions_with_zones(
pos: Tuple[int, int], enemies_perception_zones: Set[Tuple[int, int]]
) -> List[Tuple[int, int]]:
"""
Returns possible moves from the current position excluding moves that are in danger zones.
Args:
pos: Current position as (x, y).
enemies_perception_zones: A set of dangerous positions.
Returns:
A list of safe adjacent positions.
"""
moves: List[Tuple[int, int]] = Utils.get_directions(pos)
return [move for move in moves if move not in enemies_perception_zones]
+375
View File
@@ -0,0 +1,375 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Main {
// Initalizing variables
public static int POPULATIONSIZE = 0;
public static int TOURNAMENTSIZE = 0;
public static double MUTATIONRATE = 0;
// Threshold of number of mutable positions for easy level sudoku
public static int EASYTHRESHOLD = 60;
public static int HARDTHRESHOLD = 70;
// List to store the population of chromosomes
List<Chromosome> population = new ArrayList<>();
Random random = new Random();
public static void main(String[] args) {
// Base Sudoku matrix (input matrix)
int[][] baseSudoku = new int[9][9];
// List to track positions in Sudoku that are mutable
List<int[]> mutablePositions = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
// Reading the Sudoku matrix from the console input
for (int i = 0; i < 9; i++) {
// Split the input by space
String[] tokens = reader.readLine().split(" ");
for (int j = 0; j < 9; j++) {
if (tokens[j].equals("-")) {
// Empty cells are marked as 0
baseSudoku[i][j] = 0;
// Add mutable positions (i, j) to the list
mutablePositions.add(new int[]{i, j});
} else {
// Set fixed value from the input
baseSudoku[i][j] = Integer.parseInt(tokens[j]);
}
}
}
} 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());
return;
}
Main mainInstance = new Main(); // Create instance of Main class
// Choosing variables for different sudoku difficulties
if (mutablePositions.size() < EASYTHRESHOLD) { // Easy sudoku
POPULATIONSIZE = 100;
TOURNAMENTSIZE = 5;
MUTATIONRATE = 0.05;
} else if (mutablePositions.size() < HARDTHRESHOLD) { // Hard sudoku
POPULATIONSIZE = 100;
TOURNAMENTSIZE = 5;
MUTATIONRATE = 0.057;
}
else { // Ultra-hard sudoku
POPULATIONSIZE = 20000;
TOURNAMENTSIZE = 4;
MUTATIONRATE = 0.032;
}
// Generate initial population of 100 chromosomes
mainInstance.generateInitialChromosomes(POPULATIONSIZE, baseSudoku, mutablePositions);
Chromosome bestSolution = null;
int generation = 0; // Track the number of generations
while (true) {
// Evaluate the fitness of each chromosome in the population
mainInstance.evaluatePopulation();
List<Chromosome> newPopulation = new ArrayList<>();
for (int i = 0; i < mainInstance.population.size() / 2; i++) {
// Select parents using tournament selection
List<Chromosome> parents = mainInstance.tournamentSelection(TOURNAMENTSIZE);
// Perform crossover to create two children from the selected parents
Chromosome child1 = mainInstance.crossoverBySubgrids(parents.get(0), parents.get(1));
Chromosome child2 = mainInstance.crossoverBySubgrids(parents.get(1), parents.get(0));
// Apply mutation to both children
mainInstance.mutateChromosome(child1, MUTATIONRATE);
mainInstance.mutateChromosome(child2, MUTATIONRATE);
// Add both children to the new population
newPopulation.add(child1);
newPopulation.add(child2);
}
// Replace the old population with the new population
mainInstance.population = newPopulation;
// Get the best chromosome from the current population
bestSolution = mainInstance.getBestChromosome();
generation++;
// If the best solution found has a fitness of 0, print it and end the program
if (bestSolution.getFitness() == 0) {
bestSolution.printChromosome(false);
return;
}
}
}
// Generate initial population of chromosomes
public void generateInitialChromosomes(int numberOfChromosomes, int[][] baseSudoku, List<int[]> mutablePositions) {
for (int i = 0; i < numberOfChromosomes; i++) {
// Create a copy of the base Sudoku
int[][] sudoku = copyMatrix(baseSudoku);
// Randomly fill mutable positions
for (int[] pos : mutablePositions) {
int row = pos[0];
int col = pos[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.evaluateFitness(); // Evaluate its fitness
population.add(chromosome); // Add to the population
}
}
// Create a deep copy of a matrix
private int[][] copyMatrix(int[][] original) {
int[][] copy = new int[original.length][original[0].length];
for (int i = 0; i < original.length; i++) {
System.arraycopy(original[i], 0, copy[i], 0, original[i].length);
}
return copy;
}
public List<Chromosome> tournamentSelection(int tournamentSize) {
List<Chromosome> selectedParents = new ArrayList<>();
for (int i = 0; i < 2; i++) {
List<Chromosome> tournament = new ArrayList<>();
// Randomly select chromosomes for the tournament
for (int j = 0; j < tournamentSize; j++) {
Chromosome randomChromosome = population.get(random.nextInt(population.size()));
tournament.add(randomChromosome);
}
// Determine the best chromosome in the tournament based on fitness
Chromosome best = tournament.get(0);
for (Chromosome chromosome : tournament) {
if (chromosome.getFitness() < best.getFitness()) {
best = chromosome;
}
}
// Add the best chromosome to the list of selected parents
selectedParents.add(best);
}
return selectedParents;
}
public Chromosome crossoverBySubgrids(Chromosome parent1, Chromosome parent2) {
int[][] childSudoku = new int[9][9];
// Copy the entire Sudoku grid from parent1 to the child
for (int row = 0; row < 9; row++) {
System.arraycopy(parent1.getSudoku()[row], 0, childSudoku[row], 0, 9);
}
// Determine the number of subgrids to swap from parent2 to child (1-5)
int numSubgridsToSwap = random.nextInt(5) + 1;
List<Integer> selectedSubgrids = new ArrayList<>();
while (selectedSubgrids.size() < numSubgridsToSwap) {
int subgridIndex = random.nextInt(9);
if (!selectedSubgrids.contains(subgridIndex)) {
selectedSubgrids.add(subgridIndex);
}
}
// Swap the selected subgrids from parent2 into the child
for (int subgrid : selectedSubgrids) {
int rowStart = (subgrid / 3) * 3;
int colStart = (subgrid % 3) * 3;
for (int row = rowStart; row < rowStart + 3; row++) {
for (int col = colStart; col < colStart + 3; col++) {
childSudoku[row][col] = parent2.getSudoku()[row][col];
}
}
}
// Create a new chromosome with the resulting child Sudoku and evaluate its fitness
Chromosome child = new Chromosome(childSudoku, parent1.getMutablePositions());
child.evaluateFitness();
return child;
}
public void printPopulation(boolean printMutPos) {
System.out.println("Generated Population:");
int count = 1;
// Print each chromosome's Sudoku and fitness value
for (Chromosome chromosome : population) {
System.out.println("Chromosome " + count + ":");
chromosome.printChromosome(printMutPos);
System.out.println("Fitness: " + chromosome.getFitness());
System.out.println();
count++;
}
}
public void mutateChromosome(Chromosome chromosome, double mutationRate) {
int[][] sudoku = chromosome.getSudoku();
List<int[]> mutablePositions = chromosome.getMutablePositions();
// Mutate each mutable position with a probability defined by mutationRate
for (int[] pos : mutablePositions) {
if (random.nextDouble() < mutationRate) {
int row = pos[0];
int col = pos[1];
int newValue = random.nextInt(9) + 1; // Assign a new value between 1 and 9
sudoku[row][col] = newValue;
}
}
// Update the chromosome's Sudoku and recalculate its fitness
chromosome.setSudoku(sudoku);
chromosome.evaluateFitness();
}
public void evaluatePopulation() {
// Evaluate the fitness of each chromosome in the population
for (Chromosome chromosome : population) {
chromosome.evaluateFitness();
}
}
public Chromosome getBestChromosome() {
// Find and return the chromosome with the best (lowest) fitness in the population
Chromosome best = population.get(0);
for (Chromosome chromosome : population) {
if (chromosome.getFitness() < best.getFitness()) {
best = chromosome;
}
}
return best;
}
// Chromosome class representing an individual solution
public class Chromosome {
private int[][] sudoku; // Sudoku grid representing the chromosome
private List<int[]> mutablePositions; // Positions that can be changed (mutable)
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) {
this.sudoku = sudoku;
this.mutablePositions = mutablePositions;
}
public int[][] getSudoku() {
return sudoku;
}
public void setSudoku(int[][] sudoku) {
this.sudoku = sudoku;
}
public List<int[]> getMutablePositions() {
return mutablePositions;
}
public int getFitness() {
return fitness;
}
// Evaluate the fitness of the Sudoku by counting the number of row, column, and subgrid violations
public void evaluateFitness() {
fitness = countRowViolations() + countColumnViolations() + countSubgridViolations();
}
private int countRowViolations() {
int violations = 0;
// Iterate through each row to count conflicts
for (int i = 0; i < 9; i++) {
boolean[] present = new boolean[10];
for (int j = 0; j < 9; j++) {
int value = sudoku[i][j];
if (value != 0) {
if (present[value]) {
violations++; // Increment violations if the value is already seen
} else {
present[value] = true; // Mark the value as seen
}
}
}
}
return violations;
}
private int countColumnViolations() {
int violations = 0;
// Loop through each column
for (int j = 0; j < 9; j++) {
boolean[] present = new boolean[10]; // Track numbers present in the column
for (int i = 0; i < 9; i++) {
int value = sudoku[i][j];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
// Mark the number as present
present[value] = true;
}
}
}
}
return violations;
}
private int countSubgridViolations() {
int violations = 0;
// Loop through each 3x3 subgrid
for (int gridRow = 0; gridRow < 3; gridRow++) {
for (int gridCol = 0; gridCol < 3; gridCol++) {
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 col = gridCol * 3; col < gridCol * 3 + 3; col++) {
int value = sudoku[row][col];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
// Mark the number as present
present[value] = true;
}
}
}
}
}
}
return violations;
}
public void printChromosome(boolean printMutPos) {
// Print the Sudoku matrix
for (int[] row : sudoku) {
for (int j = 0; j < row.length; j++) {
System.out.print(row[j]);
if (j < row.length - 1) {
System.out.print(" ");
}
}
System.out.println();
}
// If requested, print mutable positions
if (printMutPos) {
System.out.println("Mutable Positions:");
for (int i = 0; i < mutablePositions.size(); i++) {
int[] pos = mutablePositions.get(i);
System.out.print("(" + pos[0] + ", " + pos[1] + ")");
if (i < mutablePositions.size() - 1) {
System.out.print(" ");
}
}
System.out.println();
}
}
}
}
+9 -9
View File
@@ -1,9 +1,9 @@
- 8 - - - - - 9 -
- - 7 5 - 2 8 - -
6 - - 8 - 7 - - 5
3 7 - - 8 - - 5 1
2 - - - - - - - 8
9 5 - - 4 - - 3 2
8 - - 1 - 4 - - 9
- - 1 9 - 3 6 - -
- 4 - - - - - 2 -
- - - 8 5 6 - - -
- - - 1 9 - - - -
5 - - - - 7 - 1 -
- 2 - - - 9 - 7 5
- 9 - - - 1 2 - 3
- - - - 3 - 1 - -
- 3 - - - - - 2 -
- - - - - - - - -
- - 1 - - - - - -
+1
View File
@@ -0,0 +1 @@
/home/emil/Coding/Assignments/ITAI/Sudoku_solver/other/Main.java
+412
View File
@@ -0,0 +1,412 @@
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Main {
// Initalizing variables
public static int POPULATIONSIZE = 0;
public static int TOURNAMENTSIZE = 0;
public static double MUTATIONRATE = 0;
// Threshold of number of mutable positions for easy level sudoku
public static int EASYTHRESHOLD = 60;
public static int HARDTHRESHOLD = 70;
// List to store the population of chromosomes
List<Chromosome> population = new ArrayList<>();
Random random = new Random();
public static void main(String[] args) {
// Base Sudoku matrix (input matrix)
int[][] baseSudoku = new int[9][9];
// List to track positions in Sudoku that are mutable
List<int[]> mutablePositions = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
// Reading the Sudoku matrix from the console input
for (int i = 0; i < 9; i++) {
// Split the input by space
String[] tokens = reader.readLine().split(" ");
for (int j = 0; j < 9; j++) {
if (tokens[j].equals("-")) {
// Empty cells are marked as 0
baseSudoku[i][j] = 0;
// Add mutable positions (i, j) to the list
mutablePositions.add(new int[]{i, j});
} else {
// Set fixed value from the input
baseSudoku[i][j] = Integer.parseInt(tokens[j]);
}
}
}
} 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());
return;
}
Main mainInstance = new Main(); // Create instance of Main class
// Choosing variables for different sudoku difficulties
if (mutablePositions.size() < EASYTHRESHOLD) { // Easy sudoku
POPULATIONSIZE = 100;
TOURNAMENTSIZE = 5;
MUTATIONRATE = 0.05;
} else if (mutablePositions.size() < HARDTHRESHOLD) { // Hard sudoku
POPULATIONSIZE = 100;
TOURNAMENTSIZE = 5;
MUTATIONRATE = 0.057;
}
else { // Ultra-hard sudoku
POPULATIONSIZE = 20000;
TOURNAMENTSIZE = 4;
MUTATIONRATE = 0.032;
}
// Generate initial population of 100 chromosomes
mainInstance.generateInitialChromosomes(POPULATIONSIZE, baseSudoku, mutablePositions);
Chromosome bestSolution = null;
List<Integer> fitnessValues = new ArrayList<>();
int stuckCounter = 0;
int tryUnstuckCount = 0;
boolean unstucking = false;
int INITIAL_POPULATIONSIZE = POPULATIONSIZE;
int INITIAL_TOURNAMENTSIZE = TOURNAMENTSIZE;
double INITIAL_MUTATIONRATE = MUTATIONRATE;
int generation = 0; // Track the number of generations
while (true) {
// Evaluate the fitness of each chromosome in the population
mainInstance.evaluatePopulation();
bestSolution = mainInstance.getBestChromosome();
fitnessValues.add(bestSolution.getFitness());
List<Chromosome> newPopulation = new ArrayList<>();
for (int i = 0; i < mainInstance.population.size() / 2; i++) {
// Select parents using tournament selection
List<Chromosome> parents = mainInstance.tournamentSelection(TOURNAMENTSIZE);
// Perform crossover to create two children from the selected parents
Chromosome child1 = mainInstance.crossoverBySubgrids(parents.get(0), parents.get(1));
Chromosome child2 = mainInstance.crossoverBySubgrids(parents.get(1), parents.get(0));
// Apply mutation to both children
mainInstance.mutateChromosome(child1, MUTATIONRATE);
mainInstance.mutateChromosome(child2, MUTATIONRATE);
// Add both children to the new population
newPopulation.add(child1);
newPopulation.add(child2);
}
// Replace the old population with the new population
mainInstance.population = newPopulation;
// Get the best chromosome from the current population
bestSolution = mainInstance.getBestChromosome();
generation++;
// If the best solution found has a fitness of 0, print it and end the program
if (bestSolution.getFitness() == 0) {
bestSolution.printChromosome(false);
return;
}
//change arguments when algorithm is stuck
if (fitnessValues.size() > 2) {
if (fitnessValues.get(fitnessValues.size()-1) == fitnessValues.get(fitnessValues.size()-2)){
stuckCounter++;
//System.out.println("StuckCount: " + String.valueOf(stuckCounter));
if (stuckCounter > 50){
if (MUTATIONRATE < 1){
unstucking = true;
System.out.println(MUTATIONRATE);
System.out.println(POPULATIONSIZE);
MUTATIONRATE = MUTATIONRATE * 1.1 + 0.01;
POPULATIONSIZE /= 2;
}
stuckCounter = 0;
}
} else{
stuckCounter = 0;
}
}
if (unstucking) {
//System.out.println("Unstucking");
tryUnstuckCount++;
if (tryUnstuckCount > 100){
unstucking = false;
tryUnstuckCount = 0;
POPULATIONSIZE = INITIAL_POPULATIONSIZE;
TOURNAMENTSIZE = INITIAL_TOURNAMENTSIZE;
MUTATIONRATE = INITIAL_MUTATIONRATE;
}
}
//System.out.println("UnstuckCount: " + String.valueOf(tryUnstuckCount));
}
}
// Generate initial population of chromosomes
public void generateInitialChromosomes(int numberOfChromosomes, int[][] baseSudoku, List<int[]> mutablePositions) {
for (int i = 0; i < numberOfChromosomes; i++) {
// Create a copy of the base Sudoku
int[][] sudoku = copyMatrix(baseSudoku);
// Randomly fill mutable positions
for (int[] pos : mutablePositions) {
int row = pos[0];
int col = pos[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.evaluateFitness(); // Evaluate its fitness
population.add(chromosome); // Add to the population
}
}
// Create a deep copy of a matrix
private int[][] copyMatrix(int[][] original) {
int[][] copy = new int[original.length][original[0].length];
for (int i = 0; i < original.length; i++) {
System.arraycopy(original[i], 0, copy[i], 0, original[i].length);
}
return copy;
}
public List<Chromosome> tournamentSelection(int tournamentSize) {
List<Chromosome> selectedParents = new ArrayList<>();
for (int i = 0; i < 2; i++) {
List<Chromosome> tournament = new ArrayList<>();
// Randomly select chromosomes for the tournament
for (int j = 0; j < tournamentSize; j++) {
Chromosome randomChromosome = population.get(random.nextInt(population.size()));
tournament.add(randomChromosome);
}
// Determine the best chromosome in the tournament based on fitness
Chromosome best = tournament.get(0);
for (Chromosome chromosome : tournament) {
if (chromosome.getFitness() < best.getFitness()) {
best = chromosome;
}
}
// Add the best chromosome to the list of selected parents
selectedParents.add(best);
}
return selectedParents;
}
public Chromosome crossoverBySubgrids(Chromosome parent1, Chromosome parent2) {
int[][] childSudoku = new int[9][9];
// Copy the entire Sudoku grid from parent1 to the child
for (int row = 0; row < 9; row++) {
System.arraycopy(parent1.getSudoku()[row], 0, childSudoku[row], 0, 9);
}
// Determine the number of subgrids to swap from parent2 to child (1-5)
int numSubgridsToSwap = random.nextInt(5) + 1;
List<Integer> selectedSubgrids = new ArrayList<>();
while (selectedSubgrids.size() < numSubgridsToSwap) {
int subgridIndex = random.nextInt(9);
if (!selectedSubgrids.contains(subgridIndex)) {
selectedSubgrids.add(subgridIndex);
}
}
// Swap the selected subgrids from parent2 into the child
for (int subgrid : selectedSubgrids) {
int rowStart = (subgrid / 3) * 3;
int colStart = (subgrid % 3) * 3;
for (int row = rowStart; row < rowStart + 3; row++) {
for (int col = colStart; col < colStart + 3; col++) {
childSudoku[row][col] = parent2.getSudoku()[row][col];
}
}
}
// Create a new chromosome with the resulting child Sudoku and evaluate its fitness
Chromosome child = new Chromosome(childSudoku, parent1.getMutablePositions());
child.evaluateFitness();
return child;
}
public void printPopulation(boolean printMutPos) {
System.out.println("Generated Population:");
int count = 1;
// Print each chromosome's Sudoku and fitness value
for (Chromosome chromosome : population) {
System.out.println("Chromosome " + count + ":");
chromosome.printChromosome(printMutPos);
System.out.println("Fitness: " + chromosome.getFitness());
System.out.println();
count++;
}
}
public void mutateChromosome(Chromosome chromosome, double mutationRate) {
int[][] sudoku = chromosome.getSudoku();
List<int[]> mutablePositions = chromosome.getMutablePositions();
// Mutate each mutable position with a probability defined by mutationRate
for (int[] pos : mutablePositions) {
if (random.nextDouble() < mutationRate) {
int row = pos[0];
int col = pos[1];
int newValue = random.nextInt(9) + 1; // Assign a new value between 1 and 9
sudoku[row][col] = newValue;
}
}
// Update the chromosome's Sudoku and recalculate its fitness
chromosome.setSudoku(sudoku);
chromosome.evaluateFitness();
}
public void evaluatePopulation() {
// Evaluate the fitness of each chromosome in the population
for (Chromosome chromosome : population) {
chromosome.evaluateFitness();
}
}
public Chromosome getBestChromosome() {
// Find and return the chromosome with the best (lowest) fitness in the population
Chromosome best = population.get(0);
for (Chromosome chromosome : population) {
if (chromosome.getFitness() < best.getFitness()) {
best = chromosome;
}
}
return best;
}
// Chromosome class representing an individual solution
public class Chromosome {
private int[][] sudoku; // Sudoku grid representing the chromosome
private List<int[]> mutablePositions; // Positions that can be changed (mutable)
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) {
this.sudoku = sudoku;
this.mutablePositions = mutablePositions;
}
public int[][] getSudoku() {
return sudoku;
}
public void setSudoku(int[][] sudoku) {
this.sudoku = sudoku;
}
public List<int[]> getMutablePositions() {
return mutablePositions;
}
public int getFitness() {
return fitness;
}
// Evaluate the fitness of the Sudoku by counting the number of row, column, and subgrid violations
public void evaluateFitness() {
fitness = countRowViolations() + countColumnViolations() + countSubgridViolations();
}
private int countRowViolations() {
int violations = 0;
// Iterate through each row to count conflicts
for (int i = 0; i < 9; i++) {
boolean[] present = new boolean[10];
for (int j = 0; j < 9; j++) {
int value = sudoku[i][j];
if (value != 0) {
if (present[value]) {
violations++; // Increment violations if the value is already seen
} else {
present[value] = true; // Mark the value as seen
}
}
}
}
return violations;
}
private int countColumnViolations() {
int violations = 0;
// Loop through each column
for (int j = 0; j < 9; j++) {
boolean[] present = new boolean[10]; // Track numbers present in the column
for (int i = 0; i < 9; i++) {
int value = sudoku[i][j];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
// Mark the number as present
present[value] = true;
}
}
}
}
return violations;
}
private int countSubgridViolations() {
int violations = 0;
// Loop through each 3x3 subgrid
for (int gridRow = 0; gridRow < 3; gridRow++) {
for (int gridCol = 0; gridCol < 3; gridCol++) {
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 col = gridCol * 3; col < gridCol * 3 + 3; col++) {
int value = sudoku[row][col];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
// Mark the number as present
present[value] = true;
}
}
}
}
}
}
return violations;
}
public void printChromosome(boolean printMutPos) {
// Print the Sudoku matrix
for (int[] row : sudoku) {
for (int j = 0; j < row.length; j++) {
System.out.print(row[j]);
if (j < row.length - 1) {
System.out.print(" ");
}
}
System.out.println();
}
// If requested, print mutable positions
if (printMutPos) {
System.out.println("Mutable Positions:");
for (int i = 0; i < mutablePositions.size(); i++) {
int[] pos = mutablePositions.get(i);
System.out.print("(" + pos[0] + ", " + pos[1] + ")");
if (i < mutablePositions.size() - 1) {
System.out.print(" ");
}
}
System.out.println();
}
}
}
}
+21
View File
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.example</groupId>
<artifactId>SudokuSolver</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
</project>
@@ -0,0 +1,465 @@
package com.example;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import org.knowm.xchart.SwingWrapper;
import org.knowm.xchart.XYChart;
import org.knowm.xchart.XYSeries;
import org.knowm.xchart.XYSeries.XYSeriesRenderStyle;
public class Main {
// Initalizing variables
public static int POPULATIONSIZE = 0;
public static int TOURNAMENTSIZE = 0;
public static double MUTATIONRATE = 0;
// Threshold of number of mutable positions for easy level sudoku
public static int EASYTHRESHOLD = 60;
public static int HARDTHRESHOLD = 70;
// List to store the population of chromosomes
List<Chromosome> population = new ArrayList<>();
Random random = new Random();
public static void main(String[] args) {
// Base Sudoku matrix (input matrix)
int[][] baseSudoku = new int[9][9];
// List to track positions in Sudoku that are mutable
List<int[]> mutablePositions = new ArrayList<>();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
try {
// Reading the Sudoku matrix from the console input
for (int i = 0; i < 9; i++) {
// Split the input by space
String[] tokens = reader.readLine().split(" ");
for (int j = 0; j < 9; j++) {
if (tokens[j].equals("-")) {
// Empty cells are marked as 0
baseSudoku[i][j] = 0;
// Add mutable positions (i, j) to the list
mutablePositions.add(new int[]{i, j});
} else {
// Set fixed value from the input
baseSudoku[i][j] = Integer.parseInt(tokens[j]);
}
}
}
} 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());
return;
}
Main mainInstance = new Main(); // Create instance of Main class
// Choosing variables for different sudoku difficulties
if (mutablePositions.size() < EASYTHRESHOLD) { // Easy sudoku
POPULATIONSIZE = 500000;
TOURNAMENTSIZE = 3;
MUTATIONRATE = 0.1;
} else if (mutablePositions.size() < HARDTHRESHOLD) { // Hard sudoku
POPULATIONSIZE = 100000;
TOURNAMENTSIZE = 8;
MUTATIONRATE = 0.34;
}
else { // Ultra-hard sudoku
POPULATIONSIZE = 100000;
TOURNAMENTSIZE = 10;
MUTATIONRATE = 0.0;
}
// Generate initial population of chromosomes
mainInstance.generateInitialChromosomes(POPULATIONSIZE, baseSudoku, mutablePositions);
Chromosome bestSolution = null;
List<Integer> fitnessValues = new ArrayList<>();
int generation = 0; // Track the number of generations
int stuckCounter = 0;
int tryUnstuckCount = 0;
boolean unstucking = false;
int INITIAL_POPULATIONSIZE = POPULATIONSIZE;
int INITIAL_TOURNAMENTSIZE = TOURNAMENTSIZE;
double INITIAL_MUTATIONRATE = MUTATIONRATE;
while (true) {
// Evaluate the fitness of each chromosome in the population
mainInstance.evaluatePopulation();
// Track the best fitness value in the current generation
bestSolution = mainInstance.getBestChromosome();
fitnessValues.add(bestSolution.getFitness());
List<Chromosome> newPopulation = new ArrayList<>();
for (int i = 0; i < mainInstance.population.size() / 2; i++) {
// Select parents using tournament selection
List<Chromosome> parents = mainInstance.tournamentSelection(TOURNAMENTSIZE);
// Perform crossover to create two children from the selected parents
Chromosome child1 = mainInstance.crossoverBySubgrids(parents.get(0), parents.get(1));
Chromosome child2 = mainInstance.crossoverBySubgrids(parents.get(1), parents.get(0));
// Apply mutation to both children
mainInstance.mutateChromosome(child1, MUTATIONRATE);
mainInstance.mutateChromosome(child2, MUTATIONRATE);
// Add both children to the new population
newPopulation.add(child1);
newPopulation.add(child2);
}
// Replace the old population with the new population
mainInstance.population = newPopulation;
generation++;
// Plot the fitness graph every 10 generations
if (generation % 10 == 0) {
mainInstance.plotFitness(fitnessValues);
}
// If the best solution found has a fitness of 0, print it and end the program
if (bestSolution.getFitness() == 0) {
bestSolution.printChromosome(false);
return;
}
/*
// Check if algorithm is stuck
if (fitnessValues.size() > 2) {
if (fitnessValues.get(fitnessValues.size()-1) == fitnessValues.get(fitnessValues.size()-2)){
stuckCounter++;
System.out.println("StuckCount: " + stuckCounter);
if (stuckCounter > 20){
if (MUTATIONRATE < 1){
unstucking = true;
System.out.println(MUTATIONRATE);
System.out.println(POPULATIONSIZE);
MUTATIONRATE = MUTATIONRATE * 1.1 + 0.01;
POPULATIONSIZE /= 2;
TOURNAMENTSIZE /= 2;
}
stuckCounter = 0;
}
} else {
stuckCounter = 0;
}
}
if (unstucking) {
System.out.println("Unstucking");
tryUnstuckCount++;
if (tryUnstuckCount > 100){
unstucking = false;
tryUnstuckCount = 0;
POPULATIONSIZE = INITIAL_POPULATIONSIZE;
TOURNAMENTSIZE = INITIAL_TOURNAMENTSIZE;
MUTATIONRATE = INITIAL_MUTATIONRATE;
}
}
System.out.println("UnstuckCount: " + tryUnstuckCount);
}*/
}
// Generate initial population of chromosomes
public void generateInitialChromosomes(int numberOfChromosomes, int[][] baseSudoku, List<int[]> mutablePositions) {
for (int i = 0; i < numberOfChromosomes; i++) {
// Create a copy of the base Sudoku
int[][] sudoku = copyMatrix(baseSudoku);
// Randomly fill mutable positions while ensuring no duplicates in subgrids
for (int gridRow = 0; gridRow < 3; gridRow++) {
for (int gridCol = 0; gridCol < 3; gridCol++) {
boolean[] present = new boolean[10];
List<int[]> subgridPositions = new ArrayList<>();
// Collect all positions in the current 3x3 subgrid
for (int row = gridRow * 3; row < gridRow * 3 + 3; row++) {
for (int col = gridCol * 3; col < gridCol * 3 + 3; col++) {
int value = sudoku[row][col];
if (value != 0) {
present[value] = true;
} else {
subgridPositions.add(new int[]{row, col});
}
}
}
// Randomly fill the subgrid ensuring no duplicates
for (int[] pos : subgridPositions) {
int newValue;
do {
newValue = random.nextInt(9) + 1;
} while (present[newValue]);
sudoku[pos[0]][pos[1]] = newValue;
present[newValue] = true;
}
}
}
// Create a new chromosome with the generated Sudoku and mutable positions
Chromosome chromosome = new Chromosome(sudoku, new ArrayList<>(mutablePositions));
chromosome.evaluateFitness(); // Evaluate its fitness
population.add(chromosome); // Add to the population
}
}
// Create a deep copy of a matrix
private int[][] copyMatrix(int[][] original) {
int[][] copy = new int[original.length][original[0].length];
for (int i = 0; i < original.length; i++) {
System.arraycopy(original[i], 0, copy[i], 0, original[i].length);
}
return copy;
}
public List<Chromosome> tournamentSelection(int tournamentSize) {
List<Chromosome> selectedParents = new ArrayList<>();
for (int i = 0; i < 2; i++) {
List<Chromosome> tournament = new ArrayList<>();
// Randomly select chromosomes for the tournament
for (int j = 0; j < tournamentSize; j++) {
Chromosome randomChromosome = population.get(random.nextInt(population.size()));
tournament.add(randomChromosome);
}
// Determine the best chromosome in the tournament based on fitness
Chromosome best = tournament.get(0);
for (Chromosome chromosome : tournament) {
if (chromosome.getFitness() < best.getFitness()) {
best = chromosome;
}
}
// Add the best chromosome to the list of selected parents
selectedParents.add(best);
}
return selectedParents;
}
public Chromosome crossoverBySubgrids(Chromosome parent1, Chromosome parent2) {
int[][] childSudoku = new int[9][9];
// Copy the entire Sudoku grid from parent1 to the child
for (int row = 0; row < 9; row++) {
System.arraycopy(parent1.getSudoku()[row], 0, childSudoku[row], 0, 9);
}
// Determine the number of subgrids to swap from parent2 to child (1-5)
int numSubgridsToSwap = random.nextInt(5) + 1;
List<Integer> selectedSubgrids = new ArrayList<>();
while (selectedSubgrids.size() < numSubgridsToSwap) {
int subgridIndex = random.nextInt(9);
if (!selectedSubgrids.contains(subgridIndex)) {
selectedSubgrids.add(subgridIndex);
}
}
// Swap the selected subgrids from parent2 into the child
for (int subgrid : selectedSubgrids) {
int rowStart = (subgrid / 3) * 3;
int colStart = (subgrid % 3) * 3;
for (int row = rowStart; row < rowStart + 3; row++) {
for (int col = colStart; col < colStart + 3; col++) {
childSudoku[row][col] = parent2.getSudoku()[row][col];
}
}
}
// Create a new chromosome with the resulting child Sudoku and evaluate its fitness
Chromosome child = new Chromosome(childSudoku, parent1.getMutablePositions());
child.evaluateFitness();
return child;
}
public void printPopulation(boolean printMutPos) {
System.out.println("Generated Population:");
int count = 1;
// Print each chromosome's Sudoku and fitness value
for (Chromosome chromosome : population) {
System.out.println("Chromosome " + count + ":");
chromosome.printChromosome(printMutPos);
System.out.println("Fitness: " + chromosome.getFitness());
System.out.println();
count++;
}
}
public void mutateChromosome(Chromosome chromosome, double mutationRate) {
int[][] sudoku = chromosome.getSudoku();
// With a probability defined by mutationRate, perform a mutation by swapping subgrids
if (random.nextDouble() < mutationRate) {
// Randomly select two different subgrids to swap
int subgrid1, subgrid2;
do {
subgrid1 = random.nextInt(9);
subgrid2 = random.nextInt(9);
} while (subgrid1 == subgrid2);
// Get the starting coordinates for both subgrids
int rowStart1 = (subgrid1 / 3) * 3;
int colStart1 = (subgrid1 % 3) * 3;
int rowStart2 = (subgrid2 / 3) * 3;
int colStart2 = (subgrid2 % 3) * 3;
// Swap the values in the two selected subgrids
for (int rowOffset = 0; rowOffset < 3; rowOffset++) {
for (int colOffset = 0; colOffset < 3; colOffset++) {
int temp = sudoku[rowStart1 + rowOffset][colStart1 + colOffset];
sudoku[rowStart1 + rowOffset][colStart1 + colOffset] = sudoku[rowStart2 + rowOffset][colStart2 + colOffset];
sudoku[rowStart2 + rowOffset][colStart2 + colOffset] = temp;
}
}
}
// Update the chromosome's Sudoku and recalculate its fitness
chromosome.setSudoku(sudoku);
chromosome.evaluateFitness();
}
public void evaluatePopulation() {
// Evaluate the fitness of each chromosome in the population
for (Chromosome chromosome : population) {
chromosome.evaluateFitness();
}
}
public Chromosome getBestChromosome() {
// Find and return the chromosome with the best (lowest) fitness in the population
Chromosome best = population.get(0);
for (Chromosome chromosome : population) {
if (chromosome.getFitness() < best.getFitness()) {
best = chromosome;
}
}
return best;
}
// Chromosome class representing an individual solution
public class Chromosome {
private int[][] sudoku; // Sudoku grid representing the chromosome
private List<int[]> mutablePositions; // Positions that can be changed (mutable)
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) {
this.sudoku = sudoku;
this.mutablePositions = mutablePositions;
}
public int[][] getSudoku() {
return sudoku;
}
public void setSudoku(int[][] sudoku) {
this.sudoku = sudoku;
}
public List<int[]> getMutablePositions() {
return mutablePositions;
}
public int getFitness() {
return fitness;
}
// Evaluate the fitness of the Sudoku by counting the number of row, column, and subgrid violations
public void evaluateFitness() {
fitness = countRowViolations() + countColumnViolations() + countSubgridViolations();
}
private int countRowViolations() {
int violations = 0;
// Iterate through each row to count conflicts
for (int i = 0; i < 9; i++) {
boolean[] present = new boolean[10];
for (int j = 0; j < 9; j++) {
int value = sudoku[i][j];
if (value != 0) {
if (present[value]) {
violations++; // Increment violations if the value is already seen
} else {
present[value] = true; // Mark the value as seen
}
}
}
}
return violations;
}
private int countColumnViolations() {
int violations = 0;
// Loop through each column
for (int j = 0; j < 9; j++) {
boolean[] present = new boolean[10]; // Track numbers present in the column
for (int i = 0; i < 9; i++) {
int value = sudoku[i][j];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
// Mark the number as present
present[value] = true;
}
}
}
}
return violations;
}
private int countSubgridViolations() {
int violations = 0;
// Loop through each 3x3 subgrid
for (int gridRow = 0; gridRow < 3; gridRow++) {
for (int gridCol = 0; gridCol < 3; gridCol++) {
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 col = gridCol * 3; col < gridCol * 3 + 3; col++) {
int value = sudoku[row][col];
if (value != 0) {
// If the number is already present, increment the violations count
if (present[value]) {
violations++;
} else {
// Mark the number as present
present[value] = true;
}
}
}
}
}
}
return violations;
}
public void printChromosome(boolean printMutPos) {
// Print the Sudoku matrix
for (int[] row : sudoku) {
for (int j : row) {
System.out.print(j + " ");
}
System.out.println();
}
// If requested, print mutable positions
if (printMutPos) {
System.out.println("Mutable Positions:");
for (int[] pos : mutablePositions) {
System.out.print("(" + pos[0] + ", " + pos[1] + ") ");
}
System.out.println();
}
}
}
// Method to plot the fitness values over generations
public void plotFitness(List<Integer> fitnessValues) {
XYChart chart = new XYChart(800, 600);
chart.setTitle("Fitness over Generations");
chart.setXAxisTitle("Generation");
chart.setYAxisTitle("Fitness");
XYSeries series = chart.addSeries("Fitness", null, fitnessValues);
series.setXYSeriesRenderStyle(XYSeriesRenderStyle.Line);
new SwingWrapper<>(chart).displayChart();
}
}
Binary file not shown.
@@ -0,0 +1,3 @@
artifactId=demo
groupId=com.example
version=1.0-SNAPSHOT
@@ -0,0 +1,2 @@
Main$Chromosome.class
Main.class
@@ -0,0 +1 @@
/home/emil/Coding/Assignments/ITAI/Sudoku_solver/statistical/demo/src/main/java/com/example/Main.java