//check for other similar meals that are close to the proposed meal
//d - is the day to start checking from
//t - is the meal type
function proximityAllowable(d, t){
for (pDay=d-1; (pDay gt 0 and pDay gt (d-minMealProximity-1)); pDay=pDay-1){ //check against types of the already planned meals
if (listContains(menu[pDay].type, t)){ return false; }
}
return true;
}
//check for repeat side-dishes
//d - is the day to start checking from
//iSide - is which side to check (integer, currently must be 1 or 2)
//sSide - is the value of the side dish chosen
function sideProximityAllowable(d, iSide, sSide){
if (sSide is ""){ return true; } //if not choosing a side, no need to validate, allow it.
for (pDay=d-1; (pDay gt 0 and pDay gt (d-minSideProximity-1)); pDay=pDay-1){ //check against types of the already planned meals
if (listContains(evaluate("menu[#pDay#].side#iSide#"), sSide)){
return false;
}
}
return true;
}
//this function implements all of our per-meal rules
function mealAllowable(day, randMealTypeList){
for(t=1; t lte listLen(randMealTypeList); t=t+1){ //for each type of the random meal
if (minMealProximity gt 0){ //allow 0-proximity check ("don't care")
if (not (proximityAllowable(day, listGetAt(randMealTypeList, t)))){ return false; }
}else{ return true; }
}
return true;
}
//this function will:
// - copy the meal struct from the meals array to the menu array
// - if the meal has been used the maximum number of times, it is taken out of the meals array so it won't be chosen at random again
function assignMeal(day, mealIndex){
menu_meals[mealIndex].spent=menu_meals[mealIndex].spent+1; //increment the number of times this meal has been used
menu[day] = StructNew();
menu[day].name = menu_meals[mealIndex].name;
menu[day].difficulty = menu_meals[mealIndex].difficulty;
menu[day].maxFrequency = menu_meals[mealIndex].maxFrequency;
menu[day].spent = menu_meals[mealIndex].spent;
menu[day].type = menu_meals[mealIndex].type;
menu[day].exception = "";
menu[day].side1 = "";
menu[day].side2 = "";
//assign first side
sides_list = menu_meals[mealIndex].side1; //copy string to its own variable so its not overwritten
tries = 0;
while (tries lt 20){
menu[day].side1 = application.udf.getRandomListItem(sides_list, day + tries); //send day as random seed
if (sideProximityAllowable(day, 1, menu[day].side1)) {break;}
tries=tries+1;
}
//assign second side
tries = 0;
while (tries lt 20){
menu[day].side2 = application.udf.getRandomListItem(fruit_n_veggie_list, day + tries); //send day as random seed
tries=tries+1;
if (sideProximityAllowable(day, 2, menu[day].side2)) {break;}
}
//if meal used max number of times, remove it from the array to speed future searches up
if (menu_meals[mealIndex].spent gte menu_meals[mealIndex].maxFrequency){
arrayDeleteAt(menu_meals, mealIndex);
}
}
#MonthAsString(menuMonth)# #menuYear#
bContinue = true;
//check to see if the current day is listed as an exception - if so, insert exception instead of meal
for (x_check = 1; x_check lte arrayLen(exceptions); x_check=x_check+1){
if (exceptions[x_check].date eq day){
menu[day] = exceptions[x_check];
menu[day].type = ""; //added here so that it's not needed when declaring exceptions - must exist for proximity check for nearby meals
menu[day].side1 = ""; //same^
menu[day].side2 = ""; //same^
mealMatch = true;
bContinue = false;
break;
}
}
//if current day is not an exception
if (bContinue){
randomMeal = RandRange(1, arrayLen(menu_meals)); //choose a meal at random
if (day gt 1){
if (mealAllowable(day, menu_meals[randomMeal].type)){ //does the random choice meet all requirements?
assignMeal(day, randomMeal);
mealMatch = true;
}
}else{
assignMeal(day, randomMeal);
mealMatch = true;
}
}