My goal is to make this program to take a number of pizzas and types of pizzas and count how much they cost. I decided to go with an object solution. The problem is it doesn't calculate it and it lets the program run even when The fields are empty. I literally have no idea why it doesn't calculate it. I'm also new to objects so there may be some logical mistakes.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Assignment_2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void OrderButton_Click(object sender, EventArgs e)
{
double withTax = 0;
double tax = 0;
double subTotal = 0;
var pizzas = new Pizza[3];
if(ValidateAndDeclareQuantities())
{
pizzas = Declare();
subTotal = CalcSubTotal(pizzas);
tax = CalcTax(pizzas);
withTax = CalcWithTax(pizzas);
}
}
bool ValidateAndDeclareQuantities()
{
var combolist = new List<ComboBox>();
combolist.Add(comboBox1);
combolist.Add(comboBox2);
combolist.Add(comboBox3);
var textboxlist = new List<TextBox>();
textboxlist.Add(Quantity1);
textboxlist.Add(Quantity2);
textboxlist.Add(Quantity3);
for (int i = 0; i < 3; i++)
{
if (combolist[i].Text == "Cheese" || combolist[i].Text == "Vegetable" || combolist[i].Text == "Meat")
{ }
else combolist[i].Text = "Wrong input";
}
int[] Quantities = new int[3];
for (int i = 0; i < 3; i++)
{
if (int.TryParse(textboxlist[i].Text, out Quantities[i])&&textboxlist[i].Text!=null)
{ }
else { textboxlist[i].Text = "Wrong input"; }
}
return true;
}
Pizza[] Declare()
{
var pizzas = new Pizza[3];
string type;
int price;
type = comboBox1.Text;
price = int.Parse(Quantity1.Text);
Pizza pizza1 = new Pizza(type, price);
pizzas[0] = pizza1;
type = comboBox2.Text;
price = int.Parse(Quantity2.Text);
Pizza pizza2 = new Pizza(type, price);
pizzas[1] = pizza2;
type = comboBox3.Text;
price = int.Parse(Quantity3.Text);
Pizza pizza3 = new Pizza(type, price);
pizzas[2] = pizza3;
return pizzas;
}
double CalcSubTotal(Pizza[] pizzas)
{
double subTotal = 0;
for (int i = 0; i < 3; i++)
{
subTotal += pizzas[i].Price;
}
return subTotal;
}
double CalcTax(Pizza[] pizzas)
{
double tax = 0;
for (int i = 0; i < 3; i++)
{
tax += pizzas[i].Tax;
}
return tax;
}
double CalcWithTax(Pizza[] pizzas)
{
double withTax = 0;
for (int i = 0; i < 3; i++)
{
withTax += pizzas[i].WithTax;
}
return withTax;
}
void WriteOut(double subTotal, double tax, double withTax)
{
lblSubTotal.Text = "" + subTotal;
lblTax.Text = "" + tax;
lblTotal.Text = "" + withTax;
}
}
}
And the class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assignment_2
{
class Pizza
{
string type;
int quantity;
public double Price;
public double SubTotal;
public double Tax;
public double WithTax;
public Pizza(string type, int quantity)
{
this.type = type;
this.quantity = quantity;
FindPrice();
CalcSubTotal();
CalcTax();
CalcWithTax();
}
private void FindPrice()
{
switch (type)
{
case "Cheese":
Price = 9.95;
break;
case "Vegetables":
Price = 10.95;
break;
case "Meat":
Price = 11.95;
break;
}
}
private void CalcSubTotal()
{
SubTotal = Price * quantity;
}
private void CalcTax()
{
Tax = SubTotal * 0.13;
}
private void CalcWithTax()
{
WithTax = SubTotal + Tax;
}
}
}
Solution form
The quick answers:
ValidateAndDeclareQuantities never returns false. It should (probably) return false when you set "Wrong Input".
(Minor) int[] Quantities = new int[3]; is never used, aside from writing to it.
(Minor) var pizzas = new Pizza[3]; is also never used. It just gets overwritten by Declare a few lines later. Pizza[] pizzas=null; or just Pizza[] pizzas; is a better alternative. Not the greatest structure here though.
(Minor) Your variable called price in Declare is poorly named as it appears to actually be quantity. Things like this easily throw people off.
WriteOut is never called. withTax, tax and subTotal in OrderButton_Click are probably being computed correctly, but the values aren't being outputted.
The longer answer
It's a bit on the messy side! I appreciate that it's just a learning thing - we've all been there - but good code hygiene is just as important (if not more important) than the structure of the language.
UX: Don't overwrite what the user entered - specifically, don't replace the textbox input with "wrong input"; That's better off going on some other label. I would imagine you've already felt how weird this kind of experience is whilst testing the code.
Named things that don't need a specific class: Like a cheese pizza and a ham one. Enums are your friend! Use them instead of strings like "Cheese":
public enum PizzaType{
Cheese,
Tomato
}
Using enums in this way helps avoid the wonderful world of pain that is unexpected capitalisation and it's considerably faster too. CheEse pizza anyone?
Repetition: Large portions of your code are repetitive too; You'll want to practice avoiding it as much as you can. ('DRY'/ 'Don't Repeat Yourself'). A little forward planning helps massively. Everybody has preferences on code structure; mine here would be a separate "Pizza displayer" class which holds a quantity input box and does the validation too.
Junk: Slightly related to the above, you're creating a bunch of Lists and arrays which get created each time the function is called and then are just chucked out. Create a single array of some more abstract type (like an array of "Pizza displayers") and keep that array as a property on the Form. It's minor here, but being more aware of how much trash your program creates helps make your code go faster.
Notes on floats: You should never, ever use float/ double for money. Use decimal instead, or just do everything in pennies. Floating points aren't precise and you'll hit a rounding issue sooner or later.
Related
This is for my school project and therefor I need to code without LINQ methods etc.
I'm trying to show which city has the highest temperature by finding the highest temp and then print it together with the city name.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
class City
{
public string name { get; set; }
public int temp { get; set; }
public override string ToString()
{
return $"CITY:\t{name}\nTEMP:\t{temp}°C\n";
}
}
I want to use Tostring() to print.
//=====Highest Temperature=====//
static void HighestTemp(City[] cities)
{
int highest = cities[0].temp;
for (int i = 1; i < cities.Length; i++)
{
if (highest < cities[i].temp)
{
highest = cities[i].temp;
}
}
}
I've found the highest temperature.
But the question is: How do I print it with ToString()?? I want both cities[i].name and cities[i].temp
Your issue is you found the highest temp, not the city with the highest temp.
Without using Linq or any of the shortcut methods like .OrderBy(..) or .OrderByDescending(..), you can simply just store a second variable that tracks your best i
int highestTemp = cities[0].temp;
int highestTempIndex = 0;
for (int i = 1; i < cities.Length; i++)
{
if (highest < cities[i].temp)
{
highest = cities[i].temp;
highestTempIndex = i;
}
}
var highestTempCity = cities[highestTempIndex];
And to stringify the city its as simple as:
$"{highestTempCity}"
Because overriding specifically .ToString() automates this. You also can call highestTempCity.ToString() if you like.
If you utilize the power of Linq though you can simplify this a lot by just doing:
var highestTempCity = cities.OrderByDescending(city => city.temp).First();
SOLVED!
I succeeded by doing like this:
//=====Highest temperature=====//
static int HighestTemp(City[] cities, int n)
{
int highestTemp = cities[0].temp;
var highestTempIndex = 0;
for (int i = 1; i < n; i++)
{
if (highestTemp < cities[i].temp)
{
highestTemp = cities[i].temp;
highestTempIndex = i;
}
}
return highestTempIndex;
}
From what this method return I made int Index and print the result in Main
//----------City with HIGHEST temperature----------//
index = HighestTemp(cities, n);
Console.WriteLine(cities[index].ToString());
I'm writing a C# Program to display the average grades, highest grade and lowerst grade
The result is supposed to be
the highest grade is 90.5
the lowerst grade is 77.3
the average grade is 85.633
But unfortunately show up like this
the highest grade is 1.7976931348623157E+308
the lowerst grade is -1.7976931348623157E+308
the average grade is 85.633
I had two days looking for a solution, but I couldn't, so I had to ask a question
Thank u
using System;
using System.Collections.Generic;
namespace GradeBook
{
public class Statistics
{
public double Average;
public double High;
public double Low;
}
public class Book
{
public Book()
{
grades = new List<double>();
}
public void addGrade(double grade)
{
grades.Add(grade);
}
public Statistics GetStatistics()
{
var result = new Statistics();
result.Average = 0.0;
result.High = double.MaxValue;
result.Low = double.MinValue;
foreach (var grade in grades)
{
result.Low = Math.Min(grade, result.Low);
result.High = Math.Max(grade, result.High);
result.Average += grade;
}
result.Average /= grades.Count;
return result;
}
private List<double> grades;
}
class Program
{
static void Main(string[] args)
{
Book book = new Book();
book.addGrade(89.1);
book.addGrade(90.5);
book.addGrade(77.3);
var stats = book.GetStatistics();
Console.WriteLine("the highest grade is " + stats.High);
Console.WriteLine("the lowerst grade is " + stats.Low);
Console.WriteLine($"the average grade is {stats.Average:N3}");
}
}
}
The problem is that you assgigned double.MaxValue to the High score and double.MinValue to the low.
So when you use Math.max / Math.min you are constantly getting the double.Max / double.Min.
try to just switch them in the following way (will only work assuming values are provided) :
result.High = double.MinValue;
result.Low = double.MaxValue;
So you have this code to evaluate each grade against the variables result.Low and result.High outside of the loop:
result.Low = Math.Min(grade, result.Low);
result.High = Math.Max(grade, result.High);
But you have defined them as this:
result.High = double.MaxValue;
result.Low = double.MinValue;
Therefore it isn't possible for grade > double.MaxValue, or grade < double.MinValue
A better solution is this:
var result = new Statistics();
var firstGrade = grades.DefaultIfEmpty().First(); // get the first grade in the list, or 0 if it's empty
// assign that to average, high, and low
result.Average = firstGrade;
result.High = firstGrade;
result.Low = firstGrade;
// visit every grade after the first
foreach (var grade in grades.Skip(1))
{
result.Low = Math.Min(grade, result.Low);
result.High = Math.Max(grade, result.High);
result.Average += grade;
}
result.Average /= grades.Count;
return result;
We should also consider the case that grades.Count == 0, which would throw an error on the result.Average /= grades.Count line. We can fix it like so:
if (grades.Count > 0)
{
result.Average /= grades.Count;
}
return result;
Swapping result.High to double.MinValue and result.Low to double.MaxValue should do the trick!
As others have said, you've mixed double.MaxValue anddouble.MinValue` around. Alternatively you could avoid them entirely by doing this:
public Statistics GetStatistics()
{
return new Statistics()
{
Average = grades.Average(),
High = grades.Max(),
Low = grades.Min(),
};
}
I have a very small windows form application that calculates the storage cost for a warehouse depending on the amount of deliveries per year and presents the result in form of a chart.
It's doing what it's supposed to do, but there is just one little flaw.
There is 13 columns in the first bit and then there is 12 every other time.
I want it to always be 12.
I've been trying to reorder some lines of code, it looks like it's all ok, I'm probably just missing one line of code but can't figure it out
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace StorageCost
{
public partial class Form1 : Form
{
public static int throughPot = 52000;
public static int weekly = 1000;
public static int weeklyPalletCost = 180;
public static int deliveries = 2;
public int storageCost;
public static int x = 0;
public static int currentPot = throughPot / deliveries;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Calculate();
}
private void Calculate()
{
currentPot = throughPot / deliveries;
storageCost = 0;
x = 0;
chart1.Series[0].Points[0].YValues[0] = currentPot + 4000;
for (int i = 1; i < 51; i++)
{
currentPot -= weekly;
if (x>= 51 / deliveries)
{
x = 0;
currentPot = throughPot / deliveries;
}
chart1.Series[0].Points[i].YValues[0] = currentPot + 4000;
storageCost += currentPot * weeklyPalletCost;
x++;
}
cost.Text = "Total storage cost: £" + storageCost / 100;
chart1.ChartAreas[0].RecalculateAxesScale();
chart1.Update();
}
private void deliveriesUpDown_ValueChanged(object sender, EventArgs e)
{
deliveries = (int)deliveriesUpDown.Value;
Calculate();
}
}
}
this is the full code.
all I need basically is to get the same result in the beginning as from 13th column onwards
any help will be much appreciated.
thanks in advance.
It was because the first column was done outside of the for loop!
after commenting this out
//currentPot = throughPot / deliveries;
//storageCost = 0;
//x = 0;
//chart1.Series[0].Points[0].YValues[0] = currentPot + 4000;
and changing the loop to for (int i = 0; i < 51; i++)
I got it to work as expected.
Thanks #Grimm
I didn't know about this F11, F10 thing. This helped me a lot!
When I run the code, it doesn't calculate and it doesn't show the calculations.
Wondering if my variables or something else is wrong or maybe in the wrong place.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Question_3_Retail_Price_Calculator
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
decimal costPrice = 0;
decimal markUpRateA = 0.19m;
decimal markUpRateB = 0.14m;
decimal markUpRateC = 0.12m;
decimal markUpRate = 0m;
decimal markUpTotal = 0;
decimal totalCost = 0;
// Add the items to ListBox 1
listBox1.Items.Add("Markup Rate =");
listBox1.Items.Add("Markup Total =");
listBox1.Items.Add("Total Cost =");
try
{
// Read the cost price from the user
costPrice = decimal.Parse(textBox1.Text);
}
catch (System.Exception excep )
{
MessageBox.Show(excep.Message);
}
if (costPrice <= 50)
{
// Calculate the value of the product
costPrice = (costPrice / 100) * markUpRateA;
}
else if (costPrice >= 50 && costPrice < 100)
{
// Calculate the value of the product
costPrice = (costPrice / 100) * markUpRateB;
}
else if (costPrice < 100)
{
// Calculate the value of the product
costPrice = (costPrice / 100) * markUpRateC;
}
else if (markUpRate == markUpTotal)
{
// Calculate the total monetary amount
markUpTotal = costPrice * markUpRate;
}
else
{
// Calculate the Total Cost of the product
totalCost = costPrice + markUpTotal;
}
// Output the total Cost
MessageBox.Show("Total Cost is: €" + totalCost);
}
}
}
Need some help figuring this out! Thanks in advance!
You're setting your total cost in the last else condition which will be executed only if all the other if-else conditions are not executed. That is why this code isn't working as you expect.
Even if you enter a value >100, your result is never assigned to totalCost. Because execution enters this part of your code
else if (markUpRate == markUpTotal)
{
// Calculate the total monetary amount
markUpTotal = costPrice * markUpRate;
}
and then jumps directly to the Message.Show(..) line.
There is a lot of crossover in you if else statements. If costPrice is 50, do you want to run rate A, rate B, or rate C (I think you have put your > sign the wrong way with markup rate C).
Also, why is it in a try loop? You are basically saying: "If there are no problems, assign costPrice to whatever the user entered, then skip the rest. And if there is a problem, do the rest but the costPrice will be the default value I assigned it to at the start (0)."
Basically, all the rest of the stuff should be in the try loop, not the catch loop.
Oh and read Xaero's answer as well, I have to wite this here though because i'm not allowed not comment yet :(.
I am relatively new to C# and am experiencing a problem. My program keeps throwing an error per my try catch. I have looked over everything and changed things, but nothing seems to work. Could it be the reading of the text file? or the array? or the transfer into the listbox? I really need some help with this. It has become nothing but a headache.
............................................................................................................................................................................................................................................................................................................................................................................................................................................................................
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
namespace Total_Sales_BBrantley
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnCalc_Click(object sender, EventArgs e)
{
try
{
// Declare variable to hold the amount of sales
// Declare variable to act as the accumulator
const int SIZE = 100;
double[] allSales = new double[SIZE];
double total = 0.0;
double average;
double highest = allSales[0];
double lowest = allSales[2000];
int count = 0;
// Declare a StreamReader variable.
StreamReader readFile;
// Open the file and get a StreamReader object using a relative path
readFile = File.OpenText("Sales.txt");
while (!readFile.EndOfStream && count < allSales.Length)
{
allSales[count] = int.Parse(readFile.ReadLine());
// Increment count
count++;
}
// Close the file
readFile.Close();
lstSales.Items.Add("The file contains " + count + " items:");
for (int index = 0; index < count; index++)
{
lstSales.Items.Add(allSales[index]);
}
// Display the total
double sum = allSales.Sum();
lblTotal.Text = sum.ToString();
total += sum;
average = total / allSales.Length;
lblAverage.Text = average.ToString();
for (int index = 1; index < allSales.Length; index++)
{
if (allSales[index] > highest)
{
highest = allSales[index];
}
lblHighest.Text = highest.ToString();
}
for (int index = 1; index < allSales.Length; index++)
{
if (allSales[index] < lowest)
{
lowest = allSales[index];
}
lblLowest.Text = lowest.ToString();
}
}
catch (Exception)
{
// Display an error message on bad input from file
MessageBox.Show("Error calculating the sales.");
}
}
private void btnExit_Click(object sender, EventArgs e)
{
//Closes the application
this.Close();
}
}
}
I didn't read all your code, but there's an error just at the start:
const int SIZE = 100;
double[] allSales = new double[SIZE];
<snip>
double lowest = allSales[2000];
You've declared the array to have 100 elements, but you're trying to access the 2,000th. Your array isn't that big, so you'll get an IndexOutOfRangeException on that line.
Arrays have fixed sizes in C# once declared. If you need the size to change, use the generic List class.
Bulding on martin_costello's answer, perhaps you could initialize lowest and highest like this:
double highest = double.MinValue;
double lowest = double.MaxValue;
Or at the very least, initialize these values after you have loaded your data!
Also, a tip for debugging: if you're getting an error, either display the error returned by the catch or comment out the try/catch so that you can see the error.
An example of the former:
catch (Exception ex)
{
// Display an error message on bad input from file
MessageBox.Show(string.Concat("Error calculating the sales: ", ex.Message, "\r\n", ex.StackTrace));
}