mirror of
https://github.com/coding-horror/basic-computer-games.git
synced 2025-12-21 23:00:43 -08:00
252 lines
10 KiB
C#
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();
|
|
}
|
|
}
|
|
}
|