/
evsyukov.s
/
DiceGame
Обзор
Документация
Войти
/
evsyukov.s
/
DiceGame
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/DicePoker.ConsoleApp/UI/InputHandler.cs
202 строки
8 KB
evsyukov.s
Исправлена обработка ошибок в репозитории
26 дек 2025, 18:38
26 дек 2025, 18:38
169efb5
Код
Авторство
О чём код?
using System.Text; namespace DicePoker.ConsoleApp.UI { /// <summary> /// Статический класс для обработки ввода пользователя. /// Отвечает за чтение данных из консоли, парсинг и валидацию. /// </summary> public static class InputHandler { /// <summary> /// Читает строку ввода с ограничением времени (таймаут). /// Возвращает введенную строку или null если время истекло до нажатия Enter. /// </summary> /// <param name="seconds">Количество секунд на ввод</param> /// <param name="prompt">Текст приглашения для ввода (по умолчанию "\nВаш выбор: ")</param> public static string? ReadLineWithTimeout(int seconds, string prompt = "\nВаш выбор: ") { StringBuilder line = new StringBuilder(); // Вычисляем время истечения: текущее время + указанное количество секунд DateTime end = DateTime.UtcNow.AddSeconds(seconds); // Сохраняем начальную позицию для строки таймера int timerLineTop = Console.CursorTop; // Отображаем начальное время Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine($"Осталось времени: {seconds} сек"); Console.ResetColor(); // Выводим промпт для ввода Console.Write(prompt); int lastSecondsLeft = seconds; // Цикл проверки доступных клавиш с небольшой задержкой while (DateTime.UtcNow < end) { // Вычисляем оставшееся время int secondsLeft = (int)Math.Ceiling((end - DateTime.UtcNow).TotalSeconds); // Обновляем отображение времени, если оно изменилось if (secondsLeft != lastSecondsLeft && secondsLeft >= 0) { // Сохраняем текущую позицию курсора int currentInputLeft = Console.CursorLeft; int currentInputTop = Console.CursorTop; // Переходим на строку с таймером Console.SetCursorPosition(0, timerLineTop); Console.ForegroundColor = ConsoleColor.Yellow; Console.Write($"Осталось времени: {secondsLeft} сек "); // Пробелы для затирания старого текста Console.ResetColor(); // Возвращаемся на позицию ввода Console.SetCursorPosition(currentInputLeft, currentInputTop); lastSecondsLeft = secondsLeft; } // Проверяем, была ли нажата клавиша if (Console.KeyAvailable) { ConsoleKeyInfo key = Console.ReadKey(true); // Если нажат Enter, возвращаем введенную строку if (key.Key == ConsoleKey.Enter) { Console.WriteLine(); // Переход на новую строку после ввода return line.ToString(); } // Если нажат Backspace, удаляем последний символ if (key.Key == ConsoleKey.Backspace && line.Length > 0) { line.Length--; Console.Write("\b \b"); } // Если нажат обычный символ (не управляющая клавиша), добавляем его else if (!char.IsControl(key.KeyChar)) { line.Append(key.KeyChar); Console.Write(key.KeyChar); } } // Небольшая задержка для снижения нагрузки на CPU Thread.Sleep(100); } // Если время истекло, возвращаем null Console.WriteLine(); // Переход на новую строку return null; } /// <summary> /// Парсит строку с индексами костей (через пробел) в массив целых чисел. /// Фильтрует некорректные значения, оставляя только индексы от 0 до 4 (для 5 костей). /// </summary> public static int[] ParseIndices(string input) { // Разбиваем строку по пробелам, парсим каждую часть в число // Фильтруем: берем только корректные индексы (0-4), удаляем дубликаты return [.. input.Split(' ', StringSplitOptions.RemoveEmptyEntries) .Select(s => int.TryParse(s, out int i) ? i : -1) .Where(i => i is >= 0 and < 5) .Distinct()]; } /// <summary> /// Проверяет, являются ли все индексы в строке корректными (0-4). /// </summary> public static bool AreIndicesValid(string input) { string[] parts = input.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) { return false; } foreach (string part in parts) { if (!int.TryParse(part, out int value) || value < 0 || value > 4) { return false; } } return true; } /// <summary> /// Читает имя игрока с консоли с заданным приглашением. /// </summary> public static string ReadPlayerName(string prompt, string defaultName) { Console.Write(prompt); string? name = Console.ReadLine(); return string.IsNullOrWhiteSpace(name) ? defaultName : name; } /// <summary> /// Читает целое число с консоли. /// </summary> public static int ReadInteger(string prompt, int defaultValue = 0) { Console.Write(prompt); string? input = Console.ReadLine(); return int.TryParse(input, out int result) ? result : defaultValue; } /// <summary> /// Читает целое число с консоли с валидацией и повторным запросом при ошибке. /// Продолжает запрашивать ввод, пока не будет введено корректное число в заданном диапазоне. /// </summary> /// <param name="prompt">Текст приглашения для ввода</param> /// <param name="minValue">Минимально допустимое значение (включительно)</param> /// <param name="maxValue">Максимально допустимое значение (включительно), null = без ограничения</param> public static int ReadIntegerWithValidation(string prompt, int minValue = 0, int? maxValue = null) { while (true) { Console.Write(prompt); string? input = Console.ReadLine(); // Проверяем успешность парсинга if (!int.TryParse(input, out int result)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Ошибка: введите корректное целое число."); Console.ResetColor(); continue; } // Проверяем диапазон значений if (result < minValue) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Ошибка: значение должно быть не меньше {minValue}."); Console.ResetColor(); continue; } if (maxValue.HasValue && result > maxValue.Value) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Ошибка: значение должно быть не больше {maxValue.Value}."); Console.ResetColor(); continue; } return result; } } /// <summary> /// Читает выбор пользователя из меню. /// </summary> public static string ReadChoice(string prompt = "\nВыбор: ") { Console.Write(prompt); return Console.ReadLine() ?? ""; } } }