Commit before some experiments with smart argument changing
This commit is contained in:
@@ -60,8 +60,8 @@ public class Main {
|
||||
MUTATIONRATE = 0.34;
|
||||
}
|
||||
else { // Ultra-hard sudoku
|
||||
POPULATIONSIZE = 250000;
|
||||
TOURNAMENTSIZE = 4;
|
||||
POPULATIONSIZE = 500000;
|
||||
TOURNAMENTSIZE = 3;
|
||||
MUTATIONRATE = 0.15;
|
||||
}
|
||||
|
||||
@@ -311,7 +311,7 @@ public class Main {
|
||||
|
||||
// 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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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]
|
||||
@@ -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 - - - - - -
|
||||
|
||||
@@ -66,8 +66,8 @@ public class Main {
|
||||
MUTATIONRATE = 0.34;
|
||||
}
|
||||
else { // Ultra-hard sudoku
|
||||
POPULATIONSIZE = 500000;
|
||||
TOURNAMENTSIZE = 3;
|
||||
POPULATIONSIZE = 100000;
|
||||
TOURNAMENTSIZE = 10;
|
||||
MUTATIONRATE = 0.1;
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ public class Main {
|
||||
generation++;
|
||||
|
||||
// Plot the fitness graph every 10 generations
|
||||
if (generation % 1 == 0) {
|
||||
if (generation % 10 == 0) {
|
||||
mainInstance.plotFitness(fitnessValues);
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user