Преглед изворни кода

Added Dog class for holding dog-specific data and readonly static properties with the actual data of our two dogs

Added Field for holding data of all groynes and calculating routes with it
added Groyne for holding data of a single groyne (just Y-Coordinate and the type, not X-Coordinate)
Added GroyneRun for actually running the algorithm
Added TimedGroyn for holding data of the required time between two groynes and the groynes itself (contains recursively the full route back to the root groyne)
master
benjamin.m пре 5 година
родитељ
комит
f20d35610d

+ 5
- 0
Buhnenrennen/Buhnenrennen.csproj Прегледај датотеку

@@ -43,8 +43,13 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="Dog.cs" />
<Compile Include="Field.cs" />
<Compile Include="Groyne.cs" />
<Compile Include="GroyneRun.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TimedGroyne.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />

+ 30
- 0
Buhnenrennen/Dog.cs Прегледај датотеку

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Buhnenrennen
{
class Dog
{
public static readonly Dog MINNIE = new Dog( 'M', new char[] { 'm', 'x', 'M' }, 20 );
public static readonly Dog MAX = new Dog( 'X', new char[] { 'x', 'X' }, 30 );

private char[] fitsThrough;
public char[] FitsThrough => this.fitsThrough;
private double meterPerSecond;
public double MeterPerSecond => this.meterPerSecond;
private char start;
public char Start => this.start;

private Dog( char start, char[] fitsThrough, double kmh )
{
this.start = start;
this.fitsThrough = fitsThrough;
// km/h : 3,6 = m/s ( Formula found through google )
this.meterPerSecond = kmh / 3.6;
}
}
}

+ 112
- 0
Buhnenrennen/Field.cs Прегледај датотеку

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

namespace Buhnenrennen
{
class Field
{
private Dictionary<double, List<Groyne>> groynes;
public Dictionary<double, List<Groyne>> Groynes => this.groynes;

public Field( Groyne[] level0, Groyne[] level1, Groyne[] level2, Groyne[] level3 )
{
groynes = new Dictionary<double, List<Groyne>>();
groynes.Add( 0, level0.ToList() );
groynes.Add( 70, level1.ToList() );
groynes.Add( 140, level2.ToList() );
groynes.Add( 210, level3.ToList() );
}

public Groyne[] findShortestPath( Dog dog )
{
List<Groyne> poles = new List<Groyne>();
Groyne start = groynes[ 0 ].Find( groyne => groyne.Type == dog.Start );
if ( start == null ) throw new Exception( "No start position found" );
poles.Add( start );

Groyne previous = start;
for( int level = 70; level <= groynes.Keys.Max(); level += 70 )
{
List<Groyne> candidates = groynes[ level ].Where( groyne => groyne.canPass( dog ) ).ToList();
var distances = candidates.Select( groyne => groyne.distanceTo( previous ) ).ToList();
var minDistance = distances.Min();
previous = candidates[ distances.IndexOf( minDistance ) ];
poles.Add( previous );
}

return poles.ToArray();
}

public TimedGroyne findFastestPath( Dog dog )
{
Groyne start = groynes[ 0 ].Find( groyne => groyne.Type == dog.Start );
if ( start == null ) throw new Exception( "No start position found" );

Groyne lastLevel = start;
Dictionary<int, List<TimedGroyne>> times = new Dictionary<int, List<TimedGroyne>>();
times.Add( 0, new TimedGroyne[] { new TimedGroyne( null, start, 0 ) }.ToList() );
for ( int level = 70; level <= groynes.Keys.Max(); level += 70 )
{
List<TimedGroyne> subTimes = new List<TimedGroyne>();
List<TimedGroyne> passables = times[ level - 70 ].Where( time => time.Groyne.canPass( dog ) ).ToList();
foreach ( Groyne groyne in groynes[ level ] )
{
List<TimedGroyne> possibleTimes = passables.Select( passable => new TimedGroyne( passable, groyne, passable.TotalTime + groyne.requiredTimeTo( passable.Groyne, dog ) ) ).ToList();
subTimes.Add( possibleTimes.OrderBy( time => time.TotalTime ).First() );
}
times.Add( level, subTimes );
}
return times[ 3 ].OrderBy( time => time.TotalTime ).First();
}

public Dictionary<double, List<TimedGroyne>> listFastestTimes( Dog dog )
{
Groyne start = groynes[ 0 ].Find( groyne => groyne.Type == dog.Start );
if ( start == null ) throw new Exception( "No start position found" );

Groyne lastLevel = start;
Dictionary<double, List<TimedGroyne>> times = new Dictionary<double, List<TimedGroyne>>();
times.Add( 0, new TimedGroyne[] { new TimedGroyne( null, start, 0 ) }.ToList() );
for ( int level = 70; level <= groynes.Keys.Max(); level += 70 )
{
List<TimedGroyne> subTimes = new List<TimedGroyne>();
List<TimedGroyne> passables = times[ level - 70 ].Where( time => time.Groyne.canPass( dog ) ).ToList();
foreach ( Groyne groyne in groynes[ level ] )
{
List<TimedGroyne> possibleTimes = passables.Select( passable => new TimedGroyne( passable, groyne, passable.TotalTime + groyne.requiredTimeTo( passable.Groyne, dog ) ) ).ToList();
subTimes.Add( possibleTimes.OrderBy( time => time.TotalTime ).FirstOrDefault() );
}
times.Add( level, subTimes );
}
return times;
}

public TimedGroyne getFastestSafeRoute( Dog hunter, Dog hunted )
{
var hunterMap = listFastestTimes( hunter );
var huntedMap = listFastestTimes( hunted );

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

for ( int level = 70; level <= groynes.Keys.Max(); level += 70 )
{
var huntedTimes = huntedMap[ level ];
var hunterTimes = hunterMap[ level ];

foreach( TimedGroyne time in huntedTimes )
{
if ( !safeGroynes.Contains( time.ParentGroyne.Groyne ) ) continue;
TimedGroyne hunterTime = hunterTimes.Find( _hunterTime => _hunterTime.Groyne == time.Groyne );
if ( hunterTime.TotalTime > time.TotalTime ) safeGroynes.Add( time.Groyne );
}
}

return huntedMap[ groynes.Keys.Max() ].Where( huntedRoute => safeGroynes.Contains( huntedRoute.Groyne ) ).OrderBy( huntedRoute => huntedRoute.TotalTime ).FirstOrDefault();
}
}
}

