#1 added method for parsing groyne entries in Field

Отворени
benjamin.m заяви обединяване на 3 ревизии от feature-parse-setup-files във master

+ 1
- 0
.gitignore Целия файл

@@ -1,2 +1,3 @@
.vs
obj
bin

+ 6
- 9
Buhnenrennen/Dog.cs Целия файл

@@ -12,19 +12,16 @@ namespace Buhnenrennen
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;
public char[] FitsThrough { get; private set; }
public double MeterPerSecond { get; private set; }
public char Start { get; private set; }

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

+ 41
- 56
Buhnenrennen/Field.cs Целия файл

@@ -1,85 +1,65 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Buhnenrennen
{
class Field
{
private Dictionary<double, List<Groyne>> groynes;
public Dictionary<double, List<Groyne>> Groynes => this.groynes;
public Dictionary<double, List<Groyne>> Groynes { get; private set; }
Regex groynSchema = new Regex( "(?<type>[A-Z]) (?<level>[0-9]+) (?<yCoord>[0-9\\.]+)", RegexOptions.IgnoreCase );

// if there is a number of Groynes which is not "4", the program should also be able to work
// maybe we edit this as dynamic and add a new level like "groynes.Add(x+70, levelY.ToList())" till x = highestNumberOfTestData
public Field( Groyne[] level0, Groyne[] level1, Groyne[] level2, Groyne[] level3 )
private Field( IEnumerable<string> groynes )
{
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 )
Groynes = new Dictionary<double, List<Groyne>>();
Match m;
moritz.w коментира преди 5 години

Variable ’m’ could be named as for example ‘matchedGroyne’

Variable 'm' could be named as for example 'matchedGroyne'
foreach( string groyn in groynes )
{
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 );
if ( ( m = groynSchema.Match( groyn ) ).Success )
{
char type = m.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 );
if ( !this.Groynes.ContainsKey( level ) ) this.Groynes.Add( level, new List<Groyne>() );
this.Groynes[ level ].Add( new Groyne( yCoord, type ) );
}
}

return poles.ToArray();
}

public TimedGroyne findFastestPath( Dog dog )
/**
* <summary>returns a field object loaded from entries out of File at {filename}</summary>
* <param name="filename">Location of the file to read</param>
*/
public static Field fromFile( string filename )
{
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();
return new Field( File.ReadAllLines( filename ) );
}

/**
* <summary>returns a dictionary with groynes and the fastest times the give dog is able to reach them</summary>
* <param name="dog">dog that is running to the groynes</param>
*/

public Dictionary<double, List<TimedGroyne>> listFastestTimes( Dog dog )
{
Groyne start = groynes[ 0 ].Find( groyne => groyne.Type == dog.Start );
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 )
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> 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();
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 );
@@ -87,15 +67,20 @@ namespace Buhnenrennen
return times;
}

/**
* <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 )
{
var hunterMap = listFastestTimes( hunter );
var huntedMap = listFastestTimes( hunted );

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

for ( int level = 70; level <= groynes.Keys.Max(); level += 70 )
for ( int level = 70; level <= Groynes.Keys.Max(); level += 70 )
{
var huntedTimes = huntedMap[ level ];
var hunterTimes = hunterMap[ level ];
@@ -108,7 +93,7 @@ namespace Buhnenrennen
}
}

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

+ 20
- 9
Buhnenrennen/Groyne.cs Целия файл

@@ -8,26 +8,37 @@ namespace Buhnenrennen
{
class Groyne
{
private double yCoord;
public double YCoord => this.yCoord;
private char type;
public char Type => this.type;
public double YCoord { get; private set; }
public char Type { get; private set; }

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

public bool canPass( Dog dog ) => dog.FitsThrough.Contains( Type );
/// <summary>
/// returns if given dog fits through the groyne
/// </summary>
/// <param name="dog">the dog, that wants to fit through</param>
public bool CanPass( Dog dog ) => dog.FitsThrough.Contains( Type );

public double distanceTo( Groyne groyne ) =>
/// <summary>
/// returns the distance between called and given groyne
/// </summary>
/// <param name="groyne">groyne to calculate the distance to</param>
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;
/// <summary>
/// returns the time the given {dog} needs to get to given {groyne} starting at current groyne
/// </summary>
/// <param name="groyne">groyne the dog is running to</param>
/// <param name="dog">the dog, thats running to the groyne</param>
public double RequiredTimeTo( Groyne groyne, Dog dog ) => DistanceTo( groyne ) / dog.MeterPerSecond;

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

+ 47
- 22
Buhnenrennen/GroyneRun.cs Целия файл

@@ -1,37 +1,62 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Buhnenrennen
{
class GroyneRun
{
public void Start()
Regex setupFileRegex = new Regex( "^buhnenrennen(?<number>[0-9]+).txt$", RegexOptions.IgnoreCase );
Regex intFormatRegex = new Regex( "^[0-9]+$", RegexOptions.IgnoreCase );

/// <summary>
/// asks the user to enter the number of a setup file and loads the given file
/// </summary>
private Field selectField()
{
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' )
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();
List<string> filenumbers = filenumbers_int.Select( filenumber => filenumber.ToString() ).ToList();
if ( filenumbers.Count <= 0 ) return null;
Console.WriteLine( "Es wurden Setup-Dateien mit den folgenden Nummern gefunden:" );
Console.WriteLine( "\t" + string.Join( ", ", filenumbers ) );
Console.Write( "Bitte geben sie die Nummer des gewünschten Setups an ( " + filenumbers.FirstOrDefault() + " ): " );
string number = null;
do
{
if ( number != null ) Console.Write( "Der angegebene Wert ist keine Zahl, bitte versuche es erneut ( " + filenumbers.FirstOrDefault() + " ): " );
number = Console.ReadLine();
if ( string.IsNullOrWhiteSpace( number ) )
{
number = filenumbers.FirstOrDefault();
}
);
} while ( !intFormatRegex.IsMatch( number ) );


return Field.fromFile( "setups/buhnenrennen" + number + ".txt" );
}

/// <summary>
/// loads the field and fastest route to display them in the console
/// </summary>
public void Start()
{
Field field = selectField();
if ( field == null )
{
Console.WriteLine( "Es ist leider keine Setupdatei vorhanden. Bitte leg welche an und versuche es erneut." );
Console.ReadKey();
return;
}

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


Двоични данни
Buhnenrennen/bin/Debug/Buhnenrennen.exe Целия файл


+ 0
- 6
Buhnenrennen/bin/Debug/Buhnenrennen.exe.config Целия файл

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

Двоични данни
Buhnenrennen/bin/Debug/Buhnenrennen.pdb Целия файл


Loading…
Отказ
Запис