Home > Software engineering >  How to force user to at least click on 2 out of 6 choices on a check box in c#?
How to force user to at least click on 2 out of 6 choices on a check box in c#?

Time:10-16

namespace PizzaApp
{
    public partial class PizzaOrder : Form
    {
        // Initializing the toppings to its cost
        // Double type since it could have decimal points
        public double Small = 5.50;
        public double Medium = 11.75;
        public double Large = 15.00;
        public double Pepperoni = 0.75;
        public double Onion = 0.75;
        public double Mushroom = 0.75;
        public double BlackOlives = 0.75;
        public double Pineapple = 0.75;
        public double ExtraCheese = 0.75;

        public static double Cost = 0.00; // Keeps track of total cost
        

        public PizzaOrder()
        {
            InitializeComponent();
        }

        private void orderButton_Click(object sender, EventArgs e)
        {
           
            // If small size pizza radio button is checked, I do cost - 1.50 because 2 ingredients are free
            if (smallRadioButton.Checked == true)
            {
                Cost  = Small;
                Cost -= 1.50;
            }
            // If medium size pizza radio button is checked, I do cost - 2.25 because 3 ingredients are free
            if (mediumRadioButton.Checked == true)
            {
                Cost  = Medium;
                Cost -= 2.25;
            }
            // If large size pizza radio button is checked, I do cost - 3.00 because 4 ingredients are free
            if (largeRadioButton.Checked == true)
            {
                Cost  = Large;
                Cost -= 3.00;
            }


            //Ingredrients if statements
            if (pepperoniCheckBox.Checked == true)
            {
                Cost  = Pepperoni;

            }
            if (onionCheckBox.Checked == true)
            {
                Cost  = Onion;

            }
            if (mushroomCheckBox.Checked == true)
            {
                Cost  = Mushroom;

            }
            if (blackOlivesCheckBox.Checked == true)
            {
                Cost  = BlackOlives;

            }
            if (pineappleCheckBox.Checked == true)
            {
                Cost  = Pineapple;

            }
            if (extraCheeseCheckBox.Checked == true)
            {
                Cost  = ExtraCheese;

            }

           
        }

        private void sizeGroupBox_Enter(object sender, EventArgs e)
        {

        }

        private void ingredientsGroupBox_Enter(object sender, EventArgs e)
        {

        }

        private void PizzaOrder_Load(object sender, EventArgs e)
        {

        }

        private void priceLabel_Click(object sender, EventArgs e)
        {
          
        }

        private void totalPriceTextBox_TextChanged(object sender, EventArgs e)
        {
            totalPriceTextBox.Text = Cost.ToString();
        }
    }
}

When the user takes small pizza for example 2 out of 6 ingredients are free(Medium is 3 and large is 4 free ingredients). I couldn't find any other way to implement this so I just subtracted the free ingredients from the pizza size. I'm now stuck on how to force the user to choose at least those free ingredients so the pizza wont cost less than the initial price.

CodePudding user response:

This is a common flaw in beginners code, that there is basically zero abstraction/seperation between UI and data / business logic. Consider using a proper OOP approach, then things quickly start to seem much clearer.

Example:

public enum PizzaSize
{
    Small,
    Medium,
    Large
}

public class PizzaTopping
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class PizzaOrder
{
    private static readonly Dictionary<PizzeSize, decimal> pizzaPrices = new Dictionary<PizzeSize, decimal>
    {
         { PizzaSize.Small, 5.5m },
         { PizzaSize.Medium, 11.75m },
         { PizzaSize.Large, 15m },
    };
    
    private static readonly Dictionary<PizzeSize, decimal> freeToppingsCounts = new Dictionary<PizzeSize, decimal>
    {
         { PizzaSize.Small, 2 },
         { PizzaSize.Medium, 3 },
         { PizzaSize.Large, 4 },
    };
    
    public PizzaSize Size { get; set; }
    public List<PizzaTopping> Toppings { get; set; } = new List<PizzaTopping>();
    
    public decimal GetTotalPrice()
    {
        var totalPrice = pizzaPrices[this.Size];
        var freeToppings = freeToppingsCounts[this.Size];
        var counter = 0;
        foreach (var topping in this.Toppings.OrderBy(x => x.Price))
        {
            counter  ;
            if (counter > freeToppings)
            {
                totalPrice  = topping.Price;
            }
        }
        return totalPrice;
    }
}


public class PizzaOrderForm : Form
{
    var order = GetPizzaOrder(); // create your order from the UI here
    var totalPrice = order.GetTotalPrice();
}

(Disclaimer: I quickly hacked this together in Notepad, it's not meant to be perfect, just to make my point.)

CodePudding user response:

I would start off by defining a class which holds a reference to the relevant checkbox and the price for that topping

public class Topping
{
    public CheckBox Selector {get;}
    public double Cost {get;}

    public Topping(CheckBox selector, double cost)
    {
       this.Selector = selector;
       this.Cost = cost;
    }
}

And then define an array of Topping in your form instead of a bunch of discrete variables for each one:

public partial class PizzaOrder : Form
{
   private Topping[] toppings = new Topping[]{
        new Topping(pepperoniCheckBox, 0.75),
        new Topping(onionCheckBox, 0.75),
        new Topping(mushroomCheckBox, 0.75),
        new Topping(blackOlivesCheckBox, 0.75),
        // .. etc
   };

This is useful, as you can now determine the number of selected toppings (all those which are checked)

var numToppingsSelected = toppings.Where(x => x.Selector.Checked).Count();

You can also get an IEnumerable<Topping> of the selected ones - perhaps order them by Cost and skip the cheapest 2, before getting the total cost of the remaining selection.

var selectedToppings = toppings.Where(x => x.Selector.Checked).OrderBy(x => x.Cost);
var selectedToppingsExceptFirst2 = selectedToppings.Skip(2);
var costOfRemainingToppings = selectedToppingsExceptFirst2.Sum(x => x.Cost);

Hopefully this gets you well on your way to building a more sensible order button handler. Let me know if you have any follow up questions on how to do so.

CodePudding user response:

Is part of your requirements that a user cannot have a pizza with one topping, even if they don't want any of the other five? Because if not, then you're introducing a constraint that is not supposed to be there, making this an XY problem.

I'm going to assume that this constraint should not be there. Note also that I'm trying to make minimal changes to your code, as opposed to redesigning this with more bells and whistles, because I surmise this is a beginner's task.
I would've tackled this differently from the beginning, but that would be a more advanced approach and it would require rewriting your entire solution from scratch, which is somewhat off-topic here and not a good lesson for you either.

The problem here is that your task requires considering a group of toppings ("the first two [of the list of chosen toppings] are free"), but your code only considers each topping checkbox individually. As it stands, your code is not considering the collection of toppings as a group.

I've noticed that all toppings cost the same. Is this a given? Or is it possible that toppings can have different prices?

If all toppings always cost the same, the math is very easy. The total price for the toppings is:

([amount_of_toppings] - 2) * [price_of_a_topping]

When amount_of_toppings is less than or equal to 2, you don't even have to calculate it.

How do you know the amount of toppings? Well, you count the checked boxes.

public double GetToppingsTotalPrice()
{
    int counter = 0;

    if(pepperoniCheckBox.Checked) 
        counter  ;

    if(onionCheckBox.Checked) 
        counter  ;

    // and so on

    if(counter > 2)
        return (counter-2) * this.toppingPrice;
    else
        return 0; 
}

If toppings can have different prices, then you need more information. How do you decide which toppings are free? You could presume that the cheapest ones will be free, but this is something that should be confirmed in the description.

Let's run with the idea that the cheapest two will be free. This means we need to first find out which toppings were selected, what their individual price is, remove the two lowest prices, and then add the remaining prices.

When doing these kinds of operations on a collection, LINQ is a clean and easy way to do so, so I'm going to use it in this solution.

public double GetToppingsTotalPrice()
{
    List<double> addedToppingPrices = new List<double>();

    if(pepperoniCheckBox.Checked) 
        addedToppingPrices.Add(this.Pepperoni);

    if(onionCheckBox.Checked) 
        addedToppingPrices.Add(this.Onion);

    // and so on

    // Stop here if there aren't any paid toppings.
    if(addedToppingPrices.Count() <= 2)
        return 0;

    return addedToppingPrices
             .OrderBy(x => x)  // Sort from cheapest to most expensive
             .Skip(2)          // Skip the first two
             .Sum(x => x);     // Sum the remaining numbers
}
  •  Tags:  
  • c#
  • Related