Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

отчет пз1 Магальник Бродников Запорожан

.docx
Скачиваний:
0
Добавлен:
12.02.2026
Размер:
203.34 Кб
Скачать

Отчет по практическому занятию №1

По дисциплине Мультиагентное моделирование

Задача о 8 ферзях

Выполнили студенты группы ИС221

Магальник Екатерина, Запорожан Алина, Бродников Сергей

Руководитель: Романчева Н. И.

Москва, 2025

Постановка задачи: расставить на шахматной доске размером 8 на 8 клеток фигуры восьми ферзей так, чтобы они не били друг друга.

Алгоритм:

  1. Инициализация: случайным образом расставляем всех 8 ферзей на доске (по одному на каждый столбец). Это наше начальное состояние. Оно почти гарантировано конфликтно.

  2. Оценка конфликтов: для каждого ферзя подсчитываем, сколько других ферзей бьет его (атакует по горизонтали, вертикали или диагонали).

  3. Выбор агента для хода: выбираем рандомного ферзя.

  4. Поиск лучшей позиции: для выбранного ферзя (в его столбце) мы проверяем все 8 возможных клеток. Для каждой клетки мы вычисляем, сколько конфликтов будет у ферзя, если он туда встанет.

  5. Ход: ферзь перемещается на позицию в своем столбце с наименьшим количеством конфликтов. Если таких позиций несколько, выбирается одна из них случайным образом.

  6. Повтор: шаги 2-5 повторяются до тех пор, пока общее количество конфликтов не станет равным нулю.

Блок схема алгоритма:

Листинг:

