Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- % variables (input from data file)
- enum Crops;
- enum Quality = {Regular, Silver, Gold, Iridium};
- enum Fertiliser;
- array[Crops] of float: base_growth_time;
- array[Crops] of bool: is_regrowing;
- array[Crops] of float: extra_yield;
- float: jar_time;
- array[Crops] of float: keg_time;
- array[Crops] of bool: makes_wine;
- array[Crops] of float: base_prices;
- array[Crops] of float: seed_costs;
- array[Crops] of float: jarred_prices;
- array[Crops] of float: kegged_prices;
- array[Fertiliser] of float: fert_growth_time;
- array[Quality] of float: quality_price_multiplier;
- array[Quality] of float: cask_age_time;
- array[Fertiliser] of int: fertiliser_tier;
- % run settings
- int: farming_level;
- int: planting_spaces;
- int: kegs;
- int: jars;
- int: casks;
- float: time_limit;
- float: labour_rate;
- float: usable_day_hours;
- bool: profession_tiller;
- bool: profession_artisan;
- bool: profession_agri;
- Fertiliser: fertiliser;
- set of Crops: banned_crops;
- % Decisions
- % These represent the decisions that the optimisation engine can make:
- % plants: how many of each crop to plant
- array[Crops] of var int: plants;
- constraint forall(c in Crops) (plants[c] >= 0);
- % sell_raw: how many of each crop and quality to sell per day without further processing
- array[Crops, Quality] of var float: sell_raw;
- constraint forall(c in Crops, q in Quality) (sell_raw[c,q] >= 0);
- % buy_seeds: how many seeds of each crop to buy (per day)
- array[Crops] of var float: buy_seeds;
- constraint forall(c in Crops) (buy_seeds[c] >= 0);
- % reprocess_seeds: how many of each crop and quality to turn in to seeds in the seed maker per day
- array[Crops, Quality] of var float: reprocess_seeds;
- constraint forall(c in Crops, q in Quality) (reprocess_seeds[c,q] >= 0);
- % convert_keg: how many of each crop and quality to put in a keg each day
- array[Crops, Quality] of var float: convert_keg;
- constraint forall(c in Crops, q in Quality) (convert_keg[c,q] >= 0);
- % convert_jar: how many of each crop and quality to put in a jar each day
- array[Crops, Quality] of var float: convert_jar;
- constraint forall(c in Crops, q in Quality) (convert_jar[c,q] >= 0);
- % aged_keg_product: how much of each age/grade of keg product (wine, juice, etc) to produce.
- array[Crops, Quality] of var float: aged_keg_product;
- constraint forall(c in Crops, q in Quality) (aged_keg_product[c, q] >= 0);
- % Derive variables and statistics that we need to constrain or inform those decisions
- int: fert_level = fertiliser_tier[fertiliser];
- float: gold_formula = 0.2 * (farming_level * 0.1) + 0.2 * (fert_level) * ((farming_level + 2) / 12.0) + 0.01;
- float: silver_formula = gold_formula * 2;
- float: iridium_formula = gold_formula * 0.5;
- float: iridium_frac = if fert_level >= 3 then iridium_formula else 0 endif;
- float: gold_frac = gold_formula * (1 - iridium_frac);
- float: silver_frac = if fert_level >= 3 then 1 - iridium_frac - gold_frac else (1 - iridium_frac - gold_frac) * min(silver_formula, 0.75) endif;
- float: regular_frac = 1 - iridium_frac - gold_frac - silver_frac;
- function float: growth_time(Crops: c) = ceil(base_growth_time[c] * ((if is_regrowing[c] then 1 else fert_growth_time[fertiliser] endif) - (if profession_agri then 0.1 else 0 endif)));
- array[Crops, Quality] of var float: yield;
- constraint forall(c in Crops) (
- yield[c, Regular] = plants[c] * (regular_frac + extra_yield[c]) / growth_time(c)
- );
- constraint forall(c in Crops) (
- yield[c, Silver] = plants[c] * silver_frac / growth_time(c)
- );
- constraint forall(c in Crops) (
- yield[c, Gold] = plants[c] * gold_frac / growth_time(c)
- );
- constraint forall(c in Crops) (
- yield[c, Iridium] = plants[c] * iridium_frac / growth_time(c)
- );
- array[Crops] of var float: total_kegged;
- constraint forall(c in Crops) (
- total_kegged[c] = sum(q in Quality)(convert_keg[c, q])
- );
- array[Crops] of var float: planting_rate;
- constraint forall(c in Crops) (planting_rate[c] = plants[c] * (1.0 / growth_time(c)));
- array[Crops] of var float: total_yield;
- constraint forall(c in Crops) (
- total_yield[c] = sum(q in Quality)(yield[c, q])
- );
- array[Crops] of var float: total_jarred;
- constraint forall(c in Crops) (
- total_jarred[c] = sum(q in Quality)(convert_jar[c, q])
- );
- array[Crops] of var float: total_reprocessed;
- constraint forall(c in Crops) (
- total_reprocessed[c] = sum(q in Quality)(reprocess_seeds[c, q])
- );
- % Constraints on decisions
- constraint forall(c in banned_crops) (plants[c] = 0);
- % The choices of what to do for each crop and quality must equal our yield of that crop and quality.
- constraint forall(c in Crops, q in Quality) (
- sell_raw[c, q] + convert_keg[c, q] + convert_jar[c, q] + reprocess_seeds[c, q] = yield[c, q]
- );
- % Total of the age/quality levels we assign to keg products must equal the amount produced
- constraint forall(c in Crops) (total_kegged[c] == sum(q in Quality)(aged_keg_product[c, q]));
- % Everything except wine can only be regular
- constraint forall(c in Crops) (if makes_wine[c] then true else total_kegged[c] == aged_keg_product[c, Regular] endif);
- var float: planting_time = sum(c in Crops)(if is_regrowing[c] then 0 else planting_rate[c] endif);
- var float: harvest_time = sum(c in Crops)(planting_rate[c]);
- var float: jarring_time = sum(c in Crops)(total_jarred[c] * 2);
- var float: kegging_time = sum(c in Crops)(total_kegged[c] * 2);
- var float: reprocessing_time = sum(c in Crops)(total_reprocessed[c] * 2);
- var float: cask_time = sum(c in Crops, q in Quality)(if q = Regular then 0 else aged_keg_product[c, q] * 2 endif);
- var float: total_time = planting_time + harvest_time + jarring_time + kegging_time + cask_time;
- var float: labour_value = total_time * labour_rate;
- % resources
- var int: space_used = sum(c in Crops)(plants[c]);
- constraint space_used <= planting_spaces;
- var float: kegs_used = sum(c in Crops)(total_kegged[c] * keg_time[c] / (60 * usable_day_hours));
- constraint kegs_used <= kegs;
- var float: jars_used = sum(c in Crops)(total_jarred[c] * jar_time / (60 * usable_day_hours));
- constraint jars_used <= jars;
- % Ensure we stay within our cask allowance
- var float: casks_used = sum(c in Crops, q in Quality)(aged_keg_product[c, q] * cask_age_time[q]);
- constraint casks_used <= casks;
- % We can only buy seeds that are normally available (Pierre / Joja)
- constraint forall (c in Crops) (if seed_costs[c] < 0 then buy_seeds[c] = 0 else true endif);
- % Ensure that we have enough seeds for replacement of crops that don't regrow
- constraint forall (c in Crops) (if is_regrowing[c] then true else total_reprocessed[c] * 2 + buy_seeds[c] <= planting_rate[c] endif);
- % Ensure we don't spend too much time
- constraint total_time <= time_limit;
- % Calculate revenue, costs, and profit
- var float: raw_revenue = sum (c in Crops, q in Quality) (sell_raw[c, q] * base_prices[c] * quality_price_multiplier[q]) * (if profession_tiller then 1.1 else 1 endif);
- var float: keg_revenue = sum (c in Crops, q in Quality) (aged_keg_product[c, q] * kegged_prices[c] * quality_price_multiplier[q]) * (if profession_artisan then 1.4 else 1 endif);
- var float: jar_revenue = sum (c in Crops) (total_jarred[c] * jarred_prices[c]) * (if profession_artisan then 1.4 else 1 endif);
- var float: total_revenue = raw_revenue + keg_revenue + jar_revenue;
- var float: spend_seeds = sum(c in Crops)(buy_seeds[c] * seed_costs[c]);
- var float: total_costs = spend_seeds;
- var float: profit = total_revenue - total_costs;
- % Run the optimisation
- solve maximize profit - labour_value;
- % Output results
- output [
- "Grow " ++ format(0, plants[c]) ++ " " ++ format_justify_string(0, show(c)) ++ " to produce " ++ format(0, 2, total_yield[c]) ++
- " (" ++
- format(0, 2, yield[c, Regular]) ++
- " R, " ++ format(0, 2, yield[c, Silver]) ++
- " S, " ++ format(0, 2, yield[c, Gold]) ++
- " G, " ++ format(0, 2, yield[c, Iridium]) ++
- " I)" ++
- " per day." ++
- " Sell " ++ format(0, 2, sum(q in Quality)(sell_raw[c,q])) ++ " raw" ++
- if fix(total_kegged[c] > 0.005) then ", keg " ++ format(0, 2, total_kegged[c]) else "" endif ++
- if fix(aged_keg_product[c, Silver] > 0.005) then ", age " ++ format(0, 2, aged_keg_product[c, Silver]) ++ " to silver" else "" endif ++
- if fix(aged_keg_product[c, Gold] > 0.005) then ", age " ++ format(0, 2, aged_keg_product[c, Gold]) ++ " to gold" else "" endif ++
- if fix(aged_keg_product[c, Iridium] > 0.005) then ", age " ++ format(0, 2, aged_keg_product[c, Iridium]) ++ " to iridium" else "" endif ++
- if fix(total_jarred[c] > 0.005) then ", jar " ++ format(0, 2, total_jarred[c]) else "" endif ++
- if fix(total_reprocessed[c] > 0.005) then ", Convert " ++ format(0, 2, total_reprocessed[c]) ++ " to seed" else "" endif ++
- "." ++
- if fix(buy_seeds[c] >= 0.005) then " Buy " ++ format(0, 2, buy_seeds[c]) ++ " seeds per day.\n" else "\n" endif
- | c in Crops where not (c in banned_crops) /\ fix(plants[c] > 0)];
- output [
- "Profitability: ",
- format(0, 2, fix(total_revenue)) ++ " revenue - " ++
- format(0, 2, fix(total_costs)) ++ " costs" ++
- " = " ++ format(0, 2, fix(profit)) ++
- ".\n"
- ];
- output [
- "Resources used: ",
- format(0, 2, fix(space_used)), "/", format(0, 2, planting_spaces), " spaces",
- ", ", format(0, 2, fix(kegs_used)), "/", format(0, 2, kegs), " kegs",
- ", ", format(0, 2, fix(jars_used)), "/", format(0, 2, jars), " jars",
- ", ", format(0, 2, fix(casks_used)), "/", format(0, 2, casks), " casks",
- ", ", format(0, 2, fix(total_time)), "/", format(0, 2, time_limit), " actions per day.\n"
- ];
Advertisement
Add Comment
Please, Sign In to add comment