#include <iostream>
#include <vector>
#include <memory>
using std::shared_ptr;
using std::make_shared;
int const income_interval = 6;
int const start_money = 650;
int const start_income = 50;
//just under 07:00 minutes is usually when the game ends
int const game_time = 400;
// multiple of time required to be spent
int const require_spent_multiple = 10;
// initial delay before spending is required
int const require_spent_delay = 30;
struct plan {
//plan acquisition cost
int cost;
//resulting increase in revenue
int increase;
//timeout before repeat purchase
int regen;
};
std::vector<plan> plans({
{ 50, 2, 4 },
{ 300, 15, 13 },
{ 1000, 70, 60 },
});
struct game_state {
// how much money we have now
int money;
//income on each income interval
int income;
//total money we had/have
int total;
//money spent on upgrades
int spent;
//money invested for income
int invested;
//block purchase of the plan for regen time
std::vector<int> plan_timeout;
//total elapsed time
int time;
game_state() {
money = start_money;
income = start_income;
total = money;
plan_timeout.resize( plans.size(), 0 );
time = 0;
spent = 0;
invested = 0;
}
void step() {
time++;
//step plan regen time
for( auto & pt : plan_timeout ) {
if( pt > 0 ) {
pt--;
}
}
//add new money each interval
if( time % income_interval == 0 ) {
money += income;
total += income;
}
}
bool can_buy_plan(size_t i) {
return money >= plans[i].cost
&& plan_timeout[i] == 0;
}
void buy_plan(int i) {
plan_timeout[i] += plans[i].regen;
invested += plans[i].cost;
money -= plans[i].cost;
income += plans[i].increase;
}
};
struct strategy {
shared_ptr<game_state> state;
//name of this strategy
std::string name;
//stop investing at this time, if -1 then never stop
int stop_invest_when;
strategy( std::string const & name ) :
state( new game_state ),
name(name) {
stop_invest_when = -1;
}
strategy( std::string const & name, shared_ptr<game_state> state ) :
state( state ),
name( name ) {
stop_invest_when = -1;
}
void step(int spend) {
//ensure we're spending enough
if( state->spent < spend ) {
int a = std::min( spend, state->money );
state->money -= a;
state->spent += a;
}
state->step();
step_impl();
}
virtual void step_impl() = 0;
virtual bool should_buy_plan( int i ) {
if( stop_invest_when >= 0 && state->time >= stop_invest_when ) {
return false;
}
return state->can_buy_plan(i);
}
};
struct buy_all : public strategy {
buy_all() : strategy( "buy_all" ) { }
void step_impl() {
for( int i=plans.size()-1; i >=0; --i ) {
if( should_buy_plan(i) ) {
state->buy_plan(i);
}
}
}
};
struct buy_one_plan : public strategy {
static std::string plan_name( int i ) {
char buf[32];
sprintf( buf, "Plan%d", i );
return buf;
}
int plan;
buy_one_plan(int i) :
strategy( plan_name(i) ),
plan(i) {
}
void step_impl() {
if( should_buy_plan(plan) ) {
state->buy_plan(plan);
}
}
};
struct buy_none : public strategy {
buy_none() :
strategy( "none" ) {
}
void step_impl() {
}
};
typedef std::vector<shared_ptr<strategy>> strategies;
/**
The main simulation driver. It steps through the strategies and outputs
the results at regular intervals.
*/
void run( std::string const & name, strategies const & all ) {
std::cout << std::endl;
std::cout << " - - " << name << " - - " << std::endl;
for( int i=0; i < game_time; ++i ) {
//must have spent at least this much by this time
int spend = i * require_spent_multiple;
if( i < require_spent_delay ) {
spend = 0;
}
for( auto & s : all ) {
s->step(spend);
}
//write opdate regularly
if( i % 30 == 0 ) {
for( auto & s : all ) {
std::cout << s->name << ": " << s->state->money << "/" << s->state->total << "\t";
}
std::cout << std::endl;
}
}
std::cout << "Spent/Invested" << std::endl;
for( auto & s : all ) {
std::cout << s->name << ": " << (s->state->spent+s->state->money)
<< "/" << s->state->invested << "\t";
}
std::cout << std::endl;
}
//build a stopping strategy
shared_ptr<strategy> stop_at( int time, shared_ptr<strategy> st ) {
st->stop_invest_when = time;
char buf[32];
sprintf( buf, "Stop@%d", time );
st->name += buf;
return st;
}
int main() {
run( "Variety", {
make_shared<buy_none>(),
make_shared<buy_all>(),
make_shared<buy_one_plan>(0),
make_shared<buy_one_plan>(1),
make_shared<buy_one_plan>(2),
});
//buy_all appears best, so check when to stop
run( "Stopping", {
stop_at( 180, make_shared<buy_all>() ),
stop_at( 240, make_shared<buy_all>() ),
stop_at( 300, make_shared<buy_all>() ),
stop_at( 360, make_shared<buy_all>() ),
});
//with spending the Plan0/1 appears good
run( "Stopping Plan0", {
stop_at( 180, make_shared<buy_one_plan>(1) ),
stop_at( 240, make_shared<buy_one_plan>(1) ),
stop_at( 300, make_shared<buy_one_plan>(1) ),
stop_at( 360, make_shared<buy_one_plan>(1) ),
});
}