Browse Source

Initial commit. I can't believe I haven't committed this already.....

master
Starbeamrainbowlabs 4 years ago
commit
1a3280e7a0
Signed by: sbrl
GPG Key ID: 1BE5172E637709C2
  1. 446
      .gitignore
  2. 17
      SimpleTurtle.sln
  3. 45
      SimpleTurtle/Help.txt
  4. 125
      SimpleTurtle/LSystemEngine.cs
  5. 113
      SimpleTurtle/Program.cs
  6. 27
      SimpleTurtle/Properties/AssemblyInfo.cs
  7. 55
      SimpleTurtle/SimpleTurtle.csproj
  8. 17
      SimpleTurtle/SimpleTurtle.sln
  9. 186
      SimpleTurtle/Turtle.cs
  10. 191
      SimpleTurtle/Utilities/EmbeddedFiles.cs
  11. 36
      SimpleTurtle/Utilities/Timer.cs

446
.gitignore vendored

@ -0,0 +1,446 @@ @@ -0,0 +1,446 @@
# Created by https://www.gitignore.io/api/csharp,git,monodevelop,visualstudio
### Csharp ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
**/Properties/launchSettings.json
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Uncomment the next line to ignore your web deploy settings.
# By default, sensitive information, such as encrypted password
# should be stored in the .pubxml.user file.
#*.pubxml
*.pubxml.user
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Typescript v1 declaration files
typings/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
### Git ###
*.orig
### MonoDevelop ###
#User Specific
*.usertasks
#Mono Project Files
*.resources
test-results/
### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
# User-specific files (MonoDevelop/Xamarin Studio)
# Build results
# Visual Studio 2015 cache/options directory
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
# NUNIT
# Build Results of an ATL Project
# .NET Core
# Chutzpah Test files
# Visual C++ cache files
# Visual Studio profiler
# TFS 2012 Local Workspace
# Guidance Automation Toolkit
# ReSharper is a .NET coding add-in
# JustCode is a .NET coding add-in
# TeamCity is a build add-in
# DotCover is a Code Coverage Tool
# Visual Studio code coverage results
# NCrunch
# MightyMoose
# Web workbench (sass)
# Installshield output folder
# DocProject is a documentation generator add-in
# Click-Once directory
# Publish Web Output
# TODO: Uncomment the next line to ignore your web deploy settings.
# By default, sensitive information, such as encrypted password
# should be stored in the .pubxml.user file.
#*.pubxml
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
# NuGet Packages
# The packages folder can be ignored because of Package Restore
# except build/, which is used as an MSBuild target.
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignorable files
# Microsoft Azure Build Output
# Microsoft Azure Emulator
# Windows Store app package directories and files
# Visual Studio cache files
# files ending in .cache can be ignored
# but keep track of directories ending in .cache
# Others
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
# SQL Server files
# Business Intelligence projects
# Microsoft Fakes
# GhostDoc plugin setting file
# Node.js Tools for Visual Studio
# Typescript v1 declaration files
# Visual Studio 6 build log
# Visual Studio 6 workspace options file
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
# Visual Studio LightSwitch build output
# Paket dependency manager
# FAKE - F# Make
# JetBrains Rider
# CodeRush
# Python Tools for Visual Studio (PTVS)
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Telerik's JustMock configuration file
# BizTalk build output
### VisualStudio Patch ###
# By default, sensitive information, such as encrypted password
# should be stored in the .pubxml.user file.
# End of https://www.gitignore.io/api/csharp,git,monodevelop,visualstudio

