ภาษาที่พิมพ์ ASCII ของ Tarmo ขนาด 46 ไบต์ (ที่ไม่ใช่การแข่งขัน)
1 /\| /_/\|/__\_\2 \__|/ 0n{n-a-1{~}1a{2#1}$}
เพียงแค่มองไปที่ภาษาโปรแกรมแปลก ๆ เช่น CJam มันทำให้ฉันรู้สึกเวียนหัวว่าภาษาที่แปลกประหลาดและเป็นความลับสามารถที่ฉันต้องการ "กล้าไปในที่ที่ไม่มีใครมาก่อน" และประดิษฐ์ภาษาของตัวเอง ด้วยเหตุนี้ฉันจึงสร้างภาษาของฉันเองสำหรับการพิมพ์รูปแบบ ascii
แนวคิดพื้นฐานคือคุณสามารถกำหนดเสื้อก่อนแล้วพิมพ์โดยใช้อักขระชนิดเดียวกัน '1' หรือ '2' หรือตัวเลขใดก็ได้คุณสามารถกำหนดรูปแบบการพิมพ์ของคุณเอง
เมื่อกำหนดรูปแบบแล้ว (เริ่มจากตัวเลขจนถึงจุดสิ้นสุด) - หมายเลขถัดไปจะทำการพิมพ์รูปแบบ
ตัวอย่างเช่น
1 /\| /_/\|/__\_\01
ผลลัพธ์เช่นนี้
/\
/_/\
/__\_\
จะกำหนดรูปแบบ 1 แล้วพิมพ์ทันที รูปแบบถูกกำหนดทุกอย่างคั่นด้วย '|' ตัวละคร 0 ที่ส่วนท้าย - ทำหน้าที่เหมือนการยกเลิกรูปแบบ
อักขระพิเศษเช่น '$' ถูกสงวนไว้เป็น line-feed และ '~' ถูกสงวนไว้สำหรับการเว้นวรรค - ครึ่ง - ของรูปแบบเฉพาะ
1 /\| /_/\|/__\_\01$~11$~1~11
จะแสดงผลข้อความเช่นนี้:
/\
/_/\
/__\_\
/\
/_/\
/__\_\
/\
/_/\
/__\_\
ถัดไปไปสำหรับลูป อันนั้นต้องมองเห็นได้ง่าย - ดังนั้นฉันจึงได้วงเล็บ {} ไว้สำหรับ for-loops แต่ชื่อตัวแปรนั้นตั้งชื่อโดยอัตโนมัติ - ดังนั้นวงเล็บแรกจะใช้ 'a' ตัวแปรที่สอง 'b' เป็นต้น การวนซ้ำจะเริ่มจาก 0 ถึงจำนวนเฉพาะเสมอและจะมีการกำหนดหมายเลขนั้นไว้หน้าวงเล็บปีกกา {}
'n' เป็นตัวแปรที่สงวนไว้สำหรับอินพุตฟังก์ชันทั้งหมด
ดังนั้นรหัส:
1 /\| /_/\|/__\_\0n{1$}
จะส่งออก (ด้วย n == 4):
/\
/_/\
/__\_\
/\
/_/\
/__\_\
/\
/_/\
/__\_\
/\
/_/\
/__\_\
และ '#' เป็นตัวดัดแปลงพิเศษสำหรับช่องว่างการตัดตะกั่ว
และในที่สุดการแก้ปัญหาทั้งหมด:
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
}
ด้วยอาร์กิวเมนต์บรรทัดคำสั่งเช่นนี้: -d "1 / \ | / _ / \ | / ___ \ 2 __ | / 0n {na-1 {½} 1a {2 # 1} $}" 3
จะให้ผลลัพธ์นี้:
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: } };
/\
/_/\
/__\_\
/\ \__/\
/_/\/ /_/\
/__\_\/__\_\
/\ \__/\ \__/\
/_/\/ /_/\/ /_/\
/__\_\/__\_\/__\_\