|
|
|
@@ -1,37 +1,53 @@ |
|
|
|
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; } |
|
|
|
|
|
|
|
public Field( Groyne[] level0, Groyne[] level1, Groyne[] level2, Groyne[] level3 ) |
|
|
|
Regex groynSchema = new Regex( "(?<type>[A-Z]) (?<level>[0-9]+) (?<yCoord>[0-9\\.]+)", RegexOptions.IgnoreCase ); |
|
|
|
|
|
|
|
private Field( IEnumerable<string> groynes ) |
|
|
|
{ |
|
|
|
Groynes = new Dictionary<double, List<Groyne>>(); |
|
|
|
Match m; |
|
|
|
foreach( string groyn in groynes ) |
|
|
|
{ |
|
|
|
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 ) ); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public static Field fromFile( string filename ) |
|
|
|
{ |
|
|
|
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() ); |
|
|
|
|
|
|
|
return new Field( File.ReadAllLines( filename ) ); |
|
|
|
} |
|
|
|
|
|
|
|
public Groyne[] findShortestPath( Dog dog ) |
|
|
|
{ |
|
|
|
List<Groyne> poles = new List<Groyne>(); |
|
|
|
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" ); |
|
|
|
poles.Add( start ); |
|
|
|
|
|
|
|
Groyne previous = start; |
|
|
|
for( int level = 70; level <= groynes.Keys.Max(); level += 70 ) |
|
|
|
for( int level = 70; level <= Groynes.Keys.Max(); level += 70 ) |
|
|
|
{ |
|
|
|
List<Groyne> candidates = groynes[ level ].Where( groyne => groyne.canPass( dog ) ).ToList(); |
|
|
|
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 ) ]; |
|
|
|
@@ -43,17 +59,17 @@ namespace Buhnenrennen |
|
|
|
|
|
|
|
public TimedGroyne findFastestPath( 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<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 ) |
|
|
|
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 ] ) |
|
|
|
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() ); |
|
|
|
@@ -65,17 +81,17 @@ namespace Buhnenrennen |
|
|
|
|
|
|
|
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 ] ) |
|
|
|
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() ); |
|
|
|
@@ -91,9 +107,9 @@ namespace Buhnenrennen |
|
|
|
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 ]; |
|
|
|
@@ -106,7 +122,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(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |