namespace BombsAwayConsole; /// /// Implements by writing to and reading from . /// internal class ConsoleUserInterface : BombsAwayGame.IUserInterface { /// /// Write message to console. /// /// Message to display. public void Output(string message) { Console.WriteLine(message); } /// /// Write choices with affixed indexes, allowing the user to choose by index. /// /// Message to display. /// Choices to display. /// Choice that user picked. public int Choose(string message, IList choices) { IEnumerable choicesWithIndexes = choices.Select((choice, index) => $"{choice}({index + 1})"); string choiceText = string.Join(", ", choicesWithIndexes); Output($"{message} -- {choiceText}"); ISet allowedKeys = ConsoleKeysFromList(choices); ConsoleKey? choice; do { choice = ReadChoice(allowedKeys); if (choice is null) { Output("TRY AGAIN..."); } } while (choice is null); return ListIndexFromConsoleKey(choice.Value); } /// /// Convert the given list to its equivalents. This generates keys that map /// the first element to , the second element to , /// and so on, up to the last element of the list. /// /// List whose elements will be converted to equivalents. /// equivalents from . private ISet ConsoleKeysFromList(IList list) { IEnumerable indexes = Enumerable.Range((int)ConsoleKey.D1, list.Count); return new HashSet(indexes.Cast()); } /// /// Convert the given console key to its list index equivalent. This assumes the key was generated from /// /// /// Key to convert to its list index equivalent. /// List index equivalent of key. private int ListIndexFromConsoleKey(ConsoleKey key) { return key - ConsoleKey.D1; } /// /// Read a key from the console and return it if it is in the given allowed keys. /// /// Allowed keys. /// Key read from , if it is in ; null otherwise./> private ConsoleKey? ReadChoice(ISet allowedKeys) { ConsoleKeyInfo keyInfo = ReadKey(); return allowedKeys.Contains(keyInfo.Key) ? keyInfo.Key : null; } /// /// Read key from . /// /// Key read from . private ConsoleKeyInfo ReadKey() { ConsoleKeyInfo result = Console.ReadKey(intercept: false); // Write a blank line to the console so the displayed key is on its own line. Console.WriteLine(); return result; } /// /// Allow user to choose 'Y' or 'N' from . /// /// Message to display. /// True if user chose 'Y', false if user chose 'N'. public bool ChooseYesOrNo(string message) { Output(message); ConsoleKey? choice; do { choice = ReadChoice(new HashSet(new[] { ConsoleKey.Y, ConsoleKey.N })); if (choice is null) { Output("ENTER Y OR N"); } } while (choice is null); return choice.Value == ConsoleKey.Y; } /// /// Get integer by reading a line from . /// /// Integer read from . public int InputInteger() { bool resultIsValid; int result; do { string? integerText = Console.ReadLine(); resultIsValid = int.TryParse(integerText, out result); if (!resultIsValid) { Output("PLEASE ENTER A NUMBER"); } } while (!resultIsValid); return result; } }