Imported CSharp project files
This commit is contained in:
3
.cvsignore
Normal file
3
.cvsignore
Normal file
@@ -0,0 +1,3 @@
|
||||
.vs
|
||||
bin
|
||||
obj
|
6
App.config
Normal file
6
App.config
Normal 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
172
KCC2017.csproj
Normal 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
180
Program.cs
Normal 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" );
|
||||
}
|
||||
}
|
||||
}
|
35
Properties/AssemblyInfo.cs
Normal file
35
Properties/AssemblyInfo.cs
Normal 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" )]
|
@@ -1,4 +1,4 @@
|
||||
# KnappCC2017
|
||||
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
59
Settings.cs
Normal 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
99
data/Container.cs
Normal 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
62
data/ContainerSlot.cs
Normal 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
123
data/ContainerType.cs
Normal 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
145
data/InputData.cs
Normal 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
114
data/Product.cs
Normal 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
10001
input/containers.csv
Normal file
File diff suppressed because it is too large
Load Diff
101
input/products.csv
Normal file
101
input/products.csv
Normal 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;
|
|
57
solution/OptimizeStorage.cs
Normal file
57
solution/OptimizeStorage.cs
Normal 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
59
util/CsvReader.cs
Normal 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
95
util/KContract.cs
Normal 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
83
util/PrepareUpload.cs
Normal 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
76
util/ResultWriter.cs
Normal 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
61
util/ToDelimitedString.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
25
warehouse/ContainerMaxGetExceededException.cs
Normal file
25
warehouse/ContainerMaxGetExceededException.cs
Normal 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 )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
25
warehouse/ContainerNotAtWorkStationException.cs
Normal file
25
warehouse/ContainerNotAtWorkStationException.cs
Normal 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 )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
25
warehouse/ContainerNotInStorageException.cs
Normal file
25
warehouse/ContainerNotInStorageException.cs
Normal 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 )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
25
warehouse/DestinationFillingExceededException.cs
Normal file
25
warehouse/DestinationFillingExceededException.cs
Normal 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 )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
25
warehouse/ProductMismatchExcpetion.cs
Normal file
25
warehouse/ProductMismatchExcpetion.cs
Normal 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 )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
25
warehouse/SourceFillingExhaustedException.cs
Normal file
25
warehouse/SourceFillingExhaustedException.cs
Normal 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
245
warehouse/Warehouse.cs
Normal 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 <= 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
116
warehouse/WarehouseInfos.cs
Normal 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(",")
|
||||
+ "]";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
96
warehouse/WarehouseOperation.cs
Normal file
96
warehouse/WarehouseOperation.cs
Normal 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 **/}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
25
warehouse/WorkStationCapcityExceededException.cs
Normal file
25
warehouse/WorkStationCapcityExceededException.cs
Normal 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 )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user