pruby

stardew-greenhouse.mzn

Dec 18th, 2021
178
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.16 KB | None | 0 0
  1. % variables (input from data file)
  2. enum Crops;
  3. enum Quality = {Regular, Silver, Gold, Iridium};
  4. enum Fertiliser;
  5.  
  6. array[Crops] of float: base_growth_time;
  7. array[Crops] of bool: is_regrowing;
  8. array[Crops] of float: extra_yield;
  9. float: jar_time;
  10. array[Crops] of float: keg_time;
  11. array[Crops] of bool: makes_wine;
  12. array[Crops] of float: base_prices;
  13. array[Crops] of float: seed_costs;
  14. array[Crops] of float: jarred_prices;
  15. array[Crops] of float: kegged_prices;
  16.  
  17. array[Fertiliser] of float: fert_growth_time;
  18. array[Quality] of float: quality_price_multiplier;
  19. array[Quality] of float: cask_age_time;
  20. array[Fertiliser] of int: fertiliser_tier;
  21.  
  22. % run settings
  23.  
  24. int: farming_level;
  25. int: planting_spaces;
  26. int: kegs;
  27. int: jars;
  28. int: casks;
  29. float: time_limit;
  30. float: labour_rate;
  31. float: usable_day_hours;
  32. bool: profession_tiller;
  33. bool: profession_artisan;
  34. bool: profession_agri;
  35. Fertiliser: fertiliser;
  36. set of Crops: banned_crops;
  37.  
  38. % Decisions
  39.  
  40. % These represent the decisions that the optimisation engine can make:
  41.  
  42. % plants: how many of each crop to plant
  43. array[Crops] of var int: plants;
  44. constraint forall(c in Crops) (plants[c] >= 0);
  45.  
  46. % sell_raw: how many of each crop and quality to sell per day without further processing
  47. array[Crops, Quality] of var float: sell_raw;
  48. constraint forall(c in Crops, q in Quality) (sell_raw[c,q] >= 0);
  49.  
  50. % buy_seeds: how many seeds of each crop to buy (per day)
  51. array[Crops] of var float: buy_seeds;
  52. constraint forall(c in Crops) (buy_seeds[c] >= 0);
  53.  
  54. % reprocess_seeds: how many of each crop and quality to turn in to seeds in the seed maker per day
  55. array[Crops, Quality] of var float: reprocess_seeds;
  56. constraint forall(c in Crops, q in Quality) (reprocess_seeds[c,q] >= 0);
  57.  
  58. % convert_keg: how many of each crop and quality to put in a keg each day
  59. array[Crops, Quality] of var float: convert_keg;
  60. constraint forall(c in Crops, q in Quality) (convert_keg[c,q] >= 0);
  61.  
  62. % convert_jar: how many of each crop and quality to put in a jar each day
  63. array[Crops, Quality] of var float: convert_jar;
  64. constraint forall(c in Crops, q in Quality) (convert_jar[c,q] >= 0);
  65.  
  66. % aged_keg_product: how much of each age/grade of keg product (wine, juice, etc) to produce.
  67. array[Crops, Quality] of var float: aged_keg_product;
  68. constraint forall(c in Crops, q in Quality) (aged_keg_product[c, q] >= 0);
  69.  
  70. % Derive variables and statistics that we need to constrain or inform those decisions
  71. int: fert_level = fertiliser_tier[fertiliser];
  72.  
  73. float: gold_formula = 0.2 * (farming_level * 0.1) + 0.2 * (fert_level) * ((farming_level + 2) / 12.0) + 0.01;
  74. float: silver_formula = gold_formula * 2;
  75. float: iridium_formula = gold_formula * 0.5;
  76.  
  77. float: iridium_frac = if fert_level >= 3 then iridium_formula else 0 endif;
  78. float: gold_frac = gold_formula * (1 - iridium_frac);
  79. 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;
  80. float: regular_frac = 1 - iridium_frac - gold_frac - silver_frac;
  81.  
  82. 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)));
  83.  
  84. array[Crops, Quality] of var float: yield;
  85. constraint forall(c in Crops) (
  86. yield[c, Regular] = plants[c] * (regular_frac + extra_yield[c]) / growth_time(c)
  87. );
  88. constraint forall(c in Crops) (
  89. yield[c, Silver] = plants[c] * silver_frac / growth_time(c)
  90. );
  91. constraint forall(c in Crops) (
  92. yield[c, Gold] = plants[c] * gold_frac / growth_time(c)
  93. );
  94. constraint forall(c in Crops) (
  95. yield[c, Iridium] = plants[c] * iridium_frac / growth_time(c)
  96. );
  97.  
  98. array[Crops] of var float: total_kegged;
  99. constraint forall(c in Crops) (
  100. total_kegged[c] = sum(q in Quality)(convert_keg[c, q])
  101. );
  102.  
  103. array[Crops] of var float: planting_rate;
  104. constraint forall(c in Crops) (planting_rate[c] = plants[c] * (1.0 / growth_time(c)));
  105.  
  106. array[Crops] of var float: total_yield;
  107. constraint forall(c in Crops) (
  108. total_yield[c] = sum(q in Quality)(yield[c, q])
  109. );
  110.  
  111. array[Crops] of var float: total_jarred;
  112. constraint forall(c in Crops) (
  113. total_jarred[c] = sum(q in Quality)(convert_jar[c, q])
  114. );
  115.  
  116. array[Crops] of var float: total_reprocessed;
  117. constraint forall(c in Crops) (
  118. total_reprocessed[c] = sum(q in Quality)(reprocess_seeds[c, q])
  119. );
  120.  
  121. % Constraints on decisions
  122. constraint forall(c in banned_crops) (plants[c] = 0);
  123.  
  124. % The choices of what to do for each crop and quality must equal our yield of that crop and quality.
  125. constraint forall(c in Crops, q in Quality) (
  126. sell_raw[c, q] + convert_keg[c, q] + convert_jar[c, q] + reprocess_seeds[c, q] = yield[c, q]
  127. );
  128.  
  129. % Total of the age/quality levels we assign to keg products must equal the amount produced
  130. constraint forall(c in Crops) (total_kegged[c] == sum(q in Quality)(aged_keg_product[c, q]));
  131. % Everything except wine can only be regular
  132. constraint forall(c in Crops) (if makes_wine[c] then true else total_kegged[c] == aged_keg_product[c, Regular] endif);
  133.  
  134. var float: planting_time = sum(c in Crops)(if is_regrowing[c] then 0 else planting_rate[c] endif);
  135. var float: harvest_time = sum(c in Crops)(planting_rate[c]);
  136. var float: jarring_time = sum(c in Crops)(total_jarred[c] * 2);
  137. var float: kegging_time = sum(c in Crops)(total_kegged[c] * 2);
  138. var float: reprocessing_time = sum(c in Crops)(total_reprocessed[c] * 2);
  139. var float: cask_time = sum(c in Crops, q in Quality)(if q = Regular then 0 else aged_keg_product[c, q] * 2 endif);
  140.  
  141. var float: total_time = planting_time + harvest_time + jarring_time + kegging_time + cask_time;
  142. var float: labour_value = total_time * labour_rate;
  143.  
  144. % resources
  145. var int: space_used = sum(c in Crops)(plants[c]);
  146. constraint space_used <= planting_spaces;
  147.  
  148. var float: kegs_used = sum(c in Crops)(total_kegged[c] * keg_time[c] / (60 * usable_day_hours));
  149. constraint kegs_used <= kegs;
  150.  
  151. var float: jars_used = sum(c in Crops)(total_jarred[c] * jar_time / (60 * usable_day_hours));
  152. constraint jars_used <= jars;
  153.  
  154. % Ensure we stay within our cask allowance
  155. var float: casks_used = sum(c in Crops, q in Quality)(aged_keg_product[c, q] * cask_age_time[q]);
  156. constraint casks_used <= casks;
  157.  
  158. % We can only buy seeds that are normally available (Pierre / Joja)
  159. constraint forall (c in Crops) (if seed_costs[c] < 0 then buy_seeds[c] = 0 else true endif);
  160.  
  161. % Ensure that we have enough seeds for replacement of crops that don't regrow
  162. constraint forall (c in Crops) (if is_regrowing[c] then true else total_reprocessed[c] * 2 + buy_seeds[c] <= planting_rate[c] endif);
  163.  
  164. % Ensure we don't spend too much time
  165. constraint total_time <= time_limit;
  166.  
  167. % Calculate revenue, costs, and profit
  168.  
  169. 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);
  170. 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);
  171. var float: jar_revenue = sum (c in Crops) (total_jarred[c] * jarred_prices[c]) * (if profession_artisan then 1.4 else 1 endif);
  172.  
  173. var float: total_revenue = raw_revenue + keg_revenue + jar_revenue;
  174.  
  175. var float: spend_seeds = sum(c in Crops)(buy_seeds[c] * seed_costs[c]);
  176.  
  177. var float: total_costs = spend_seeds;
  178.  
  179. var float: profit = total_revenue - total_costs;
  180.  
  181. % Run the optimisation
  182. solve maximize profit - labour_value;
  183.  
  184. % Output results
  185. output [
  186. "Grow " ++ format(0, plants[c]) ++ " " ++ format_justify_string(0, show(c)) ++ " to produce " ++ format(0, 2, total_yield[c]) ++
  187. " (" ++
  188. format(0, 2, yield[c, Regular]) ++
  189. " R, " ++ format(0, 2, yield[c, Silver]) ++
  190. " S, " ++ format(0, 2, yield[c, Gold]) ++
  191. " G, " ++ format(0, 2, yield[c, Iridium]) ++
  192. " I)" ++
  193. " per day." ++
  194. " Sell " ++ format(0, 2, sum(q in Quality)(sell_raw[c,q])) ++ " raw" ++
  195. if fix(total_kegged[c] > 0.005) then ", keg " ++ format(0, 2, total_kegged[c]) else "" endif ++
  196. if fix(aged_keg_product[c, Silver] > 0.005) then ", age " ++ format(0, 2, aged_keg_product[c, Silver]) ++ " to silver" else "" endif ++
  197. if fix(aged_keg_product[c, Gold] > 0.005) then ", age " ++ format(0, 2, aged_keg_product[c, Gold]) ++ " to gold" else "" endif ++
  198. if fix(aged_keg_product[c, Iridium] > 0.005) then ", age " ++ format(0, 2, aged_keg_product[c, Iridium]) ++ " to iridium" else "" endif ++
  199. if fix(total_jarred[c] > 0.005) then ", jar " ++ format(0, 2, total_jarred[c]) else "" endif ++
  200. if fix(total_reprocessed[c] > 0.005) then ", Convert " ++ format(0, 2, total_reprocessed[c]) ++ " to seed" else "" endif ++
  201. "." ++
  202. if fix(buy_seeds[c] >= 0.005) then " Buy " ++ format(0, 2, buy_seeds[c]) ++ " seeds per day.\n" else "\n" endif
  203. | c in Crops where not (c in banned_crops) /\ fix(plants[c] > 0)];
  204.  
  205. output [
  206. "Profitability: ",
  207. format(0, 2, fix(total_revenue)) ++ " revenue - " ++
  208. format(0, 2, fix(total_costs)) ++ " costs" ++
  209. " = " ++ format(0, 2, fix(profit)) ++
  210. ".\n"
  211. ];
  212.  
  213. output [
  214. "Resources used: ",
  215. format(0, 2, fix(space_used)), "/", format(0, 2, planting_spaces), " spaces",
  216. ", ", format(0, 2, fix(kegs_used)), "/", format(0, 2, kegs), " kegs",
  217. ", ", format(0, 2, fix(jars_used)), "/", format(0, 2, jars), " jars",
  218. ", ", format(0, 2, fix(casks_used)), "/", format(0, 2, casks), " casks",
  219. ", ", format(0, 2, fix(total_time)), "/", format(0, 2, time_limit), " actions per day.\n"
  220. ];
  221.  
Advertisement
Add Comment
Please, Sign In to add comment