using System; using Cairo; using System.Text.RegularExpressions; using System.Resources; using System.Collections.Generic; namespace SBRL.SimpleTurtle { public class Area { public double X; public double Y; public double Width; public double Height; public Area(double inX, double inY, double inWidth, double inHeight) { X = inX; Y = inY; Width = inWidth; Height = inHeight; } } public class Turtle { private bool strictMode = false; private string commandQueue; private PointD position; private Area bounds; private double heading; private double headingStep; public double HeadingStep { get { return headingStep; } set { headingStep = value; } } private double movementStep ; public double MovementStep { get { return movementStep; } set { movementStep = value; } } public Turtle () { Reset(); } public void ApplyDefinitions(Dictionary definitions) { foreach(KeyValuePair definition in definitions) { switch(definition.Key.ToLower()) { case "angle": HeadingStep = double.Parse(definition.Value); break; } } } public bool Commands(string commandText) { // Remove all whitespace commandText = Regex.Replace(commandText, @"\s+", ""); commandText = commandText.Replace("h", "f"); string okCommands = "f+-"; foreach(char ch in commandText) { if(okCommands.Contains(ch.ToString())) { switch(ch) { case 'f': Forwards(); break; case '+': Turn(false); break; case '-': Turn(true); break; default: if (strictMode) { Console.WriteLine("The unexpected character '{0}' slipped through the net!", ch); return false; } break; } } else if(strictMode) { Console.Error.WriteLine("Error: unexpected character '{0}'", ch); return false; } } commandQueue += commandText; return true; } public void Draw(string filename, bool reset = true) { ImageSurface canvas = new ImageSurface(Format.ARGB32, (int)Math.Ceiling(bounds.Width + 10), (int)Math.Ceiling(bounds.Height + 10)); Context context = new Context(canvas); position = new PointD(-bounds.X + 5, -bounds.Y + 5); heading = 0; context.LineWidth = 3; context.MoveTo(position); foreach(char ch in commandQueue) { switch(ch) { case 'f': PointD newPosition = new PointD( position.X + movementStep * Math.Sin(heading), position.Y + movementStep * Math.Cos(heading) ); context.LineTo(newPosition); position = newPosition; break; case '+': heading += headingStep; break; case '-': heading -= headingStep; break; } } context.Stroke(); canvas.WriteToPng(string.Format(filename)); context.Dispose(); canvas.Dispose(); if(reset) Reset(); } public void Forwards() { PointD newPosition = new PointD( position.X + MovementStep * Math.Sin(heading), position.Y + MovementStep * Math.Cos(heading) ); if (newPosition.X > bounds.X + bounds.Width) bounds.Width += newPosition.X - position.X; if (newPosition.Y > bounds.Y + bounds.Height) bounds.Height += newPosition.Y - position.Y; if (newPosition.X < bounds.X) { bounds.X = newPosition.X; bounds.Width += position.X - newPosition.X; } if (newPosition.Y < bounds.Y) { bounds.Y = newPosition.Y; bounds.Height += position.Y - newPosition.Y; } position = newPosition; } public void Turn(bool anticlockwise = false) { if (!anticlockwise) heading += HeadingStep; else heading -= HeadingStep; } public void Reset() { commandQueue = string.Empty; position = new PointD(0, 0); bounds = new Area(position.X, position.Y, 1, 1); heading = 0; headingStep = Math.PI / 2; movementStep = 25; } } }