• Categories
    • Unread
    • Recent
    • Popular
    • Users
    • Groups
    • Register
    • Login

    [Challenge] BB Gets Drunk

    Scheduled Pinned Locked Moved Development and Coding
    3 Posts 1 Posters 566 Views 1 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • AlmostA Offline
      Almost
      last edited by

      Partially for fun, partially to test my skills, and partially to get other members to solve my problems for me, I’ve decided to post a little programming challenge. If it goes well, maybe we’ll do more, or maybe I’ll post them with my solutions to show off various concepts and (hopefully) get feedback on where things could be improved.

      I hope you guys will give these a chance and that you enjoy working on them.

      BB Get’s Drunk

      Scuzz’s birthday is coming up, and we’ve decided to all get together and get drunk!
      We know we need:
      12 cans of cider
      2 bottles vodka
      1 bottle whiskey
      6 beers
      4 bottles red wine
      2 bottles white wine

      We also know that
      Scuzz has 6 cans of cider, 1 bottle gin, and 2 bottles of red wine
      Schamper has 2 cans of cider, and 1 bottle of white wine
      Jelly has 3 bottles red wine and 1 bottle vodka
      That freeloader Sly only has protein shakes
      Almost has 6 beers and 1 bottle red wine
      Choob has 1 bottle whiskey and 12 cans of cider

      What we want to do is satisfy our drinking list as best as possible. We also want to keep track of who’s going to bring what drinks to avoid accidentally bringing too much (bear with me, I know this situation isn’t perfect) as well as keep track of what we’re missing.

      E.g. One solution would be:
      Scuzz brings 6 cans of cider and 2 bottles red wine
      Schamper brings 2 cans of cider and 1 bottle white wine
      Jelly brings 2 bottles red wine and 1 bottle vodka
      Almost brings 6 beers
      Choob brings 1 bottle whiskey and 4 cans cider
      We’re missing 1 bottle white wine and 1 bottle vodka.

      This is a simplified variation on a real problem I came across. The current solution is really bad - It took me half an hour to analyze 40 lines to figure out how it did what it was supposed to do. I’m sure there’s a better way to do it, and I’m trying to find it, but figured you guys might be interested in this as well.

      The current structure of the solution is something like this:

      class Alcohol {
          public string name;
          public int quantity;
      }
      
      class AlcoholInventoryItem  {
          public string person;
          public Alcohol alcohol;
      }
      
      public AlcoholInentoryItem[] GetWhoWillBringWhat(Alcohol[] wanted, AlcoholInventoryItem[] have);
      

      Feel free to use this as a starting point or do it with a completely different structure (I know this one is pretty bad, that’s why I’m trying to come up with other solutions)

      Anyway, Let me know if you need clarification, and good luck!

      AlmostA 1 Reply Last reply Reply Quote
      • AlmostA Offline
        Almost @Almost
        last edited by

        Here’s my first solution

        public class Alcohol
                {
                    public string Name;
                    public int Quantity;
        
                    public Alcohol(string name, int quantity)
                    {
                        Name = name;
                        Quantity = quantity;
                    }
                }
        
                public class AlcoholInventoryItem
                {
                    public string Person;
                    public Alcohol Alcohol;
        
                    public AlcoholInventoryItem(String person, String alcoholName, int quantity)
                    {
                        Person = person;
                        this.Alcohol = new Alcohol(alcoholName, quantity);
                    }
                }
        
                public static IEnumerable<AlcoholInventoryItem> WhoIsBringingWhat(IEnumerable<Alcohol> wanted, IEnumerable<AlcoholInventoryItem> have)
                {
                    var whoIsBringingWhat = new List<AlcoholInventoryItem>();
                    // Iterate through everything we want
                    foreach (var currentAlcohol in wanted)
                    {
                        // Get all inventory items that are for this type of alcohol
                        IEnumerable<AlcoholInventoryItem> currentAlcoholInventory  = have.Where(item => item.Alcohol.Name == currentAlcohol.Name);
                        // Get how many we have unsatisfied
                        int numStillWanted = currentAlcohol.Quantity;
                        // Iterate through our inventory
                        foreach (var currentAlcoholInventoryItem in currentAlcoholInventory)
                        {
                            // If we still want some, this person will bring some
                            if (numStillWanted > 0)
                            {
                                // Bring as much as we want or as much as you have - which ever is less
                                var bringing = new AlcoholInventoryItem(currentAlcoholInventoryItem.Person, currentAlcoholInventoryItem.Alcohol.Name,
                                    Math.Min(currentAlcoholInventoryItem.Alcohol.Quantity, numStillWanted));
                                // Figure out how much we still need
                                numStillWanted -= bringing.Alcohol.Quantity;
                                // Mark who is bringing this and how much
                                whoIsBringingWhat.Add(bringing);
                            }
                        }
                        // We've gone through all our inventory - are we still missing some?
                        if (numStillWanted > 0)
                        {
                            whoIsBringingWhat.Add(new AlcoholInventoryItem(null, currentAlcohol.Name, numStillWanted));
                        }
                    }
                    return whoIsBringingWhat;
                }
        

        Yay C#.

        The outerloop iterates through what we want, the inner loop iterates through what we have. As it’s iterating through the inner loop, it tries to get each person to bring as much as they can up to the number we want. Then at the end, if we still want more, we add it.

        I feel like this could be simplified more. For example, I’m not a fan of the fact that I have a if (numStillWanted > 0) outside of the inner loop. I think there’s probably a more functional way, but I haven’t found it yet.

        1 Reply Last reply Reply Quote
        • AlmostA Offline
          Almost
          last edited by

          Really minor improvement, but in order to remove that extra if (numStillWanted > 0) we could consider any alcohol that we don’t have as inventory that belongs to no one.

          To make this work in the code, we just add a line outside the outer loop:
          have = have.concat(wanted.select(cur => new AlcoholInventoryItem(null, cur.Name, cur.Quantity));

          With this, we’re assured that we will never be left with numStillWanted > 0 after the inner loop because in the case where no one has any of the alcohol we want, our inventory consists of alcohol that belongs to no one that has exactly the quantity we want.

          1 Reply Last reply Reply Quote
          • 1 / 1
          • First post
            Last post
          Online Users