|
|
|
|
|
|
|
|
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 ) |
|
|
|
|
|
|
|
|
Groynes = new Dictionary<double, List<Groyne>>(); |
|
|
|
|
|
Match m; |
|
|
|
|
|
foreach( string groyn in groynes ) |
|
|
{ |
|
|
{ |
|
|
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 ) |
|
|
|
|
|
|
|
|
if ( ( m = groynSchema.Match( groyn ) ).Success ) |
|
|
{ |
|
|
{ |
|
|
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 ); |
|
|
|
|
|
|
|
|
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 ) |
|
|
|
|
|
{ |
|
|
|
|
|
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 ] ) |
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* <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 ) |
|
|
{ |
|
|
{ |
|
|
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(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
Variable ’m’ could be named as for example ‘matchedGroyne’