Quellcode durchsuchen

converted console-application to winforms application

implemented generation and displaying of a graphical result instead of console output
winforms
benjamin.m vor 5 Jahren
Ursprung
Commit
76d379456d

+ 34
- 1
Buhnenrennen/Buhnenrennen.csproj Datei anzeigen

@@ -5,7 +5,7 @@
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{E3E00F47-D7F1-45F4-B4BB-0305F8074833}</ProjectGuid>
<OutputType>Exe</OutputType>
<OutputType>WinExe</OutputType>
<RootNamespace>Buhnenrennen</RootNamespace>
<AssemblyName>Buhnenrennen</AssemblyName>
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
@@ -32,9 +32,24 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<PropertyGroup>
<ApplicationIcon>favicon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="DragonSkills99.ControlCollection">
<HintPath>..\libs\DragonSkills99.ControlCollection.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\libs\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
@@ -44,15 +59,33 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Dog.cs" />
<Compile Include="DoubleBufferedPanel.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Field.cs" />
<Compile Include="GraphicGenerator.cs" />
<Compile Include="Groyne.cs" />
<Compile Include="GroyneRun.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Scripter.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Scripter.Designer.cs">
<DependentUpon>Scripter.cs</DependentUpon>
</Compile>
<Compile Include="TimedGroyne.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Scripter.resx">
<DependentUpon>Scripter.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Content Include="favicon.ico" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

+ 20
- 0
Buhnenrennen/DoubleBufferedPanel.cs Datei anzeigen

@@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Buhnenrennen
{
class DoubleBufferedPanel : Panel
{
public DoubleBufferedPanel()
{
DoubleBuffered = true;
SetStyle( ControlStyles.DoubleBuffer | ControlStyles.UserPaint |
ControlStyles.AllPaintingInWmPaint, true );
UpdateStyles();
}
}
}

+ 13
- 8
Buhnenrennen/Field.cs Datei anzeigen

