721 lines
21 KiB
JavaScript
721 lines
21 KiB
JavaScript
const fs = require("fs");
|
|
const util = require("util");
|
|
const dice = require("fast-dice-coefficient");
|
|
const asm = require("./compiler.js");
|
|
const { ingredients } = require("./download");
|
|
let reference = JSON.parse(fs.readFileSync("base.json"));
|
|
function deepCopy(a) {
|
|
return JSON.parse(JSON.stringify(a));
|
|
}
|
|
function isRef(a) {
|
|
return reference.includes(a);
|
|
}
|
|
function isRefOrUnCrafty(a) {
|
|
//if this chem has no need to be made or cannot be made.
|
|
if (!isRef(a)) {
|
|
return !chems.ChemFind(a).recipe.some((x) => x.yields != 0);
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
function isCrafty(a) {
|
|
if (isRef(a)) {
|
|
return true;
|
|
}
|
|
return chems.ChemFind(a).recipe.some((x) => x.yields != 0);
|
|
}
|
|
class Recipe {
|
|
constructor(name, recipe, ignition) {
|
|
this.name = name;
|
|
this.recipe = recipe;
|
|
this.ignition = ignition;
|
|
}
|
|
}
|
|
//a binder.
|
|
class asmBind {
|
|
static outOfBoundsErrror(int) {
|
|
if (int > 10 || int < 1) {
|
|
throw "Please enter a digit between 1 and 10";
|
|
}
|
|
}
|
|
|
|
static move(amount, source, target, out) {
|
|
asmBind.outOfBoundsErrror(source);
|
|
|
|
asmBind.outOfBoundsErrror(target);
|
|
|
|
out.push(`mov ${amount}, ${source}, ${target}\n`);
|
|
}
|
|
static moveMixToOut(out) {
|
|
out.push(`movall 9, 10\n`);
|
|
}
|
|
|
|
static setTemp(temprature, out) {
|
|
out.push(`temp 9, ${temprature}\n`);
|
|
}
|
|
|
|
static isolate(amount, order, source, target, out) {
|
|
asmBind.outOfBoundsErrror(source);
|
|
|
|
asmBind.outOfBoundsErrror(target);
|
|
|
|
out.push(`iso ${amount}, ${order}, ${source}, ${target}\n`);
|
|
}
|
|
|
|
static end(out) {
|
|
out.push("compile\n");
|
|
}
|
|
static print(text, out) {
|
|
out.push(`print ${text}`);
|
|
}
|
|
static compile(a) {
|
|
return asm.assembler(a);
|
|
}
|
|
static pill(out) {
|
|
out.push("pill 9\n");
|
|
}
|
|
}
|
|
function getYieldModifier(a) {
|
|
try {
|
|
return a.yields / a.chemarray.reduce((a, b) => a + b[1], 0);
|
|
} catch {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
let chems = JSON.parse(fs.readFileSync("out.json"));
|
|
util.inspect.defaultOptions.depth = null;
|
|
|
|
//this proc allows me to have lienencey involving naming.
|
|
chems.ChemFind = function (a) {
|
|
//this is a very pretty way of accounting for string parsing issues.
|
|
if (a in chems) {
|
|
return chems[a];
|
|
} else {
|
|
let leven = [];
|
|
|
|
for (const item in chems) {
|
|
leven.push([dice(a, item), item]);
|
|
}
|
|
leven.sort((a, b) => b[0] - a[0]);
|
|
return chems[leven[0][1]];
|
|
}
|
|
};
|
|
chems.getRecipes = function () {
|
|
return Object.values(chems)
|
|
.map((x) => x.recipe)
|
|
.flat()
|
|
.filter((x) => x == undefined || x.chemarray.length != 0);
|
|
};
|
|
// rough thing, kinda just gonna let it be?
|
|
function recursiveScore(a) {
|
|
function score(a) {
|
|
const current = a.chemarray;
|
|
let total = current.length * 3;
|
|
let points = 0;
|
|
for (const x in current) {
|
|
if (isRef(current[x][0])) {
|
|
points += 3;
|
|
continue;
|
|
}
|
|
if (chems.ChemFind(current[x][0]).yields != 0) {
|
|
points++;
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
return (points / total) * 100;
|
|
}
|
|
|
|
let base = [0, {}];
|
|
function recursive(a) {
|
|
let filtered = a.recipe.filter((x) => x.yields != 0);
|
|
|
|
if (filtered.length == 0) {
|
|
base[1][a.name] = a.recipe[0];
|
|
return;
|
|
}
|
|
let best;
|
|
if (filtered.length == 1) {
|
|
base[0] += score(filtered[0]);
|
|
base[1][a.name] = filtered[0];
|
|
best = filtered[0];
|
|
} else {
|
|
let comparision = [];
|
|
for (let x in filtered) {
|
|
comparision.push([x, score(filtered[x])]);
|
|
}
|
|
comparision.sort((a, b) => b[1] - a[1]);
|
|
best = filtered[comparision[0][0]];
|
|
base[0] += score(best);
|
|
base[1][a.name] = best;
|
|
}
|
|
let reagents = best.chemarray.filter((x) => !isRef(x[0]));
|
|
for (x in reagents) {
|
|
recursive(chems.ChemFind(reagents[x][0]));
|
|
}
|
|
}
|
|
recursive(a);
|
|
|
|
return base[1];
|
|
}
|
|
chems["thc"] = chems.ChemFind("Tetrahydrocannabinol");
|
|
|
|
class crafty {
|
|
//prohbably gonna get merged with ingredients, its kinda weird that we have two that do the same thing.
|
|
constructor(
|
|
temp,
|
|
chems,
|
|
wanted,
|
|
order,
|
|
name,
|
|
ignition,
|
|
yields,
|
|
yieldmodifier,
|
|
) {
|
|
this.temp = temp;
|
|
this.chems = chems;
|
|
this.wanted = wanted;
|
|
this.order = order;
|
|
this.name = name;
|
|
this.ignition = ignition;
|
|
this.total = wanted.reduce((a, b) => a + b[1], 0);
|
|
this.yields = yields;
|
|
this.yieldmodifier = yieldmodifier;
|
|
}
|
|
}
|
|
|
|
class beaker {
|
|
//this class is on a pretty strict lockdown because troubleshooting this will be impossible
|
|
constructor(chems, max = 100, beakernumber) {
|
|
this.chems = chems;
|
|
this.max = max;
|
|
this.beakernumber = beakernumber;
|
|
this.temp = 293.15;
|
|
}
|
|
sortCrafty() {
|
|
this.chems = this.chems.sort((a, b) => isCrafty(b[0]) - isCrafty(a[0]));
|
|
}
|
|
|
|
toPreset() {
|
|
return this.chems
|
|
.filter((x) => isRef(x[0]))
|
|
.map((x) => x.join("="))
|
|
.join(";");
|
|
}
|
|
|
|
total() {
|
|
return this.chems.reduce((a, b) => a + b[1], 0);
|
|
}
|
|
//returns the reagent name, amount, and order in the beaker
|
|
free() {
|
|
return [this.max - this.total(), this.beakernumber];
|
|
}
|
|
|
|
getReagent(a) {
|
|
let chems = this.chems;
|
|
for (var x in chems) {
|
|
if (chems[x][0] == a) {
|
|
return [chems[x][0], chems[x][1], Number(x) + 1, this.beakernumber];
|
|
}
|
|
}
|
|
return [a, 0, -1, -1];
|
|
}
|
|
changeReagent(a, b) {
|
|
let found = this.chems.find((x) => x[0] == a);
|
|
found[1] += b;
|
|
if (found[1] < 0) {
|
|
//future caroline, this is because the beaker is less than zero.
|
|
//ie subracted too much
|
|
throw "A beaker has reached a negative balance, This is a bug in the algorithm. Progress is irrecoverable.";
|
|
}
|
|
if (found[1] == 0) {
|
|
this.chems = this.chems.filter((x) => x[0] != a);
|
|
}
|
|
if (this.total() > this.max) {
|
|
throw "A beaker has ovweflowed, This is a bug in the algorithm. Progress is irrecoverable.";
|
|
}
|
|
}
|
|
|
|
addReagent(a) {
|
|
if (typeof a != typeof []) {
|
|
throw "The reagent is the incorrect type. This is a bug in the algorithm. Progress is irrecoverable.";
|
|
}
|
|
if (a.length != 2) {
|
|
throw "The reagent is an array, but isn't in the proper format.";
|
|
}
|
|
if (this.total >= this.max) {
|
|
throw "The beaker cannot fit anymore reagent in, and thus cannot be added to. This is a bug in the algorithm. Progress is irrecoverable. ";
|
|
}
|
|
if (a[1] == 0) {
|
|
return;
|
|
}
|
|
if (this.chems.some((x) => x[0] == a[0])) {
|
|
//adds to the production
|
|
this.chems.find((x) => x[0] == a[0])[1] += a[1];
|
|
} else {
|
|
//other wise it just adds it to the total production quota
|
|
this.chems.push(a);
|
|
}
|
|
|
|
if (this.total() > this.max) {
|
|
throw "My nam is (u dont need to remember) Guanglai Kangyi, age 15, the past month to me is, only graduation tests. the entrance into high-school brings really exciting and worry-ing days. till i met these 2 very special guys......";
|
|
}
|
|
}
|
|
//added chem is optional we get the existing reactions vs the ones if we add it
|
|
premtiveReactions(addeChem = undefined) {
|
|
let reactions = chems.getRecipes().filter((x) => x != undefined);
|
|
let localchems = this.chems.map((x) => x[0]);
|
|
if (addeChem != undefined) {
|
|
localchems.push(addeChem);
|
|
}
|
|
|
|
function allIn(addeChem, chems) {
|
|
//gets a list of all names of chems
|
|
addeChem = addeChem.map((x) => x[0]);
|
|
return !addeChem
|
|
.map((x) => localchems.includes(x))
|
|
.some((x) => x == false);
|
|
}
|
|
reactions = reactions.filter((x) => allIn(x.chemarray));
|
|
return reactions;
|
|
}
|
|
ifaddedWillReact(a) {
|
|
//JS lacks the ability to compare arrays so this is just a makeshift way of doing it.
|
|
//we compare existing reactions vs reactions if the chem was added.
|
|
let newreaction = this.premtiveReactions(a[0]);
|
|
let oldreaction = this.premtiveReactions().map((x) => x.name);
|
|
if (oldreaction.join("") != newreaction.map((x) => x.name).join("")) {
|
|
return [
|
|
true,
|
|
newreaction.filter((x) => !oldreaction.includes(x.name)),
|
|
this.beakernumber,
|
|
this.free(),
|
|
];
|
|
} else {
|
|
return [false, [], this.beakernumber, this.free()];
|
|
}
|
|
}
|
|
}
|
|
|
|
class BeakerGroup {
|
|
constructor(max, recipes) {
|
|
this.outBeakers = [new beaker([], 100, 9), new beaker([], max, 10)];
|
|
this.beakers = [];
|
|
this.recipes = recipes;
|
|
}
|
|
startCraft() {
|
|
let out = [];
|
|
this.recipes.forEach((x) => {
|
|
out.push(this.craftChem(x));
|
|
});
|
|
return out.flat();
|
|
}
|
|
numberOfBeakers() {
|
|
return this.beakers.length;
|
|
}
|
|
totalFree() {
|
|
return this.beakers.map((x) => x.free());
|
|
}
|
|
supplyReagents(chem, destination, outCommands) {
|
|
if (chem[1] == 0) {
|
|
return;
|
|
}
|
|
//we get the chems which match the input and sort by largest. We filter it
|
|
let avaliable = this.beakers
|
|
.map((x) => x.getReagent(chem[0]))
|
|
.sort((a, b) => a[1] + b[1])
|
|
.filter((x) => x[1] > 0);
|
|
let totalfree = 0;
|
|
if (avaliable.length > 1) {
|
|
totalfree = avaliable.reduce((a, b) => a + b[1], 0);
|
|
} else {
|
|
totalfree = avaliable[0][1];
|
|
}
|
|
//this gets the total amount of chems in the beakergroup
|
|
if (chem[1] > totalfree) {
|
|
console.log(chem);
|
|
console.log(totalfree);
|
|
console.log(this.beakers);
|
|
throw "NOT ENOUGH CHEMS TO SUPPLY!!!!!!!!";
|
|
}
|
|
//gets the total amount supplied thus far
|
|
let totalmoved = 0;
|
|
for (x in avaliable) {
|
|
//we can break once we are done
|
|
if (totalmoved == chem[1]) {
|
|
break;
|
|
}
|
|
let current = avaliable[x];
|
|
//due is the amount left we have to transfer
|
|
let due = chem[1] - totalmoved;
|
|
//this is the difference between what we have to take and which is avaliable
|
|
let difference = due - current[1];
|
|
//if due isn't zero or less then we have to conform to the difference and draw what we can in future loops
|
|
if (difference > 0) {
|
|
due -= difference;
|
|
}
|
|
totalmoved += due;
|
|
this.beakers[current[3] - 1].changeReagent(chem[0], 0 - due);
|
|
outCommands.push(`#Isolating ${due}u of ${chem[0]} to ${destination}\n`);
|
|
asmBind.isolate(due, current[2], current[3], destination, outCommands);
|
|
}
|
|
}
|
|
|
|
craftChem(crafty) {
|
|
//console.log(crafty)
|
|
// console.log(this.beakers)
|
|
let outCommands = [];
|
|
let mixtemp = this.outBeakers[0].temp;
|
|
if (this.ignition >= mixtemp) {
|
|
asmBind.setTemp(crafty.ignition - 20, outCommands, mixtemp);
|
|
this.outBeakers[0].temp = crafty.ignition - 20;
|
|
}
|
|
if (crafty.total <= 101) {
|
|
for (var x in crafty.wanted) {
|
|
this.supplyReagents(crafty.wanted[x], 9, outCommands);
|
|
}
|
|
if (crafty.temp != -1) {
|
|
asmBind.setTemp(crafty.temp + 20, outCommands, mixtemp);
|
|
this.outBeakers[0].temp = crafty.temp + 20;
|
|
}
|
|
|
|
if (crafty.order == 0) {
|
|
asmBind.moveMixToOut(outCommands);
|
|
asmBind.end(outCommands);
|
|
} else {
|
|
outCommands.push(
|
|
`#returning ${crafty.chems}u of ${crafty.name} from mix.\n`,
|
|
);
|
|
this.returnFromMix([crafty.name, crafty.chems], outCommands);
|
|
}
|
|
} else {
|
|
let due = crafty.total;
|
|
let modifier = 100 / due;
|
|
let ref = deepCopy(crafty.wanted);
|
|
while (true) {
|
|
let moved = 0;
|
|
let toMove = 0;
|
|
let end = false;
|
|
if (100 > ref.reduce((a, b) => a + b[1], 0)) {
|
|
end = true;
|
|
}
|
|
for (x in crafty.wanted) {
|
|
let wanted = crafty.wanted[x];
|
|
if (!end) {
|
|
toMove = Math.floor(wanted[1] * modifier);
|
|
} else {
|
|
toMove = ref[x][1];
|
|
}
|
|
moved += toMove;
|
|
ref[x][1] -= toMove;
|
|
due -= toMove;
|
|
this.supplyReagents([wanted[0], toMove], 9, outCommands);
|
|
}
|
|
|
|
if (crafty.temp != -1) {
|
|
asmBind.setTemp(crafty.temp + 20, outCommands);
|
|
this.outBeakers[0].temp = crafty.temp + 20;
|
|
}
|
|
|
|
if (crafty.order != 0) {
|
|
outCommands.push(
|
|
`#returning ${moved * crafty.yieldmodifier}u of ${crafty.name} from mix.\n`,
|
|
);
|
|
this.returnFromMix(
|
|
[crafty.name, moved * crafty.yieldmodifier],
|
|
outCommands,
|
|
);
|
|
} else if (due != 0) {
|
|
asmBind.pill(outCommands);
|
|
}
|
|
|
|
if (end) {
|
|
// console.log(due)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//console.log(outCommands.join(""))
|
|
return outCommands;
|
|
}
|
|
|
|
returnFromMix(a, outCommands) {
|
|
this.avoidReact(a).forEach((x) => {
|
|
outCommands.push(`#moving ${x[1]}u of ${a[0]} to ${x[0]}\n`);
|
|
asmBind.move(x[1], 9, x[0], outCommands);
|
|
});
|
|
}
|
|
addBeaker(beaker) {
|
|
if (8 > this.beakers.length) {
|
|
this.beakers.push(beaker);
|
|
} else {
|
|
throw "You can only fit 8 beakers in a chemi compiler unless you have some whacky stuff invovling moving outs.";
|
|
}
|
|
}
|
|
allocate(free, a) {
|
|
//this finds a free location to put a chem
|
|
//free is the places it can choose to put it.
|
|
let out = [];
|
|
let due = a[1];
|
|
let sent = 0;
|
|
for (x in free) {
|
|
let current = free[x];
|
|
if (due == 0) {
|
|
break;
|
|
}
|
|
if (current[0] == 0) {
|
|
continue;
|
|
}
|
|
if (current[0] > due) {
|
|
this.beakers[current[1] - 1].addReagent([a[0], due]);
|
|
sent = due;
|
|
due = 0;
|
|
} else {
|
|
due -= current[0];
|
|
this.beakers[current[1] - 1].addReagent([a[0], current[0]]);
|
|
sent = current[0];
|
|
}
|
|
//this logs the chem and the stuff moved
|
|
out.push([current[1], sent]);
|
|
}
|
|
//it is logged so we can issue commands to the compiler to execute these orders.
|
|
return out;
|
|
}
|
|
|
|
///This function yields a place where a chemical can be added and it wont react, if a place exists for itl
|
|
avoidReact(a) {
|
|
let free = this.totalFree();
|
|
if (a[1] > free.reduce((a, b) => a[0] + b[0])) {
|
|
throw "not enough space to move reagents.";
|
|
}
|
|
|
|
let ReactMap = this.beakers.map((x) => x.ifaddedWillReact(a));
|
|
if (
|
|
!ReactMap.some(
|
|
(x) =>
|
|
x[0] == true && ReactMap.map((x) => x[1].temp == -1).includes(true),
|
|
)
|
|
) {
|
|
return this.allocate(free, a);
|
|
} else {
|
|
ReactMap = ReactMap.filter((x) => !x[0]);
|
|
//the throw here is kinda pointless because this function will fail because throw happens
|
|
if (a[1] > ReactMap.reduce((a, b) => a + b[3], 0)) {
|
|
console.log(ReactMap.reduce((a, b) => a + b[3], 0));
|
|
console.log(a);
|
|
throw "not enough space to move reagents.";
|
|
}
|
|
//it requires a map of free(), which is x[3]
|
|
return this.allocate(
|
|
ReactMap.map((x) => x[3]),
|
|
a,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
function proportionFinder(a, wanted, array, order, OptimalRecipes) {
|
|
console.log(a);
|
|
//converts the Stoichenemtry proportions to absolute values for production
|
|
let StoichiometricValues = [];
|
|
//for each element in the chem array
|
|
a.chemarray.forEach((current) => {
|
|
//we deep copy so the modifications dont alter the entry, for other recipes dependant upon it
|
|
current = deepCopy(current);
|
|
//this formula is calculates the amount of chems needed.
|
|
current[1] = current[1] * Math.ceil(wanted / a.yields);
|
|
console.log(current);
|
|
console.log(OptimalRecipes);
|
|
if (!isRefOrUnCrafty(current[0])) {
|
|
proportionFinder(
|
|
OptimalRecipes[current[0]],
|
|
current[1],
|
|
array,
|
|
order + 1,
|
|
OptimalRecipes,
|
|
);
|
|
}
|
|
|
|
StoichiometricValues.push(current);
|
|
});
|
|
//finds the ignition temprature of chems inside the beakers
|
|
//this is to help prevent explosions
|
|
if (StoichiometricValues.length != 0) {
|
|
let ignitionSearch = StoichiometricValues.map(
|
|
(x) => chems.ChemFind(x[0]).ignition,
|
|
).filter((x) => x != 0);
|
|
let ignition = a.ignition;
|
|
//if there is any of them which are sensitive then the ignition temp is set to that.
|
|
if (!ignitionSearch.length == 0) {
|
|
ignition = ignitionSearch.sort((a, b) => b - a)[0];
|
|
}
|
|
|
|
let ym = getYieldModifier(a);
|
|
//the total number of parts times the yield modifier is equal to the total output
|
|
//this is done because the rounding makes things funky
|
|
let newtotal = StoichiometricValues.reduce((a, b) => a + b[1], 0) * ym;
|
|
|
|
if (array.map((x) => x.name).includes(a.name)) {
|
|
let found = array.find((x) => x.name == a.name);
|
|
for (x in StoichiometricValues) {
|
|
found.wanted[x][1] += StoichiometricValues[x][1];
|
|
}
|
|
found.chems += newtotal;
|
|
found.total += StoichiometricValues.reduce((a, b) => a + b[1], 0);
|
|
return;
|
|
}
|
|
|
|
array.push(
|
|
new crafty(
|
|
a.temp,
|
|
newtotal,
|
|
StoichiometricValues,
|
|
order,
|
|
a.name,
|
|
ignition,
|
|
a.yields,
|
|
ym,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
function getInput(a) {
|
|
//this gets a detailed list of the raw "materials" used to make the chems.
|
|
//takes direct input from ProportionFinder
|
|
//this gets all the recipes names and all their components
|
|
let genned = a.map((x) => x.name);
|
|
let search = a.map((x) => x.wanted);
|
|
let needed = {};
|
|
for (x in search) {
|
|
//if a chem has a recipe we remove it because we're making it, it is not needed to be in the raw input
|
|
search[x] = search[x].filter((x) => !genned.includes(x[0]));
|
|
}
|
|
search = search.flat();
|
|
|
|
search.forEach((x) => {
|
|
//we create a table of the every instance of the recipes
|
|
if (needed[x[0]] !== undefined) {
|
|
//if it exists we add to it
|
|
needed[x[0]] += x[1];
|
|
} else {
|
|
//if it doesn't, we start it
|
|
needed[x[0]] = x[1];
|
|
}
|
|
});
|
|
//tbh I'd prefer a pair situation rather than a object {} for various reasons
|
|
let keys = Object.keys(needed);
|
|
let out = [];
|
|
for (var x in keys) {
|
|
out.push([keys[x], Math.ceil(needed[keys[x]])]);
|
|
}
|
|
|
|
let total = out.reduce((a, b) => a + b[1], 0);
|
|
//beaker groups are the language of allocation
|
|
//allowing all beakers to be treated as one distrbuted object is an adaptable framework.
|
|
let beakergroup = new BeakerGroup(100, a);
|
|
beakersneeded = Math.ceil(total / 100);
|
|
//1 beaker is bad because we cant avoid reactions.
|
|
if (beakersneeded == 1) {
|
|
beakersneeded++;
|
|
}
|
|
for (i = 1; i != beakersneeded + 1; i++) {
|
|
beakergroup.addBeaker(new beaker([], 100, i));
|
|
}
|
|
//this is the way we assign chems to beakers as to avoid all reactions where possible
|
|
out.forEach((x) => {
|
|
beakergroup.avoidReact(x);
|
|
});
|
|
//so I think the most effective way of handling side affects is seperate from allocation
|
|
//the code will get really nonsensicale
|
|
return beakergroup;
|
|
}
|
|
|
|
util.inspect.defaultOptions.depth = null;
|
|
function arbitraryToParts(abritrary) {
|
|
//the system is programmed to work in parts
|
|
//this converts arbitrary input to totals
|
|
let partTotal = abritrary.reduce((a, b) => a + b[1], 0);
|
|
abritrary = abritrary.map((x) => [x[0], x[1] / partTotal]);
|
|
let input = new Recipe(
|
|
"output",
|
|
[
|
|
new ingredients(
|
|
"N/A",
|
|
-1,
|
|
parts.reduce((a, b) => a + b[1], 0),
|
|
parts,
|
|
"out",
|
|
0,
|
|
),
|
|
],
|
|
0,
|
|
);
|
|
return [input, partTotal];
|
|
}
|
|
function main(input, debug = false) {
|
|
let wanted = 0;
|
|
if (input.length == 1) {
|
|
wanted = input[0][1];
|
|
input = chems.ChemFind(input[0][0]);
|
|
} else {
|
|
let converted = arbitraryToParts(input);
|
|
input = converted[0];
|
|
wanted = converted[1];
|
|
}
|
|
|
|
let out = [];
|
|
let OptimalRecipes = recursiveScore(input);
|
|
let base = Object.values(OptimalRecipes)[0];
|
|
proportionFinder(base, wanted, out, 0, OptimalRecipes);
|
|
let beakers = getInput(out.sort((a, b) => b.order - a.order));
|
|
beakers.beakers.forEach((x) => {
|
|
x.sortCrafty();
|
|
console.log(x.toPreset());
|
|
console.log(x);
|
|
});
|
|
let outcommands = beakers.startCraft();
|
|
let nondebug = outcommands.filter((x) => x[0] != "#");
|
|
let output = asmBind.compile(nondebug.join(""));
|
|
|
|
if (!debug) {
|
|
console.log(nondebug.join(""));
|
|
console.log(output);
|
|
} else {
|
|
console.log(outcommands.join(""));
|
|
}
|
|
let mood = "\x1b[36m%s\x1b[0m";
|
|
if (output.length > 2000) {
|
|
mood = "\x1b[31m%s\x1b[0m";
|
|
}
|
|
console.log(
|
|
"\x1b[36m%s\x1b[0m",
|
|
`number of lines of code = ${nondebug.length}`,
|
|
);
|
|
console.log(
|
|
"\x1b[36m%s\x1b[0m",
|
|
`total u output should be ~${input.recipe[0].yields}`,
|
|
);
|
|
console.log(mood, `total amount of chars of code are ${output.length}`);
|
|
if (mood.includes("31")) {
|
|
console.log(
|
|
"for some reason the eldritch technology (magic) of the chemicompiler really only supports 2000 chars of code",
|
|
);
|
|
console.log(
|
|
"you must manually split up the commands into bite size pieces in order for the script to not hault midway through.",
|
|
);
|
|
console.log(
|
|
"this might be due to something involving it being 2 kilobyte of data but thats either here nor there.",
|
|
);
|
|
}
|
|
console.log(`expected ouput in exit beaker if lower than 100 chems and in pills if higher.\n
|
|
${parts.map((x) => x.join(" ")).join(", ")}`);
|
|
console.log(
|
|
"not all pills are created equal. Depending on the yield multiplier some may have more some may have less",
|
|
);
|
|
console.log("meths is 0.75; the maximum output is 75 per pill.");
|
|
}
|
|
|
|
let parts = [["Meth", 100]];
|
|
main(parts, false);
|