Files
basic-computer-games/06_Banner/csharp/banner.cs
Martin Thoma e64fb6795c MAINT: Apply pre-commit
Remove byte-order-marker pre-commit check as there would be
many adjustments necessary
2022-03-05 09:29:23 +01:00

252 lines
10 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
namespace banner
{
class Banner
{
private int Horizontal { get; set; }
private int Vertical { get; set; }
private bool Centered { get; set; }
private string Character { get; set; }
private string Statement { get; set; }
// This provides a bit-ended representation of each symbol
// that can be output. Each symbol is defined by 7 parts -
// where each part is an integer value that, when converted to
// the binary representation, shows which section is filled in
// with values and which are spaces. i.e., the 'filled in'
// parts represent the actual symbol on the paper.
Dictionary<char, int[]> letters = new Dictionary<char, int[]>()
{
{' ', new int[] { 0, 0, 0, 0, 0, 0, 0 } },
{'A', new int[] {505, 37, 35, 34, 35, 37, 505} },
{'B', new int[] {512, 274, 274, 274, 274, 274, 239} },
{'C', new int[] {125, 131, 258, 258, 258, 131, 69} },
{'D', new int[] {512, 258, 258, 258, 258, 131, 125} },
{'E', new int[] {512, 274, 274, 274, 274, 258, 258} },
{'F', new int[] {512, 18, 18, 18, 18, 2, 2} },
{'G', new int[] {125, 131, 258, 258, 290, 163, 101} },
{'H', new int[] {512, 17, 17, 17, 17, 17, 512} },
{'I', new int[] {258, 258, 258, 512, 258, 258, 258} },
{'J', new int[] {65, 129, 257, 257, 257, 129, 128} },
{'K', new int[] {512, 17, 17, 41, 69, 131, 258} },
{'L', new int[] {512, 257, 257, 257, 257, 257, 257} },
{'M', new int[] {512, 7, 13, 25, 13, 7, 512} },
{'N', new int[] {512, 7, 9, 17, 33, 193, 512} },
{'O', new int[] {125, 131, 258, 258, 258, 131, 125} },
{'P', new int[] {512, 18, 18, 18, 18, 18, 15} },
{'Q', new int[] {125, 131, 258, 258, 322, 131, 381} },
{'R', new int[] {512, 18, 18, 50, 82, 146, 271} },
{'S', new int[] {69, 139, 274, 274, 274, 163, 69} },
{'T', new int[] {2, 2, 2, 512, 2, 2, 2} },
{'U', new int[] {128, 129, 257, 257, 257, 129, 128} },
{'V', new int[] {64, 65, 129, 257, 129, 65, 64} },
{'W', new int[] {256, 257, 129, 65, 129, 257, 256} },
{'X', new int[] {388, 69, 41, 17, 41, 69, 388} },
{'Y', new int[] {8, 9, 17, 481, 17, 9, 8} },
{'Z', new int[] {386, 322, 290, 274, 266, 262, 260} },
{'0', new int[] {57, 69, 131, 258, 131, 69, 57} },
{'1', new int[] {0, 0, 261, 259, 512, 257, 257} },
{'2', new int[] {261, 387, 322, 290, 274, 267, 261} },
{'3', new int[] {66, 130, 258, 274, 266, 150, 100} },
{'4', new int[] {33, 49, 41, 37, 35, 512, 33} },
{'5', new int[] {160, 274, 274, 274, 274, 274, 226} },
{'6', new int[] {194, 291, 293, 297, 305, 289, 193} },
{'7', new int[] {258, 130, 66, 34, 18, 10, 8} },
{'8', new int[] {69, 171, 274, 274, 274, 171, 69} },
{'9', new int[] {263, 138, 74, 42, 26, 10, 7} },
{'?', new int[] {5, 3, 2, 354, 18, 11, 5} },
{'*', new int[] {69, 41, 17, 512, 17, 41, 69} },
{'=', new int[] {41, 41, 41, 41, 41, 41, 41} },
{'!', new int[] {1, 1, 1, 384, 1, 1, 1} },
{'.', new int[] {1, 1, 129, 449, 129, 1, 1} }
};
/// <summary>
/// This displays the provided text on the screen and then waits for the user
/// to enter a integer value greater than 0.
/// </summary>
/// <param name="DisplayText">Text to display on the screen asking for the input</param>
/// <returns>The integer value entered by the user</returns>
private int GetNumber(string DisplayText)
{
Console.Write(DisplayText);
string TempStr = Console.ReadLine();
Int32.TryParse(TempStr, out int TempInt);
if (TempInt <= 0)
{
throw new ArgumentException($"{DisplayText} must be greater than zero");
}
return TempInt;
}
/// <summary>
/// This displays the provided text on the screen and then waits for the user
/// to enter a Y or N. It cheats by just looking for a 'y' and returning that
/// as true. Anything else that the user enters is returned as false.
/// </summary>
/// <param name="DisplayText">Text to display on the screen asking for the input</param>
/// <returns>Returns true or false</returns>
private bool GetBool(string DisplayText)
{
Console.Write(DisplayText);
return (Console.ReadLine().StartsWith("y", StringComparison.InvariantCultureIgnoreCase));
}
/// <summary>
/// This displays the provided text on the screen and then waits for the user
/// to enter an arbitrary string. That string is then returned 'as-is'.
/// </summary>
/// <param name="DisplayText">Text to display on the screen asking for the input</param>
/// <returns>The string entered by the user.</returns>
private string GetString(string DisplayText)
{
Console.Write(DisplayText);
return (Console.ReadLine().ToUpper());
}
/// <summary>
/// This queries the user for the various inputs needed by the program.
/// </summary>
private void GetInput()
{
Horizontal = GetNumber("Horizontal ");
Vertical = GetNumber("Vertical ");
Centered = GetBool("Centered ");
Character = GetString("Character (type 'ALL' if you want character being printed) ");
Statement = GetString("Statement ");
// We don't care about what the user enters here. This is just telling them
// to set the page in the printer.
_ = GetString("Set page ");
}
/// <summary>
/// This prints out a single character of the banner - adding
/// a few blanks lines as a spacer between characters.
/// </summary>
private void PrintChar(char ch)
{
// In the trivial case (a space character), just print out the spaces
if (ch.Equals(' '))
{
Console.WriteLine(new string('\n', 7 * Horizontal));
return;
}
// If a specific character to be printed was provided by the user,
// then user that as our ouput character - otherwise take the
// current character
char outCh = Character == "ALL" ? ch : Character[0];
int[] letter = new int[7];
try
{
letters[outCh].CopyTo(letter, 0);
}
catch (KeyNotFoundException)
{
throw new KeyNotFoundException($"The provided letter {outCh} was not found in the letters list");
}
// This iterates through each of the parts that make up
// each letter. Each part represents 1 * Horizontal lines
// of actual output.
for (int idx = 0; idx < 7; idx++)
{
// New int array declarations default to zeros
// numSections decides how many 'sections' need to be printed
// for a given line of each character
int[] numSections = new int[7];
// fillInSection decides whether each 'section' of the
// character gets filled in with the character or with blanks
int[] fillInSection = new int[9];
// This uses the value in each part to decide which
// sections are empty spaces in the letter or filled in
// spaces. For each section marked with 1 in fillInSection,
// that will correspond to 1 * Vertical characters actually
// being output.
for (int exp = 8; exp >= 0; exp--)
{
if (Math.Pow(2, exp) < letter[idx])
{
fillInSection[8 - exp] = 1;
letter[idx] -= (int)Math.Pow(2, exp);
if (letter[idx] == 1)
{
// Once we've exhausted all of the sections
// defined in this part of the letter, then
// we marked that number and break out of this
// for loop.
numSections[idx] = 8 - exp;
break;
}
}
}
// Now that we know which sections of this part of the letter
// are filled in or spaces, we can actually create the string
// to print out.
string lineStr = "";
if (Centered)
lineStr += new string(' ', (int)(63 - 4.5 * Vertical) * 1 / 1 + 1);
for (int idx2 = 0; idx2 <= numSections[idx]; idx2++)
{
lineStr = lineStr + new string(fillInSection[idx2] == 0 ? ' ' : outCh, Vertical);
}
// Then we print that string out 1 * Horizontal number of times
for (int lineidx = 1; lineidx <= Horizontal; lineidx++)
{
Console.WriteLine(lineStr);
}
}
// Finally, add a little spacer after each character for readability.
Console.WriteLine(new string('\n', 2 * Horizontal - 1));
}
/// <summary>
/// This prints the entire banner based in the parameters
/// the user provided.
/// </summary>
private void PrintBanner()
{
// Iterate through each character in the statement
foreach (char ch in Statement)
{
PrintChar(ch);
}
// In the original version, it would print an additional 75 blank
// lines in order to feed the printer paper...don't really need this
// since we're not actually printing.
// Console.WriteLine(new string('\n', 75));
}
/// <summary>
/// Main entry point into the banner class and handles the main loop.
/// </summary>
public void Play()
{
GetInput();
PrintBanner();
}
}
class Program
{
static void Main(string[] args)
{
new Banner().Play();
}
}
}