@@ -16,15 +16,15 @@ namespace Buhnenrennen
private Field( IEnumerable<string> groynes )
{
Groynes = new Dictionary<double, List<Groyne>>();
Match m;
Match matchedGroyne;
foreach( string groyn in groynes )
{
if ( ( m = groynSchema.Match( groyn ) ).Success )
if ( ( matchedGroyne = groynSchema.Match( groyn ) ).Success )
{
char type = m.Groups[ "type" ].Value.FirstOrDefault();
char type = matchedGroyne.Groups[ "type" ].Value.FirstOrDefault();
// Forcing a multiple of 70 by using '/ 70 * 70'
int level = int.Parse( m.Groups[ "level" ].Value ) / 70 * 70;
double yCoord = double.Parse( m.Groups[ "yCoord" ].Value );
int level = int.Parse( matchedGroyne.Groups[ "level" ].Value ) / 70 * 70;
double yCoord = double.Parse( matchedGroyne.Groups[ "yCoord" ].Value.Replace( ",", "" ).Replace( ".", "," ) );
if ( !this.Groynes.ContainsKey( level ) ) this.Groynes.Add( level, new List<Groyne>() );
this.Groynes[ level ].Add( new Groyne( yCoord, type ) );
}
@@ -67,15 +67,20 @@ namespace Buhnenrennen
return times;
}

public TimedGroyne getFastestSafeRoute( Dog hunter, Dog hunted )
{
return this.getFastestSafeRoute( hunter, hunted, out _, out _ );
}

/**
* <summary>returns the fastest route for {hunted} where {hunted} will always be faster than {hunter}</summary>
* <param name="hunted">The dog, which will be hunted and is not to be catched ( Minnie )</param>
* <param name="hunter">The dog, with the desire to hunt the {hunted} dog ( Max )</param>
*/
public TimedGroyne getFastestSafeRoute( Dog hunter, Dog hunted )
public TimedGroyne getFastestSafeRoute( Dog hunter, Dog hunted, out Dictionary<double, List<TimedGroyne>> hunterMap, out Dictionary<double, List<TimedGroyne>> huntedMap )
{
var hunterMap = listFastestTimes( hunter );
var huntedMap = listFastestTimes( hunted );
hunterMap = listFastestTimes( hunter );
huntedMap = listFastestTimes( hunted );

List<Groyne> safeGroynes = new List<Groyne>();
safeGroynes.Add( Groynes[ 0 ].Find( groyne => groyne.Type == hunted.Start ) );

+ 253
- 0
Buhnenrennen/GraphicGenerator.cs Datei anzeigen

@@ -0,0 +1,253 @@
using DragonSkills99.ControlCollection;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Buhnenrennen
{
static class GraphicGenerator
{
/// <summary>
/// generates an image from field, hunter and hunted and returns it
/// </summary>
/// <param name="field">field to use for calculations</param>
/// <param name="hunter">hunting dog ( Max )</param>
/// <param name="hunted">hunted dog ( Minnie )</param>
public static Image generateField( Field field, Dog hunter, Dog hunted )
{
TimedGroyne safePath = field.getFastestSafeRoute( Dog.MAX, Dog.MINNIE, out var hunterMap, out var huntedMap );

float borderWidth = 7.5F;
int boxRadius = 25;
Size imagePadding = new Size( 10, 10 );
Size imageSize = new Size( imagePadding.Width, imagePadding.Height );
Font font = new Font( "Consolas", 30F );
Font nameFont = new Font( "Consolas", 50F );
Brush hunterBrush = new SolidBrush( Color.DarkRed );
Brush hunterFillBrush = new SolidBrush( Color.Red );
Brush huntedBrush = new SolidBrush( Color.DarkBlue );
Brush huntedFillBrush = new SolidBrush( Color.Cyan );
Brush safePathBrush = new SolidBrush( Color.Gold );

Size boxSpacing = new Size( 700, 50 );
Size boxSize = new Size( 300, 200 );
int levels = ( ( int ) field.Groynes.Keys.Max() / 70 ) + 1; // + 1 cause 0 is also a level and hasn't been included yet

imageSize.Width += boxSize.Width * levels;
imageSize.Width += boxSpacing.Width * ( levels - 1 );

int hunterBoxCount = field.Groynes.Values.Select( groyneList => groyneList.Count ).Max();
imageSize.Height += boxSize.Height * hunterBoxCount;
imageSize.Height += boxSpacing.Height * ( hunterBoxCount - 1 );

Image img = new Bitmap( imageSize.Width, imageSize.Height );
using( Graphics graphics = Graphics.FromImage( img ) )
{
Dictionary<Groyne, RectangleF> groynePositions = new Dictionary<Groyne, RectangleF>();
Dictionary<Groyne, Brush> groyneBorderBrush = new Dictionary<Groyne, Brush>();
int height = imageSize.Height - imagePadding.Height;
int yPadding = ( height - 2 * boxSize.Height ) / 3;
int xOffset = imagePadding.Width / 2;

Rectangle rect = new Rectangle( new Point( xOffset, imagePadding.Height / 2 + yPadding ), boxSize );
graphics.FillRectangle( hunterFillBrush, rect );
graphics.DrawRectangle( new Pen( hunterBrush, borderWidth ), rect );
graphics.DrawStringCenteredTo( "Max", nameFont, hunterBrush, rect );
Groyne hunterStart = field.Groynes[ 0 ].Find( groyne => groyne.Type == hunter.Start );
groynePositions.Add( hunterStart, rect );
groyneBorderBrush.Add( hunterStart, hunterBrush );
rect = rect.Clone();
rect.Y += rect.Height + yPadding;
graphics.FillRoundedRectangle( huntedFillBrush, rect, boxRadius );
graphics.DrawRoundedRectangle( new Pen( huntedBrush, borderWidth ), rect, boxRadius );
graphics.DrawStringCenteredTo( "Minnie", nameFont, huntedBrush, rect );
Groyne huntedStart = field.Groynes[ 0 ].Find( groyne => groyne.Type == hunted.Start );
groynePositions.Add( huntedStart, rect );
groyneBorderBrush.Add( huntedStart, huntedBrush );
rect = rect.Clone();

for ( int level = 70; level <= field.Groynes.Keys.Max(); level += 70 )
{
int prevLevel = level - 70;
int numLevel = level / 70;
List<Groyne> groynes = field.Groynes[ level ];
groynes = groynes.Select( groyne => groyne ).ToList(); // Clone array so original array won't be touched/sorted
groynes.OrderBy( groyne => groyne.YCoord ); // Ordered by yCoord ascending

xOffset += boxSize.Width;
xOffset += boxSpacing.Width;
yPadding = ( height - groynes.Count() * boxSize.Height ) / ( groynes.Count() + 1 );
rect.Y = 0;
rect.X = xOffset;

//int xOffset = numLevel * boxSize.Width;
//xOffset += numLevel * boxSpacing.Width;
//xOffset += imagePadding.Width / 2;

foreach( Groyne groyne in groynes )
{
rect.Y += yPadding;
groynePositions.Add( groyne, rect );
var huntedTimedGroyne = huntedMap[ level ].Find( timedGroyne => timedGroyne.Groyne == groyne );
var hunterTimedGroyne = hunterMap[ level ].Find( timedGroyne => timedGroyne.Groyne == groyne );
var fillBrush = huntedTimedGroyne.TotalTime > hunterTimedGroyne.TotalTime ? hunterFillBrush : huntedFillBrush;
var brush = huntedTimedGroyne.TotalTime > hunterTimedGroyne.TotalTime ? hunterBrush : huntedBrush;
groyneBorderBrush.Add( groyne, brush );

if ( groyne.Type == 'x' )
{
graphics.FillRectangle( fillBrush, rect );
} else
{
graphics.FillRoundedRectangle( fillBrush, rect, boxRadius );
}

graphics.DrawStringCenteredTo( hunterTimedGroyne.TotalTimeConverted, font, hunterBrush, rect, VerticalPosition.Top, 10 );
graphics.DrawStringCenteredTo( huntedTimedGroyne.TotalTimeConverted, font, huntedBrush, rect, VerticalPosition.Bottom, 10 );
graphics.DrawStringCenteredTo( hunterTimedGroyne.DistanceConverted, font, hunterBrush, rect, VerticalPosition.Top, boxSize.Height / 4 );
graphics.DrawStringCenteredTo( huntedTimedGroyne.DistanceConverted, font, huntedBrush, rect, VerticalPosition.Bottom, boxSize.Height / 4 );
graphics.ConnectRectangles( new Pen( hunterBrush, borderWidth ), groynePositions[ groyne ], groynePositions[ hunterTimedGroyne.ParentGroyne.Groyne ] );
graphics.ConnectRectangles( new Pen( huntedBrush, borderWidth ), groynePositions[ groyne ], groynePositions[ huntedTimedGroyne.ParentGroyne.Groyne ], borderWidth );

rect = rect.Clone();
rect.Y += boxSize.Height;
}
}

TimedGroyne safePathSub = safePath;

do
{
graphics.ConnectRectangles( new Pen( safePathBrush, borderWidth ), groynePositions[ safePathSub.Groyne ], groynePositions[ safePathSub.ParentGroyne.Groyne ], borderWidth );
safePathSub = safePathSub.ParentGroyne;
} while ( safePathSub.ParentGroyne != null );

foreach( var groyne in groyneBorderBrush.Keys )
{
var brush = groyneBorderBrush[ groyne ];
var rectF = groynePositions[ groyne ];

if( groyne.Type == 'x' || groyne.Type == 'X' )
{
graphics.DrawRectangle( new Pen( brush, borderWidth ), rectF.Round() );
} else
{
graphics.DrawRoundedRectangle( new Pen( brush, borderWidth ), rectF, boxRadius );
}
}
}
return img;
}

/// <summary>
/// rounds a give RectangeF to a Rectangle and returns it
/// </summary>
/// <param name="rectangle">rectangle to round</param>
public static Rectangle Round( this RectangleF rectangle )
{
return new Rectangle( ( int ) Math.Round( rectangle.X ), ( int ) Math.Round( rectangle.Y ), ( int ) Math.Round( rectangle.Width ), ( int ) Math.Round( rectangle.Height ) );
}

/// <summary>
/// draws a line between two rectangles
/// </summary>
/// <param name="graphics">graphics object to draw to</param>
/// <param name="pen">pen to draw with</param>
/// <param name="from">rectangle to start at</param>
/// <param name="to">rectengles to stop at</param>
/// <param name="offset">offset of the drawn line ( offset = 0 means perfectly centered )</param>
public static void ConnectRectangles( this Graphics graphics, Pen pen, RectangleF from, RectangleF to, float offset = 0 )
{
if ( from.IntersectsWith( to ) ) return; // do nothing if rectangles are overlapping to prevent errors
PointF fromPt, toPt;

if ( from.IntersectsVerticallyWith( to ) )
{
fromPt = new PointF( from.X + ( from.Width / 2 ) + offset, from.Top > to.Top ? from.Top : from.Bottom );
toPt = new PointF( to.X + ( to.Width / 2 ) + offset, from.Top < to.Top ? to.Top : to.Bottom );
} else
{
fromPt = new PointF( from.Left > to.Left ? from.Left : from.Right, from.Y + ( from.Height / 2 ) + offset );
toPt = new PointF( from.Left < to.Left ? to.Left : to.Right, to.Y + ( to.Height / 2 ) + offset );
}

graphics.DrawLine( pen, fromPt, toPt );
}

/// <summary>
/// tests if [me] instersects with [other] vertically
/// </summary>
public static bool IntersectsVerticallyWith( this RectangleF me, RectangleF other )
{
RectangleF meClone = me.Clone();
RectangleF otherClone = other.Clone();
meClone.Y = 0;
otherClone.Y = 0;
return meClone.IntersectsWith( otherClone );
}

/// <summary>
/// tests if [me] instersects with [other] horizontally
/// </summary>
public static bool IntersectsHorizontallyWith( this RectangleF me, RectangleF other )
{
RectangleF meClone = me.Clone();
RectangleF otherClone = other.Clone();
meClone.X = 0;
otherClone.X = 0;
return meClone.IntersectsWith( otherClone );
}

/// <summary>
/// draws a string horizontally centered in given rectangle
/// </summary>
/// <param name="graphics">graphics object to draw to</param>
/// <param name="text">text to draw</param>
/// <param name="font">font to draw the text with</param>
/// <param name="brush">brush to use for drawing</param>
/// <param name="centerTo">rectangle, the text should be centered in</param>
/// <param name="positioning">vertical alignment of the text</param>
/// <param name="topMiddlePadding">offset of the text from border ( ignored if positioning = centered )</param>
public static void DrawStringCenteredTo( this Graphics graphics, string text, Font font, Brush brush, RectangleF centerTo, VerticalPosition positioning = VerticalPosition.Middle, float topMiddlePadding = 0 )
{
graphics.DrawString( text, font, brush, centerTo.CenterTo( graphics.MeasureString( text, font ), positioning, topMiddlePadding ) );
}
/// <summary>
/// calculates point for text to be centered in rectangle and returns it
/// </summary>
/// <param name="rect">rectangle, the text should be centered in</param>
/// <param name="measured">measured size of the text to draw</param>
/// <param name="positioning">vertical alignment of the text</param>
/// <param name="topMiddlePadding">offset of the text from border ( ignored if positioning = centered )</param>
public static PointF CenterTo( this RectangleF rect, SizeF measured, VerticalPosition positioning = VerticalPosition.Middle, float topMiddlePadding = 0 )
{
PointF point = new PointF( rect.X, rect.Y );

point.X += ( rect.Width / 2 ) - ( measured.Width / 2 );

switch( positioning )
{
case VerticalPosition.Bottom:
point.Y += rect.Height - ( measured.Height + topMiddlePadding );
break;
case VerticalPosition.Middle:
point.Y += ( rect.Height / 2 ) - ( measured.Height / 2 );
break;
case VerticalPosition.Top:
point.Y += topMiddlePadding;
break;
}
return point;
}

public enum VerticalPosition
{
Top, Middle, Bottom
}
}
}

+ 5
- 2
Buhnenrennen/Program.cs Datei anzeigen

@@ -4,6 +4,7 @@ using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Buhnenrennen
{
@@ -11,10 +12,12 @@ namespace Buhnenrennen
{
// Buhne (de) = Groyne (en)

[STAThread]
static void Main( string[] args )
{
GroyneRun run = new GroyneRun();
run.Start();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
Application.Run( new Scripter() );
}
}
}

+ 159
- 0
Buhnenrennen/Scripter.Designer.cs Datei anzeigen

@@ -0,0 +1,159 @@
namespace Buhnenrennen
{
partial class Scripter
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose( bool disposing )
{
if ( disposing && ( components != null ) )
{
components.Dispose();
}
base.Dispose( disposing );
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Scripter));
this.label1 = new System.Windows.Forms.Label();
this.setupFiles = new System.Windows.Forms.ComboBox();
this.startCalculation = new System.Windows.Forms.Button();
this.graphicBox = new System.Windows.Forms.PictureBox();
this.graphicsPanel = new Buhnenrennen.DoubleBufferedPanel();
this.realSizeSlider = new System.Windows.Forms.TrackBar();
this.saveImageAs = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)(this.graphicBox)).BeginInit();
this.graphicsPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.realSizeSlider)).BeginInit();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(12, 9);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(66, 13);
this.label1.TabIndex = 0;
this.label1.Text = "Setup-Datei:";
//
// setupFiles
//
this.setupFiles.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.setupFiles.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.setupFiles.FormattingEnabled = true;
this.setupFiles.Location = new System.Drawing.Point(12, 25);
this.setupFiles.Name = "setupFiles";
this.setupFiles.Size = new System.Drawing.Size(776, 21);
this.setupFiles.TabIndex = 1;
//
// startCalculation
//
this.startCalculation.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.startCalculation.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
this.startCalculation.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.startCalculation.Location = new System.Drawing.Point(713, 415);
this.startCalculation.Name = "startCalculation";
this.startCalculation.Size = new System.Drawing.Size(75, 23);
this.startCalculation.TabIndex = 2;
this.startCalculation.Text = "Berechnen";
this.startCalculation.UseVisualStyleBackColor = false;
this.startCalculation.Click += new System.EventHandler(this.startCalculation_Click);
//
// graphicBox
//
this.graphicBox.Location = new System.Drawing.Point(0, 0);
this.graphicBox.Name = "graphicBox";
this.graphicBox.Size = new System.Drawing.Size(776, 357);
this.graphicBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
this.graphicBox.TabIndex = 3;
this.graphicBox.TabStop = false;
//
// graphicsPanel
//
this.graphicsPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.graphicsPanel.AutoScroll = true;
this.graphicsPanel.Controls.Add(this.graphicBox);
this.graphicsPanel.Location = new System.Drawing.Point(12, 52);
this.graphicsPanel.Name = "graphicsPanel";
this.graphicsPanel.Size = new System.Drawing.Size(776, 357);
this.graphicsPanel.TabIndex = 4;
this.graphicsPanel.SizeChanged += new System.EventHandler(this.graphicsPanel_SizeChanged);
this.graphicsPanel.Resize += new System.EventHandler(this.graphicsPanel_Resize);
//
// realSizeSlider
//
this.realSizeSlider.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.realSizeSlider.Location = new System.Drawing.Point(12, 415);
this.realSizeSlider.Maximum = 100;
this.realSizeSlider.Name = "realSizeSlider";
this.realSizeSlider.Size = new System.Drawing.Size(571, 45);
this.realSizeSlider.TabIndex = 5;
this.realSizeSlider.Scroll += new System.EventHandler(this.realSizeSlider_Scroll);
//
// saveImageAs
//
this.saveImageAs.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.saveImageAs.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
this.saveImageAs.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
this.saveImageAs.Location = new System.Drawing.Point(589, 415);
this.saveImageAs.Name = "saveImageAs";
this.saveImageAs.Size = new System.Drawing.Size(118, 23);
this.saveImageAs.TabIndex = 6;
this.saveImageAs.Text = "Bild speichern als...";
this.saveImageAs.UseVisualStyleBackColor = false;
this.saveImageAs.Click += new System.EventHandler(this.saveImageAs_Click);
//
// Scripter
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(45)))), ((int)(((byte)(45)))), ((int)(((byte)(45)))));
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.saveImageAs);
this.Controls.Add(this.realSizeSlider);
this.Controls.Add(this.graphicsPanel);
this.Controls.Add(this.startCalculation);
this.Controls.Add(this.setupFiles);
this.Controls.Add(this.label1);
this.ForeColor = System.Drawing.Color.White;
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
this.Name = "Scripter";
this.Text = "Buhnenrennen";
this.Load += new System.EventHandler(this.Scripter_Load);
((System.ComponentModel.ISupportInitialize)(this.graphicBox)).EndInit();
this.graphicsPanel.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.realSizeSlider)).EndInit();
this.ResumeLayout(false);
this.PerformLayout();

}

