using Microsoft.Win32; using Lab9.Models; using Lab9.Services; using Lab9.Strategies; using System.Globalization; using System.Text; using System.Windows; using System.Windows.Documents; using System.Windows.Media; using System.IO; using System.Text.RegularExpressions; namespace Lab9 { public partial class MainWindow : Window { private readonly SortingContext _context = new(); private readonly IReadOnlyList _strategies; private int[] _currentArray = Array.Empty(); private SortResult? _lastResult; public MainWindow() { InitializeComponent(); _strategies = new List { new TimSortStrategy(), new MsdRadixSortStrategy(), new CommunistSortStrategy() }; UpdatePreview("Массив ещё не сформирован."); ResetMetrics(); } private void ElementCountSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs e) { if (!IsLoaded) { return; } ElementCountTextBox.Text = ((int)ElementCountSlider.Value).ToString(CultureInfo.InvariantCulture); } private void ElementCountTextBox_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e) { if (!IsLoaded) { return; } if (int.TryParse(ElementCountTextBox.Text, out var value)) { value = Math.Clamp(value, (int)ElementCountSlider.Minimum, (int)ElementCountSlider.Maximum); ElementCountSlider.Value = value; } } private void GenerateArray_Click(object sender, RoutedEventArgs e) { var count = (int)ElementCountSlider.Value; var random = new Random(); _currentArray = Enumerable.Range(0, count) .Select(_ => random.Next(-250, 1000)) .ToArray(); _lastResult = null; ClearLog(); ResetMetrics(); UpdatePreview($"Исходный массив:{Environment.NewLine}{FormatArray(_currentArray)}"); } private void LoadFromFile_Click(object sender, RoutedEventArgs e) { var dialog = new OpenFileDialog { Filter = "Текстовые файлы (*.txt)|*.txt|Все файлы (*.*)|*.*" }; if (dialog.ShowDialog() != true) { return; } try { _currentArray = ArrayIoService.ReadArrayFromFile(dialog.FileName); _lastResult = null; ClearLog(); ResetMetrics(); UpdatePreview($"Массив из файла:{Environment.NewLine}{FormatArray(_currentArray)}"); } catch (Exception ex) { MessageBox.Show( $"Не удалось прочитать файл.\n{ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error); } } private void StartSorting_Click(object sender, RoutedEventArgs e) { if (_currentArray.Length == 0) { MessageBox.Show( "Сначала сгенерируй массив или загрузи его из файла. Машина без данных сортирует только воздух.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Warning); return; } var strategy = GetSelectedStrategy(); var ascending = DescendingCheckBox.IsChecked != true; _context.ContextStrategy = strategy; _lastResult = _context.Execute(_currentArray, ascending, enableLogging: true); ComparisonsTextBlock.Text = _lastResult.Metrics.Comparisons.ToString(CultureInfo.InvariantCulture); MovesTextBlock.Text = _lastResult.Metrics.Moves.ToString(CultureInfo.InvariantCulture); ElapsedTextBlock.Text = $"{_lastResult.Elapsed.TotalMilliseconds:F6} мс"; RenderLog(_lastResult.Log); UpdatePreview( $"Исходный массив:{Environment.NewLine}{FormatArray(_currentArray)}{Environment.NewLine}{Environment.NewLine}" + $"Результат ({_lastResult.AlgorithmName}):{Environment.NewLine}{FormatArray(_lastResult.SortedArray)}"); } private void SaveToFile_Click(object sender, RoutedEventArgs e) { if (_currentArray.Length == 0) { MessageBox.Show( "Сохранять пока нечего. Даже файл не любит пустые жесты.", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Warning); return; } var dialog = new SaveFileDialog { Filter = "Текстовые файлы (*.txt)|*.txt", FileName = "sorting_result.txt" }; if (dialog.ShowDialog() != true) { return; } try { var content = BuildExportContent(); File.WriteAllText(dialog.FileName, content, Encoding.UTF8); MessageBox.Show( "Результаты сохранены в файл.", "Готово", MessageBoxButton.OK, MessageBoxImage.Information); } catch (Exception ex) { MessageBox.Show( $"Не удалось сохранить файл.\n{ex.Message}", "Ошибка", MessageBoxButton.OK, MessageBoxImage.Error); } } private void Clear_Click(object sender, RoutedEventArgs e) { _currentArray = Array.Empty(); _lastResult = null; ClearLog(); ResetMetrics(); UpdatePreview("Массив очищен."); } private void OpenAnalysis_Click(object sender, RoutedEventArgs e) { var analysisWindow = new AnalysisWindow(_strategies, DescendingCheckBox.IsChecked == true) { Owner = this }; analysisWindow.ShowDialog(); } private ISortStrategy GetSelectedStrategy() { if (MsdRadioButton.IsChecked == true) { return _strategies.OfType().First(); } if (CommunistRadioButton.IsChecked == true) { return _strategies.OfType().First(); } return _strategies.OfType().First(); } private void ResetMetrics() { ComparisonsTextBlock.Text = "0"; MovesTextBlock.Text = "0"; ElapsedTextBlock.Text = "0.000000 мс"; } private void UpdatePreview(string text) { ArrayPreviewTextBlock.Text = text; } private void ClearLog() { LogRichTextBox.Document.Blocks.Clear(); } private static string FormatArray(int[] array) { if (array.Length == 0) { return "Пустой массив."; } return string.Join(" ", array); } private void RenderLog(string log) { LogRichTextBox.Document.Blocks.Clear(); var regex = new Regex(@"\[-?\d+\]", RegexOptions.Compiled); var lines = log.Replace("\r\n", "\n").Split('\n'); foreach (var line in lines) { var paragraph = new Paragraph { Margin = new Thickness(0) }; if (string.IsNullOrWhiteSpace(line)) { paragraph.Inlines.Add(new Run(" ")); LogRichTextBox.Document.Blocks.Add(paragraph); continue; } var lastIndex = 0; foreach (Match match in regex.Matches(line)) { if (match.Index > lastIndex) { paragraph.Inlines.Add(new Run(line.Substring(lastIndex, match.Index - lastIndex))); } paragraph.Inlines.Add(new Run(match.Value) { Background = Brushes.LightSkyBlue, FontWeight = FontWeights.Bold }); lastIndex = match.Index + match.Length; } if (lastIndex < line.Length) { paragraph.Inlines.Add(new Run(line.Substring(lastIndex))); } LogRichTextBox.Document.Blocks.Add(paragraph); } } private string BuildExportContent() { var builder = new StringBuilder(); builder.AppendLine("Лабораторная работа №9. Внутренняя сортировка данных"); builder.AppendLine($"Исходный массив: {string.Join(", ", _currentArray)}"); builder.AppendLine($"Режим сортировки: {(DescendingCheckBox.IsChecked == true ? "По убыванию" : "По возрастанию")}"); if (_lastResult is null) { builder.AppendLine("Сортировка ещё не запускалась."); return builder.ToString(); } builder.AppendLine($"Алгоритм: {_lastResult.AlgorithmName}"); builder.AppendLine($"Отсортированный массив: {string.Join(", ", _lastResult.SortedArray)}"); builder.AppendLine($"Количество сравнений: {_lastResult.Metrics.Comparisons}"); builder.AppendLine($"Количество пересылок: {_lastResult.Metrics.Moves}"); builder.AppendLine($"Время сортировки: {_lastResult.Elapsed.TotalMilliseconds:F6} мс"); builder.AppendLine(); builder.AppendLine("Пошаговый журнал:"); builder.AppendLine(_lastResult.Log); return builder.ToString(); } } }