LSystemEngine/SimpleTurtle/Turtle.cs

187 lines
3.9 KiB
C#
Executable File

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<string, string> definitions)
{
foreach(KeyValuePair<string, string> 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;
}
}
}