#endregion

private System.Windows.Forms.Label label1;
private System.Windows.Forms.ComboBox setupFiles;
private System.Windows.Forms.Button startCalculation;
private System.Windows.Forms.PictureBox graphicBox;
private DoubleBufferedPanel graphicsPanel;
private System.Windows.Forms.TrackBar realSizeSlider;
private System.Windows.Forms.Button saveImageAs;
}
}

+ 101
- 0
Buhnenrennen/Scripter.cs Datei anzeigen

@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Buhnenrennen
{
public partial class Scripter : Form
{
Regex setupFileRegex = new Regex( "^buhnenrennen(?<number>[0-9]+).txt$", RegexOptions.IgnoreCase );
Regex intFormatRegex = new Regex( "^[0-9]+$", RegexOptions.IgnoreCase );
public Scripter()
{
InitializeComponent();
}

/// <summary>
/// loads the available script files on first form displaying
/// </summary>
private void Scripter_Load( object sender, EventArgs e )
{
var filenumbers_int = Directory.GetFiles( "setups", "buhnenrennen*.txt" )
.Select( Path.GetFileName )
.Where( file => setupFileRegex.IsMatch( file ) )
.Select( file => int.Parse( setupFileRegex.Match( file ).Groups[ "number" ].Value ) ).ToList();
filenumbers_int.Sort();

if ( filenumbers_int.Count <= 0 )
{
MessageBox.Show( "Es wurden keine Setup-Dateien gefunden, bitte legt erst welche an und startet das Programm dann erneut." );
Application.Exit();
return;
}

List<string> filenames = filenumbers_int.Select( filenumber => "buhnenrennen" + filenumber.ToString() ).ToList();
setupFiles.Items.AddRange( filenames.ToArray() );
setupFiles.SelectedIndex = 0;
}

/// <summary>
/// calculates anything, draws an image and displays it
/// </summary>
private void startCalculation_Click( object sender, EventArgs e )
{
Field field = Field.fromFile( "setups/" + setupFiles.SelectedItem + ".txt" );
graphicBox.Image?.Dispose();
graphicBox.Image = GraphicGenerator.generateField( field, Dog.MAX, Dog.MINNIE );
realSizeSlider_Scroll( sender, e );
}

/// <summary>
/// triggers image resizing
/// </summary>
private void graphicsPanel_Resize( object sender, EventArgs e )
{
realSizeSlider_Scroll( sender, e );
}

/// <summary>
/// triggers image resizing
/// </summary>
private void graphicsPanel_SizeChanged( object sender, EventArgs e )
{
realSizeSlider_Scroll( sender, e );
}

/// <summary>
/// set the size relative between panel-size and image-size ( 0 = panel-size, 100 = image-size )
/// </summary>
private void realSizeSlider_Scroll( object sender, EventArgs e )
{
if ( graphicBox.Image == null ) return;
Size panelImageDiff = new Size( graphicBox.Image.Width - graphicsPanel.Width, graphicBox.Image.Height - graphicsPanel.Height );
float realSizeMod = realSizeSlider.Value / 100F;
graphicBox.Width = graphicsPanel.Width + ( int ) ( panelImageDiff.Width * realSizeMod ) - 25;
graphicBox.Height = graphicsPanel.Height + ( int ) ( panelImageDiff.Height * realSizeMod ) - 25;
}

SaveFileDialog sfd = new SaveFileDialog();

/// <summary>
/// opens a dialog to ask, where to save the file and then saves it
/// </summary>
private void saveImageAs_Click( object sender, EventArgs e )
{
sfd.Filter = "Bild-Datei|*.png";
if ( graphicBox.Image != null && sfd.ShowDialog() == DialogResult.OK )
{
graphicBox.Image.Save( sfd.FileName, ImageFormat.Png );
}
}
}
}

