Created
June 14, 2013 16:27
-
-
Save Khubajsn/5783322 to your computer and use it in GitHub Desktop.
Twitach - Turtle WITh A CHalk.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| namespace Twitach | |
| { | |
| class TwitachException : Exception | |
| { | |
| public TwitachException(string message) : base(message) { } | |
| } | |
| class Command | |
| { | |
| public string Identifier; | |
| private List<Argument> Arguments; | |
| public static string[] Identifiers = new string[] { | |
| "forward", "left", "right", "pen", "color" | |
| }; | |
| public static bool IsValidIdentifier(string id) | |
| { | |
| return Command.Identifiers.Contains(id); | |
| } | |
| public T GetArgument<T>(int index) where T : struct | |
| { | |
| try | |
| { | |
| return (T)this.Arguments[index].Value; | |
| } | |
| catch | |
| { | |
| return default(T); | |
| } | |
| } | |
| public Command(string id, List<string> rawArguments) | |
| { | |
| id = id.ToLower(); | |
| if (!Command.IsValidIdentifier(id)) | |
| { | |
| throw new TwitachException("Unknown command identifier '" + id + "'"); | |
| } | |
| this.Identifier = id; | |
| this.Arguments = new List<Argument>(); | |
| foreach (string rawArgument in rawArguments) | |
| { | |
| this.Arguments.Add(new Argument(rawArgument)); | |
| } | |
| } | |
| public override string ToString() | |
| { | |
| if (this.Identifier == null) | |
| { | |
| throw new InvalidOperationException("Command.ToString was called, whilst the command's identifier is null."); | |
| } | |
| if (this.Arguments.Count == 0) | |
| { | |
| return this.Identifier + "(void)"; | |
| } | |
| else | |
| { | |
| return this.Identifier + "(" + String.Join(",", this.Arguments) + ")"; | |
| } | |
| } | |
| } | |
| class Argument | |
| { | |
| public object Value; | |
| public Type ValueType; | |
| public Argument(string value) | |
| { | |
| bool isString = false; | |
| foreach (char c in value) | |
| { | |
| if (!Char.IsDigit(c)) | |
| { | |
| isString = false; | |
| break; | |
| } | |
| } | |
| if (isString) | |
| { | |
| this.Value = value; | |
| this.ValueType = Type.GetType("System.String"); | |
| } | |
| else | |
| { | |
| try | |
| { | |
| this.Value = Convert.ToInt32(value); | |
| this.ValueType = Type.GetType("System.Int32"); | |
| } | |
| catch (System.FormatException) | |
| { | |
| throw new TwitachException("Argument value '" + value + "' was found to be integer, however, Convert.ToInt32 has thrown a System.FormatException."); | |
| } | |
| } | |
| } | |
| public override string ToString() | |
| { | |
| return (string)this.Value; | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.ComponentModel; | |
| using System.Data; | |
| using System.Drawing; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Windows.Forms; | |
| using System.IO; | |
| namespace Twitach | |
| { | |
| public partial class TwitachForm : Form | |
| { | |
| public TwitachForm() | |
| { | |
| InitializeComponent(); | |
| } | |
| private void Form1_Load(object sender, EventArgs e) | |
| { | |
| Bitmap b = new Bitmap(700, 700); | |
| this.pictureBox1.Image = b; | |
| } | |
| private void loadScriptFromFileButton_Click(object sender, EventArgs e) | |
| { | |
| Lexer l = new Lexer(); | |
| l.Commands.Clear(); | |
| FileStream fs = new FileStream("D:\\inputs\\twitach1.txt", FileMode.Open); | |
| try | |
| { | |
| l.Lex(fs); | |
| Renderer.Commands = l.Commands; | |
| Renderer.Position = new TurtlePos(); | |
| Renderer.Angle = new TurtleAngle(); | |
| Renderer.RenderSteps(1000, Graphics.FromImage(this.pictureBox1.Image)); | |
| this.pictureBox1.Invalidate(); | |
| } | |
| finally | |
| { | |
| fs.Close(); | |
| } | |
| } | |
| private void button1_Click(object sender, EventArgs e) | |
| { | |
| this.pictureBox1.Invalidate(); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.IO; | |
| using System.Diagnostics; | |
| namespace Twitach | |
| { | |
| class Lexer | |
| { | |
| public List<Command> Commands = new List<Command>(); | |
| public void Lex(Stream s) | |
| { | |
| string buffer = ""; | |
| string identifier = ""; | |
| List<string> arguments = new List<string>(); | |
| int lineNumber = 1; | |
| int caretPosition = 0; | |
| LexerAction currentAction = LexerAction.None; | |
| StreamReader sr = new StreamReader(s); | |
| while (!sr.EndOfStream) | |
| { | |
| char c = (char)sr.Read(); | |
| char nextChar = (char)sr.Peek(); | |
| caretPosition++; | |
| if (c == '\n') | |
| { | |
| lineNumber++; | |
| caretPosition = 0; | |
| } | |
| if (currentAction == LexerAction.None) | |
| { | |
| if (Char.IsLetter(c)) { | |
| currentAction = LexerAction.ReadingIdentifier; | |
| buffer += c; | |
| } | |
| else if (Char.IsWhiteSpace(c)) | |
| { | |
| continue; | |
| } | |
| else | |
| { | |
| throw new LexerException("Character not allowed here - at line " + lineNumber + " character " + caretPosition + ": '" + c + "'."); | |
| } | |
| } | |
| else if (currentAction == LexerAction.ReadingIdentifier) | |
| { | |
| if (Char.IsLetter(c)) | |
| { | |
| buffer += c; | |
| } | |
| else if (Char.IsWhiteSpace(c)) { | |
| continue; | |
| } | |
| else if (c == '(') | |
| { | |
| identifier = buffer; | |
| buffer = ""; | |
| currentAction = LexerAction.ReadingArguments; | |
| } | |
| else | |
| { | |
| throw new LexerException("Expected letter, got '" + c + "' - line " + lineNumber + " character " + caretPosition + " instead of '" + c + "'."); | |
| } | |
| } | |
| else if (currentAction == LexerAction.ReadingArguments) | |
| { | |
| if (Char.IsLetterOrDigit(c) || c == '-' || c == '+') | |
| { | |
| buffer += c; | |
| } | |
| else if (c == ',') | |
| { | |
| arguments.Add(buffer); | |
| buffer = ""; | |
| } | |
| else if (c == ')') | |
| { | |
| if (buffer.Length > 0) // If the command only receives one argument, it's still in the buffer. | |
| { | |
| arguments.Add(buffer); | |
| } | |
| this.Commands.Add(new Command(identifier, arguments)); | |
| buffer = ""; | |
| identifier = ""; | |
| arguments.Clear(); | |
| currentAction = LexerAction.None; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| enum LexerAction | |
| { | |
| None, | |
| ReadingIdentifier, | |
| ReadingArguments | |
| } | |
| class LexerException : Exception { | |
| public LexerException(string message) : base(message) { } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections.Generic; | |
| using System.Linq; | |
| using System.Text; | |
| using System.Drawing; | |
| namespace Twitach | |
| { | |
| class Renderer | |
| { | |
| public static List<Command> Commands; | |
| public static TurtlePos Position; | |
| public static TurtleAngle Angle; | |
| public static Pen Pen = Pens.Black; | |
| public static bool PenActive; | |
| public static Graphics G; | |
| public static void RenderSteps(int stepsAmount, Graphics g) | |
| { | |
| Renderer.Position = new TurtlePos(); | |
| Renderer.Angle = new TurtleAngle(); | |
| Renderer.PenActive = false; | |
| Renderer.Pen = Pens.Black; | |
| Renderer.G = g; | |
| Renderer.G.FillRectangle(Brushes.White, 0, 0, 700, 700); | |
| if (Renderer.Commands == null) | |
| { | |
| return; | |
| } | |
| foreach (Command cmd in Renderer.Commands) | |
| { | |
| if (cmd.Identifier == "pen") | |
| { | |
| Renderer.PenActive = cmd.GetArgument<int>(0) > 0; | |
| Renderer.Pen = new Pen(Renderer.Pen.Color, cmd.GetArgument<int>(0)); | |
| } | |
| else if (cmd.Identifier == "color") | |
| { | |
| Renderer.Pen = new Pen(Color.FromArgb(cmd.GetArgument<int>(0), cmd.GetArgument<int>(1), cmd.GetArgument<int>(2)), Renderer.Pen.Width); | |
| } | |
| else if (cmd.Identifier == "forward") | |
| { | |
| Renderer.Move(cmd.GetArgument<int>(0)); | |
| } | |
| else if (cmd.Identifier == "left" || cmd.Identifier == "right") | |
| { | |
| Renderer.Angle.RotateByDegrees((cmd.Identifier == "left" ? 1 : -1) * cmd.GetArgument<int>(0)); | |
| } | |
| } | |
| } | |
| private static void Move(int px) | |
| { | |
| double targetX = Renderer.Position.x + (px * Math.Cos(Renderer.Angle.Radians)); | |
| double targetY = Renderer.Position.y - (px * Math.Sin(Renderer.Angle.Radians)); | |
| if (Renderer.PenActive) | |
| { | |
| int tx = (int)Math.Round(targetX); | |
| int ty = (int)Math.Round(targetY); | |
| Renderer.G.DrawLine(Renderer.Pen, Renderer.Position.ToPoint(), new Point(tx, ty)); | |
| } | |
| Renderer.Position.x = targetX; | |
| Renderer.Position.y = targetY; | |
| } | |
| } | |
| public class TurtlePos | |
| { | |
| public double x = 350.0; | |
| public double y = 350.0; | |
| public Point ToPoint() | |
| { | |
| return new Point((int)Math.Round(this.x), (int)Math.Round(this.y)); | |
| } | |
| } | |
| public class TurtleAngle | |
| { | |
| public int Degrees; | |
| public double Radians; | |
| public TurtleAngle() | |
| { | |
| this.Degrees = 90; | |
| this.Radians = 0.0; | |
| this.RecalculateRadians(); | |
| } | |
| private void RecalculateRadians() | |
| { | |
| this.Radians = this.Degrees * Math.PI / 180; | |
| } | |
| public void RotateByDegrees(int degreesAmount) | |
| { | |
| if (degreesAmount < 0) | |
| { | |
| degreesAmount = Math.Abs(degreesAmount); | |
| if ((this.Degrees - degreesAmount) >= 0) | |
| { | |
| this.Degrees -= degreesAmount; | |
| } | |
| else | |
| { | |
| this.Degrees = 360 - Math.Abs(degreesAmount - this.Degrees); | |
| } | |
| } | |
| else | |
| { | |
| this.Degrees = this.Degrees + degreesAmount; | |
| } | |
| this.Degrees %= 360; | |
| this.RecalculateRadians(); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment