#Tarmo's ascii printing language, 46 bytes.
1 /\| /_/\|/__\_\2 \__|/ 0n{n-a-1{~}1a{2#1}$}
Just by looking to such odd programming languages like CJam, it's makes me bit dizzy how complex, unnatural and cryptic language can be, that I wanted to "boldly go where no man has gone before", and invent my own language. As a result I've created my own language for ascii patterns printing.
Basic idea is that you can define first patten and then printing - using same kind of character '1' or '2' or whatever number - you can define your own print pattern.
Once pattern is defined (Starts from number till number end) - next numbers will execute pattern printing.
For example
1 /\| /_/\|/__\_\01
Outputs like this:
/\ /_/\ /__\_\
Will define pattern 1 and then print it right away. Pattern is defined everything separated with '|' character. 0 at the end - acts like pattern termination.
Special characters like '$' are reserved as line-feed, and '~' is reserved for spacing - half - of specific pattern.
1 /\| /_/\|/__\_\01$~11$~1~11
Will outputs text like this:
/\ /_/\ /__\_\ /\ /_/\ /__\_\ /\ /_/\ /__\_\
Next goes for-loops. That one needs to be easily visible - so I've retained {} brackets for for-loops, but variable names are auto-named - so first bracket will use 'a' variable, second 'b' and so on. Iteration will go always from 0 to specific number - and that number is defined before {} brackets.
'n' is reserved variable for whole function input.
So code:
1 /\| /_/\|/__\_\0n{1$}
Will outputs ( With n == 4 ):
/\ /_/\ /__\_\ /\ /_/\ /__\_\ /\ /_/\ /__\_\ /\ /_/\ /__\_\
And '#' is special modifier for trim lead whitespace.
And finally whole solution:
DrawPatterns.cs:
using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using Microsoft.CSharp; class DrawPatterns { //Command line parameters - for example like this: "1 /\| /_/\|/__\_\2 \__|/ 0n{n-a-1{~}1a{2#1}$}" 3 static Dictionary<char, String[]> patterns = new Dictionary<char,string[]>(); static string Tabs(int n) { if( n < 0 ) n = 0; String r = ""; for( int i = 0; i < n ; i++ ) r += " "; return r; } static int[] left = new int[10]; static int top = Console.CursorTop; static int lastTop = Console.CursorTop; static public void DoPrint(char c, char modifier = ' ') { if (c == '$') { for (int i = 0; i < left.Length; i++) left[i] = 0; top = lastTop + 1; return; } if (!patterns.ContainsKey(c)) return; if (modifier == '½' || modifier == '~') { int maxSize = patterns[c].Select(x => x.Length).Max(); for( int i = 0; i < left.Length; i++ ) left[i] += maxSize / 2; return; } int iLine = 0; foreach (var l in patterns[c]) { Console.SetCursorPosition(left[iLine], top + iLine); if( top + iLine > lastTop ) lastTop = top + iLine; String s = l; if (modifier == '#') s = s.TrimStart(' '); Console.WriteLine(s); left[iLine] += s.Length; iLine++; } } static void Main(string[] _args) { List<String> args = _args.ToList(); String todo = ""; String code = ""; char nextVar = 'a'; String lf = "\r\n"; int align = 1; char lastModifier = ' '; int nextArg = 1; Dictionary<String, String> argValues = new Dictionary<string,string>(); bool bDebug = false; if (args.Count != 0 && args[0].ToLower() == "-d") { bDebug = true; args.RemoveAt(0); } if (args.Count == 0) { Console.WriteLine("Usage: DrawPatterns.cs [options] \"script\" <arguments to script>"); Console.WriteLine("[options] allowed:"); Console.WriteLine("-d - debug"); return; } String prog = args[0]; for( int i = 0; i < prog.Length; i++ ) { char c = prog[i]; // Define pattern. if (c >= '0' && c <= '9' && !patterns.ContainsKey(c)) { String p = Regex.Match(prog.Substring(i + 1), "[^0-9]*").Groups[0].Value; patterns[c] = p.Split('|'); i += p.Length; if( prog[i + 1] == '0' ) i++; continue; } String procRemain = prog.Substring(i); // modifier specified, but pattern number is not provided - use first pattern. if( lastModifier != ' ' && ( c < '0' || c > '9' ) ) { code += Tabs(align); code += "print('1' , '" + lastModifier + "');" + lf; lastModifier = ' '; } switch ( c ) { case '{': code += Tabs(align); code += "for ( int " + nextVar + " = 0; " + nextVar + " < " + todo + " ; " + nextVar + "++ )" + lf; // Check for all variable names if they can be used in program. foreach ( var m in Regex.Matches(todo, "[a-zA-Z_][a-zA-Z0-9_]*", RegexOptions.Singleline) ) { String varName = m.ToString(); if( varName.Length == 1 && varName[0] <= nextVar ) // Already declared as a loop. continue; if( argValues.ContainsKey(varName ) ) continue; if( nextArg >= args.Count ) { Console.WriteLine("Insufficient parameters provided to script - argument '" + varName + "' value is needed"); return; } argValues[varName] = args[nextArg]; nextArg++; } code += Tabs(align); code += "{" + lf; nextVar++; todo = ""; align++; break; case '}': align--; code += Tabs(align); code += "}" + lf; break; default: if (((c >= '0' && c <= '9') || c == '<' || c == '$') && todo == "") { code += Tabs(align); code += "print('" + c + "' , '" + lastModifier + "');" + lf; lastModifier = ' '; continue; } if (c == '½' || c == '~' || c == '#') { lastModifier = c; continue; } if( c == '\r' || c == '\n' ) continue; todo += c; break; } } //for String code2 = ""; code2 += "using System;" + lf; code2 += "public class ExecClass { static void Exec( Action<char, char> print"; object[] invokeArgs = new object[ argValues.Count+1]; invokeArgs[0] = new Action<char, char>(DoPrint); int iValueIndex = 1; foreach ( var kv in argValues ) { code2 += ","; code2 += "int " + kv.Key; invokeArgs[iValueIndex] = Int32.Parse(kv.Value); iValueIndex++; } code2 += ") {" + lf; code2 += code; code2 += "} };"; if( bDebug ) { int line = 1; String lineNumberedCode =Regex.Replace(code2, "^(.*)$", delegate(Match m) { return (line++).ToString("d2") + ": " + m.Value; }, RegexOptions.Multiline ); Console.WriteLine(lineNumberedCode); Console.WriteLine(); Console.WriteLine(); } left[0] = Console.CursorLeft; for( int i = 1; i < left.Length; i++ ) left[i] = left[0]; top = Console.CursorTop; try { var compileResult = new CSharpCodeProvider().CompileAssemblyFromSource( new CompilerParameters() { GenerateExecutable = false, GenerateInMemory = true }, code2); if (compileResult.Errors.HasErrors) { foreach (CompilerError ce in compileResult.Errors) { if (ce.IsWarning) continue; Console.WriteLine("{0}({1},{2}: error {3}: {4}", ce.FileName, ce.Line, ce.Column, ce.ErrorNumber, ce.ErrorText); } return; } var method = compileResult.CompiledAssembly.GetType("ExecClass").GetMethod("Exec", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); method.Invoke(null, invokeArgs); } catch (Exception ex) { Console.WriteLine(ex.Message); } Console.SetCursorPosition(1, lastTop); Console.WriteLine(); Console.WriteLine(); } //Main }
With command line arguments like this: -d "1 /| //|/___\2 _|/ 0n{n-a-1{½}1a{2#1}$}" 3
Will outputs this:
01: using System; 02: public class ExecClass { static void Exec( Action<char, char> print,int n) { 03: for ( int a = 0; a < n ; a++ ) 04: { 05: for ( int b = 0; b < n-a-1 ; b++ ) 06: { 07: print('1' , '~'); 08: } 09: print('1' , ' '); 10: for ( int c = 0; c < a ; c++ ) 11: { 12: print('2' , ' '); 13: print('1' , '#'); 14: } 15: print('$' , ' '); 16: } 17: } }; /\ /_/\ /__\_\ /\ \__/\ /_/\/ /_/\ /__\_\/__\_\ /\ \__/\ \__/\ /_/\/ /_/\/ /_/\ /__\_\/__\_\/__\_\