#1 added method for parsing groyne entries in Field

開啟中
benjamin.m 請求將 3 次程式碼提交從 feature-parse-setup-files 合併至 master

+ 1
- 0
.gitignore 查看文件

.vs .vs
obj obj
bin

+ 6
- 9
Buhnenrennen/Dog.cs 查看文件

public static readonly Dog MINNIE = new Dog( 'M', new char[] { 'm', 'x', 'M' }, 20 ); 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 ); 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 ) 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 ) // km/h : 3,6 = m/s ( Formula found through google )
this.meterPerSecond = kmh / 3.6;
MeterPerSecond = kmh / 3.6;
} }
} }
} }

+ 41
- 56
Buhnenrennen/Field.cs 查看文件

using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace Buhnenrennen namespace Buhnenrennen
{ {
class Field 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;

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 ) 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" ); if ( start == null ) throw new Exception( "No start position found" );


Groyne lastLevel = start; Groyne lastLevel = start;
Dictionary<double, List<TimedGroyne>> times = new Dictionary<double, List<TimedGroyne>>(); Dictionary<double, List<TimedGroyne>> times = new Dictionary<double, List<TimedGroyne>>();
times.Add( 0, new TimedGroyne[] { new TimedGroyne( null, start, 0 ) }.ToList() ); 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> 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() ); subTimes.Add( possibleTimes.OrderBy( time => time.TotalTime ).FirstOrDefault() );
} }
times.Add( level, subTimes ); times.Add( level, subTimes );
return times; 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 ) public TimedGroyne getFastestSafeRoute( Dog hunter, Dog hunted )
{ {
var hunterMap = listFastestTimes( hunter ); var hunterMap = listFastestTimes( hunter );
var huntedMap = listFastestTimes( hunted ); var huntedMap = listFastestTimes( hunted );


List<Groyne> safeGroynes = new List<Groyne>(); 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 huntedTimes = huntedMap[ level ];
var hunterTimes = hunterMap[ level ]; var hunterTimes = hunterMap[ level ];
} }
} }


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 查看文件

{ {
class Groyne 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 ) 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² // distance: distance² = A² + B²
// A: 70 // A: 70
// B: difference of Y-Coordinates // B: difference of Y-Coordinates
Math.Sqrt( Math.Pow( 70, 2 ) + Math.Pow( YCoord - groyne.YCoord, 2 ) ); 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 + " )"; public override string ToString() => Type + "( " + YCoord + " )";
} }

+ 47
- 22
Buhnenrennen/GroyneRun.cs 查看文件

using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;


namespace Buhnenrennen namespace Buhnenrennen
{ {
class GroyneRun 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 ); TimedGroyne safePath = field.getFastestSafeRoute( Dog.MAX, Dog.MINNIE );



二進制
Buhnenrennen/bin/Debug/Buhnenrennen.exe 查看文件


+ 0
- 6
Buhnenrennen/bin/Debug/Buhnenrennen.exe.config 查看文件

<?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…
取消
儲存