import random import numpy as np from typing import List, Tuple, Optional class EightQueensSolver: def __init__(self, n=8): self.n = n self.solutions = [] def is_safe(self, board: List[int], row: int, col: int) -> bool: """Проверка безопасности размещения ферзя""" for i in range(col): # Проверка строки и диагоналей if board[i] == row or \ abs(board[i] - row) == abs(i - col): return False return True def solve_backtracking(self, board: List[int] = None, col: int = 0): """Решение методом backtracking""" if board is None: board = [-1] * self.n if col >= self.n: self.solutions.append(board.copy()) return True for row in range(self.n): if self.is_safe(board, row, col): board[col] = row self.solve_backtracking(board, col + 1) board[col] = -1 return False def genetic_algorithm(self, population_size=100, generations=1000): """Генетический алгоритм для решения""" def fitness(chromosome): """Функция приспособленности (меньше конфликтов = лучше)""" conflicts = 0 for i in range(self.n): for j in range(i + 1, self.n): if chromosome[i] == chromosome[j] or \ abs(chromosome[i] - chromosome[j]) == abs(i - j): conflicts += 1 return -conflicts # Отрицательное значение для максимизации # Создание начальной популяции population = [random.sample(range(self.n), self.n) for _ in range(population_size)] for generation in range(generations): # Оценка приспособленности fitness_scores = [fitness(ind) for ind in population] # Проверка на найденное решение if max(fitness_scores) == 0: solution = population[fitness_scores.index(0)] return solution, generation # Селекция (турнирная) selected = [] for _ in range(population_size): tournament = random.sample(list(zip(population, fitness_scores)), 3) winner = max(tournament, key=lambda x: x[1])[0] selected.append(winner) # Скрещивание (одноточечное) new_population = [] for i in range(0, population_size, 2): parent1, parent2 = selected[i], selected[i + 1] crossover_point = random.randint(1, self.n - 1) child1 = parent1[:crossover_point] + parent2[crossover_point:] child2 = parent2[:crossover_point] + parent1[crossover_point:] new_population.extend([child1, child2]) # Мутация (с вероятностью 10%) for i in range(population_size): if random.random() < 0.1: pos1, pos2 = random.sample(range(self.n), 2) new_population[i][pos1], new_population[i][pos2] = \ new_population[i][pos2], new_population[i][pos1] population = new_population return None, generations def min_conflicts(self, max_steps=1000): """Алгоритм минимизации конфликтов""" # Случайная начальная расстановка current = list(range(self.n)) random.shuffle(current) for step in range(max_steps): # Находим все конфликтующие ферзи conflicts = [] for col in range(self.n): conflict_count = 0 for other_col in range(self.n): if col != other_col and ( current[col] == current[other_col] or abs(current[col] - current[other_col]) == abs(col - other_col) ): conflict_count += 1 conflicts.append(conflict_count) # Если решение найдено if sum(conflicts) == 0: return current, step # Выбираем случайный конфликтующий ферзь conflicting_queens = [i for i in range(self.n) if conflicts[i] > 0] if not conflicting_queens: return current, step queen = random.choice(conflicting_queens) # Находим позицию с минимальными конфликтами min_conflicts = float('inf') best_row = current[queen] for row in range(self.n): if row == current[queen]: continue conflict_count = 0 for other_col in range(self.n): if queen != other_col and ( row == current[other_col] or abs(row - current[other_col]) == abs(queen - other_col) ): conflict_count += 1 if conflict_count < min_conflicts: min_conflicts = conflict_count best_row = row current[queen] = best_row return current, max_steps def print_board(self, solution: List[int]): """Визуализация доски""" print(" " + "-" * (self.n * 2 + 1)) for row in range(self.n): line = "|" for col in range(self.n): if solution[col] == row: line += "Q|" else: line += " |" print(line) print(" " + "-" * (self.n * 2 + 1)) print() # Демонстрация работы всех алгоритмов def main(): solver = EightQueensSolver() print("=== Backtracking (все решения) ===") solver.solve_backtracking() print(f"Найдено решений: {len(solver.solutions)}") if solver.solutions: solver.print_board(solver.solutions[0]) print("=== Генетический алгоритм ===") solution, generations = solver.genetic_algorithm() if solution and all(solution[i] != solution[j] and abs(solution[i] - solution[j]) != abs(i - j) for i in range(8) for j in range(i + 1, 8)): print(f"Решение найдено за {generations} поколений:") solver.print_board(solution) else: print("Решение не найдено") print("=== Алгоритм минимизации конфликтов ===") solution, steps = solver.min_conflicts() # Теперь правильно вызываем метод # Проверяем, действительно ли это решение is_valid_solution = all(solution[i] != solution[j] and abs(solution[i] - solution[j]) != abs(i - j) for i in range(8) for j in range(i + 1, 8)) if is_valid_solution: print(f"Решение найдено за {steps} шагов:") solver.print_board(solution) else: print(f"Решение не найдено после {steps} шагов") print("Лучшая найденная расстановка:") solver.print_board(solution) if __name__ == "__main__": main() import random def draw_simple_chessboard(solution): """Простая ASCII отрисовка доски""" n = len(solution) print(f"\n╔{'═' * 25}╗") print(f"║ РЕШЕНИЕ ЗАДАЧИ О 8 ФЕРЗЯХ ║") print(f"╚{'═' * 25}╝") print(" A B C D E F G H") print(" ╔═════════════════╗") for row in range(n): print(f"{8 - row} ║", end="") for col in range(n): if solution[col] == row: print(" Q", end="") else: print(" ·", end="") print(" ║", end="") # Показываем координаты ферзей для этой строки queens_in_row = [chr(65 + col) for col, r in enumerate(solution) if r == row] if queens_in_row: print(f" Ферзь на {', '.join(queens_in_row)}", end="") print() print(" ╚═════════════════╝") print(" A B C D E F G H") # Вывод координат всех ферзей print(f"\n📋 Координаты ферзей:") for col, row in enumerate(solution): print(f" {chr(65 + col)}: {8 - row}") # Быстрое решение и отрисовка def quick_solve(): n = 8 board = list(range(n)) random.shuffle(board) for step in range(100): conflicts = 0 for i in range(n): for j in range(i + 1, n): if board[i] == board[j] or abs(board[i] - board[j]) == abs(i - j): conflicts += 1 if conflicts == 0: return board, step + 1 # Исправляем один конфликт for col in range(n): for other_col in range(n): if col != other_col and ( board[col] == board[other_col] or abs(board[col] - board[other_col]) == abs(col - other_col) ): # Пробуем переместить ферзя for try_row in range(n): if try_row != board[col]: old_conflicts = sum( 1 for c in range(n) if c != col and ( board[col] == board[c] or abs(board[col] - board[c]) == abs(col - c) ) ) new_conflicts = sum( 1 for c in range(n) if c != col and ( try_row == board[c] or abs(try_row - board[c]) == abs(col - c) ) ) if new_conflicts < old_conflicts: board[col] = try_row break break return board, 100 # Запускаем решение и отрисовку print("🎯 Решаем задачу о 8 ферзях...") solution, steps = quick_solve() if all(solution[i] != solution[j] and abs(solution[i] - solution[j]) != abs(i - j) for i in range(8) for j in range(i + 1, 8)): draw_simple_chessboard(solution) print(f"\n✅ Решение найдено за {steps} шагов!") else: print("❌ Решение не найдено в данной попытке")

Результат работы программы: