Imported CSharp project files

This commit is contained in:
Daniel Brunner
2017-03-12 10:39:32 +01:00
parent 476b278aef
commit c162661415
32 changed files with 12164 additions and 1 deletions

3
.cvsignore Normal file
View File

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

6
App.config Normal file
View File

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

172
KCC2017.csproj Normal file
View File

@@ -0,0 +1,172 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{7F2D3E68-6906-411E-9BDD-88DA3BAC0A6D}</ProjectGuid>
<OutputType>Exe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>com.knapp.KCC2017</RootNamespace>
<AssemblyName>KCC2017</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<IsWebBootstrapper>false</IsWebBootstrapper>
<CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
<TargetFrameworkProfile />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;__SG_CONTRACTS</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RunCodeAnalysis>false</RunCodeAnalysis>
<CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
<CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
<CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
<CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
<CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
<CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
<CodeContractsNonNullObligations>True</CodeContractsNonNullObligations>
<CodeContractsBoundsObligations>True</CodeContractsBoundsObligations>
<CodeContractsArithmeticObligations>True</CodeContractsArithmeticObligations>
<CodeContractsEnumObligations>True</CodeContractsEnumObligations>
<CodeContractsRedundantAssumptions>True</CodeContractsRedundantAssumptions>
<CodeContractsAssertsToContractsCheckBox>True</CodeContractsAssertsToContractsCheckBox>
<CodeContractsRedundantTests>True</CodeContractsRedundantTests>
<CodeContractsMissingPublicRequiresAsWarnings>True</CodeContractsMissingPublicRequiresAsWarnings>
<CodeContractsMissingPublicEnsuresAsWarnings>False</CodeContractsMissingPublicEnsuresAsWarnings>
<CodeContractsInferRequires>True</CodeContractsInferRequires>
<CodeContractsInferEnsures>False</CodeContractsInferEnsures>
<CodeContractsInferEnsuresAutoProperties>True</CodeContractsInferEnsuresAutoProperties>
<CodeContractsInferObjectInvariants>False</CodeContractsInferObjectInvariants>
<CodeContractsSuggestAssumptions>True</CodeContractsSuggestAssumptions>
<CodeContractsSuggestAssumptionsForCallees>True</CodeContractsSuggestAssumptionsForCallees>
<CodeContractsSuggestRequires>True</CodeContractsSuggestRequires>
<CodeContractsNecessaryEnsures>True</CodeContractsNecessaryEnsures>
<CodeContractsSuggestObjectInvariants>False</CodeContractsSuggestObjectInvariants>
<CodeContractsSuggestReadonly>True</CodeContractsSuggestReadonly>
<CodeContractsRunInBackground>True</CodeContractsRunInBackground>
<CodeContractsShowSquigglies>True</CodeContractsShowSquigglies>
<CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
<CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
<CodeContractsCustomRewriterAssembly />
<CodeContractsCustomRewriterClass />
<CodeContractsLibPaths />
<CodeContractsExtraRewriteOptions />
<CodeContractsExtraAnalysisOptions />
<CodeContractsSQLServerOption />
<CodeContractsBaseLineFile />
<CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
<CodeContractsSkipAnalysisIfCannotConnectToCache>False</CodeContractsSkipAnalysisIfCannotConnectToCache>
<CodeContractsFailBuildOnWarnings>False</CodeContractsFailBuildOnWarnings>
<CodeContractsBeingOptimisticOnExternal>True</CodeContractsBeingOptimisticOnExternal>
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
<LangVersion>5</LangVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<PropertyGroup>
<StartupObject>com.knapp.KCC2017.Program</StartupObject>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.IO.Compression" />
<Reference Include="System.IO.Compression.FileSystem" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="data\Container.cs" />
<Compile Include="data\ContainerSlot.cs" />
<Compile Include="data\ContainerType.cs" />
<Compile Include="data\Product.cs" />
<Compile Include="data\InputData.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Settings.cs" />
<Compile Include="solution\OptimizeStorage.cs" />
<Compile Include="util\CsvReader.cs" />
<Compile Include="util\KContract.cs" />
<Compile Include="util\PrepareUpload.cs" />
<Compile Include="util\ResultWriter.cs" />
<Compile Include="util\ToDelimitedString.cs" />
<Compile Include="warehouse\ContainerMaxGetExceededException.cs" />
<Compile Include="warehouse\ContainerNotAtWorkStationException.cs" />
<Compile Include="warehouse\ContainerNotInStorageException.cs" />
<Compile Include="warehouse\DestinationFillingExceededException.cs" />
<Compile Include="warehouse\ProductMismatchExcpetion.cs" />
<Compile Include="warehouse\SourceFillingExhaustedException.cs" />
<Compile Include="warehouse\Warehouse.cs" />
<Compile Include="warehouse\WarehouseInfos.cs" />
<Compile Include="warehouse\WarehouseOperation.cs" />
<Compile Include="warehouse\WorkStationCapcityExceededException.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="input\containers.csv">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="input\products.csv">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.5">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
<Install>false</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

Binary file not shown.

180
Program.cs Normal file
View File