+ 505
- 0
Buhnenrennen/Scripter.resx Datei anzeigen

@@ -0,0 +1,505 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.

mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
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
JZKtx6TLuesAAAAASUVORK5CYII=
</value>
</data>
</root>

+ 20
- 0
Buhnenrennen/TimedGroyne.cs Datei anzeigen

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Buhnenrennen
{
@@ -11,6 +12,25 @@ namespace Buhnenrennen
public TimedGroyne ParentGroyne { get; set; }
public Groyne Groyne { get; set; }
public double TotalTime { get; set; }
public string TotalTimeConverted
{
get
{
string label = "";
int rest = ( int ) TotalTime;
int seconds = rest % 60;
rest = rest / 60;
int minutes = rest % 60;
int hours = rest / 60;

if ( hours > 0 ) label += hours + "h ";
if ( hours > 0 || minutes > 0 ) label += minutes + "min ";
label += seconds + "s ";
return label;
}
}
public double Distance => ParentGroyne.Groyne.DistanceTo( Groyne );
public string DistanceConverted => ( Math.Round( Distance * 100 ) / 100 ) + "m";

public List<TimedGroyne> FullRoute {
get {

BIN
Buhnenrennen/favicon.ico Datei anzeigen


BIN
favicon.ico Datei anzeigen


BIN
libs/DragonSkills99.ControlCollection.dll Datei anzeigen


BIN
libs/Newtonsoft.Json.dll Datei anzeigen


Laden…
Abbrechen
Speichern