|
|
|
@ -6,44 +6,40 @@ using System.Collections.Generic;
@@ -6,44 +6,40 @@ using System.Collections.Generic;
|
|
|
|
|
|
|
|
|
|
namespace SBRL.SimpleTurtle |
|
|
|
|
{ |
|
|
|
|
public class Area |
|
|
|
|
{ |
|
|
|
|
public double X; |
|
|
|
|
public double Y; |
|
|
|
|
public double Width; |
|
|
|
|
public double Height; |
|
|
|
|
public class TurtleState : ICloneable { |
|
|
|
|
public PointD Position; |
|
|
|
|
public double Heading; |
|
|
|
|
|
|
|
|
|
public Area(double inX, double inY, double inWidth, double inHeight) |
|
|
|
|
{ |
|
|
|
|
X = inX; |
|
|
|
|
Y = inY; |
|
|
|
|
Width = inWidth; |
|
|
|
|
Height = inHeight; |
|
|
|
|
public TurtleState(PointD inPosition, double inHeading) { |
|
|
|
|
Position = inPosition; |
|
|
|
|
Heading = inHeading; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public object Clone() { |
|
|
|
|
return new TurtleState(Position, Heading); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public class Turtle |
|
|
|
|
{ |
|
|
|
|
private bool strictMode = false; |
|
|
|
|
public 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 readonly Stack<TurtleState> states = new Stack<TurtleState>(); |
|
|
|
|
public PointD Position { |
|
|
|
|
get => states.Peek().Position; |
|
|
|
|
protected set => states.Peek().Position = value; |
|
|
|
|
} |
|
|
|
|
private double movementStep ; |
|
|
|
|
public double MovementStep |
|
|
|
|
{ |
|
|
|
|
get { return movementStep; } |
|
|
|
|
set { movementStep = value; } |
|
|
|
|
public double Heading { |
|
|
|
|
get => states.Peek().Heading; |
|
|
|
|
protected set => states.Peek().Heading = value; |
|
|
|
|
} |
|
|
|
|
private Area bounds; |
|
|
|
|
|
|
|
|
|
public Turtle () |
|
|
|
|
{ |
|
|
|
|
public double HeadingStep { get; set; } |
|
|
|
|
public double MovementStep { get; set; } |
|
|
|
|
|
|
|
|
|
public Turtle () { |
|
|
|
|
Reset(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -83,15 +79,21 @@ namespace SBRL.SimpleTurtle
@@ -83,15 +79,21 @@ namespace SBRL.SimpleTurtle
|
|
|
|
|
case '-': |
|
|
|
|
Turn(true); |
|
|
|
|
break; |
|
|
|
|
case '[': |
|
|
|
|
Save(); |
|
|
|
|
break; |
|
|
|
|
case ']': |
|
|
|
|
Restore(); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
if (strictMode) { |
|
|
|
|
if (StrictMode) { |
|
|
|
|
Console.WriteLine("The unexpected character '{0}' slipped through the net!", ch); |
|
|
|
|
return false; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else if(strictMode) |
|
|
|
|
else if(StrictMode) |
|
|
|
|
{ |
|
|
|
|
Console.Error.WriteLine("Error: unexpected character '{0}'", ch); |
|
|
|
|
return false; |
|
|
|
@ -105,28 +107,28 @@ namespace SBRL.SimpleTurtle
@@ -105,28 +107,28 @@ namespace SBRL.SimpleTurtle
|
|
|
|
|
{ |
|
|
|
|
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; |
|
|
|
|
Position = new PointD(-bounds.X + 5, -bounds.Y + 5); |
|
|
|
|
Heading = 0; |
|
|
|
|
|
|
|
|
|
context.LineWidth = 3; |
|
|
|
|
context.MoveTo(position); |
|
|
|
|
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) |
|
|
|
|
Position.X + MovementStep * Math.Sin(Heading), |
|
|
|
|
Position.Y + MovementStep * Math.Cos(Heading) |
|
|
|
|
); |
|
|
|
|
context.LineTo(newPosition); |
|
|
|
|
position = newPosition; |
|
|
|
|
Position = newPosition; |
|
|
|
|
break; |
|
|
|
|
case '+': |
|
|
|
|
heading += headingStep; |
|
|
|
|
Heading += HeadingStep; |
|
|
|
|
break; |
|
|
|
|
case '-': |
|
|
|
|
heading -= headingStep; |
|
|
|
|
Heading -= HeadingStep; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -142,44 +144,57 @@ namespace SBRL.SimpleTurtle
@@ -142,44 +144,57 @@ namespace SBRL.SimpleTurtle
|
|
|
|
|
public void Forwards() |
|
|
|
|
{ |
|
|
|
|
PointD newPosition = new PointD( |
|
|
|
|
position.X + MovementStep * Math.Sin(heading), |
|
|
|
|
position.Y + MovementStep * Math.Cos(heading) |
|
|
|
|
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; |
|
|
|
|
bounds.Width += newPosition.X - Position.X; |
|
|
|
|
if (newPosition.Y > bounds.Y + bounds.Height) |
|
|
|
|
bounds.Height += newPosition.Y - position.Y; |
|
|
|
|
bounds.Height += newPosition.Y - Position.Y; |
|
|
|
|
if (newPosition.X < bounds.X) |
|
|
|
|
{ |
|
|
|
|
bounds.X = newPosition.X; |
|
|
|
|
bounds.Width += position.X - newPosition.X; |
|
|
|
|
bounds.Width += Position.X - newPosition.X; |
|
|
|
|
} |
|
|
|
|
if (newPosition.Y < bounds.Y) |
|
|
|
|
{ |
|
|
|
|
bounds.Y = newPosition.Y; |
|
|
|
|
bounds.Height += position.Y - newPosition.Y; |
|
|
|
|
bounds.Height += Position.Y - newPosition.Y; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
position = newPosition; |
|
|
|
|
Position = newPosition; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void Turn(bool anticlockwise = false) |
|
|
|
|
{ |
|
|
|
|
if (!anticlockwise) |
|
|
|
|
heading += HeadingStep; |
|
|
|
|
Heading += HeadingStep; |
|
|
|
|
else |
|
|
|
|
heading -= HeadingStep; |
|
|
|
|
Heading -= HeadingStep; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void Save() |
|
|
|
|
{ |
|
|
|
|
states.Push(states.Peek().Clone() as TurtleState); |
|
|
|
|
} |
|
|
|
|
public bool Restore() { |
|
|
|
|
if (states.Count <= 1) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
states.Pop(); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public void Reset() |
|
|
|
|
{ |
|
|
|
|
states.Clear(); |
|
|
|
|
states.Push(new TurtleState(new PointD(0, 0), 0)); |
|
|
|
|
|
|
|
|
|
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; |
|
|
|
|
bounds = new Area(Position.X, Position.Y, 1, 1); |
|
|
|
|
HeadingStep = Math.PI / 2; |
|
|
|
|
MovementStep = 25; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|