@@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.IO;
using com.knapp.KCC2017.solution;
using com.knapp.KCC2017.util;
using com.knapp.KCC2017.warehouse;
using com.knapp.KCC2017.data;
namespace com.knapp.KCC2017
{
static class Program
{
static void Main( )
{
Console.Out.WriteLine("KNAPP Coding Contest 2017: Starting...");
Warehouse warehouse = null;
WarehouseInfos infosBefore = null;
WarehouseInfos infosAfter = null;
try
{
Console.Out.WriteLine("#... LOADING DATA ...");
InputData input = InputData.CreateFromCsv( );
warehouse = new Warehouse( input );
infosBefore = warehouse.BuildWarehouseInfos();
}
catch( Exception e )
{
ShowException( e, "Exception in startup code" );
Console.Out.WriteLine( "Press <enter>" );
Console.In.ReadLine( );
throw;
}
Console.Out.WriteLine( "# optimization" );
Console.Out.WriteLine( "### Your output starts here" );
OptimizeStorage optimizer = new OptimizeStorage( warehouse );
WriteProperties( optimizer, Settings.outPropertyFilename );
optimizer.Optimize();
Console.Out.WriteLine( "### Your output stops here" );
try
{
infosAfter = warehouse.BuildWarehouseInfos();
PrintStatisticsDiff( Console.Out, infosBefore, infosAfter );
PrepareUpload.WriteResult( warehouse.GetResult() );
PrepareUpload.CreateZipFile();
Console.Out.WriteLine( ">>> Created " + Settings.outZipFilename );
}
catch ( Exception e )
{
ShowException( e, "Exception in shutdown code" );
throw;
}
Console.Out.WriteLine( "Press <enter>" );
Console.In.ReadLine( );
}
private static void PrintStatisticsDiff( TextWriter writer, WarehouseInfos left, WarehouseInfos right )
{
writer.WriteLine( "# =============================================================================" );
writer.WriteLine( "#" );
writer.WriteLine( "# Empty | containers | slot" );
foreach ( ContainerType ct in ContainerType.Values )
{
writer.WriteLine( "# {0,10} | {1,5} ( {2,6:+##,##0;-##,##0;+0}) | {3,5} ({4,6:+##,##0;-##,##0;+0})"
, ct
, left.emptyContainers[ ct.Ordinal ]
, right.emptyContainers[ ct.Ordinal ] - left.emptyContainers[ ct.Ordinal ]
, right.emptySlots[ ct.Ordinal ]
, right.emptySlots[ ct.Ordinal ] - left.emptySlots[ ct.Ordinal ]
);
}
writer.WriteLine( "# {0,10} | {1,5} ( {2,6:+##,##0;-##,##0;+0}) | {3,5} ({4,6:+##,##0;-##,##0;+0})"
, "[TOTAL]"
, left.emptyContainers[ 0 ]
, right.emptyContainers[ 0 ] - left.emptyContainers[ 0 ]
, left.emptySlots[ 0 ]
, right.emptySlots[ 0 ] - left.emptySlots[ 0 ]
);
writer.WriteLine( "#" );
writer.WriteLine( "# SCORE: {0,6} (exclusive upload time) ", GetScore( left, right ) );
writer.WriteLine( "#" );
writer.WriteLine( "# =============================================================================" );
}
public static int GetScore( WarehouseInfos left, WarehouseInfos right )
{
int score = 0;
foreach( var ct in ContainerType.Values )
{
score += (right.emptySlots[ ct.Ordinal ] - left.emptySlots[ ct.Ordinal ] ) * ( 4 / ct.NumberOfSlots );
}
score += 2 * ( right.emptyContainers[ 0 ] - left.emptyContainers[ 0 ] );
return score;
}
/// <summary>
/// Helper function to write the properties to the file
/// </summary>
/// <param name="solution"></param>
/// <param name="outFilename"></param>
/// <exception cref="ArgumentException">when either solution.InstituteId or solution.ParticipantName is not valid</exception>
private static void WriteProperties(OptimizeStorage solution, string outFilename)
{
KContract.Requires<ArgumentException>( !string.IsNullOrWhiteSpace( solution.ParticipantName ), "solution.ParticipantName must not be empty - please set to correct value" );
KContract.Requires<ArgumentException>( !string.IsNullOrWhiteSpace(solution.InstituteId), "solution.InstituteId must not be empty - please set to correct value");
if (File.Exists(outFilename))
{
File.Delete( outFilename);
}
using (StreamWriter stream = new StreamWriter(outFilename))
{
stream.WriteLine( "# -*- conf-javaprop -*-" );
stream.WriteLine( "participant = {0} {1}", solution.InstituteId, solution.ParticipantName );
stream.WriteLine( "technology = c#" );
}
}
/// <summary>
/// write exception to console.error
/// includes inner exception and data
/// </summary>
/// <param name="e">exception that should be shown</param>
/// <param name="codeSegment">segment where the exception was caught</param>
public static void ShowException( Exception e, string codeSegment )
{
KContract.Requires( e != null, "e is mandatory but is null" );
KContract.Requires( ! string.IsNullOrWhiteSpace(codeSegment), "codeSegment is mandatory but is null or whitespace" );
Console.Out.WriteLine( "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" );
Console.Out.WriteLine( codeSegment );
Console.Out.WriteLine( "[{0}]: {1}", e.GetType( ).Name, e.Message );
for ( Exception inner = e.InnerException
; inner != null
; inner = inner.InnerException )
{
System.Console.WriteLine( ">>[{0}] {1}"
, inner.GetType( ).Name
, inner.Message
);
}
if ( e.Data != null && e.Data.Count > 0 )
{
Console.Error.WriteLine( "------------------------------------------------" );
Console.Error.WriteLine( "Data in exception:" );
foreach( KeyValuePair<string, string> elem in e.Data )
{
Console.Error.WriteLine( "[{0}] : '{1}'", elem.Key, elem.Value );
}
}
Console.Out.WriteLine( "------------------------------------------------" );
Console.Out.WriteLine( e.StackTrace );
Console.Out.WriteLine( "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" );
}
}
}

View File

@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle( "KCC2016" )]
[assembly: AssemblyDescription( "" )]
[assembly: AssemblyConfiguration( "" )]
[assembly: AssemblyCompany( "" )]
[assembly: AssemblyProduct( "KCC2016" )]
[assembly: AssemblyCopyright( "Copyright © 2016" )]
[assembly: AssemblyTrademark( "" )]
[assembly: AssemblyCulture( "" )]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible( false )]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid( "0c76da1d-443c-4815-a13d-0af7b0c1778c" )]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion( "1.0.0.0" )]
[assembly: AssemblyFileVersion( "1.0.0.0" )]

View File

@@ -1,4 +1,4 @@
# KnappCC2017 # KnappCC2017
Knapp Coding Contest 2017 Knapp Coding Contest 2017
The master branch only contains the files provided by Knapp AG (not even decompressed). This branch only contains the provided project files for CSharp without any modifications.

59
Settings.cs Normal file
View File

@@ -0,0 +1,59 @@
using com.knapp.KCC2017.util;
namespace com.knapp.KCC2017
{
/// <summary>
/// class containing settings for the program
///
/// DO NOT MODIFY THE SETTINGS
///
/// </summary>
public static class Settings
{
/// <summary>
/// Directory for the input files
/// </summary>
public const string DataPath = @"input";
/// <summary>
/// Filename for input of product data
/// </summary>
public const string InProductFilename = "products.csv";
/// <summary>
/// Filename for input of container data
/// </summary>
public const string InContainerFilename = "containers.csv";
/// <summary>
/// Directory where the output will be written
/// </summary>
public const string OutputPath = @"";
/// <summary>
/// Path where the source can be found
/// </summary>
public const string sourceDirectory = @"..\..\";
/// <summary>
/// Name of the results file
/// </summary>
public const string outResultFilename = @"warehouse-operations.csv";
/// <summary>
/// Name of the properties file
/// </summary>
public const string outPropertyFilename = @"KCC2017.properties";
/// <summary>
/// Name of the zip-file that is generated
/// </summary>
public const string outZipFilename = @"upload2017.zip";
/// <summary>
/// Name of the source directory within the zip file
/// </summary>
public const string zipSourceDirectory = "src/";
}
}

Binary file not shown.

99
data/Container.cs Normal file
View File

@@ -0,0 +1,99 @@
using com.knapp.KCC2017.entities;
using com.knapp.KCC2017.util;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace com.knapp.KCC2017.data
{
public class Container
{
/// <summary>
/// Container code (it's unique name)
/// </summary>
public string Code { get; private set; }
/// <summary>
/// Container type
/// </summary>
public ContainerType ContainerType { get; private set; }
private readonly ContainerSlot[] slots;
/// <summary>
/// constructor
/// </summary>
/// <param name="code">code of this container</param>
/// <param name="containerType">type of this container</param>
public Container( string code, ContainerType containerType )
{
this.Code = code;
this.ContainerType = containerType;
slots = new ContainerSlot[ ContainerType.NumberOfSlots ];
for( int i = 0; i < slots.Length; ++i )
{
slots[ i ] = new ContainerSlot( this, i );
}
}
/// <summary>
/// Is container empty (all slots are empty)
/// </summary>
/// <returns>true container is empty, false in any other case</returns>
public bool IsEmpy()
{
return ! slots.Any( s => !s.IsEmpty() );
}
/// <summary>
/// Return a collection with all slots
/// </summary>
/// <returns></returns>
public ReadOnlyCollection<ContainerSlot> GetSlots()
{
return new ReadOnlyCollection<ContainerSlot>( slots );
}
/// <summary>
/// Get a list with all empty slots in the container
/// </summary>
/// <returns>a list with empty slots, an empty list if non are empty</returns>
public List<ContainerSlot> GetEmptySlots()
{
return slots.Where( s => s.IsEmpty() ).ToList();
}
/// <summary>
/// Stringify this
/// </summary>
/// <returns>a human readable string representing this instance</returns>
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append( "Container[ code= " ).Append( Code );
sb.Append( ", type = " ).Append( ContainerType );
sb.Append( "] {" );
foreach( var slot in slots )
{
if( slot.IsEmpty() )
{
sb.Append("<empty>, ");
}
else
{
sb.Append( slot.Product.Code ).Append( ", #" ).Append(slot.Quantity).Append(",");
}
}
return sb.ToString();
}
}
}

62
data/ContainerSlot.cs Normal file
View File

