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
| <Reference Include="System.Xml" /> | <Reference Include="System.Xml" /> | ||||
| </ItemGroup> | </ItemGroup> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| <Compile Include="Dog.cs" /> | |||||
| <Compile Include="Field.cs" /> | |||||
| <Compile Include="Groyne.cs" /> | |||||
| <Compile Include="GroyneRun.cs" /> | |||||
| <Compile Include="Program.cs" /> | <Compile Include="Program.cs" /> | ||||
| <Compile Include="Properties\AssemblyInfo.cs" /> | <Compile Include="Properties\AssemblyInfo.cs" /> | ||||
| <Compile Include="TimedGroyne.cs" /> | |||||
| </ItemGroup> | </ItemGroup> | ||||
| <ItemGroup> | <ItemGroup> | ||||
| <None Include="App.config" /> | <None Include="App.config" /> |
| 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; | |||||
| } | |||||
| } | |||||
| } |
| 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(); | |||||
| } | |||||
| } | |||||
| } |
| 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 + " )"; | |||||
| } | |||||
| } |
| 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(); | |||||
| } | |||||
| } | |||||
| } |
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Linq; | using System.Linq; | ||||
| using System.Security.Permissions; | |||||
| using System.Text; | using System.Text; | ||||
| using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
| { | { | ||||
| class Program | class Program | ||||
| { | { | ||||
| // Buhne (de) = Groyne (en) | |||||
| static void Main( string[] args ) | static void Main( string[] args ) | ||||
| { | { | ||||
| GroyneRun run = new GroyneRun(); | |||||
| run.Start(); | |||||
| } | } | ||||
| } | } | ||||
| } | } |
| 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; | |||||
| } | |||||
| } | |||||
| } |
| <?xml version="1.0" encoding="utf-8" ?> | |||||
| <configuration> | |||||
| <startup> | |||||
| <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> | |||||
| </startup> | |||||
| </configuration> |