Загрузка данных


using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace KeyboardTrainer
{
    public partial class MainWindow : Window
    {
        // Словарь: клавиша -> кнопка на экране
        private Dictionary<Key, Button> keyButtons = new Dictionary<Key, Button>();
        
        // Тренировочные данные
        private string targetText = "";
        private string userInput = "";
        private int errorCount = 0;
        private DateTime startTime;
        private bool sessionActive = false;
        
        public MainWindow()
        {
            InitializeComponent();
            CreateKeyboardLayout();
        }
        
        /// <summary>
        /// Создание визуальной клавиатуры
        /// </summary>
        private void CreateKeyboardLayout()
        {
            // Раскладка клавиш по рядам
            string[][] keyboardRows = new string[][]
            {
                new string[] { "`", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "=", "Backspace" },
                new string[] { "Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\" },
                new string[] { "CapsLock", "A", "S", "D", "F", "G", "H", "J", "K", "L", ";", "'", "Enter" },
                new string[] { "Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "/", "Shift" },
                new string[] { "Ctrl", "Win", "Alt", "Space", "Alt", "Win", "Ctrl" }
            };
            
            keyboardPanel.Children.Clear();
            keyButtons.Clear();
            
            foreach (var row in keyboardRows)
            {
                StackPanel rowPanel = new StackPanel
                {
                    Orientation = Orientation.Horizontal,
                    HorizontalAlignment = HorizontalAlignment.Center,
                    Margin = new Thickness(0, 0, 0, 5)
                };
                
                foreach (string keyName in row)
                {
                    Button btn = new Button
                    {
                        Content = keyName,
                        Width = GetKeyWidth(keyName),
                        Height = 45,
                        Margin = new Thickness(2),
                        IsEnabled = false, // Неинтерактивная клавиатура — только для подсветки
                        Background = Brushes.LightGray
                    };
                    
                    // Сохраняем соответствие реальной клавиши и кнопки
                    Key mappedKey = MapKeyNameToKey(keyName);
                    if (mappedKey != Key.None)
                        keyButtons[mappedKey] = btn;
                    
                    rowPanel.Children.Add(btn);
                }
                keyboardPanel.Children.Add(rowPanel);
            }
        }
        
        /// <summary>
        /// Определение ширины кнопки в зависимости от названия клавиши
        /// </summary>
        private double GetKeyWidth(string keyName)
        {
            return keyName switch
            {
                "Space" => 300,
                "Backspace" => 100,
                "Tab" => 80,
                "CapsLock" => 95,
                "Enter" => 95,
                "Shift" => 110,
                "Ctrl" => 70,
                "Alt" => 70,
                "Win" => 70,
                _ => 55
            };
        }
        
        /// <summary>
        /// Преобразование названия кнопки в значение перечисления Key
        /// </summary>
        private Key MapKeyNameToKey(string name)
        {
            return name switch
            {
                "Backspace" => Key.Back,
                "Tab" => Key.Tab,
                "CapsLock" => Key.CapsLock,
                "Enter" => Key.Enter,
                "Shift" => Key.LeftShift,
                "Ctrl" => Key.LeftCtrl,
                "Alt" => Key.LeftAlt,
                "Win" => Key.LWin,
                "Space" => Key.Space,
                _ when name.Length == 1 && char.IsLetterOrDigit(name[0]) => 
                    (Key)Enum.Parse(typeof(Key), name.ToUpper(), true),
                _ => Key.None
            };
        }
        
        /// <summary>
        /// Генерация случайной строки по уровню сложности
        /// </summary>
        private string GenerateRandomString()
        {
            Random rnd = new Random();
            int difficulty = cmbDifficulty.SelectedIndex; // 0-Easy, 1-Medium, 2-Hard
            
            int length = difficulty switch
            {
                0 => 10,
                1 => 20,
                2 => 35,
                _ => 15
            };
            
            string chars = difficulty switch
            {
                0 => "abcdefghijklmnopqrstuvwxyz ",
                1 => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ",
                2 => "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.,!?- ",
                _ => "abcdefghijklmnopqrstuvwxyz "
            };
            
            return new string(Enumerable.Repeat(chars, length)
                .Select(s => s[rnd.Next(s.Length)]).ToArray());
        }
        
        /// <summary>
        /// Старт тренировки
        /// </summary>
        private void BtnStart_Click(object sender, RoutedEventArgs e)
        {
            targetText = GenerateRandomString();
            txtTargetText.Text = targetText;
            userInput = "";
            errorCount = 0;
            txtUserInput.Text = "";
            txtUserInput.IsEnabled = true;
            txtUserInput.Focus();
            startTime = DateTime.Now;
            sessionActive = true;
            UpdateStats();
        }
        
        /// <summary>
        /// Обработка ввода текста
        /// </summary>
        private void TxtUserInput_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (!sessionActive) return;
            
            userInput = txtUserInput.Text;
            
            // Подсчёт ошибок (позиционное сравнение)
            int newErrorCount = 0;
            for (int i = 0; i < userInput.Length; i++)
            {
                if (i >= targetText.Length || userInput[i] != targetText[i])
                    newErrorCount++;
            }
            errorCount = newErrorCount;
            
            // Проверка завершения
            if (userInput.Length >= targetText.Length)
            {
                sessionActive = false;
                txtUserInput.IsEnabled = false;
                MessageBox.Show($"Тренировка завершена!\nОшибок: {errorCount}\n" +
                    $"Скорость: {CalculateSpeed()} зн/мин", "Результат");
            }
            
            UpdateStats();
            
            // Подсветка текущей позиции в целевой строке
            HighlightCurrentPosition();
        }
        
        /// <summary>
        /// Подсветка текущего символа для ввода
        /// </summary>
        private void HighlightCurrentPosition()
        {
            if (string.IsNullOrEmpty(targetText)) return;
            
            int pos = userInput.Length;
            if (pos < targetText.Length)
            {
                string highlighted = targetText.Substring(0, pos) + 
                    "→" + targetText[pos] + "←" + 
                    targetText.Substring(pos + 1);
                txtTargetText.Text = highlighted;
            }
            else
            {
                txtTargetText.Text = targetText;
            }
        }
        
        /// <summary>
        /// Обновление статистики
        /// </summary>
        private void UpdateStats()
        {
            txtErrors.Text = errorCount.ToString();
            txtSpeed.Text = $"{CalculateSpeed()} зн/мин";
        }
        
        /// <summary>
        /// Расчёт скорости набора (знаков в минуту)
        /// </summary>
        private int CalculateSpeed()
        {
            if (!sessionActive || startTime == DateTime.MinValue) return 0;
            double minutes = (DateTime.Now - startTime).TotalMinutes;
            if (minutes <= 0) return 0;
            int correctChars = Math.Max(0, userInput.Length - errorCount);
            return (int)(correctChars / minutes);
        }
        
        /// <summary>
        /// Подсветка нажатой клавиши
        /// </summary>
        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            // Основная клавиша
            if (keyButtons.ContainsKey(e.Key))
            {
                keyButtons[e.Key].Background = Brushes.LightGreen;
            }
            
            // Обработка модификаторов
            if (e.KeyboardDevice.IsKeyDown(Key.LeftShift) && keyButtons.ContainsKey(Key.LeftShift))
                keyButtons[Key.LeftShift].Background = Brushes.LightGreen;
            if (e.KeyboardDevice.IsKeyDown(Key.RightShift) && keyButtons.ContainsKey(Key.RightShift))
                keyButtons[Key.RightShift].Background = Brushes.LightGreen;
            if (e.KeyboardDevice.IsKeyDown(Key.LeftCtrl) && keyButtons.ContainsKey(Key.LeftCtrl))
                keyButtons[Key.LeftCtrl].Background = Brushes.LightGreen;
            if (e.KeyboardDevice.IsKeyDown(Key.LeftAlt) && keyButtons.ContainsKey(Key.LeftAlt))
                keyButtons[Key.LeftAlt].Background = Brushes.LightGreen;
        }
        
        /// <summary>
        /// Сброс подсветки клавиши
        /// </summary>
        private void Window_KeyUp(object sender, KeyEventArgs e)
        {
            if (keyButtons.ContainsKey(e.Key))
            {
                keyButtons[e.Key].Background = Brushes.LightGray;
            }
            
            if (!e.KeyboardDevice.IsKeyDown(Key.LeftShift) && keyButtons.ContainsKey(Key.LeftShift))
                keyButtons[Key.LeftShift].Background = Brushes.LightGray;
            if (!e.KeyboardDevice.IsKeyDown(Key.RightShift) && keyButtons.ContainsKey(Key.RightShift))
                keyButtons[Key.RightShift].Background = Brushes.LightGray;
            if (!e.KeyboardDevice.IsKeyDown(Key.LeftCtrl) && keyButtons.ContainsKey(Key.LeftCtrl))
                keyButtons[Key.LeftCtrl].Background = Brushes.LightGray;
            if (!e.KeyboardDevice.IsKeyDown(Key.LeftAlt) && keyButtons.ContainsKey(Key.LeftAlt))
                keyButtons[Key.LeftAlt].Background = Brushes.LightGray;
        }
    }
}