이보다 짧은 C # 3 버전을 얻을 수 없습니다. 나는 문자 수를 정확히 알지 못하지만 잃어버린 것 같습니다. :-(
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace PyramidRenderer
{
/// <summary>
/// Generates ASCII-art pyramids at user-specified horizontal locations to
/// the standard output stream.
/// </summary>
public class Program
{
/// <summary>
/// Generates one or more ASCII-art pyramids at the locations specified and
/// sends them to the standard output stream.
/// </summary>
/// <param name="args">The command-line arguments. These should be non-negative
/// integers that specify the horizontal distance of each additional pyramid from the
/// preceeding pyramid. Whether or not any distances are suppplied, a pyramid
/// is rendered at the starting location.</param>
public static void Main(string[] args)
{
try
{
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
int[] pyramidDistances = ParsePyramidLocationsFromCommandLine(args).ToArray();
PyramidCollection pyramids = new PyramidCollection(pyramidDistances);
pyramids.RenderToText(Console.Out);
}
catch (ArgumentException ex)
{
Console.Error.WriteLine(ex.Message);
}
}
/// <summary>
/// Handler for the unhandled exception. This just displays the error message to
/// the standard error stream.
/// </summary>
/// <param name="sender">Required but unnecessary sender object for the event handler.</param>
/// <param name="e">The object that represents the exception.</param>
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
Debug.Assert(e.ExceptionObject != null);
string exceptionText;
Exception ex = e.ExceptionObject as Exception;
if (ex == null)
exceptionText = e.ExceptionObject.ToString();
else
exceptionText = ex.Message;
Console.Error.WriteLine(exceptionText);
}
/// <summary>
/// Takes the command-line arguments and converts them to a sequence of
/// non-negative integers.
/// </summary>
/// <param name="args">The command-line arguments as supplied to Main.</param>
/// <returns>A sequence of integers that represent the user’s distance selections.</returns>
/// <exception cref="ArgumentException">An invalid argument was supplied.</exception>
private static IEnumerable<int> ParsePyramidLocationsFromCommandLine(string[] args)
{
Debug.Assert(args != null);
foreach (string arg in args)
{
int result;
if (int.TryParse(arg, out result))
{
if (result < 0)
throw new ArgumentException(string.Format("Invalid distance specified: {0}", arg));
yield return result;
}
else
{
throw new ArgumentException(string.Format("Invalid option: {0}", arg));
}
}
}
}
/// <summary>
/// Represents a single pyramid to be rendered.
/// </summary>
internal class Pyramid
{
/// <summary>
/// The height of the pyramids in text rows. The width of each pyramid will be
/// twice the height.
/// </summary>
internal const int Height = 10;
/// <summary>
/// The length in characters of the horizontal unit distance in which the user
/// specifies the pyramid distances.
/// </summary>
internal const int PyramidUnits = 2;
/// <summary>
/// The character to output as the background of the pyramids.
/// </summary>
private const char backgroundChar = ' ';
/// <summary>
/// The character to output as the left edge of the pyramids.
/// </summary>
private const char leftEdgeChar = '/';
/// <summary>
/// The character to output within each pyramid, between the edges.
/// </summary>
private const char brickChar = '-';
/// <summary>
/// The character to output as the right edge of the pyramids.
/// </summary>
private const char rightEdgeChar = '\\';
/// <summary>
/// The absolute horizonal location of the pyramid’s bottom left corner as
/// specified in PyramidUnits.
/// </summary>
private int position;
/// <summary>
/// Constructs a new pyramid object at the specified location.
/// </summary>
/// <param name="position">The absolute horizonal location of the pyramid’s bottom
/// left corner in PyramidUnits.</param>
internal Pyramid(int position)
{
Debug.Assert(position >= 0);
this.position = position;
}
/// <summary>
/// Renders a single row the pyramid to the supplied text stream starting at
/// the indicated location.
/// </summary>
/// <param name="textWriter">The output stream to which the pyramid is to
/// be rendered.</param>
/// <param name="row">The row of the pyramid to render. Zero is the top row,
/// and Height - 1 is the bottom row.</param>
/// <param name="startingPosition">The text character position—indexed at zero—at
/// which the rendering is to begin. If non-zero, this identifies the column one
/// past the ending location of the previous pyramid.</param>
/// <returns>The horizontal location (in characters) at which the next item
/// may be rendered.</returns>
internal int RenderRow(TextWriter textWriter, int row, int startingPosition)
{
Debug.Assert(textWriter != null);
Debug.Assert(row >= 0);
Debug.Assert(startingPosition >= 0);
int leftBoundary = Height - 1 - row + position * PyramidUnits;
int rightBoundary = Height + row + position * PyramidUnits;
startingPosition = RenderField(textWriter, backgroundChar, startingPosition, leftBoundary);
startingPosition = RenderField(textWriter, leftEdgeChar, startingPosition, leftBoundary + 1);
startingPosition = RenderField(textWriter, brickChar, startingPosition, rightBoundary);
startingPosition = RenderField(textWriter, rightEdgeChar, startingPosition, rightBoundary + 1);
return startingPosition;
}
/// <summary>
/// Outputs a sequence of repeated characters from the indicated starting position to
/// just before the ending position, unless the starting position is already equal to
/// or greater than the ending position.
/// </summary>
/// <param name="textWriter">The output stream to which the field is to be rendered.</param>
/// <param name="character">The character to be repeated in the output.</param>
/// <param name="startingPosition">The location at which rendering may begin in
/// characters indexed at zero.</param>
/// <param name="endingPosition">The location one past the location at which rendering
/// is to end.</param>
/// <returns>The position at which the next field may begin.</returns>
private static int RenderField(TextWriter textWriter, char character, int startingPosition, int endingPosition)
{
Debug.Assert(textWriter != null);
Debug.Assert(startingPosition >= 0);
Debug.Assert(endingPosition >= 0);
int charCount = endingPosition - startingPosition;
if (charCount <= 0)
return startingPosition;
textWriter.Write(new string(character, charCount));
return endingPosition;
}
}
/// <summary>
/// A collection of pyramids to be displayed.
/// </summary>
internal class PyramidCollection
{
/// <summary>
/// A left-to-right ordered list of the pyramids that the user has
/// requested to be rendered.
/// </summary>
List<Pyramid> allPyramids = new List<Pyramid>();
/// <summary>
/// Constructs a new pyramid collection.
/// </summary>
/// <param name="distances">The distances of each non-leftmost pyramid (in PyramidUnits) after
/// the previous pyramid. The total number of pyramids will be one greater than the length of
/// the distances array.</param>
internal PyramidCollection(int[] distances)
{
Debug.Assert(distances != null);
int nextPosition = 0;
allPyramids.Add(new Pyramid(nextPosition));
foreach (int nextDistance in distances)
{
Debug.Assert(nextDistance >= 0);
try
{
checked
{
nextPosition += nextDistance;
int endLocation = nextPosition * Pyramid.PyramidUnits + Pyramid.Height * 2;
}
}
catch (OverflowException)
{
// Ignore any pyramids specified beyond the integer maximum distance.
break;
}
allPyramids.Add(new Pyramid(nextPosition));
}
}
/// <summary>
/// Outputs ASCII-art images of the pyramids in this collection to the
/// provided output stream.
/// </summary>
/// <param name="textWriter">The output stream to which the pyramids
/// are to be rendered.</param>
internal void RenderToText(TextWriter textWriter)
{
Debug.Assert(textWriter != null);
for (int row = 0; row < Pyramid.Height; row++)
{
int startingPosition = 0;
foreach (Pyramid pyramid in allPyramids)
{
startingPosition = pyramid.RenderRow(textWriter, row, startingPosition);
}
textWriter.WriteLine();
}
}
}
}