@@ -0,0 +1,62 @@
using com.knapp.KCC2017.entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace com.knapp.KCC2017.data
{
public class ContainerSlot
{
public Container Container { get; private set; }
public Product Product { get; private set; }
public int Index { get; private set; }
public int Quantity { get; private set; }
public ContainerSlot( Container container, int index )
{
this.Container = container;
this.Index = index;
}
public bool IsEmpty()
{
return Product == null;
}
public override string ToString()
{
if( IsEmpty() )
{
return "ContainerSlot[]";
}
return "ContainerSlot[ product= " + Product + ", quantitiy= " + Quantity + "]";
}
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// should only be called internal!!! otherwise you could tamper with the result
// (Warehouse.apply(moveItems), InputData.readContainers())
public void _SetProduct( Product product)
{
this.Product = product;
}
public void _SetQuantity( int quantity )
{
this.Quantity = quantity;
if ( quantity == 0 )
{
Product = null;
}
}
}
}

123
data/ContainerType.cs Normal file
View File

@@ -0,0 +1,123 @@
using com.knapp.KCC2017.util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace com.knapp.KCC2017.data
{
/// <summary>
/// Represents the base type for the type of a container type
/// The Types can be
/// ContainerType.Full
/// ContainerType.Quarter
/// ContainerType.Half
///
/// This is a .NET implementation of enums with data as they exist in Jaba
/// </summary>
public class ContainerType : EnumBase<ContainerType>
{
public static readonly ContainerType Full = new ContainerType( "Full" , 1 );
public static readonly ContainerType Half = new ContainerType("Half", 2);
public static readonly ContainerType Quarter = new ContainerType("Quarter", 4);
/// <summary>
/// The strign identifying this 'enum'
/// </summary>
public string Token { get; protected set; }
/// <summary>
/// Gets the ordinal of the enum
/// The order in which they have been declared in the deriving class
/// </summary>
public int Ordinal { get; protected set; }
/// <summary>
/// The number of slots available in a container of this type
/// </summary>
public int NumberOfSlots { get; protected set; }
public override string ToString()
{
return Token;
}
public override int GetHashCode()
{
return Token.GetHashCode();
}
/// <summary>
/// Get the number of different types that have been declared
/// </summary>
public static int Count
{
get
{
return values.Count;
}
}
/// <summary>
/// Get all declared types
/// </summary>
public static IEnumerable<ContainerType> Values
{
get
{
return values;
}
}
public static ContainerType Get( string token )
{
return values.FirstOrDefault( r => r.Token.Equals( token, StringComparison.InvariantCulture ) );
}
/// <summary>
/// Equality operation
/// Equals when the other ContainerType is not null and the token (Full, Half, Quarter) matches
/// </summary>
/// <param name="obj">object to compare with</param>
/// <returns>true when obj is a Product and has the same code, false in any other case</returns>
public override bool Equals(object obj)
{
ContainerType other = obj as ContainerType;
return other != null
&& this.Token == other.Token;
}
private ContainerType( string token, int numberOfSlots )
{
Token = token;
NumberOfSlots = numberOfSlots;
Add(this);
Ordinal = values.Count;
}
/// <summary>
/// Add a concrete type to the List
/// </summary>
/// <param name="value"></param>
private static void Add( ContainerType value )
{
values.Add( value );
}
}
public abstract class EnumBase<T>
{
/// <summary>
/// store all declared derived types of T
/// (all declared 'enums')
/// </summary>
protected readonly static List<T> values = new List<T>();
}
}

145
data/InputData.cs Normal file
View File

@@ -0,0 +1,145 @@
using com.knapp.KCC2017.data;
using com.knapp.KCC2017.entities;
using com.knapp.KCC2017.util;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
namespace com.knapp.KCC2017
{
/// <summary>
/// Container class for all input into the solution
/// </summary>
public class InputData
{
/// <summary>
/// List of all products that are used in this contest
/// </summary>
private readonly List<Product> products = new List<Product>();
/// <summary>
/// List of all containers (storage and workstation)
/// </summary>
private readonly List<Container> containers = new List<Container>();
/// <summary>
/// Get a read-only collection of all products
/// </summary>
/// <returns>readon-only collection with all products</returns>
public ReadOnlyCollection<Product> GetProducts()
{
return new ReadOnlyCollection<Product>( products );
}
/// <summary>
/// Get a read-only collection of all containes (storage and workstation)
/// </summary>
/// <returns>read-onyl collection of all containers</returns>
public ReadOnlyCollection<Container> GetContainers()
{
return new ReadOnlyCollection<Container>( containers );
}
/// <summary>
/// Create from outside only via CreateFromCsv
/// </summary>
private InputData( )
{/* EMPTY */ }
/// <summary>
/// Load all input data from the csv files and create instance (and composite instances)
/// </summary>
/// <returns>a newly created ínstance of the inout</returns>
public static InputData CreateFromCsv()
{
InputData input = new InputData();
input.LoadProductsFromCsv( System.IO.Path.Combine( Settings.DataPath, Settings.InProductFilename ) );
input.LoadContainersFromCsv( System.IO.Path.Combine( Settings.DataPath, Settings.InContainerFilename ) );
return input;
}
/// <summary>
/// Load all products from the CSV
/// </summary>
/// <param name="fullFilename">full path of the csv</param>
private void LoadProductsFromCsv( string fullFilename )
{
KContract.Requires( !string.IsNullOrWhiteSpace( fullFilename ), "fullFilename mandatory but is null or whitespace" );
foreach ( Product product in CsvReader.ReadCsvFile<Product>( fullFilename ) )
{
products.Add( product );
}
System.Console.Out.WriteLine( "+++ loaded: {0} products", products.Count );
}
/// <summary>
/// Load all containers from csv
/// </summary>
/// <param name="fullFilename">full path of the csv</param>
private void LoadContainersFromCsv( string fullFilename )
{
KContract.Requires( !string.IsNullOrWhiteSpace( fullFilename ), "fullFilename mandatory but is null or whitespace" );
using ( StreamReader streamReader = new StreamReader( fullFilename ) )
{
string line;
while ( ( line = streamReader.ReadLine() ) != null )
{
if ( !string.IsNullOrWhiteSpace( line )
&& !line.StartsWith( "#" ) )
{
string[] fields = line.Split(new[] { ';' });
string code = fields[ 0 ].Trim();
ContainerType type = ContainerType.Get( fields[1].Trim() );
Container container = new Container( code, type );
for ( int i = 2, s = 0; i < fields.Length; i += 2, ++s )
{
if ( !string.IsNullOrWhiteSpace( fields[ i ] ) )
{
Product p = FindProductByCode( fields[i].Trim() );
int quantity = int.Parse( fields[i+1]);
container.GetSlots()[ s ]._SetProduct( p );
container.GetSlots()[ s ]._SetQuantity( quantity );
}
}
containers.Add( container );
}
}
}
System.Console.Out.WriteLine( "+++ loaded: {0} containers", containers.Count );
}
/// <summary>
/// Helper function to find product
/// </summary>
/// <param name="productCode"></param>
/// <returns>product wuth goven code</returns>
/// <exception cref=""></exception>
private Product FindProductByCode( string productCode )
{
Product result = products.Find( p => p.Code.Equals( productCode ) );
if( result == null )
{
throw new KeyNotFoundException("no product found for code " + productCode );
}
return result;
}
}
}

114
data/Product.cs Normal file
View File

