While i still have questions about a few things about this. Like i'm not 100% sure what is or is not a transaction, as well as a few other things, but the following should get you 90%+ of what you're looking for.
I apologize in advance for the verbosity of the code.
#ifndef NODE_HPP
#define NODE_HPP
#include <compare>
#include <memory>
enum class operation
{
buy = 0,
sell = 1,
hold = 2,
};
struct node
{
operation op{};
std::shared_ptr<const node> parent{};
int value{};
int type{};
auto operator<=>(const node& other) const
{
return profit() <=> other.profit();
}
int calculate() const
{
switch (op)
{
case operation::buy:
{
return -value;
}
case operation::sell:
{
return value;
}
case operation::hold:
{
return 0;
}
default:
{
return 0;
}
}
}
int profit() const
{
if (parent == nullptr)
{
return value;
}
return calculate() + parent->profit();
}
std::string op_to_string() const
{
switch (op)
{
case operation::buy:
{
return "Buy";
}
case operation::sell:
{
return "Sell";
}
case operation::hold:
{
return "Hold";
}
}
}
std::string print() const
{
if (parent == nullptr)
{
return "";
}
return parent->print() + " " + op_to_string() + " " + std::to_string(value);
}
};
#endif // NODE_HPP
#ifndef FUNCS_HPP
#define FUNCS_HPP
#include <array>
#include "node.hpp"
std::shared_ptr<const node> find_best(const std::array<std::array<int, 3>, 2>& prices, int max_trans);
std::shared_ptr<const node> recurse_root(
const std::array<std::array<int, 3>, 2>& prices, int curr_trans,
int max_trans, int curr_day, std::shared_ptr<const node> parent);
std::shared_ptr<const node> sell(
const std::array<std::array<int, 3>, 2>& prices, int curr_trans,
int max_trans, int curr_day, std::shared_ptr<const node> parent);
std::shared_ptr<const node> buy(const std::array<std::array<int, 3>, 2>& prices,
int curr_trans, int max_trans, int curr_day,
std::shared_ptr<const node> parent, int type);
std::shared_ptr<const node> hold(
const std::array<std::array<int, 3>, 2>& prices, int curr_trans,
int max_trans, int curr_day, std::shared_ptr<const node> parent);
std::shared_ptr<const node> decide(
const std::array<std::array<int, 3>, 2>& prices, int curr_trans,
int max_trans, int curr_day, std::shared_ptr<const node> parent);
#endif // FUNCS_HPP
#include "funcs.hpp"
#include <iostream>
std::shared_ptr<const node> sell(
const std::array<std::array<int, 3>, 2>& prices, const int curr_trans,
const int max_trans, const int curr_day, std::shared_ptr<const node> parent)
{
return recurse_root(
prices, curr_trans + 1, max_trans, curr_day,
std::make_shared<node>(node{ .op = operation::sell,
.parent = parent,
.value = prices[parent->type][curr_day],
.type = parent->type }));
}
std::shared_ptr<const node> buy(const std::array<std::array<int, 3>, 2>& prices,
const int curr_trans, const int max_trans,
const int curr_day,
std::shared_ptr<const node> parent,
const int type)
{
return recurse_root(
prices, curr_trans, max_trans, curr_day + 1,
std::make_shared<node>(node{ .op = operation::buy,
.parent = std::move(parent),
.value = prices[type][curr_day],
.type = type }));
}
std::shared_ptr<const node> hold(
const std::array<std::array<int, 3>, 2>& prices, const int curr_trans,
const int max_trans, const int curr_day, std::shared_ptr<const node> parent)
{
return recurse_root(prices, curr_trans, max_trans, curr_day + 1,
std::make_shared<node>(node{ .op = operation::hold,
.parent = parent,
.value = 0,
.type = parent->type }));
}
operation find_last_op(std::shared_ptr<const node> parent)
{
while (parent != nullptr && parent->op == operation::hold)
{
parent = parent->parent;
}
if (parent == nullptr)
{
return operation::sell;
}
return parent->op;
}
std::shared_ptr<const node> decide(
const std::array<std::array<int, 3>, 2>& prices, const int curr_trans,
const int max_trans, const int curr_day, std::shared_ptr<const node> parent,
operation op)
{
switch (op)
{
case operation::buy:
{
const auto h_result =
hold(prices, curr_trans, max_trans, curr_day, parent);
const auto s_result =
sell(prices, curr_trans, max_trans, curr_day, parent);
return std::max(h_result, s_result,
[](const std::shared_ptr<const node>& a,
const std::shared_ptr<const node>& b)
{ return a->profit() < b->profit(); });
}
case operation::sell:
{
auto result = hold(prices, curr_trans, max_trans, curr_day, parent);
for (int i = 0; i < static_cast<int>(prices.size()); ++i)
{
const auto b_result =
buy(prices, curr_trans, max_trans, curr_day, parent, i);
result = std::max(result, b_result,
[](const std::shared_ptr<const node>& a,
const std::shared_ptr<const node>& b)
{ return a->profit() < b->profit(); });
}
return result;
}
case operation::hold:
{
return decide(prices, curr_trans, max_trans, curr_day, parent,
find_last_op(parent));
}
}
}
std::shared_ptr<const node> decide(
const std::array<std::array<int, 3>, 2>& prices, const int curr_trans,
const int max_trans, const int curr_day, std::shared_ptr<const node> parent)
{
return decide(prices, curr_trans, max_trans, curr_day, parent, parent->op);
}
std::shared_ptr<const node> recurse_root(
const std::array<std::array<int, 3>, 2>& prices, const int curr_trans,
const int max_trans, const int curr_day, std::shared_ptr<const node> parent)
{
if (curr_trans >= max_trans)
{
return parent;
}
if (curr_day >= static_cast<int>(prices[0].size()))
{
return parent;
}
return decide(prices, curr_trans, max_trans, curr_day, parent);
}
std::shared_ptr<const node> find_best(
const std::array<std::array<int, 3>, 2>& prices, const int max_trans)
{
return recurse_root(
prices, 0, max_trans, 0,
std::make_shared<const node>(node{ .op = operation::sell }));
}
Which can then be called like this
#include <array>
#include <iostream>
#include "funcs.hpp"
#include "node.hpp"
int main()
{
constexpr auto max_trans = 3;
auto prices = std::array<std::array<int, 3>, 2>{
{ { 2, 6, 3 }, { 4, 2, 8 } }
};
const auto result = find_best(prices, max_trans);
std::cout << "\n";
std::cout << result->profit();
std::cout << "\n";
std::cout << result->print();
std::cout << "\ndone!";
}
An example output run:
10
Buy 2 Sell 6 Buy 2 Sell 8 Hold 0
done!⏎
You can customize the print message to your heart's content, i didn't put it in the format you outlined (one of the other things i had a question about), but to do so is a small modification to the print function.
Forewarning, i only tested this on the one example you provided. As is probably obvious from the hard-coding of the array size.
I think the code is pretty clear and easy to modify and identify any issues, that may arise, and i'll look for any questions you may have about it.
Hope this helps!
c
before buying again? – Astrogate