Commit before some experiments with smart argument changing

This commit is contained in:
emil
2024-12-01 19:57:30 +03:00
parent 26d454c976
commit 1562f775af
12 changed files with 1358 additions and 15 deletions
+3 -3
View File
@@ -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() {
+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]
+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 - - - - - -
@@ -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);
}