2
\$\begingroup\$

I need help for logic or pseudo code on how to implement a rules/formula for customer in how they choose drinks(& the toppings). I have more than 10 types of customer and I want to set preferences for everyone of them. E.g : a boy prefer juice (60%), soda(30%) and tea (10%), while an adult in suit prefer coffee(80%), juice (20%). The boy would decide to add topping (70%), and would prefer chocolate(50%), jelly(30%),bubble(20%) as the topping.

What is the best way to implement that? And one thing that concern me that some of the toppings or even drinks are actually might be unavailable because its not ready or need to be unlocked first by leveling up or another reason.

Additional info: i am using unity, and have game manager, customer and player/shop scripts.

\$\endgroup\$
4
\$\begingroup\$

To deal with items changing in availability over time, I'd store your characters' preferences for each drink/topping as a relative weight:

// Data structure that can be shared between
// characters with the same tastes.
[CreateAssetMenu( filename = "NewPreferences.asset", menuName = "Characters/Preferences")]
public class Preferences : ScriptableObject {
     public struct Preference {
          public readonly DrinkItem item;
          public readonly float weight;

          public Preference(DrinkItem item, float weight) {
               this.item = item;
               this.weight = weight;
          }
     }

     // Expose in Inspector, but keep private.
     [System.Serializable]
     Preference[] preferences;

     // You can also digest this to a dictionary
     // if your lists get huge.    
     public Preference GetPreference(DrinkItem item) {
          return System.Array.Find(preferences, p => p.item == item);
     }
}

So if the boy archetype has a relative preference weight of 3 for orange juice and 6 for apple juice, then he's twice as likely to choose apple juice as he is to choose orange juice, whenever both are available. Your numbers don't need to hit any specific total, they just have to be non-negative. A weight of zero (or absence from the list) means they will never order the item.

Next, your ordering system can have something like this:

 // Keep this around so it doesn't need to be re-allocated.
 List<Preferences.Preference> weightedOptions = new List<Preferences.Preference>();

 public DrinkItem Choose(Preferences preferences) {
      // Build a shortlist of options the customer likes.
      float totalWeight = 0f;
      weightedOptions.Clear();

      foreach(var item in CurrentDrinkMenu) {
           var pref = preferences.GetPreference(item);
            if(pref.weight == 0f)
                 continue;
            totalWeight += pref.weight;
            weightedOptions.Add(pref);
      }

      // Pick a point in this range.
      float choice = Random.value * totalWeight;
      totalWeight = 0f;

      // Find which item corresponds to this pick.
      foreach(var option in weightedOptions) {
            totalWeight += option.weight;
            if(totalWeight >= choice)
                 return option.item;
      }
      // Should hit only in exceptional scenarios
      // (Customer likes nothing on the menu,
      // or data was ill-formatted with negatives/NaNs)
      return DefaultOrder;
 }

If you need, you could also return a very tiny weight for items the customer doesn't like, so they'll fall back on those options if there's nothing else in the menu they like.

\$\endgroup\$
3
  • \$\begingroup\$ Wow, thank you very much sir, i really like the idea about storing preferences in that way and ordering system especially how it goes through current drink menu list. I never thought about making list for available menu before, instead i just keep looping and checking availability for each choice which i know its not the convenient way. \$\endgroup\$
    – Goofy_Phie
    Jul 28 '18 at 17:31
  • \$\begingroup\$ sir, what scriptableObject pros in usage for this? ,i mean what if i replace scriptableObject with a standard preference class ? i am in doubt because i already have a preference class declared/attached in my customer class. \$\endgroup\$
    – Goofy_Phie
    Jul 30 '18 at 7:18
  • 1
    \$\begingroup\$ It lets preferences exist as assets in your project folders, kind of like prefabs. That way they can be referenced & shared by many objects (whereas a raw class referenced in a MonoBehaviour gets duplicated with each instance) \$\endgroup\$
    – DMGregory
    Jul 30 '18 at 7:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.