Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@sehe
Created November 26, 2012 02:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sehe/4146271 to your computer and use it in GitHub Desktop.
Save sehe/4146271 to your computer and use it in GitHub Desktop.
2-Shipments
*.o
main
*.sw[op]
Price 1=$2.00 Price 2=$7.00 Price 3=$8.50
s New York 23 14 11
s Miami 25 25 25
s Los Angeles 40 13 17
s Houston 100 30 10
s Chicago 42 23 19
s New York 0 0 15
s Miami 13 17 21
o Los Angeles 15 10 15
o New York 12 24 8
o Houston 75 45 10
o Chicago 20 15 15
o New York 15 0 0
s Los Angeles 10 20 10
s Houston 0 30 40
o New York 15 15 25
o Chicago 75 30 40
s New York 20 15 20
o Houston 10 20 10
// Created by sehe on 11/26/12.
// Copyright (c) 2012 sehe. All rights reserved.
//
#include "logic.h"
#include <iostream>
#include <algorithm>
#include <cassert>
#include <map>
#include <iomanip>
using namespace std;
namespace /* anonymous */
{
typedef map<string, Warehouse> Warehouses;
typedef long Warehouse::* QtyProp;
/////////////////////////////////////
// IO primitives
std::ostream& operator<<(std::ostream& os, Warehouse const& a)
{ return os << a.quantity1 << '\t' << a.quantity2 << '\t' << a.quantity3; }
std::ostream& operator<<(std::ostream& os, Warehouses::value_type const& a)
{ return os << a.first << '\t' << a.second; }
std::ostream& operator<<(std::ostream& os, Card const& a)
{ return os << a.type << '\t' << a.location << '\t' << a.mutation1 << '\t' << a.mutation2 << '\t' << a.mutation3; }
/////////////////////////////////////
struct CompareByQty
{
CompareByQty(QtyProp qfptr) : _qfptr(qfptr) {}
typedef Warehouses::value_type V;
bool operator()(V const& a, V const& b) const
{ return (a.second.*_qfptr) < (b.second.*_qfptr); }
QtyProp const _qfptr;
};
pair<string, long> TryFillOrder(Warehouse& location, long& inorder, QtyProp qprop, Warehouses& tx)
{
auto& stock = (location.*qprop);
auto fill = min(stock, inorder);
inorder -= fill;
stock -= fill;
if (inorder)
{
auto it = max_element(tx.begin(), tx.end(), CompareByQty(qprop));
auto& remote = it->second;
auto& remote_stock = remote.*qprop;
if (inorder<=remote_stock)
{
auto back_order = make_pair(it->first, inorder);
// It would be rather nice to make this recursive:
// TryFillOrder(remote, inorder, qprop, tx);
inorder -= inorder;
remote_stock -= inorder;
return back_order;
}
}
return make_pair("", 0);
}
struct FilledOrder
{
long fill1, fill2, fill3, back1, back2, back3;
bool usedBackorder() { return back1 || back2 || back3; }
bool empty() { return !usedBackorder() && !fill1 && !fill2 && !fill3; }
};
FilledOrder FillOrder(Card const& order, Warehouses& warehouses)
{
assert('o' == order.type);
auto rollback = warehouses; // prepare rollback
auto unfilled = order;
auto& from = warehouses[order.location];
auto back1 = TryFillOrder(from, unfilled.mutation1, &Warehouse::quantity1, warehouses);
auto back2 = TryFillOrder(from, unfilled.mutation2, &Warehouse::quantity2, warehouses);
auto back3 = TryFillOrder(from, unfilled.mutation3, &Warehouse::quantity3, warehouses);
if (unfilled.mutation1 || unfilled.mutation2 || unfilled.mutation3)
{
rollback.swap(warehouses); // rollback any changes
cout << "Order Unfilled\n";
} else
{
if (back1.second)
cout << back1.second << " of item 1 shipped from " << back1.first << " to " << order.location << "\n";
if (back2.second)
cout << back2.second << " of item 2 shipped from " << back2.first << " to " << order.location << "\n";
if (back3.second)
cout << back3.second << " of item 3 shipped from " << back3.first << " to " << order.location << "\n";
return {
order.mutation1 - back1.second,
order.mutation2 - back2.second,
order.mutation3 - back3.second,
back1.second, back2.second, back3.second
};
}
return {0};
}
void ProcessShipment(Card const& shipment, Warehouses& warehouses)
{
assert('s' == shipment.type);
cout << "-------- ProcessShipment\n" << shipment << '\n';
auto& loc = warehouses[shipment.location];
loc.quantity1 += shipment.mutation1;
loc.quantity2 += shipment.mutation2;
loc.quantity3 += shipment.mutation3;
cout << shipment.location << '\t' << loc << '\n';
}
double ComputeBillTotal(FilledOrder const& filled, Pricing const& pricing)
{
double total = 0;
total += pricing.price1 * filled.back1;
total += pricing.price2 * filled.back2;
total += pricing.price3 * filled.back3;
total *= 1.10; // 10% markup for backordered items
total += pricing.price1 * filled.fill1;
total += pricing.price2 * filled.fill2;
total += pricing.price3 * filled.fill3;
return total;
}
void ProcessOrder(Card const& order, Warehouses& stores, Pricing const& pricing)
{
cout << "-------- ProcessOrder\n" << order << '\n';
auto filled = FillOrder(order, stores);
if (!filled.empty())
{
if (filled.usedBackorder())
for (auto& wh: stores)
std::cout << "New stock: " << wh << "\n";
else
std::cout << "New stock: " << *stores.find(order.location) << "\n";
double bill = ComputeBillTotal(filled, pricing);
std::cout << "Price of Order: $" << std::fixed << std::setprecision(2) << bill << "\n";
}
}
}
void RunSimulation(vector<Card> const& cards, Pricing const& pricing)
{
Warehouses stores;
for (const auto& card : cards)
switch (card.type)
{
case 'o': ProcessOrder(card, stores, pricing); break;
case 's': ProcessShipment(card, stores); break;
}
}
// Created by sehe on 11/26/12.
// Copyright (c) 2012 sehe. All rights reserved.
//
#pragma once
#include <string>
#include <vector>
struct Warehouse
{
long quantity1;
long quantity2;
long quantity3;
};
struct Pricing
{
double price1;
double price2;
double price3;
};
struct Card
{
char type;
std::string location;
long mutation1;
long mutation2;
long mutation3;
};
void RunSimulation(std::vector<Card> const& cards, Pricing const& pricing);
// Created by sehe on 11/26/12.
// Copyright (c) 2012 sehe. All rights reserved.
//
#include "logic.h"
#include "parsing.h"
using namespace std;
int main()
{
Pricing pricing;
vector<Card> cards;
if (ParseFile("cards.txt", pricing, cards))
RunSimulation(cards, pricing);
}
all:main
main: parsing.o logic.o
CPPFLAGS+=-Wall
CPPFLAGS+=-g -O4
CXXFLAGS+=$(CPPFLAGS) -std=c++0x
CPPFLAGS+=-I ~/custom/boost/
%:%.cpp
$(CXX) $(CXXFLAGS) $^ -o $@ $(LDFLAGS)
// Created by sehe on 11/26/12.
// Copyright (c) 2012 sehe. All rights reserved.
//
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/adapted.hpp>
#include <fstream>
#include "logic.h"
using namespace std;
BOOST_FUSION_ADAPT_STRUCT(Pricing , (double, price1)(double , price2)(double , price3));
BOOST_FUSION_ADAPT_STRUCT(Warehouse, (long , quantity1)(long, quantity2)(long, quantity3));
BOOST_FUSION_ADAPT_STRUCT(Card , (char , type)(string , location)(long , mutation1)(long, mutation2)(long, mutation3));
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;
bool ParseFile(string filename, Pricing& pricing, vector<Card>& cards)
{
ifstream recordsFile(filename.c_str());
recordsFile.unsetf(ios::skipws);
if (!recordsFile) {
cerr << "Could not open " << filename << endl;
return false;
}
typedef boost::spirit::istream_iterator It;
try
{
using namespace qi;
using phx::ref;
It f(recordsFile), l;
{
int index = 1;
auto fmt = "Price" > omit[uint_(ref(index)++)] > '=' > -lit('$') > double_;
if (!phrase_parse(f, l, fmt > fmt > fmt > +eol, blank, pricing))
{
cerr << "Can't parse pricing header\n";
return false;
}
}
auto city = raw[eps >> "New York"|"Miami"|"Los Angeles"|"Houston"|"Chicago"];
auto fmt = char_("so") >> city >> uint_ >> uint_ >> uint_;
if (!phrase_parse(f, l, *eol >> fmt % +eol >> *eol > eoi, blank, cards))
{
cout << "Couldn't parse card list (#" << cards.size()+1 << ")\n";
return false;
}
} catch(qi::expectation_failure<It> const & e)
{
string s;
istringstream iss(string(e.first, e.last));
getline(iss, s);
cerr << "Unexpected input '" << s << "'\n";
return false;
}
return true;
}
// Created by sehe on 11/26/12.
// Copyright (c) 2012 sehe. All rights reserved.
//
#pragma once
#include "logic.h"
bool ParseFile(std::string filename, Pricing& pricing, std::vector<Card>& cards);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment