Skip to content

Instantly share code, notes, and snippets.

@Ruffo324
Last active September 27, 2020 16:27
Show Gist options
  • Save Ruffo324/89d47de91a8e0232b94a911d3c3e1d7a to your computer and use it in GitHub Desktop.
Save Ruffo324/89d47de91a8e0232b94a911d3c3e1d7a to your computer and use it in GitHub Desktop.
using System;
using System.Linq;
namespace ConsoleApp1
{
/// <summary>
/// Target:
/// 1) Read in Number of students
/// 2) Create array with number of elements for age (int) & weight (double)
/// 3) Reading of age & weight
/// 4) Search for the most difficult students (mobbing!)
/// 5) Count how many students are 16 years old.
/// X) Calculate average age
/// XX) Determine total weight of the class
/// </summary>
internal class Program
{
private static readonly (int min, int max) RandomAgeRange = (min: 10, max: 95);
private static readonly (double min, double max) RandomWeightRange = (min: 45f, max: 185f);
private static readonly ConsoleColor OriginalConsoleForeground = Console.ForegroundColor;
private delegate bool TryParseMethod<TResult>(string? str, out TResult parsedResult);
/// <summary>
/// Overload/Wrapper of <see cref="Console.ReadLine" />.
/// Prints the given <paramref name="prefix" /> first on the same line.
/// <example>"Age > "</example>
/// </summary>
private static string ReadLine(string prefix = "> ")
{
Console.Write(prefix);
return Console.ReadLine() ?? string.Empty;
}
/// <summary>
/// Read the console input until the user input is parsable to <typeparamref name="TResult" />.
/// Use the <paramref name="fallback" /> parameter, to define fallback/default values after X tries.
/// </summary>
private static TResult ParseUntilValid<TResult>(TryParseMethod<TResult> tryParse, string? retryMessage = null, (TResult fallbackValue, int afterTries)? fallback = null,
string? inputPrefix = null)
where TResult : unmanaged
{
inputPrefix ??= "> ";
TResult parsedValue;
string userInput;
var tries = fallback?.afterTries ?? -1;
while (!tryParse(userInput = ReadLine(tries == decimal.Zero ? $"([ENTER] for default) {inputPrefix}" : inputPrefix), out parsedValue))
{
if (tries == -1 || --tries > 0)
{
var input = userInput;
RunInColor(ConsoleColor.Red, () => Console.WriteLine(retryMessage ?? $"User input \"{input}\" does not match the excepted type \"{typeof(TResult)}\"!"));
}
else
{
return fallback?.fallbackValue
?? throw new ArgumentNullException(nameof(fallback), $"{nameof(fallback)}.{nameof(fallback.Value.fallbackValue)} is not allowed to be null.");
}
}
return parsedValue;
}
private static void PrintLine(char lineChar = '#')
=> Console.WriteLine(string.Empty.PadRight(Console.BufferWidth, lineChar));
private static void TryWriteCentered(string text)
=> Console.WriteLine(text.Length > Console.BufferWidth ? text : string.Empty.PadLeft((Console.BufferWidth - text.Length) / 2) + text);
private static void EmptyLine()
=> Console.WriteLine();
private static void WholeProgram()
{
PrintLine();
TryWriteCentered("Simple students coding session task");
TryWriteCentered("BUT SLIGHTLY OVER ENGINEERED!");
PrintLine();
EmptyLine();
// Read amount of students.
Console.WriteLine("Number of students in class?");
var studentsInClass = ParseUntilValid<int>(int.TryParse);
var students = Enumerable.Repeat<(int number, int age, double weight)>((default, default, default), studentsInClass);
Console.WriteLine("Automatic generate random values? ['true' / 'false'] (false is default)");
var autoFill = ParseUntilValid<bool>(bool.TryParse, fallback: (false, 0));
if (autoFill)
{
var random = new Random();
var randomAge = new Func<int>(() => random.Next(RandomAgeRange.min, RandomAgeRange.max));
var randomWeight = new Func<double>(() => random.NextDouble() * (RandomWeightRange.max - RandomWeightRange.min) + RandomWeightRange.min);
students = students.Select((s, i) => (number: i + 1, age: randomAge(), weight: randomWeight())).ToList();
}
else
{
const int inputPadding = 10;
var getAge = new Func<int>(() => ParseUntilValid<int>(int.TryParse, inputPrefix: $"{"Age".PadRight(inputPadding)} > "));
var getWeight = new Func<double>(() => ParseUntilValid<double>(double.TryParse, inputPrefix: $"{"Weight".PadRight(inputPadding)} > "));
students = students.Select((s, i) =>
{
PrintLine('-');
Console.WriteLine($"Enter properties of student no. \"{i + 1}\".");
return (number: i + 1, age: getAge(), weight: getWeight());
}).ToList();
PrintLine('-');
}
// Print students overview.
PrintLine();
TryWriteCentered($"Students data {(autoFill ? "generated" : "collected")}.");
PrintLine();
var pad = new Func<double, string>(d => $"{d}".PadRight(5));
foreach (var (number, age, weight) in students)
{
Console.WriteLine("Nr. " + pad(number) + "Age: " + pad(age) + "Weight: " + pad(weight));
}
PrintLine();
EmptyLine();
EmptyLine();
TryWriteCentered("NO. 4) Fattiest/heaviest student:");
TryWriteCentered($"{students.Max(s => s.weight)} KG");
EmptyLine();
TryWriteCentered("NO. 5) Number of students who are 16 years old:");
TryWriteCentered($"{students.Count(s => s.age == 16)} students.");
EmptyLine();
TryWriteCentered("NO. 6/X) Average age of the class:");
TryWriteCentered($"{students.Average(s => s.age)} years.");
EmptyLine();
TryWriteCentered("NO. 7/XX) Total weight of class:");
TryWriteCentered($"{students.Sum(s => s.weight)} KG");
EmptyLine();
PrintLine();
RunInColor(ConsoleColor.Cyan, () => TryWriteCentered("Have a nice day!"));
}
private static void RunInColor(ConsoleColor color, Action action)
{
Console.ForegroundColor = color;
action();
Console.ForegroundColor = OriginalConsoleForeground;
}
private static void Main()
{
do
{
Console.Clear();
WholeProgram();
PrintLine();
RunInColor(ConsoleColor.Red, () => Console.WriteLine("Press 'e' to exit. Otherwise the program run's again."));
} while (Console.ReadLine()?.ToLower() != "e");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment