Содержание
В этом контрольном задании мы разработаем финальную версию нашей игры «Угадай число», используя методы в C#, а также те знания, которые были получены нами в предыдущих частях учебника. Задание будет следующим: разделите код приложения на отдельные методы: вывод текста в консоль, чтение числа, введенного пользователя и раунд игры, а также организуйте в игре возможность проверки ранее введенных пользователем чисел. Если пользователь пытается дважды ввести одно и то же число, то такая попытка не засчитывается и программа должна сделать повторный запрос.
Финальная версия игры «Угадай число»
Исходный код приложения
На данный момент, код нашей игры выглядит следующим образом:
string stop = ""; do { int number; //число, которое загадываем string inFile = @"number.txt"; TextReader oldIn = Console.In; FileStream inputStream; inputStream = File.Open(inFile, FileMode.OpenOrCreate); using StreamReader reader = new(inputStream); Console.SetIn(reader); string? numString = Console.ReadLine(); if (string.IsNullOrEmpty(numString)) //если строка пустая (в файле ничего нет) number = Random.Shared.Next(0, 10); //генерируем случайное число else number = Convert.ToInt32(numString); //получаем число из файла Console.SetIn(oldIn); //возвращаем поток ввода к значению по умолчанию for (int i = 1; i < 5; i++) { Console.ForegroundColor = ConsoleColor.Blue; Console.Write($"Попытка {i}. Угадай число: "); //тут пользователь должен ввести число Console.ForegroundColor = ConsoleColor.Yellow; int n = Convert.ToInt32(Console.ReadLine());//тут мы переводим пользовательский ввод из строки в целое число while ((n < 0) || (n > 10)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Вводите числа не меньше 0 и не больше 10"); Console.ForegroundColor = ConsoleColor.Blue; Console.Write("Введите число "); Console.ForegroundColor = ConsoleColor.Yellow; n = Convert.ToInt32(Console.ReadLine()); } bool notGuess = n != number; if (notGuess) { if (i == 4) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Вы проиграли. Было загадано число {number}"); break; } } else { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Поздравляю! Вы победили!"); break; } Console.ForegroundColor = ConsoleColor.White; if (n < number) { Console.WriteLine("Больше"); } else { Console.WriteLine("Меньше"); } } Console.ForegroundColor = ConsoleColor.DarkRed; Console.WriteLine("Сыграем ещё раз? Для того, чтобы закончить игру, наберите слово \"Stop\". Для продолжение нажмите Enter"); stop = Console.ReadLine(); Console.ForegroundColor = ConsoleColor.White; } while (stop.ToLower() != "stop"); Console.WriteLine("GAME OVER"); Console.ReadKey();
Изменим его, используя методы в C#.
Выделение методов из исходного кода
Первый метод, который мы должны создать и использовать в игре — вывод цветного текста в консоль. То есть параметрами метода должны выступать значение цвета и строка. При этом, если посмотреть внимательно на исходный код нашей программы, то можно увидеть, что где-то мы выводим текст, перенося курсор на новую строку, а где-то — нет. Этот момент мы также должны учесть в нашей программе. Напишем код этого метода:
void WriteColorText(string text, ConsoleColor color, bool useCrLf = false) { ConsoleColor oldColor = Console.ForegroundColor;//запоминаем текущай цвет Console.ForegroundColor = color; //устанавливаем новый цвет if (useCrLf) //будем переносить строку? Console.WriteLine(text); else Console.Write(text); Console.ForegroundColor = oldColor; //возвращаем старый цвет }
здесь мы меняем цвет текста в консоли на заданный в параметрах метода, запоминая при этом текущий цвет. Для того, чтобы определиться с тем, необходимо ли переходить на новую строку, мы используем необязательный параметр метода. То есть, по умолчанию, мы не будем переходить на новую строку после вывода текста.
Применим этот метод в нашей игре:
string stop = ""; do { int number; //число, которое загадываем string inFile = @"number.txt"; TextReader oldIn = Console.In; FileStream inputStream; inputStream = File.Open(inFile, FileMode.OpenOrCreate); using StreamReader reader = new(inputStream); Console.SetIn(reader); string? numString = Console.ReadLine(); if (string.IsNullOrEmpty(numString)) //если строка пустая (в файле ничего нет) number = Random.Shared.Next(0, 10); //генерируем случайное число else number = Convert.ToInt32(numString); //получаем число из файла Console.SetIn(oldIn); //возвращаем поток ввода к значению по умолчанию for (int i = 1; i < 5; i++) { WriteColorText($"Попытка {i}. Угадай число: ", ConsoleColor.Blue); Console.ForegroundColor = ConsoleColor.Yellow; int n = Convert.ToInt32(Console.ReadLine());//тут мы переводим пользовательский ввод из строки в целое число while ((n < 0) || (n > 10)) { WriteColorText("Вводите числа не меньше 0 и не больше 10", ConsoleColor.Red); WriteColorText("Введите число ", ConsoleColor.Blue); Console.ForegroundColor = ConsoleColor.Yellow; n = Convert.ToInt32(Console.ReadLine()); } bool notGuess = n != number; if (notGuess) { if (i == 4) { WriteColorText($"Вы проиграли. Было загадано число {number}", ConsoleColor.Red); break; } } else { WriteColorText("Поздравляю! Вы победили!", ConsoleColor.Green); break; } Console.ForegroundColor = ConsoleColor.White; if (n < number) { WriteColorText("Больше", ConsoleColor.White); } else { WriteColorText("Меньше", ConsoleColor.White); } } WriteColorText("Сыграем ещё раз? Для того, чтобы закончить игру, наберите слово \"Stop\". Для продолжение нажмите Enter", ConsoleColor.DarkRed); stop = Console.ReadLine(); Console.ForegroundColor = ConsoleColor.White; } while (stop.ToLower() != "stop"); Console.WriteLine("GAME OVER"); Console.ReadKey();
Как можно видеть, исходный код стал немного короче и понятнее за счёт того, что мы избавились от некоторых повторяющихся строк кода. Теперь выделим работу внутреннего цикла while
в отдельный метод чтения числа:
int ReadNumber() { Console.ForegroundColor = ConsoleColor.Yellow; int n = Convert.ToInt32(Console.ReadLine()); while ((n < 0) || (n > 10)) { WriteColorText("Вводите числа не меньше 0 и не больше 10", ConsoleColor.Red); WriteColorText("Введите число ", ConsoleColor.Blue); Console.ForegroundColor = ConsoleColor.Yellow; n = Convert.ToInt32(Console.ReadLine()); } return n; }
и сразу напишем метод отдельного раунда игры — выделим из кода программы начальную генерацию числа и цикл for
в отдельный метод:
string? Lap() { int number; //число, которое загадываем string inFile = @"number.txt"; TextReader oldIn = Console.In; FileStream inputStream; inputStream = File.Open(inFile, FileMode.OpenOrCreate); using StreamReader reader = new(inputStream); Console.SetIn(reader); string? numString = Console.ReadLine(); if (string.IsNullOrEmpty(numString)) //если строка пустая (в файле ничего нет) number = Random.Shared.Next(0, 10); //генерируем случайное число else number = Convert.ToInt32(numString); //получаем число из файла Console.SetIn(oldIn); //возвращаем поток ввода к значению по умолчанию for (int i = 1; i < 5; i++) { WriteColorText($"Попытка {i}. Угадай число: ", ConsoleColor.Blue); int n = ReadNumber(); bool notGuess = n != number; if (notGuess) { if (i == 4) { WriteColorText($"Вы проиграли. Было загадано число {number}", ConsoleColor.Red); break; } } else { WriteColorText("Поздравляю! Вы победили!", ConsoleColor.Green); break; } Console.ForegroundColor = ConsoleColor.White; if (n < number) { WriteColorText("Больше", ConsoleColor.White); } else { WriteColorText("Меньше", ConsoleColor.White); } } WriteColorText("Сыграем ещё раз? Для того, чтобы закончить игру, наберите слово \"Stop\". Для продолжение нажмите Enter", ConsoleColor.DarkRed); Console.ForegroundColor = ConsoleColor.White; return Console.ReadLine(); }
Остается только использовать этот метод в основном коде приложения:
string? stop; do { stop = Lap(); } while (stop?.ToLower() != "stop"); Console.WriteLine("GAME OVER"); Console.ReadKey();
Метод Lap()
возвращает нам строку, которую вводит пользователь после очередного раунда.
Организация проверки введенных ранее чисел
Теперь мы должны каким-либо образом организовать в нашей игре проверку того, что пользователь пытается ввести ранее введенное число. Как это сделать, используя полученные нами ранее знания? Мы должны «научить» нашу игру «запоминать» ходы игрока. Сделать это можно, используя массивы. Для начала определим новую переменную-массив в основном коде нашего приложения
string? stop; int[] steps; //здесь будем сохранять ходы игрока do { //код цикла } while (stop?.ToLower() != "stop");
Для работы с массивом у нас имеются следующие вводные: пользователь может вводить только числа от 0 до 10, попыток у пользователя — 4, после каждого раунда игра должна «забыть» всё, что вводил пользователь. Таким образом, наш массив должен иметь длину 4 и изначально содержать значения, которые пользователь не может ввести, например, каждый элемент по умолчанию должен быть равен -1. Почему именно так? Дело в том, что по умолчанию, как только мы создадим массив, каждый элемент нашего массива получит значение 0. Если пользователь попытается ввести 0 в консоль, то программа сразу посчитает это повтором ввода. Более того, и сама программа может «загадать» 0 и тогда игрок заведомо проигрывает. Инициализировать массив мы будем перед каждым новым раундом следующим образом:
string? stop; int[] steps; //здесь будем сохранять ходы игрока do { steps = [-1, -1, -1, -1]; //начальная инициализация массива перед очередным раундом stop = Lap(); //запускаем раунд } while (stop?.ToLower() != "stop");
Как теперь записывать и проверять ходы игрока, используя этот массив? У нас есть цикл for
(см код метода Lap()
) и мы можем использовать счётчик этого цикла, чтобы определить на какой попытке находится пользователь, чтобы по номеру попытки задавать значение элемента массива, например, 1- попытка — это элемент с индексом 0 в массиве, 4-я попытка — элемент с индексом 3 и т.д. Ну а проверить наличие того или иного числа в массиве мы можем, используя любой цикл. Таким образом, метод проверки ранее введенного числа должен принимать следующие параметры: значение, которое необходимо проверить, номер попытки. Возвращать метод должен признак того, корректное значение или нет. Создадим новый метод:
bool CheckStep(int value, int currentLap) { foreach (int step in steps) { if (step == value) { WriteColorText("Вы уже вводили это число. Попробуйте ещё раз", ConsoleColor.Red, true); return false; } } steps[currentLap] = value; return true; }
Вначале, мы проверяем есть ли заданное число в массиве и, если есть, то выдаем сообщение пользователю и сразу выходим из метода. Если же число ранее не вводилось, то мы, используя параметр метода currentLap
, записываем это значение в массив:
steps[currentLap] = value;
и возвращаем значение true
— введено корректное значение. Теперь необходимо каким-либо образом использовать этот метод в нашем коде. Проверку числа мы проводим в методе ReadNumber()
, поэтому логично будет в этом же методе и применить CheckStep()
. Изменим метод ReadNumber()
следующим образом:
int ReadNumber(int lap) { Console.ForegroundColor = ConsoleColor.Yellow; int n = Convert.ToInt32(Console.ReadLine()); while ((n < 0) || (n > 10) || CheckStep(n, lap) == false) { WriteColorText("Вводите числа не меньше 0 и не больше 10", ConsoleColor.Red, true); WriteColorText("Введите число ", ConsoleColor.Blue); Console.ForegroundColor = ConsoleColor.Yellow; n = Convert.ToInt32(Console.ReadLine()); } return n; }
Здесь мы добавили параметр метода int lap
, в котором будем передавать порядковый номер попытки, а также немного изменили условие цикла, включив в него наш новый метод CheckStep()
. Таким образом, теперь цикл while
будет повторять до тех пор пока пользователь не введет корректное число, которое ранее не использовалось в раунде игры. И нам остается только немного изменить вызов метода ReadNumber()
:
string? Lap() { //тут загадываем число for (int i = 1; i < 5; i++) { WriteColorText($"Попытка {i}. Угадай число: ", ConsoleColor.Blue); int n = ReadNumber(i-1); //тут остальной код раунда } WriteColorText("Сыграем ещё раз? Для того, чтобы закончить игру, наберите слово \"Stop\". Для продолжение нажмите Enter", ConsoleColor.DarkRed, true); Console.ForegroundColor = ConsoleColor.White; return Console.ReadLine(); }
Так как цикл for
начинается с 1, а индексы в массиве — с 0, то в параметры метода мы передаем i-1
, чтобы сохранить порядок записи указанных пользователем чисел в массиве и не выйти за его границы на четвертой попытке.
Теперь все задачи выполнены и наша игра «Угадай число» готова к использованию:
Итого
Итак, на протяжении трех частей мы разрабатывали и дорабатывали свою первую программу на C# — игру «Угадай число». Пусть это и довольно простая, но, тем не менее, вполне рабочая программа, которую можно использовать. Конечно, игру можно дорабатывать дальше, например, сейчас мы не застрахованы от случаев, когда пользователь вводит не целое число, а например, дробное или вообще буквы — в этом случае программа аварийно завершит свою работу. Про обработку таких ситуаций мы обязательно с вами поговорим в части «Обработка исключений», но уже в контексте выполнения других, более сложных задач.
Полный исходный код игры «Угадай число»
string? stop; int[] steps; //здесь будем сохранять ходы игрока do { steps = [-1, -1, -1, -1]; //начальная инициализация массива перед очередным раундом stop = Lap(); //запускаем раунд } while (stop?.ToLower() != "stop"); Console.WriteLine("GAME OVER"); Console.ReadKey(); void WriteColorText(string text, ConsoleColor color, bool useCrLf = false) { ConsoleColor oldColor = Console.ForegroundColor;//запоминаем текущай цвет Console.ForegroundColor = color; //устанавливаем новый цвет if (useCrLf) //будем переносить строку? Console.WriteLine(text); else Console.Write(text); Console.ForegroundColor = oldColor; //возвращаем старый цвет } bool CheckStep(int value, int currentLap) { foreach (int step in steps) { if (step == value) { WriteColorText("Вы уже вводили это число. Попробуйте ещё раз", ConsoleColor.Red, true); return false; } } steps[currentLap] = value; return true; } int ReadNumber(int lap) { Console.ForegroundColor = ConsoleColor.Yellow; int n = Convert.ToInt32(Console.ReadLine()); while ((n < 0) || (n > 10) || CheckStep(n, lap) == false) { WriteColorText("Вводите числа не меньше 0 и не больше 10", ConsoleColor.Red, true); WriteColorText("Введите число ", ConsoleColor.Blue); Console.ForegroundColor = ConsoleColor.Yellow; n = Convert.ToInt32(Console.ReadLine()); } return n; } string? Lap() { int number; //число, которое загадываем string inFile = @"number.txt"; TextReader oldIn = Console.In; FileStream inputStream; inputStream = File.Open(inFile, FileMode.OpenOrCreate); using StreamReader reader = new(inputStream); Console.SetIn(reader); string? numString = Console.ReadLine(); if (string.IsNullOrEmpty(numString)) //если строка пустая (в файле ничего нет) number = Random.Shared.Next(0, 10); //генерируем случайное число else number = Convert.ToInt32(numString); //получаем число из файла Console.SetIn(oldIn); //возвращаем поток ввода к значению по умолчанию for (int i = 1; i < 5; i++) { WriteColorText($"Попытка {i}. Угадай число: ", ConsoleColor.Blue); int n = ReadNumber(i-1); bool notGuess = n != number; if (notGuess) { if (i == 4) { WriteColorText($"Вы проиграли. Было загадано число {number}", ConsoleColor.Red, true); break; } } else { WriteColorText("Поздравляю! Вы победили!", ConsoleColor.Green, true); break; } Console.ForegroundColor = ConsoleColor.White; if (n < number) { WriteColorText("Больше", ConsoleColor.White, true); } else { WriteColorText("Меньше", ConsoleColor.White, true); } } WriteColorText("Сыграем ещё раз? Для того, чтобы закончить игру, наберите слово \"Stop\". Для продолжение нажмите Enter", ConsoleColor.DarkRed, true); Console.ForegroundColor = ConsoleColor.White; return Console.ReadLine(); }