Skip to content

Commit

Permalink
refactor level stacking
Browse files Browse the repository at this point in the history
Discard orders with duplicate IDs #11
  • Loading branch information
JamesBremner committed Jul 2, 2020
1 parent 7bb7883 commit e60f460
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 53 deletions.
2 changes: 1 addition & 1 deletion build/codeblocks/timberAllocation.cbp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<Option object_output="obj/Debug/" />
<Option type="1" />
<Option compiler="gcc_v83" />
<Option parameters="../data/t3.txt" />
<Option parameters="../data/timber-alloc-data.txt" />
<Compiler>
<Add option="-g" />
</Compiler>
Expand Down
50 changes: 40 additions & 10 deletions src/TimberAllocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ class cTimber : public cSpace

void used( bool f = true )
{
myUsed = true;
myUsed = f;
}
bool isUsed() const
{
Expand All @@ -93,6 +93,15 @@ class cTimber : public cSpace
return myLevel;
}

void usedbyLevel( bool f )
{
myUsedbyLevel = f;
}
bool isUsedbyLevel()
{
return myUsedbyLevel;
}

std::string myUserID;
int myCount;

Expand All @@ -101,6 +110,7 @@ class cTimber : public cSpace
timber_t myStock; // if an allocated order, the stock allocated to
bool myUsed; // true if a stock that haveen used to cut orders
int myLevel; // the location of the top of the highest level cut
bool myUsedbyLevel; // true if stock has been allocated to current level
};

class cInventory
Expand Down Expand Up @@ -153,14 +163,18 @@ class cLevel
public:
timberv_t myOrder; // orders
timber_t myStock; // stock allocated to level
int myAreaUsed;

cLevel()
: myAreaUsed( 0 )
{

}
void removePacked(); // remove orders that have been packed

/** remove orders that have been packed
@return 0: none packed, 1: some packed, 2: all packed
*/
int removePacked();

std::string text() const;
int height() const
{
Expand All @@ -174,10 +188,16 @@ class cLevel
{
myAreaUsed += order->myLength * order->myWidth;
}
int wastage() const
{
return height() * ( myStock->myLength * myStock->myWidth - myAreaUsed );
}
/** Volume wasted when level cut from stock
@return volume wasted
This calculates wastage only for the currently stacked level
so this needs to be called for each stacked level
*/
int wastage() const;

private:
int myAreaUsed;
};

class cInstance
Expand All @@ -203,6 +223,14 @@ class cInstance
*/
void expandCount();

/// Number of orders that could not fit
int unPackedCount() const
{
return (int)myUnpacked.size();
}

bool isEveryIDUnique();

timberv_t myOrder; /// the timbers that have to be delivered

std::vector<std::pair<timber_t,timber_t>> myAllocation;
Expand Down Expand Up @@ -280,7 +308,7 @@ bool CS2LNW(
cLevel& level, int h );