+ 34
- 0
Buhnenrennen/Groyne.cs Прегледај датотеку

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

namespace Buhnenrennen
{
class Groyne
{
private double yCoord;
public double YCoord => this.yCoord;
private char type;
public char Type => this.type;

public Groyne( double yCoord, char type )
{
this.yCoord = yCoord;
this.type = type;
}

public bool canPass( Dog dog ) => dog.FitsThrough.Contains( Type );

public double distanceTo( Groyne groyne ) =>
// distance: distance² = A² + B²
// A: 70
// B: difference of Y-Coordinates
Math.Sqrt( Math.Pow( 70, 2 ) + Math.Pow( YCoord - groyne.YCoord, 2 ) );

public double requiredTimeTo( Groyne groyne, Dog dog ) => distanceTo( groyne ) / dog.MeterPerSecond;

public override string ToString() => Type + "( " + YCoord + " )";
}
}

+ 51
- 0
Buhnenrennen/GroyneRun.cs Прегледај датотеку

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

namespace Buhnenrennen
{
class GroyneRun
{
public void Start()
{
Field field = new Field(
new Groyne[] {
new Groyne( 42.95, 'M' ),
new Groyne( 168.6, 'X' )
},
new Groyne[] {
new Groyne( 76.4, 'm' ),
new Groyne( 45.9, 'x' ),
new Groyne( 117.4, 'm' )
},
new Groyne[] {
new Groyne( 42.2, 'm' ),
new Groyne( 109.35, 'm' ),
new Groyne( 158.7, 'x' )
},
new Groyne[] {
new Groyne( 49.4, 'm' ),
new Groyne( 83.1, 'm' ),
new Groyne( 148.7, 'x' ),
new Groyne( 103.5 , 'x' )
}
);

TimedGroyne safePath = field.getFastestSafeRoute( Dog.MAX, Dog.MINNIE );

if ( safePath == null )
{
Console.WriteLine( "Es gibt leider keine sichere Route..." );
}
else
{
Console.WriteLine( "Die sichere Route für Minnie ist: " + string.Join( " -> ", safePath.FullRoute.Select( routePart => routePart.Groyne.ToString() ) ) );
Console.WriteLine( "Minnie braucht für sie ~" + Math.Round( safePath.TotalTime ) + " Sekunde(n) ( ~" + Math.Round( safePath.TotalTime / 60 ) + " Minute(n) )" );
}

Console.ReadKey();
}
}
}

+ 5
- 0
Buhnenrennen/Program.cs Прегледај датотеку

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;

@@ -8,8 +9,12 @@ namespace Buhnenrennen
{
class Program
{
// Buhne (de) = Groyne (en)

static void Main( string[] args )
{
GroyneRun run = new GroyneRun();
run.Start();
}
}
}

+ 32
- 0
Buhnenrennen/TimedGroyne.cs Прегледај датотеку

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

namespace Buhnenrennen
{
class TimedGroyne
{
public TimedGroyne ParentGroyne { get; set; }
public Groyne Groyne { get; set; }
public double TotalTime { get; set; }

public List<TimedGroyne> FullRoute {
get {
List<TimedGroyne> fullRoute;
if ( ParentGroyne != null ) fullRoute = ParentGroyne.FullRoute;
else fullRoute = new List<TimedGroyne>();
fullRoute.Add( this );
return fullRoute;
}
}

public TimedGroyne( TimedGroyne parentGroyne, Groyne groyne, double time )
{
ParentGroyne = parentGroyne;
Groyne = groyne;
TotalTime = time;
}
}
}

BIN
Buhnenrennen/bin/Debug/Buhnenrennen.exe Прегледај датотеку


+ 6
- 0
Buhnenrennen/bin/Debug/Buhnenrennen.exe.config Прегледај датотеку

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
</startup>
</configuration>

BIN
Buhnenrennen/bin/Debug/Buhnenrennen.pdb Прегледај датотеку


Loading…
Откажи
Сачувај