@@ -0,0 +1,114 @@
using com.knapp.KCC2017.util;
using com.knapp.KCC2017.data;
using System;
using System.Collections.Generic;
using System.Linq;
namespace com.knapp.KCC2017.entities
{
/// <summary>
/// A product that is handled in a warehouse
/// </summary>
public class Product
{
/// <summary>
/// store for the max quanitites for each slot type
/// </summary>
private readonly Dictionary<ContainerType, int> maxQuantities = new Dictionary<ContainerType, int>();
/// <summary>
/// Unique code of this product
/// </summary>
public string Code { get; private set; }
/// <summary>
/// Get stringified representation of this instance
/// </summary>
/// <returns>strign with infos for this instance</returns>
public override string ToString( )
{
return string.Format("Product[ code={0}, maxQuantities={1}]"
, Code
, CollapseMaxQuantites()
); ;
}
/// <summary>
/// Create a product from the given data
/// </summary>
/// <param name="dataAsArray"></param>
public Product( string[] dataAsArray )
{
KContract.Requires( dataAsArray != null, "dataAsArray mandatory but is null" );
KContract.Requires( dataAsArray.Length >= 3, "dataAsArray must contain at least 3 elements :" + dataAsArray[0] );
KContract.Requires<ArgumentException>( !string.IsNullOrWhiteSpace( dataAsArray[ 0 ] ), "Code must not be null @ offset 0" );
Code = dataAsArray[ 0 ].Trim( );
foreach( ContainerType t in ContainerType.Values )
{
maxQuantities.Add( t, 0 );
}
for ( int i = 1; i < dataAsArray.Length; i += 2 )
{
ContainerType t = ContainerType.Get(dataAsArray[i]);
if ( default(ContainerType) == t )
{
throw new ArgumentException( string.Format( "Unknonwn ContainerType '{0}' for product {1}", dataAsArray[i], Code ) );
}
maxQuantities[t] = int.Parse(dataAsArray[i + 1]);
}
if( maxQuantities.Count != 3 )
{
throw new InvalidOperationException("to few quantitites");
}
}
/// <summary>
/// Get the number of max. allowed items for the given slot/ container type
/// </summary>
/// <param name="containerType">the type for which to return the max. number of items</param>
/// <returns>max. number of allowed items for given type</returns>
public int GetMaxQuantity( ContainerType containerType )
{
return maxQuantities[ containerType ];
}
/// <summary>
/// Equality operation
/// </summary>
/// <param name="obj">object to compare with</param>
/// <returns>true when obj is a Product and has the same code, false in any other case</returns>
public override bool Equals( object obj )
{
Product other = obj as Product;
return other != null
&& this.Code == other.Code;
}
/// <summary>
/// GetHashCode method
/// since Equals is defined
/// </summary>
/// <returns>the product code</returns>
public override int GetHashCode( )
{
return Code.GetHashCode( );
}
/// <summary>
/// Helper function to print the maxQuantities beautifully
/// </summary>
/// <returns>a beautifully looking string with all the quantities</returns>
private string CollapseMaxQuantites()
{
return "{" + string.Join(", ", maxQuantities.Select( t => t.Key + "=" + t.Value ) ) + "}";
}
}
}

10001
input/containers.csv Normal file

File diff suppressed because it is too large Load Diff

101
input/products.csv Normal file
View File

@@ -0,0 +1,101 @@
# code;(container-type;max-slot-quantity;)+
PROD000001;Full;96;
PROD000002;Full;55;Half;25;Quarter;10;
PROD000003;Full;415;Half;207;Quarter;103;
PROD000004;Full;48;
PROD000005;Full;122;Half;60;Quarter;29;
PROD000006;Full;55;Half;25;Quarter;10;
PROD000007;Half;201;Quarter;100;
PROD000008;Full;102;Half;51;
PROD000009;Full;28;
PROD000010;Full;127;Half;63;Quarter;31;
PROD000011;Quarter;31;
PROD000012;Full;198;Half;98;Quarter;48;
PROD000013;Half;20;Quarter;9;
PROD000014;Full;207;Half;103;Quarter;51;
PROD000015;Full;51;Half;23;Quarter;9;
PROD000016;Full;51;Half;23;Quarter;9;
PROD000017;Half;96;Quarter;48;
PROD000018;Full;396;Half;198;Quarter;99;
PROD000019;Full;36;Half;18;Quarter;9;
PROD000020;Full;40;Half;20;Quarter;10;
PROD000021;Full;102;Half;51;
PROD000022;Half;23;Quarter;9;
PROD000023;Full;36;Half;18;Quarter;9;
PROD000024;Full;48;
PROD000025;Full;198;Half;98;
PROD000026;Quarter;50;
PROD000027;Full;29;
PROD000028;Half;195;Quarter;97;
PROD000029;Full;9;
PROD000030;Full;130;Half;64;Quarter;31;
PROD000031;Quarter;51;
PROD000032;Full;192;Half;96;Quarter;48;
PROD000033;Full;407;Half;203;Quarter;101;
PROD000034;Full;139;Half;67;Quarter;31;
PROD000035;Full;9;
PROD000036;Full;99;
PROD000037;Full;195;Half;97;Quarter;48;
PROD000038;Full;49;
PROD000039;Full;96;
PROD000040;Full;61;Half;30;
PROD000041;Full;42;Half;20;Quarter;9;
PROD000042;Full;415;Half;205;Quarter;100;
PROD000043;Full;396;Half;198;Quarter;99;
PROD000044;Full;55;Half;25;Quarter;10;
PROD000045;Full;46;Half;22;Quarter;10;
PROD000046;Half;105;Quarter;50;
PROD000047;Full;55;Half;25;Quarter;10;
PROD000048;Full;50;
PROD000049;Full;9;
PROD000050;Full;20;Half;9;
PROD000051;Full;400;Half;200;Quarter;100;
PROD000052;Quarter;31;
PROD000053;Full;207;Half;103;Quarter;51;
PROD000054;Full;9;
PROD000055;Full;36;Half;18;Quarter;9;
PROD000056;Full;18;Half;9;
PROD000057;Full;388;Half;194;Quarter;97;
PROD000058;Quarter;9;
PROD000059;Full;61;Half;28;
PROD000060;Full;49;
PROD000061;Full;10;
PROD000062;Quarter;49;
PROD000063;Full;387;Half;193;Quarter;96;
PROD000064;Full;61;Half;30;
PROD000065;Full;48;
PROD000066;Full;42;Half;20;Quarter;9;
PROD000067;Quarter;103;
PROD000068;Full;120;Half;60;Quarter;30;
PROD000069;Quarter;101;
PROD000070;Full;202;Half;100;Quarter;49;
PROD000071;Quarter;10;
PROD000072;Full;192;Half;96;
PROD000073;Full;120;Half;60;Quarter;30;
PROD000074;Full;46;Half;22;Quarter;10;
PROD000075;Full;101;
PROD000076;Full;100;
PROD000077;Full;119;Half;59;Quarter;29;
PROD000078;Full;62;Half;31;
PROD000079;Half;102;Quarter;51;
PROD000080;Half;194;Quarter;97;
PROD000081;Quarter;31;
PROD000082;Full;112;Half;56;Quarter;28;
PROD000083;Full;122;Half;60;Quarter;29;
PROD000084;Full;390;Half;194;Quarter;96;
PROD000085;Full;65;Half;30;
PROD000086;Full;127;Half;61;Quarter;28;
PROD000087;Half;18;Quarter;9;
PROD000088;Full;116;Half;58;Quarter;29;
PROD000089;Full;101;
PROD000090;Full;115;Half;57;Quarter;28;
PROD000091;Full;105;Half;50;
PROD000092;Full;97;
PROD000093;Full;20;Half;10;
PROD000094;Full;116;Half;58;Quarter;29;
PROD000095;Full;29;
PROD000096;Full;9;
PROD000097;Full;20;Half;10;
PROD000098;Full;206;Half;102;Quarter;50;
PROD000099;Half;21;Quarter;10;
PROD000100;Full;10;
1 # code;(container-type;max-slot-quantity;)+
2 PROD000001;Full;96;
3 PROD000002;Full;55;Half;25;Quarter;10;
4 PROD000003;Full;415;Half;207;Quarter;103;
5 PROD000004;Full;48;
6 PROD000005;Full;122;Half;60;Quarter;29;
7 PROD000006;Full;55;Half;25;Quarter;10;
8 PROD000007;Half;201;Quarter;100;
9 PROD000008;Full;102;Half;51;
10 PROD000009;Full;28;
11 PROD000010;Full;127;Half;63;Quarter;31;
12 PROD000011;Quarter;31;
13 PROD000012;Full;198;Half;98;Quarter;48;
14 PROD000013;Half;20;Quarter;9;
15 PROD000014;Full;207;Half;103;Quarter;51;
16 PROD000015;Full;51;Half;23;Quarter;9;
17 PROD000016;Full;51;Half;23;Quarter;9;
18 PROD000017;Half;96;Quarter;48;
19 PROD000018;Full;396;Half;198;Quarter;99;
20 PROD000019;Full;36;Half;18;Quarter;9;
21 PROD000020;Full;40;Half;20;Quarter;10;
22 PROD000021;Full;102;Half;51;
23 PROD000022;Half;23;Quarter;9;
24 PROD000023;Full;36;Half;18;Quarter;9;
25 PROD000024;Full;48;
26 PROD000025;Full;198;Half;98;
27 PROD000026;Quarter;50;
28 PROD000027;Full;29;
29 PROD000028;Half;195;Quarter;97;
30 PROD000029;Full;9;
31 PROD000030;Full;130;Half;64;Quarter;31;
32 PROD000031;Quarter;51;
33 PROD000032;Full;192;Half;96;Quarter;48;
34 PROD000033;Full;407;Half;203;Quarter;101;
35 PROD000034;Full;139;Half;67;Quarter;31;
36 PROD000035;Full;9;
37 PROD000036;Full;99;
38 PROD000037;Full;195;Half;97;Quarter;48;
39 PROD000038;Full;49;
40 PROD000039;Full;96;
41 PROD000040;Full;61;Half;30;
42 PROD000041;Full;42;Half;20;Quarter;9;
43 PROD000042;Full;415;Half;205;Quarter;100;
44 PROD000043;Full;396;Half;198;Quarter;99;
45 PROD000044;Full;55;Half;25;Quarter;10;
46 PROD000045;Full;46;Half;22;Quarter;10;
47 PROD000046;Half;105;Quarter;50;
48 PROD000047;Full;55;Half;25;Quarter;10;
49 PROD000048;Full;50;
50 PROD000049;Full;9;
51 PROD000050;Full;20;Half;9;
52 PROD000051;Full;400;Half;200;Quarter;100;
53 PROD000052;Quarter;31;
54 PROD000053;Full;207;Half;103;Quarter;51;
55 PROD000054;Full;9;
56 PROD000055;Full;36;Half;18;Quarter;9;
57 PROD000056;Full;18;Half;9;
58 PROD000057;Full;388;Half;194;Quarter;97;
59 PROD000058;Quarter;9;
60 PROD000059;Full;61;Half;28;
61 PROD000060;Full;49;
62 PROD000061;Full;10;
63 PROD000062;Quarter;49;
64 PROD000063;Full;387;Half;193;Quarter;96;
65 PROD000064;Full;61;Half;30;
66 PROD000065;Full;48;
67 PROD000066;Full;42;Half;20;Quarter;9;
68 PROD000067;Quarter;103;
69 PROD000068;Full;120;Half;60;Quarter;30;
70 PROD000069;Quarter;101;
71 PROD000070;Full;202;Half;100;Quarter;49;
72 PROD000071;Quarter;10;
73 PROD000072;Full;192;Half;96;
74 PROD000073;Full;120;Half;60;Quarter;30;
75 PROD000074;Full;46;Half;22;Quarter;10;
76 PROD000075;Full;101;
77 PROD000076;Full;100;
78 PROD000077;Full;119;Half;59;Quarter;29;
79 PROD000078;Full;62;Half;31;
80 PROD000079;Half;102;Quarter;51;
81 PROD000080;Half;194;Quarter;97;
82 PROD000081;Quarter;31;
83 PROD000082;Full;112;Half;56;Quarter;28;
84 PROD000083;Full;122;Half;60;Quarter;29;
85 PROD000084;Full;390;Half;194;Quarter;96;
86 PROD000085;Full;65;Half;30;
87 PROD000086;Full;127;Half;61;Quarter;28;
88 PROD000087;Half;18;Quarter;9;
89 PROD000088;Full;116;Half;58;Quarter;29;
90 PROD000089;Full;101;
91 PROD000090;Full;115;Half;57;Quarter;28;
92 PROD000091;Full;105;Half;50;
93 PROD000092;Full;97;
94 PROD000093;Full;20;Half;10;
95 PROD000094;Full;116;Half;58;Quarter;29;
96 PROD000095;Full;29;
97 PROD000096;Full;9;
98 PROD000097;Full;20;Half;10;
99 PROD000098;Full;206;Half;102;Quarter;50;
100 PROD000099;Half;21;Quarter;10;
101 PROD000100;Full;10;