/// Use pack2 engine to do 2D level cutting
bool CS2Pack2(
void CS2Pack2(
cInstance& I,
cLevel& level, int h );

Expand All @@ -300,11 +328,13 @@ void AllocateOrder(

/** Record the V cut for a level in the instance
@param[in] I the instance
@param[in] level
@param[in] stock
@param[in] h height for cut at top of level
*/
void CutLevel(
cInstance& I,
cLevel& level );
timber_t stock,
int h );

void ReturnToInventory(
cInventory& I );
Expand Down
93 changes: 52 additions & 41 deletions src/taCutter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ void LevelsToStock(
std::vector< cLevel >& levels,
cInventory& inventory )
{
for( timber_t t : inventory.myStock )
t->usedbyLevel( false );
for ( auto& level : levels )
{
LevelToStock( I, level, inventory.myStock );
Expand All @@ -87,7 +89,11 @@ LevelToStock(
bool found = false;
for( timber_t t : stock )
{
if( t->isUsed() )
// check if this stock was previously allocated to this level
// if so, it means that the level could not be packed into the stock
// probably because the W and/or length were too short
// in any case we do not want to allocate the stock again
if( t->isUsedbyLevel() )
continue;

int stockHeight = t->myHeight;
Expand Down Expand Up @@ -132,11 +138,15 @@ void LevelCuts(
cInventory& inventory )
{
bool allPacked;

// loop over levels
for( cLevel& level : levels )
{
std::cout << "cutting level " << level.text() << "\n";

for( timber_t t : inventory.myStock )
t->usedbyLevel( false );

do
{
/* stack levels
Expand All @@ -151,41 +161,54 @@ void LevelCuts(
h < level.myStock->myHeight; // does stock have enough height to stack another level?
h += level.height() ) // up one level
{

// Use 2D cutting algorithm to cut orders from level.

#ifdef USE_CS2LNW
allPacked = CS2LNW( I, level, h );
#endif // USE_CS2LNW
#ifdef USE_CS2Pack2
allPacked = CS2Pack2( I, level, h );
CS2Pack2( I, level, h );
#endif // CS2Pack2

if( allPacked )
// remove packed timbers from level
int ret = level.removePacked();

if( ret == 2 )
{
// all timbers in this level are packed
std::cout << "all timbers in this level are packed\n";
allPacked = true;
break;
}

// remove timbers from level that have been packed
level.removePacked();

// TODO: return unused remainders to inventory
if( ret == 1 )
{
// some packed
continue;
}

if( ! allPacked )
if( ret == 0 )
{
// stock timber exhausted, need to allocate another
if( ! LevelToStock( I, level, inventory.myStock ) )
{
// no suitable stock available
std::cout << " no suitable stock available\n";
I.addUnpacked( level.myOrder );
allPacked = true;
}
// nothing packed
level.myStock->usedbyLevel( true );
break;
}

} // loop back to cut another level from the stock

if( ! allPacked )
{
// stock timber exhausted, need to allocate another
if( ! LevelToStock( I, level, inventory.myStock ) )
{
// no suitable stock available
std::cout << " no suitable stock available\n";
I.addUnpacked( level.myOrder );
return;
}
}

}
while( ! allPacked );
}
Expand All @@ -194,8 +217,6 @@ void LevelCuts(
// success
return;
}


}
bool CS2LNW(
cInstance& I,
Expand Down Expand Up @@ -245,7 +266,7 @@ bool CS2LNW(
return allPacked;
}

bool CS2Pack2(
void CS2Pack2(
cInstance& I,
cLevel& level, int h )
{
Expand Down Expand Up @@ -295,7 +316,8 @@ bool CS2Pack2(
*/
CutLevel(
I,
level );
level.myStock,
h + level.height() );
}

AllocateOrder(
Expand All @@ -309,7 +331,7 @@ bool CS2Pack2(
if( ! packedCount )
{
std::cout << "nothing fit\n";
return false;
return;
}

// at least one order was cut for this stock
Expand Down Expand Up @@ -352,8 +374,6 @@ bool CS2Pack2(
// add it to the instance cut list
I.myCut.push_back( cut );
}

return ( packedCount == level.size() );
}

void AllocateOrder(
Expand All @@ -376,22 +396,22 @@ void AllocateOrder(
}
void CutLevel(
cInstance& I,
cLevel& level )
timber_t stock,
int h )
{
timber_t stock = level.myStock;

stock->level( level.height() );
stock->level( h );

if( level.height() == stock->myHeight )
if( h == stock->myHeight )
{
//no need for a cut, we are at the top of the stock
return;
}
I.myCut.push_back( cCut(
stock,
'H',
level.height(),
level.height() ));
h,
h ));
}

void ReturnToInventory(
Expand All @@ -404,21 +424,12 @@ void ReturnToInventory(
I.myStock.end(),
[] ( timber_t t )
{
std::cout << "remove? " <<t->isUsed() <<" " <<t->level() <<" "<<t->myHeight << "\n";
return( t->isUsed() && t->level() == t->myHeight );
t->level( 0 );
t->used( false );
return( ! t->myHeight );
} ),
I.myStock.end() );

// adjust height of partially used stock
for( timber_t t : I.myStock )
{
if( ! t->isUsed() )
continue;

t->myHeight -= t->level();
t->level( 0 );
t->used( false );
}
}
void DisplayWastage( std::vector<cLevel>& levels )
{
Expand Down
35 changes: 35 additions & 0 deletions src/taInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <sstream>
#include <memory>
#include <vector>
#include <set>
#include <algorithm>
#include "TimberAllocation.h"

Expand Down Expand Up @@ -38,6 +39,7 @@ void cInstance::read(
break;
}
}
isEveryIDUnique();
Inventory.expandCount();
expandCount();
}
Expand Down Expand Up @@ -95,5 +97,38 @@ void cInstance::addUnpacked( timberv_t& unpacked )
myUnpacked.end(),
unpacked.begin(), unpacked.end() );
}
bool cInstance::isEveryIDUnique()
{
std::set<std::string> IDset, dupIDset;
bool first = true;
for( timber_t t: myOrder )
{
if( ! IDset.insert( t->myUserID ).second )
{
if( dupIDset.insert( t->myUserID ).second )
{
if( first )
{
std::cout << "Discarding duplicate IDs ( tid11 ):\n";
first = false;
}
std::cout << t->myUserID << " ";
}
}
}

myOrder.erase(
remove_if(
myOrder.begin(),
myOrder.end(),
[&dupIDset] ( timber_t t )
{
return( dupIDset.find(t->myUserID) != dupIDset.end() );
} ),
myOrder.end() );

std::cout << "\n" << myOrder.size() << " unique order IDs\n";
return true;
}
}

Loading

0 comments on commit e60f460

Please sign in to comment.