17
SimpleTurtle.sln

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 2012
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleTurtle", "SimpleTurtle\SimpleTurtle.csproj", "{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}.Debug|x86.ActiveCfg = Debug|x86
{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}.Debug|x86.Build.0 = Debug|x86
{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}.Release|x86.ActiveCfg = Release|x86
{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal

45
SimpleTurtle/Help.txt

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
SimpleTurtle L-System Renderer
by Starbeamrainbowlabs
Usage:
./SimpleTurtle.exe {options}
Options:
-i --input-file The file that contains the input L-System parameters. Defaults to stdin.
-o --output-dir The output directory in which to save the rendered / simulated L-System generations. Defaults to the name of the input file, minus the file extension - or just simply 'l-system'.
-s --skip-gen The starting generation. Default: 0.
-c --count The number of generations to render. Default: 5
-d --step-dist The number of pixels the turtle will walk forwards at a time. Default: 25.
Input File Format:
The first line is the seed (the starting state).
Subsequent lines beginning with a # (hash sign) are ignored.
Rules are declared with an equals sign - i.e. f=f-f+, or fb=fbfafcfafb.
Lines starting with an exclamation mark specify directives that should be passed to the turtle - i.e. !angle=1.0472
Turtle Directives:
angle Sets the angle by which the turtle should turn. Note that this is specified in radians.
Example Input Files:
Hilbert Curve:
-----
a
a=-bf+afa+fb-
b=+af-bfb-fa+
-----
Dragon Curve:
-----
f
f=f-h
h=f+h
-----
Sierpinski Triangle
-----
f
!angle=1.0472
h=f+h+f
f=h-f-h
-----

125
SimpleTurtle/LSystemEngine.cs

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Policy;
namespace SBRL.Algorithms.LSystem
{
public class Rule
{
public string Find;
public string Replace;
public Rule(string inFind, string inReplace)
{
Find = inFind;
Replace = inReplace;
}
}
/// <summary>
/// Simulates an L-System.
/// Implemented according to http://www.cs.unm.edu/~joel/PaperFoldingFractal/L-system-rules.html
/// </summary>
public class LSystemEngine
{
public readonly string Root;
private List<Rule> rules = new List<Rule>();
public int GenerationCount { get; private set; }
public string CurrentGeneration { get; private set; }
public Dictionary<string, string> Definitions { get; private set; }
public LSystemEngine(string inRoot)
{
CurrentGeneration = Root = inRoot;
Definitions = new Dictionary<string, string>();
}
public void AddRule(string find, string replace)
{
rules.Add(new Rule(find, replace));
}
public string Simulate()
{
List<KeyValuePair<int, Rule>> rulePositions = new List<KeyValuePair<int, Rule>>();
// Find all the current positions
foreach(Rule rule in rules)
{
List<int> positions = AllIndexesOf(CurrentGeneration, rule.Find);
foreach (int pos in positions)
rulePositions.Add(new KeyValuePair<int, Rule>(pos, rule));
}
rulePositions.Sort(compareRulePairs);
string nextGeneration = CurrentGeneration;
int replaceOffset = 0;
foreach(KeyValuePair<int, Rule> rulePos in rulePositions)
{
int nextPos = rulePos.Key + replaceOffset;
nextGeneration = nextGeneration.Substring(0, nextPos) + rulePos.Value.Replace + nextGeneration.Substring(nextPos + rulePos.Value.Find.Length);
replaceOffset += rulePos.Value.Replace.Length - rulePos.Value.Find.Length;
}
CurrentGeneration = nextGeneration;
GenerationCount++;
return CurrentGeneration;
}
private int compareRulePairs(KeyValuePair<int, Rule> a, KeyValuePair<int, Rule> b)
{
return a.Key - b.Key;
}
/// <summary>
/// From http://stackoverflow.com/a/2641383/1460422
/// </summary>
/// <param name="str"></param>
/// <param name="value"></param>
/// <returns></returns>
private List<int> AllIndexesOf(string str, string value) {
if (String.IsNullOrEmpty(value))
throw new ArgumentException("the string to find may not be empty", "value");
List<int> indexes = new List<int>();
for (int index = 0;; index += value.Length) {
index = str.IndexOf(value, index);
if (index == -1)
return indexes;
indexes.Add(index);
}
}
public static LSystemEngine FromFile(string filename)
{
return FromStream(new StreamReader(filename));
}
public static LSystemEngine FromStream(StreamReader source)
{
LSystemEngine resultSystem = new LSystemEngine(source.ReadLine());
string nextLine = string.Empty;
while (true) {
nextLine = source.ReadLine();
if (nextLine == null)
break;
if (!nextLine.Contains("=") || nextLine.StartsWith("#") || nextLine.Trim().Length == 0)
continue;
string[] parts = nextLine.Split(new char[]{'='}, 2);
if(parts[0].StartsWith("!"))
{
// This is a definition
resultSystem.Definitions.Add(parts[0].Trim('!'), parts[1]);
}
else
{
resultSystem.AddRule(parts[0].Trim(), parts[1].Trim());
}
}
return resultSystem;
}
}
}

113
SimpleTurtle/Program.cs

@ -0,0 +1,113 @@ @@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.IO;
using SBRL.Utilities;
using SBRL.SimpleTurtle;
namespace SBRL.Algorithms.LSystem
{
class MainClass
{
public static void Main(string[] args)
{
string inputFilename = string.Empty;
string outputDirectory = string.Empty;
int startingGeneration = 0;
int generations = 5;
int stepCount = 25;
for (int i = 0; i < args.Length; i++)
{
switch (args[i].ToLower())
{
case "--help":
Console.WriteLine(EmbeddedFiles.ReadAllText("SimpleTurtle.Help.txt"));
return;
case "--input-file":
case "-i":
inputFilename = args[++i];
break;
case "--output-dir":
case "-o":
outputDirectory = args[++i];
break;
case "--skip-gen":
case "-s":
startingGeneration = int.Parse(args[++i]);
break;
case "--count":
case "-c":
generations = int.Parse(args[++i]);
break;
case "--step-dist":
case "-d":
stepCount = int.Parse(args[++i]);
break;
}
}
StreamReader source;
if (inputFilename == string.Empty)
source = new StreamReader(Console.OpenStandardInput());
else
source = new StreamReader(inputFilename);
if (outputDirectory == string.Empty) {
if (inputFilename == string.Empty)
outputDirectory = "./l-system";
else
outputDirectory = inputFilename.Substring(0, inputFilename.LastIndexOf("."));
}
// Normalise & create the output directory
outputDirectory = outputDirectory.TrimEnd('/') + "/";
if(!Directory.Exists(outputDirectory))
Directory.CreateDirectory(outputDirectory);
LSystemEngine lsystem = LSystemEngine.FromStream(source);
foreach (KeyValuePair<string, string> kvp in lsystem.Definitions)
{
Console.WriteLine("Setting {0} to {1}.", kvp.Key, kvp.Value);
}
Turtle turtle = new Turtle();
Timer gentimer = Timer.GetStarted(), stagetimer = Timer.GetStarted();
for (int i = startingGeneration; i < generations; i++)
{
stagetimer.Reset(); gentimer.Reset();
Console.Write($"Generation {i}: ");
turtle.ApplyDefinitions(lsystem.Definitions);
turtle.MovementStep = stepCount;
turtle.Commands(lsystem.CurrentGeneration);
turtle.Draw($"{outputDirectory}lsystem_generation_{i}.png");
Console.Write("{0:0.000000}s draw", stagetimer.GetElapsedSeconds());
stagetimer.Reset();
// ----------
lsystem.Simulate();
Console.Write(", {0:0.000000}s simulation", stagetimer.GetElapsedSeconds());
stagetimer.Reset();
// ----------
File.WriteAllText($"{outputDirectory}lsystem_generation_{i}.txt", lsystem.CurrentGeneration);
Console.WriteLine(
", {0:0.000000}s textoutput - {1:0.000000}s total",
stagetimer.GetElapsedSeconds(),
gentimer.GetElapsedSeconds()
);
}
//Turtle turtle = new Turtle();
//turtle.Commands(Console.ReadLine());
//turtle.Draw("turtleImage.png");
}
}
}

27
SimpleTurtle/Properties/AssemblyInfo.cs

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("SimpleTurtle")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Starbeamrainbowlabs")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

55
SimpleTurtle/SimpleTurtle.csproj

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
<ProjectGuid>{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>SBRL.SimpleTurtle</RootNamespace>
<AssemblyName>SimpleTurtle</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<ProductVersion>8.0.30703</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
<DebugType>full</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Externalconsole>true</Externalconsole>
<PlatformTarget>x86</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="Mono.Cairo" />
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Turtle.cs" />
<Compile Include="LSystemEngine.cs" />
<Compile Include="Utilities\EmbeddedFiles.cs" />
<Compile Include="Utilities\Timer.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Help.txt">
<LogicalName>SimpleTurtle.Help.txt</LogicalName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Folder Include="Utilities\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

17
SimpleTurtle/SimpleTurtle.sln

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleTurtle", "SimpleTurtle.csproj", "{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x86 = Debug|x86
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}.Debug|x86.ActiveCfg = Debug|x86
{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}.Debug|x86.Build.0 = Debug|x86
{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}.Release|x86.ActiveCfg = Release|x86
{1AF04EB3-4F9C-4AA6-98C5-693F6B54DB24}.Release|x86.Build.0 = Release|x86
EndGlobalSection
EndGlobal

186
SimpleTurtle/Turtle.cs

@ -0,0 +1,186 @@ @@ -0,0 +1,186 @@
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;
}
}
}

191
SimpleTurtle/Utilities/EmbeddedFiles.cs

@ -0,0 +1,191 @@ @@ -0,0 +1,191 @@
using System;
using System.Reflection;
using System.IO;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace SBRL.Utilities
{
/// <summary>
/// A collection of static methods for manipulating embedded resources.
/// </summary>
/// <description>
/// v0.5, by Starbeamrainbowlabs <feedback@starbeamrainbowlabs.com>
/// Last updated 8th August 2016.
/// Licensed under MPL-2.0.
///
/// Changelog:
/// v0.1 (25th July 2016):
/// - Initial release.
/// v0.2 (8th August 2016):
/// - Changed namespace.
/// v0.3 (21st January 2017):
/// - Added GetRawReader().
/// v0.4 (8th April 2017):
/// - Removed unnecessary using statement.
/// v0.5 (3rd September 2017):
/// - Changed namespace
/// </description>
public static class EmbeddedFiles
{
/// <summary>
/// An array of the filenames of all the resources embedded in the calling assembly.
/// </summary>
/// <value>The resource list.</value>
public static string[] ResourceList
{
get
{
return Assembly.GetCallingAssembly().GetManifestResourceNames();
}
}
public static string GetResourceListText()
{
StringWriter result = new StringWriter();
result.WriteLine("Files embedded in {0}:", Assembly.GetCallingAssembly().GetName().Name);
foreach (string filename in ResourceList)
result.WriteLine(" - {0}", filename);
return result.ToString();
}
/// <summary>
/// Writes a list of embedded resources to the Console's standard output.
/// </summary>
public static void WriteResourceList()
{
Console.WriteLine(GetResourceListText());
}
/// <summary>
/// Gets a StreamReader attached to the specified embedded resource.
/// </summary>
/// <param name="filename">The filename of the embedded resource to get a StreamReader of.</param>
/// <returns>A StreamReader attached to the specified embedded resource.</returns>
public static StreamReader GetReader(string filename)
{
return new StreamReader(GetRawReader(filename));
}
/// <summary>
/// Gets a raw Stream that's attached to the specified embedded resource.
/// Useful when you want to copy an embedded resource to some other stream.
/// </summary>
/// <param name="filename">The path to the embedded resource.</param>
/// <returns>A raw Stream object attached to the specified file..</returns>
public static Stream GetRawReader(string filename)
{
return Assembly.GetCallingAssembly().GetManifestResourceStream(filename);
}
/// <summary>
/// Gets the specified embedded resource's content as a byte array.
/// </summary>
/// <param name="filename">The filename of the embedded resource to get conteent of.</param>
/// <returns>The specified embedded resource's content as a byte array.</returns>
public static byte[] ReadAllBytes(string filename)
{
// Referencing the Result property will block until the async method completes
return ReadAllBytesAsync(filename).Result;
}
/// <summary>
/// Gets the specified embedded resource's content as a byte array asynchronously.
/// </summary>
/// <param name="filename">The filename of the embedded resource to get conteent of.</param>
/// <returns>The specified embedded resource's content as a byte array.</returns>
public static async Task<byte[]> ReadAllBytesAsync(string filename)
{
using (Stream resourceStream = Assembly.GetCallingAssembly().GetManifestResourceStream(filename))
using (MemoryStream temp = new MemoryStream())
{
await resourceStream.CopyToAsync(temp);
return temp.ToArray();
}
}
/// <summary>
/// Gets all the text stored in the specified embedded resource.
/// </summary>
/// <param name="filename">The filename to fetch the content of.</param>
/// <returns>All the text stored in the specified embedded resource.</returns>
public static string ReadAllText(string filename)
{
using (StreamReader resourceReader = new StreamReader(Assembly.GetCallingAssembly().GetManifestResourceStream(filename)))
{
return resourceReader.ReadToEnd();
}
}
/// <summary>
/// Gets all the text stored in the specified embedded resource asynchronously.
/// </summary>
/// <param name="filename">The filename to fetch the content of.</param>
/// <returns>All the text stored in the specified embedded resource.</returns>
public static async Task<string> ReadAllTextAsync(string filename)
{
using (StreamReader resourceReader = new StreamReader(Assembly.GetCallingAssembly().GetManifestResourceStream(filename)))
{
return await resourceReader.ReadToEndAsync();
}
}
/// <summary>
/// Enumerates the lines of text in the specified embedded resource.
/// </summary>
/// <param name="filename">The filename of the embedded resource to enumerate.</param>
/// <returns>An IEnumerator that enumerates the specified embedded resource.</returns>
public static IEnumerator<string> EnumerateLines(string filename)
{
using (StreamReader resourceReader = new StreamReader(Assembly.GetCallingAssembly().GetManifestResourceStream(filename)))
{
string nextLine;
while ((nextLine = resourceReader.ReadLine()) != null)
{
yield return nextLine;
}
}
}
/// <summary>
/// Enumerates the lines of text in the specified embedded resource asynchronously.
/// Each successive call returns a task that, when complete, returns the next line of text stored
/// in the embedded resource.
/// </summary>
/// <param name="filename">The filename of the embedded resource to enumerate.</param>
/// <returns>An IEnumerator that enumerates the specified embedded resource.</returns>
public static IEnumerable<Task<string>> EnumerateLinesAsync(string filename)
{
using (StreamReader resourceReader = new StreamReader(Assembly.GetCallingAssembly().GetManifestResourceStream(filename)))
{
while (!resourceReader.EndOfStream)
{
yield return resourceReader.ReadLineAsync();
}
}
}
/// <summary>
/// Gets all the lines of text in the specified embedded resource.
/// You might find EnumerateLines(string filename) more useful depending on your situation.
/// </summary>
/// <param name="filename">The filename to obtain the lines of text from.</param>
/// <returns>A list of lines in the specified embedded resource.</returns>
public static List<string> GetAllLines(string filename)
{
// Referencing the Result property will block until the async method completes
return GetAllLinesAsync(filename).Result;
}
/// <summary>
/// Gets all the lines of text in the specified embedded resource asynchronously.
/// </summary>
/// <param name="filename">The filename to obtain the lines of text from.</param>
/// <returns>A list of lines in the specified embedded resource.</returns>
public static async Task<List<string>> GetAllLinesAsync(string filename)
{
List<string> lines = new List<string>();
IEnumerable<Task<string>> lineIterator = EnumerateLinesAsync(filename);
foreach (Task<string> nextLine in lineIterator)
{
lines.Add(await nextLine);
}
return lines;
}
}
}

36
SimpleTurtle/Utilities/Timer.cs

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
using System;
namespace SBRL.Utilities
{
public class Timer
{
public DateTime StartTime { get; private set; }
public Timer() { }
public static Timer GetStarted()
{
Timer result = new Timer();
result.Start();
return result;
}
public void Start()
{
StartTime = DateTime.Now;
}
public float GetElapsedSeconds()
{
DateTime now = DateTime.Now;
TimeSpan elasped = now - StartTime;
StartTime = now;
return (float)elasped.Ticks / TimeSpan.TicksPerSecond;
}
public void Reset()
{
Start();
}
}
}
Loading…
Cancel
Save