View File

@@ -0,0 +1,57 @@
using System;
using System.Linq;
using System.Collections.Generic;
using com.knapp.KCC2017.data;
using com.knapp.KCC2017.entities;
using com.knapp.KCC2017.util;
using com.knapp.KCC2017.warehouse;
namespace com.knapp.KCC2017.solution
{
public class OptimizeStorage
{
/// <summary>
///
/// Your name
/// Please set in constructor
/// </summary>
public string ParticipantName { get; private set; }
/// <summary>
///
/// The Id of your institute - please refer to the handout
/// Please set in constructor
/// </summary>
public string InstituteId { get; private set; }
/// <summary>
/// local reference to the global warehouse
/// </summary>
private readonly Warehouse warehouse;
/// <summary>
/// Create the solution instance
///
/// Do all your preparations here
///
/// </summary>
public OptimizeStorage( Warehouse warehouse )
{
KContract.Requires( warehouse != null, "input required but is null" );
this.warehouse = warehouse;
//Your code goes here
ParticipantName = ;
InstituteId = ;
}
public void Optimize()
{
//YOUR CODE GOES HERE
}
}
}

59
util/CsvReader.cs Normal file
View File

@@ -0,0 +1,59 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
namespace com.knapp.KCC2017.util
{
internal static class CsvReader
{
/// <summary>
/// read lines from a CSV file, create instances of type Target by calling a string[] constructor
/// </summary>
/// <typeparam name="Target">type to create</typeparam>
/// <param name="fullFileName">Full path to the csv file</param>
/// <returns>a list of instances or a empty list</returns>
public static List<Target> ReadCsvFile<Target>( string fullFileName )
where Target : class
{
KContract.Requires( !string.IsNullOrWhiteSpace( fullFileName ), "fullFileName mandatory but is null" );
if ( false == File.Exists( fullFileName ) )
{
throw new InvalidOperationException(string.Format("CSV-Input file does not exist: '{0}'", fullFileName ) );
}
ConstructorInfo ctorInfo = typeof( Target ).GetConstructor( new [] { typeof(string[]) } );
if ( null == ctorInfo )
{
throw new InvalidOperationException( string.Format( "Target '{0}' can not be constructed because it does not contain a ctor with string [] as argument"
, typeof( Target).FullName ) );
}
List<Target> objects = new List<Target>();
using (StreamReader streamReader = new StreamReader( fullFileName ))
{
string line;
while ((line = streamReader.ReadLine() ) != null )
{
if ( !string.IsNullOrWhiteSpace( line )
&& !line.StartsWith("#"))
{
string[] fields = line.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
Target t = (Target)ctorInfo.Invoke(new object[] { fields });
objects.Add(t);
}
}
}
return objects;
}
}
}

95
util/KContract.cs Normal file
View File

@@ -0,0 +1,95 @@
using System;
using System.Diagnostics;
namespace com.knapp.KCC2017.util
{
/// <summary>
/// Helper class to assert preconditions in methods
/// </summary>
public static class KContract
{
/// <summary>
/// Assert condition and throw ArgumentException when not satisfied
/// </summary>
/// <param name="condition">condition to check --> false throws exception</param>
/// <param name="message">message that is shown</param>
public static void Assert( bool condition, string message )
{
if ( !condition )
{
Assert<ArgumentException>( condition, message );
}
}
/// <summary>
/// Assert condition and throw ArgumentException when not satisfied
/// </summary>
/// <typeparam name="X">Type of exception to throw</typeparam>
/// <param name="condition">condition to check --> false throws exception</param>
/// <param name="message">message that is shown</param>
public static void Assert<X>( bool condition, string message )
where X : Exception, new()
{
if ( !condition )
{
StackTrace trace = new StackTrace( 1, false );
StackFrame frame = trace.GetFrame( 1 );
Type offendingType = frame.GetMethod( ).DeclaringType;
string methodName = frame.GetMethod( ).Name;
string fullMessage = string.Format( "Methode {0}.{1}: {2}"
, offendingType.Name
, methodName
, message
);
X x = (X)Activator.CreateInstance( typeof( X ), fullMessage );
throw x;
}
}
/// <summary>
/// Require precondition and throw ArgumentException when not satisfied
/// </summary>
/// <param name="condition">condition to check --> false throws exception</param>
/// <param name="message">message that is shown</param>
public static void Requires( bool condition
, string message = "Ungültige Argumente (Requires)"
)
{
if ( !condition )
{
Requires<ArgumentException>( condition, message );
}
}
/// <summary>
/// Require precondition and throw ArgumentException when not satisfied
/// </summary>
/// <typeparam name="X">Type of exception to throw</typeparam>
/// <param name="condition">condition to check --> false throws exception</param>
/// <param name="message">message that is shown</param>
public static void Requires<X>( bool condition
, string message = "Ungültige Argumente (Requires)"
) where X : Exception,new()
{
if ( !condition )
{
StackTrace trace = new StackTrace( 1, false );
StackFrame frame = trace.GetFrame( 1 );
Type offendingType = frame.GetMethod( ).DeclaringType;
string methodName = frame.GetMethod( ).Name;
string fullMessage = string.Format( "Methode {0}.{1}: {2}"
, offendingType.Name
, methodName
, message
);
X x = (X)Activator.CreateInstance( typeof( X ), fullMessage );
throw x;
}
}
}
}

83
util/PrepareUpload.cs Normal file
View File

@@ -0,0 +1,83 @@
using com.knapp.KCC2017.warehouse;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
namespace com.knapp.KCC2017.util
{
/// <summary>
/// Helper class to create zip for upload
/// </summary>
public static class PrepareUpload
{
/// <summary>
/// **KNAPP use only
/// Create uploadable zip file
///
/// </summary>
public static void CreateZipFile()
{
string resultsFile = Path.Combine( Settings.OutputPath, Settings.outResultFilename );
string propertiesFile = Path.Combine( Settings.OutputPath, Settings.outPropertyFilename );
string zipFile = Path.Combine( Settings.OutputPath, Settings.outZipFilename );
if ( File.Exists( zipFile ) )
{
File.Delete( zipFile );
}
using ( ZipArchive archive = ZipFile.Open( zipFile, ZipArchiveMode.Create ) )
{
archive.CreateEntryFromFile( resultsFile, Settings.outResultFilename );
archive.CreateEntryFromFile( propertiesFile, Settings.outPropertyFilename );
AddSourceDirectoryToZipFile( Settings.zipSourceDirectory, archive, Settings.sourceDirectory );
}
}
/// <summary>
/// ** KNAPP use only
/// Add a source folder to the upload zip
/// bin and obj folders are ignored
/// </summary>
/// <param name="directoryPrefix">prefix of the directory</param>
/// <param name="archive">zip archive to add the contents of the directory to</param>
/// <param name="pathName">path to add to the zip file</param>
private static void AddSourceDirectoryToZipFile( string directoryPrefix, ZipArchive archive, string pathName )
{
foreach(var file in Directory.GetFiles( pathName ) )
{
string zipName = file.Substring( Settings.sourceDirectory.Length );
archive.CreateEntryFromFile( file, directoryPrefix + zipName);
}
foreach ( var subDir in Directory.GetDirectories( pathName ) )
{
if ( !subDir.EndsWith( "bin" )
&& !subDir.EndsWith( "obj" ) )
{
AddSourceDirectoryToZipFile( directoryPrefix, archive, subDir );
}
}
}
/// <summary>
/// ** KNAPP use only
/// Write the created results to the export file
/// </summary>
/// <param name="operations">enumerable with operations created during optimization</param>
public static void WriteResult( IEnumerable<WarehouseOperation> operations )
{
using ( StreamWriter writer = new StreamWriter( Path.Combine( Settings.OutputPath, Settings.outResultFilename ) ) )
{
foreach ( var operation in operations )
{
writer.WriteLine( operation.ToResultString() );
}
}
}
}
}

76
util/ResultWriter.cs Normal file
View File

@@ -0,0 +1,76 @@
using com.knapp.KCC2017.entities;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace com.knapp.KCC2017.util
{
/// <summary>
/// Write for result file
///
/// Should not be modified
///
/// </summary>
public class ResultWriter : IDisposable
{
private readonly StreamWriter resultFileWriter;
/// <summary>
/// Create a result writer that will write to the given file
/// An existing file is deleted
/// </summary>
/// <param name="filename"></param>
public ResultWriter( string filename )
{
KContract.Requires( ! string.IsNullOrWhiteSpace( filename ), "filename required but is null or whitespace" );
if ( File.Exists( filename ) )
{
File.Delete( filename );
}
resultFileWriter = new StreamWriter( filename );
}
/// <summary>
/// Write the results within the collection into the file
/// </summary>
/// <param name="result">the list with results as Tuples (tick, replenOrder)</param>
public void Write( object[] result )
{
KContract.Requires( result != null, "result mandatory but is required" );
foreach( var row in result )
{
//TODO
}
}
/// <summary>
/// Dispose
/// closes resultFilewriter
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose( bool disposing )
{
if ( disposing )
{
resultFileWriter.Flush( );
resultFileWriter.Close( );
}
}
/// <summary>
/// Dispose
/// </summary>
public void Dispose( )
{
Dispose( true );
}
}
}

61
util/ToDelimitedString.cs Normal file
View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace com.knapp.KCC2017.util
{
/// <summary>
/// Helper class for some extension methods to pretty print arrays or colelction
/// </summary>
public static class ToDelimitedStringClass
{
public static string ToDelimitedString( this object[] source, string delimiter )
{
StringBuilder sb = new StringBuilder();
foreach ( var element in source )
{
if ( sb.Length != 0 )
{
sb.Append( delimiter );
}
sb.Append( element.ToString() );
}
return sb.ToString();
}
public static string ToDelimitedString<T>( this ReadOnlyCollection<T> source, string delimiter )
{
StringBuilder sb = new StringBuilder();
foreach ( var element in source )
{
if ( sb.Length != 0 )
{
sb.Append( delimiter );
}
sb.Append( element.ToString() );
}
return sb.ToString();
}
public static string ToDelimitedString( this int[] source, string delimiter )
{
StringBuilder sb = new StringBuilder();
foreach ( var element in source )
{
if ( sb.Length != 0 )
{
sb.Append( delimiter );
}
sb.Append( element.ToString() );
}
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Runtime.Serialization;
namespace com.knapp.KCC2017.warehouse
{
[Serializable]
internal class ContainerMaxGetExceededException : Exception
{
public ContainerMaxGetExceededException()
{
}
public ContainerMaxGetExceededException( string message ) : base( message )
{
}
public ContainerMaxGetExceededException( string message, Exception innerException ) : base( message, innerException )
{
}
protected ContainerMaxGetExceededException( SerializationInfo info, StreamingContext context ) : base( info, context )
{
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Runtime.Serialization;
namespace com.knapp.KCC2017.warehouse
{
[Serializable]
internal class ContainerNotAtWorkStationException : Exception
{
public ContainerNotAtWorkStationException()
{
}
public ContainerNotAtWorkStationException( string message ) : base( message )
{
}
public ContainerNotAtWorkStationException( string message, Exception innerException ) : base( message, innerException )
{
}
protected ContainerNotAtWorkStationException( SerializationInfo info, StreamingContext context ) : base( info, context )
{
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Runtime.Serialization;
namespace com.knapp.KCC2017.warehouse
{
[Serializable]
internal class ContainerNotInStorageException : Exception
{
public ContainerNotInStorageException()
{
}
public ContainerNotInStorageException( string message ) : base( message )
{
}
public ContainerNotInStorageException( string message, Exception innerException ) : base( message, innerException )
{
}
protected ContainerNotInStorageException( SerializationInfo info, StreamingContext context ) : base( info, context )
{
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Runtime.Serialization;
namespace com.knapp.KCC2017.warehouse
{
[Serializable]
internal class DestinationFillingExceededException : Exception
{
public DestinationFillingExceededException()
{
}
public DestinationFillingExceededException( string message ) : base( message )
{
}
public DestinationFillingExceededException( string message, Exception innerException ) : base( message, innerException )
{
}
protected DestinationFillingExceededException( SerializationInfo info, StreamingContext context ) : base( info, context )
{
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Runtime.Serialization;
namespace com.knapp.KCC2017.warehouse
{
[Serializable]
internal class ProductMismatchExcpetion : Exception
{
public ProductMismatchExcpetion()
{
}
public ProductMismatchExcpetion( string message ) : base( message )
{
}
public ProductMismatchExcpetion( string message, Exception innerException ) : base( message, innerException )
{
}
protected ProductMismatchExcpetion( SerializationInfo info, StreamingContext context ) : base( info, context )
{
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Runtime.Serialization;
namespace com.knapp.KCC2017.warehouse
{
[Serializable]
internal class SourceFillingExhaustedException : Exception
{
public SourceFillingExhaustedException()
{
}
public SourceFillingExhaustedException( string message ) : base( message )
{
}
public SourceFillingExhaustedException( string message, Exception innerException ) : base( message, innerException )
{
}
protected SourceFillingExhaustedException( SerializationInfo info, StreamingContext context ) : base( info, context )
{
}
}
}

245
warehouse/Warehouse.cs Normal file
View File

@@ -0,0 +1,245 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using com.knapp.KCC2017.data;
using com.knapp.KCC2017.entities;
using System.Collections.ObjectModel;
namespace com.knapp.KCC2017.warehouse
{
/// <summary>
/// Class that represents the warehouse
/// - contains all the data
/// - provides all necessary functions
/// - stores your moves to the result file
/// </summary>
public class Warehouse
{
// ----------------------------------------------------------------------------
// -- DO NOT CHANGE THESE -----------------------------------------------------
// (your result will be evaluated on the server with these settings)
public const int WORK_STATION_CAPACITY = 5;
public const int CONTAINER_MAX_GET = 5000;
/// <summary>
/// Data coming from the data files (containers and products)
/// </summary>
private readonly InputData inputData;
/// <summary>
/// The containers at the workstation
/// </summary>
private readonly Dictionary<string,Container> workStation = new Dictionary<string, Container>( WORK_STATION_CAPACITY );
internal int currentNumberOfGets = 0;
internal int currentNumberOfMoves = 0;
internal int currentNumberOfPuts = 0;
private readonly List<WarehouseOperation> result = new List<WarehouseOperation>();
private WarehouseInfos warehouseInfos;
public Warehouse( InputData inputData )
{
this.inputData = inputData;
}
/// <summary>
/// Get all containers that are in the warehouse
/// (that is storage and workstation)
/// </summary>
/// <returns>the ContainerCollection containing all containers in the warehouse</returns>
public ReadOnlyCollection<Container> GetAllContainers()
{
return inputData.GetContainers();
}
/// <summary>
/// Get all containers currently at the workstation
/// </summary>
/// <returns>returns all containers at the workstation, an empty collection if there are none</returns>
public ReadOnlyCollection<Container> GetContainersAtWorkStation()
{
List<Container> copy = new List<Container>();
foreach( Container container in workStation.Values )
{
copy.Add( container );
}
return new ReadOnlyCollection<Container>( copy );
}
/// <summary>
/// Get all containers currently in storage
/// </summary>
/// <returns>collection of all containers in storage and not in workstation</returns>
public ReadOnlyCollection<Container> GetContainersInStorage()
{
List<Container> copy = new List<Container>( GetAllContainers() );
return new ReadOnlyCollection<Container>( copy.Except( workStation.Values.ToList() ).ToList() );
}
/// <summary>
/// Get the number of remaining get operations
/// </summary>
/// <returns></returns>
public int GetRemainingMovesToWorkstation()
{
return CONTAINER_MAX_GET - currentNumberOfGets;
}
/// <summary>
/// Get or build an WarehoouseInfos instance with the current data
/// </summary>
/// <returns>WarehouuseInfo instance with the current data</returns>
public WarehouseInfos BuildWarehouseInfos()
{
if( warehouseInfos == null )
{
warehouseInfos = new WarehouseInfos( this );
}
return warehouseInfos;
}
public IEnumerable<WarehouseOperation> GetResult()
{
return result;
}
/// <summary>
/// Move a container form storage to the workstations
/// </summary>
/// <param name="container">the container to move</param>
/// <exception cref="ArgumentException">when container is null</exception>
/// <exception cref="ContainerNotInStorageException">when the container is already at the workstation</exception>
/// <exception cref="WorkStationCapcityExceededException">when there are no free slots at the workstation</exception>
/// <exception cref="ContainerMaxGetExceededException">when the maximum number of gets has been reached</exception>
public void MoveToWorkStation( Container container )
{
if( container == null )
{
throw new ArgumentException( "container must not be null" );
}
result.Add( new WarehouseOperation.GetContainer( container ) );
if( workStation.ContainsKey( container.Code ) )
{
throw new ContainerNotInStorageException( "container is already at workstation: " + container );
}
if( workStation.Count >= WORK_STATION_CAPACITY )
{
throw new WorkStationCapcityExceededException( "containers at workstation are limited to " + WORK_STATION_CAPACITY.ToString() + " => @WorkStation= " + workStation.Values );
}
if( currentNumberOfGets >= CONTAINER_MAX_GET )
{
throw new ContainerMaxGetExceededException( "container gets are limited to " + CONTAINER_MAX_GET.ToString() );
}
workStation.Add( container.Code, container );
++currentNumberOfGets;
}
/// <summary>
/// Transfer a counted number of items from one slot to another slot
/// </summary>
/// <param name="source">slot from which to remove the items</param>
/// <param name="destination">slot into whcih to put the items</param>
/// <param name="quantity">the number of items to transfer</param>
/// <exception cref="ArgumentException">when either source or destination is null or or quantity &lt;= 0 or there are no products at the source</exception>
/// <exception cref="ContainerNotAtWorkStationException">when either source or destination container are not at the workstation</exception>
/// <exception cref="SourceFillingExhaustedException">when the quantity to transfer is higher than the number of items in the source</exception>
/// <exception cref="ProductMismatchExcpetion">when the destination is not empty and contains already a different product</exception>
/// <exception cref="DestinationFillingExceededException">when the total quantity in the destination (existing+transferred) exceeds the max quantity of the product for that type of slot/ container</exception>
public void TransferItems( ContainerSlot source, ContainerSlot destination, int quantity )
{
warehouseInfos = null; //invalidate the statistics
if( source == null || destination == null )
{
throw new ArgumentException( "source or dest is null" );
}
WarehouseOperation.MoveItems moveItemOperation = new WarehouseOperation.MoveItems( source, destination, quantity );
if ( quantity <= 0 )
{
throw new ArgumentException("quantity must be >0: " + moveItemOperation );
}
if ( source.IsEmpty() )
{
throw new ArgumentException("no products at source: " + moveItemOperation );
}
if ( !workStation.ContainsKey( source.Container.Code ) )
{
throw new ContainerNotAtWorkStationException( "source container not at workstation: " + moveItemOperation + "=> @WorkStation: " + workStation.Values );
}
if ( !workStation.ContainsKey( destination.Container.Code ) )
{
throw new ContainerNotAtWorkStationException( "destination container not at workstation: " + moveItemOperation + "=> @WorkStation: " + workStation.Values );
}
if( source.Quantity < quantity )
{
throw new SourceFillingExhaustedException("can't take " + quantity + " items from source: " + moveItemOperation );
}
if ( !destination.IsEmpty() )
{
if( source.Product != destination.Product )
{
throw new ProductMismatchExcpetion("mismatching products: " + moveItemOperation );
}
}
if( destination.Quantity + quantity > source.Product.GetMaxQuantity( destination.Container.ContainerType ) )
{
throw new DestinationFillingExceededException( "can't put #" + quantity + " to destination: " + moveItemOperation
+ " => max/slot=" + source.Product.GetMaxQuantity( destination.Container.ContainerType ) );
}
Product sourceProduct = source.Product;
source._SetQuantity( source.Quantity - quantity );
destination._SetQuantity( destination.Quantity + quantity );
destination._SetProduct( sourceProduct );
result.Add( moveItemOperation );
++currentNumberOfMoves;
}
/// <summary>
/// Move containers from workstation back to storage
/// </summary>
/// <param name="container">the container to move</param>
/// <exception cref="ArgumentException">when container is null</exception>
/// <exception cref="ContainerNotAtWorkStationException">when the container is not at the workstation</exception>
public void MoveToStorage( Container container )
{
if( container == null )
{
throw new ArgumentException("container must not be null");
}
result.Add( new WarehouseOperation.PutContainer( container ) );
if ( !workStation.ContainsKey( container.Code ) )
{
throw new ContainerNotAtWorkStationException( "source container not at workstation: " + container );
}
workStation.Remove( container.Code );
++currentNumberOfPuts;
}
}
}

116
warehouse/WarehouseInfos.cs Normal file
View File

@@ -0,0 +1,116 @@
using com.knapp.KCC2017.data;
using com.knapp.KCC2017.util;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace com.knapp.KCC2017.warehouse
{
/// <summary>
/// Helper class to store a SNAPSHOT of the warehouse statistics
/// </summary>
public class WarehouseInfos
{
public readonly int[] totalContainers;
public readonly int[] totalSlots;
public readonly ReadOnlyCollection<Container> containersAtWorkStation;
public readonly int numberOfGets;
public readonly int numberOfPuts;
public readonly int numberOfMoves;
public readonly int[] emptyContainers;
public readonly int[] emptySlots;
public WarehouseInfos( Warehouse warehouse )
{
totalContainers = CountTotalContainers( warehouse );
totalSlots = CountTotalSlots( warehouse );
emptyContainers = CountEmptyContainers( warehouse );
emptySlots = CountEmptysSlots( warehouse );
containersAtWorkStation = warehouse.GetContainersAtWorkStation();
numberOfGets = warehouse.currentNumberOfGets;
numberOfPuts = warehouse.currentNumberOfPuts;
numberOfMoves = warehouse.currentNumberOfMoves;
}
private int[] CountTotalContainers( Warehouse warehouse )
{
int[] result = new int[ContainerType.Count + 1 ];
foreach( var container in warehouse.GetAllContainers() )
{
result[ 0 ]++;
result[ container.ContainerType.Ordinal ]++;
}
return result;
}
private int[] CountTotalSlots( Warehouse warehouse )
{
int[] result = new int[ContainerType.Count + 1 ];
foreach ( var container in warehouse.GetAllContainers() )
{
result[ 0 ] += container.ContainerType.NumberOfSlots;
result[ container.ContainerType.Ordinal ] += container.ContainerType.NumberOfSlots;
}
return result;
}
private int[] CountEmptysSlots( Warehouse warehouse )
{
int[] result = new int[ContainerType.Count + 1 ];
foreach ( var container in warehouse.GetAllContainers() )
{
foreach ( var slot in container.GetSlots() )
{
if ( slot.IsEmpty() )
{
result[ 0 ]++;
result[ container.ContainerType.Ordinal ]++;
}
}
}
return result;
}
private int[] CountEmptyContainers( Warehouse warehouse )
{
int[] result = new int[ContainerType.Count + 1 ];
foreach( var container in warehouse.GetAllContainers() )
{
if( container.IsEmpy() )
{
result[ 0 ]++;
result[ container.ContainerType.Ordinal ]++;
}
}
return result;
}
public override string ToString()
{
return "WarehouseInfos[totalContainers=" + totalContainers.ToDelimitedString(",")
+ ", totalSlots=" + totalSlots.ToDelimitedString(",")
+ ", containersAtWorkStation=" + containersAtWorkStation.ToDelimitedString(",")
+ ", numberOfGets=" + numberOfGets + ", numberOfPuts=" + numberOfPuts //
+ ", numberOfMoves=" + numberOfMoves //
+ ", emptyContainers=" + emptyContainers.ToDelimitedString(",")
+ ", emptySlots=" + emptySlots.ToDelimitedString(",")
+ "]";
}
}
}

View File

@@ -0,0 +1,96 @@
using com.knapp.KCC2017.data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace com.knapp.KCC2017.warehouse
{
/// <summary>
/// **KNAPP use only
/// Base class for all operations carried out during optimization
/// as get, move, store
/// </summary>
public abstract class WarehouseOperation
{
private readonly string resultString;
/// <summary>
/// Create instance with given data
/// </summary>
/// <param name="args">data of operation as object array</param>
protected WarehouseOperation( params object[] args )
{
StringBuilder sb = new StringBuilder();
sb.Append( GetType().Name ).Append( ";" );
foreach( var arg in args )
{
sb.Append( arg.ToString() ).Append( ";" );
}
resultString = sb.ToString();
}
public override string ToString()
{
return resultString;
}
public string ToResultString()
{
return resultString;
}
/// <summary>
/// Representation of MoveToWorkStation action
/// </summary>
public class GetContainer : WarehouseOperation
{
public GetContainer( Container container )
: base ( container.Code )
{ /** empty **/ }
}
/// <summary>
/// Representation of TransferItems action
/// </summary>
public class MoveItems : WarehouseOperation
{
public ContainerSlot Source { get; private set; }
public ContainerSlot Destination { get; private set; }
public int Quantity { get; private set; }
public MoveItems( ContainerSlot source, ContainerSlot destination, int quantity )
: base ( source.Container.Code, source.Index
, destination.Container.Code, destination.Index
, quantity )
{
this.Source = source;
this.Destination = destination;
this.Quantity = quantity;
}
public override string ToString()
{
return "MoveItems[source=" + Source.Container.Code + "/" + Source.Index
+ ", destination="+ Destination.Container.Code + "/" + Destination.Index
+ ", quantity=" + Quantity + "]";
}
}
/// <summary>
/// Representation of MoveToStoreage action
/// </summary>
public class PutContainer : WarehouseOperation
{
public PutContainer( Container container )
: base( container.Code )
{ /** empty **/}
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Runtime.Serialization;
namespace com.knapp.KCC2017.warehouse
{
[Serializable]
internal class WorkStationCapcityExceededException : Exception
{
public WorkStationCapcityExceededException()
{
}
public WorkStationCapcityExceededException( string message ) : base( message )
{
}
public WorkStationCapcityExceededException( string message, Exception innerException ) : base( message, innerException )
{
}
protected WorkStationCapcityExceededException( SerializationInfo info, StreamingContext context ) : base( info, context )
{
}
}
}