sl4v
sl4v

Reputation: 21

Problems when displaying ASCII art letters in C#

Code

namespace testasciiart
{
    class MainClass
    {
        public static string a()
        {
            string astring = String.Empty;
            string[] aarray =
            {
                "_____   ",
                "\\__  \\  ",
                " / __ \\_",
                "(____  /",
                "     \\/ "
            };
            for (int i = 0; i < aarray.Length; i++)
            {
                astring += aarray[i] + "\n";
            };
            return astring;
        }

        public static string b()
        {
            string bstring = String.Empty;
            string[] barray =
            {
                "___.    ",
                "\\_ |__  ",
                " | __ \\ ",
                " | \\_\\ \\",
                " |___  /",
                "     \\/ "
            };
            for (int i = 0; i < barray.Length; i++)
            {
                bstring += barray[i] + "\n";
            }
            return bstring;
        }


        public static void Main(string[] args)
        {
            Console.WriteLine(a() + b());
        }
    }
}

my problem is when i try to do:

Console.WriteLine(a() + b()); 

it comes out like the image below rather than printing the second letter after the first letter, on the same line.

enter image description here

how can i fix this?

Upvotes: 2

Views: 760

Answers (2)

TheGeneral
TheGeneral

Reputation: 81523

The problem is you need to join the letter at the array level. I.e Each array has several lines for the character, you need to join each of the lines. It makes sense really

Updated Approach

The advantage is you give it text, you can set up different font libraries

public interface IFont
{
   Dictionary<char, Func<string[]>> Mapping { get; }
}

public class MyFont : IFont
{
   public static string[] b = {
      "___.    ",
      "\\_ |__  ",
      " | __ \\ ",
      " | \\_\\ \\",
      " |___  /",
      "     \\/ "};

   public static string[] a = {
      "_____   ",
      "\\__  \\  ",
      " / __ \\_",
      "(____  /",
      "     \\/ "};

   public Dictionary<char, Func<string[]>> Mapping { get; } 
             = new Dictionary<char, Func<string[]>>{
                   { 'b', () => b},
                   { 'a', () => a}};     
}

Generic Join

public static string JoinLetters<T>(int space, string text)
   where T : class, IFont, new()
{
   var font = new T();

   // get the letters
   var arrays = text.ToCharArray()                      
                    .Where(x => font.Mapping.ContainsKey(x))
                    .Select(x => font.Mapping[x].Invoke())
                    .ToList();

   // get the max height and width
   var h = arrays.Max(x => x.Length);
   var w = arrays.Max(x => x.Max(y => y.Length)) + space;

   var result = new string[h];

   // join each letter    
   // if the letter is too short, add default width
   foreach (var array in arrays)
      for (var j = 0; j < h; j++)
         result[j] += (j >= array.Length ? " " : array[j]).PadRight(w);

   return string.Join(Environment.NewLine, result);
}

Usage

static void Main()
{
   Console.WriteLine(JoinLetters<MyFont>(2, "abba"));
}

Output

  _____     ___.      ___.      _____   
  \__  \    \_ |__    \_ |__    \__  \  
   / __ \_   | __ \    | __ \    / __ \_
  (____  /   | \_\ \   | \_\ \  (____  /
       \/    |___  /   |___  /       \/ 
                 \/        \/

Original Approach

A simple solution might be to describe your letters like this

public static string[] b()
{
   string[] barray =
      {
         "___.    ",
         "\\_ |__  ",
         " | __ \\ ",
         " | \\_\\ \\",
         " |___  /",
         "     \\/ "
      };
   return barray;
}

Use a join method

public static string JoinLetters(int space, params Func<string[]>[] args)
{
   // get the letters
   var arrays = args.Select(x => x.Invoke()).ToList();

   // get the max height
   var h = arrays.Max(x => x.Length);

   // get the max letter width
   var w = arrays.Max(x => x.Max(y => y.Length));

   var result = new string[h];

   // join each letter    
   foreach (var array in arrays)
      for (var j = 0; j < h; j++)
      {
         // Add padding space
         result[j] += new string(' ', space);

         // if the letter is too short, add default width
         if (j >= array.Length)
            result[j] += new string(' ', w);
         else
            result[j] += array[j].PadRight(w);
       }

   return string.Join(Environment.NewLine, result);
}

Usasge

public static void Main(string[] args)
{
   // note, the 2 is just a space between letters
   Console.WriteLine(JoinLetters(2, a, b, b, a));
}

Add pepper and salt to taste

Output

  _____     ___.      ___.      _____   
  \__  \    \_ |__    \_ |__    \__  \  
   / __ \_   | __ \    | __ \    / __ \_
  (____  /   | \_\ \   | \_\ \  (____  /
       \/    |___  /   |___  /       \/ 
                 \/        \/

Full Demo Here

Upvotes: 4

Rufus L
Rufus L

Reputation: 37050

Another alternative would be to manually set the cursor position in the console window each time you write a letter, which allows you to do other operations between writing letters, and still have them "joined" on the same line as you write them.

To begin with, let's make your letter arrays constants:

private static readonly string[] A =
{
    "_____   ",
    "\\__  \\  ",
    " / __ \\_",
    "(____  /",
    "     \\/ "
};

private static readonly string[] B =
{
    "___.    ",
    "\\_ |__  ",
    " | __ \\ ",
    " | \\_\\ \\",
    " |___  /",
    "     \\/ "
};

Now what we can do is write a method that draws a letter by writing each line of the array, but manually setting the cursor position to the next line (but at the same starting column) each time.

To do this, we can capture the initial values for the cursor, as well as the width of the longest line (so we can manually set the cursor at the end of the letter when we're done). Then, for each line, we just write the line, increment the top (which moves the cursor down), and set the cursor back to the starting "left" position.

At the end, we move the cursor back to the original top, and one space to the right of our longest line:

private static void DrawLetter(string[] letter)
{
    var top = Console.CursorTop;
    var left = Console.CursorLeft;
    var width = letter.Max(line => line.Length);

    foreach (var line in letter)
    {
        Console.Write(line);
        Console.SetCursorPosition(left, ++Console.CursorTop); // <- Increment top here
    }

    Console.SetCursorPosition(left + width + 1, top);
}

One other thing we may need is a method that sets our cursor at the next line. To do this, I've hard-coded 7 as the max rows a letter would have, plus one, and then set the cursor position down that many rows, and to the first column (0):

private static void DrawNewLine()
{
    Console.SetCursorPosition(0, 7);
}

Now we can write our letters like:

static void Main()
{
    DrawLetter(A);
    DrawLetter(B);
    DrawLetter(B);
    DrawLetter(A);

    DrawNewLine();

    GetKeyFromUser("\nPress any key to exit...");
}

Output

enter image description here

Now if we want to be fancy, we can write another method that takes a params argument (which allows a variable number of arguments to be sent to a method), which will write out many letters at once (calling our helper method above):

private static void DrawLetters(params string[][] letters)
{
    foreach (var letter in letters)
    {
        DrawLetter(letter);
    }
}

Using this method, our code above can now be replaced with:

static void Main()
{
    DrawLetters(A, B, B, A);

    DrawNewLine();

    GetKeyFromUser("\nPress any key to exit...");
}

Upvotes: 0

Related Questions