Skip to content

Commit ef7343b

Browse files
Updated 'Weighing Machine ' exercise (#1672)
Update `weighing-machine` exercise Co-authored-by: Erik Schierboom <[email protected]>
1 parent 81db17e commit ef7343b

File tree

7 files changed

+120
-242
lines changed

7 files changed

+120
-242
lines changed

exercises/concept/weighing-machine/.docs/hints.md

+22-10
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,41 @@
55
- [Properties][docs.microsoft.com-properties]
66
- [Using Properties][docs.microsoft.com-using-properties]
77

8-
## 1. Allow the weight to be set on the weighing machine
8+
## 1. Allow the weighing machine to have a precision
99

10-
A property with a private [backing field][docs.microsoft.com-properties-with-backing-fields] is appropriate here.
10+
- You need to add a [get-only property][stackoverflow.com-get-only-properties] to store the precision in.
11+
- You can initialize the `get`-only property from the constructor (and only from the constructor).
1112

12-
## 2. Ensure that a negative input weight is rejected.
13+
## 2. Allow the weight to be set on the weighing machine
1314

14-
Add [validation][stackoverflow.com-validating-properties] to the `InputWeight`'s `set` accessor to throw an exception.
15+
- You should add a property with a private [backing field][docs.microsoft.com-properties-with-backing-fields].
1516

16-
## 3. Allow the US weight to be retrieved
17+
## 3. Ensure that a negative input weight is rejected
1718

18-
A property can return a reference to an object.
19+
- The `value` keyword is used to refer to the value the caller wants the property to have.
20+
- Add [validation][stackoverflow.com-validating-properties] to the `Weight`'s `set` accessor to throw an exception when the value is invalid.
1921

20-
## 4. Allow the machine's units to be set to pounds
22+
## 4. Allow a tare adjustment to be applied to the weighing machine
2123

22-
`Units` is a good candidate for an [auto-implemented property][docs.microsoft.com-auto-implemented-properties].
24+
- You should add an [auto-implemented property][docs.microsoft.com-auto-implemented-properties] for the tare adjustment.
2325

24-
## 5. Allow a tare adjustment to be applied to the weighing machine
26+
## 5. Ensure that the weighing machine has a default tare adjustment
2527

26-
Accessors can have [different access levels][docs.microsoft.com-properties-and-restricted-access] to each other.
28+
- You can initialize an [auto-implemented property][docs.microsoft.com-auto-implemented-properties] like you can initialize a field.
29+
30+
## 6. Allow the weight to be retrieved
31+
32+
- You should add a `get`-only property in which the correct display weight is calculated.
33+
34+
## 7. Show the Display weight string properly
35+
36+
- You should [format-string][stackoverflow.com-format-string] appropriately.
2737

2838
[docs.microsoft.com-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
2939
[docs.microsoft.com-using-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties
3040
[docs.microsoft.com-properties-with-backing-fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties#properties-with-backing-fields
3141
[stackoverflow.com-validating-properties]: https://stackoverflow.com/questions/4946227/validating-properties-in-c-sharp
3242
[docs.microsoft.com-auto-implemented-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties
3343
[docs.microsoft.com-properties-and-restricted-access]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/restricting-accessor-accessibility
44+
[stackoverflow.com-get-only-properties]: https://stackoverflow.com/questions/2719699/when-should-use-readonly-and-get-only-properties
45+
[stackoverflow.com-format-string]: https://stackoverflow.com/questions/7108850/variable-decimal-places-in-net-string-formatters
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,74 @@
11
# Instructions
22

3-
In this exercise you'll be modelling a weighing machine.
3+
In this exercise you'll be modelling a weighing machine with Kilograms as a Unit.
44

5-
The weight can be set and retrieved in pounds or kilograms and cannot be negative.
5+
You have 6 tasks each of which requires you to implement one or more properties:
66

7-
The weight can be displayed in SI units or US units
8-
, pounds and ounces.
7+
## 1. Allow the weighing machine to have a precision
98

10-
A tare adjustment can be applied to the weight (for instance to deduct the
11-
weight of a container). This can be any value (even negative or a value that makes the display weight negative)
12-
as there are doubts about the accuracy
13-
of the weighing machine. For security reasons this value cannot be retrieved.
14-
15-
Note that:
16-
17-
```
18-
display-weight = input-weight - tare-adjustment
19-
```
20-
21-
Conversion ratios are as follows:
22-
23-
- 16 ounces to a pound
24-
- 2.20462 kg to a pound
25-
26-
For Example:
27-
28-
- 60 kilograms == 132.2772 ponds
29-
- 132.2772 pounds == 132 pounds 4 ounces
30-
31-
You have 5 tasks each of which requires you to implement one or
32-
more properties:
33-
34-
## 1. Allow the weight to be set on the weighing machine
35-
36-
Implement the `WeigingMachine.InputWeight` property to allow the weight to be get and set:
9+
To cater to different demands, we allow each weighing machine to be customized with a precision (the number of digits after the decimal separator).
10+
Implement the `WeigingMachine` class to have a get-only `Precision` property set to the constructor's `precision` argument:
3711

3812
```csharp
39-
var wm = new WeighingMachine();
40-
wm.InputWeight = 60m;
13+
var wm = new WeighingMachine(precision: 3);
4114

42-
// => wm.InputWeight == 60m
15+
// => wm.Precision == 3
4316
```
4417

45-
## 2. Allow specifying the unit used by the weighing machine
46-
47-
Implement the `WeigingMachine.Unit` property to allow the unit to be set. `Unit.Kilograms` should be the default value:
18+
## 2. Allow the weight to be set on the weighing machine
4819

20+
Implement the `WeigingMachine.Weight` property to allow the weight to be get _and_ set:
4921

5022
```csharp
51-
var wm = new WeighingMachine();
23+
var wm = new WeighingMachine(precision: 3);
24+
wm.Weight = 60.5;
5225

53-
// => wm.Unit == Kilograms
26+
// => wm.Weight == 60.5
5427
```
5528

5629
## 3. Ensure that a negative input weight is rejected
5730

58-
Add validation to the `WeighingMachine.InputWeight` property to throw an `ArgumentOutOfRangeException` when trying to set it to a negative weight:
31+
Clearly, someone cannot have a negative weight.
32+
Add validation to the `WeighingMachine.Weight` property to throw an `ArgumentOutOfRangeException` when trying to set it to a negative weight:
5933

6034
```csharp
61-
var wm = new WeighingMachine();
62-
wm.InputWeight = -10m; // Throws an ArgumentOutOfRangeException
35+
var wm = new WeighingMachine(precision: 3);
36+
wm.Weight = -10; // Throws an ArgumentOutOfRangeException
6337
```
6438

65-
## 4. Allow the US weight to be retrieved
39+
## 4. Allow a tare adjustment to be applied to the weighing machine
6640

67-
Implement the `WeighingMachine.USDisplayWeight` property and the `USWeight` class:
41+
The tare adjustment can be any value (even negative or a value that makes the display weight negative)
42+
Implement the `WeighingMachine.TareAdjustment` property to allow the tare adjustment to be set:
6843

6944
```csharp
70-
var wm = new WeighingMachine();
71-
wm.InputWeight = 60m;
45+
var wm = new WeighingMachine(precision: 3);
46+
wm.TareAdjustment = -10.6;
7247

73-
var usw = wm.USDisplayWeight;
74-
// => usw.Pounds == 132 && usw.Ounces == 4
48+
// => wm.TareAdjustment == -10.6
7549
```
7650

77-
## 5. Allow the machine's unit to be set to pounds
51+
## 5. Ensure that the weighing machine has a default tare adjustment
7852

79-
Implement the `WeighingMachine.Unit` property:
53+
After some thorough testing, it appears that due to a manifacturing issue all weighing machines have a bias towards overestimating the weight by `5`.
54+
Change the `WeighingMachine.TareAdjustment` property to `5` as its default value.
8055

8156
```csharp
82-
var wm = new WeighingMachine();
83-
wm.InputWeight = 175.5m;
84-
wm.Unit = Unit.Pounds;
57+
var wm = new WeighingMachine(precision: 3);
8558

86-
var usw = wm.USDisplayWeight;
87-
// => usw.Pounds == 175 && usw.Ounces == 8
59+
// => wm.TareAdjustment == 5.0
8860
```
8961

90-
## 6. Allow a tare adjustment to be applied to the weighing machine
62+
## 6. Allow the weight to be retrieved
9163

92-
Implement the `WeighingMachine.TareAdjustment` and `WeighingMachine.DisplayWeight` properties:
64+
Implement the `WeighingMachine.DisplayWeight` property which shows weight after tare adjustment and with the correct precision applied:
65+
Note that:
66+
``` display-weight = input-weight - tare-adjustment ```
9367

9468
```csharp
95-
var wm = new WeighingMachine();
96-
wm.InputWeight = 100m;
97-
wm.TareAdjustment = 10m;
69+
var wm = new WeighingMachine(precision: 3);
70+
wm.TareAdjustment = 10;
71+
wm.Weight = 60.567;
9872

99-
// => wm.DisplayWeight == 90m
100-
```
73+
// => wm.DisplayWeight == "50.567 kg"
74+
```
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,36 @@
11
using System;
22

3-
enum Unit
4-
{
5-
Pounds,
6-
Kilograms
7-
}
8-
93
class WeighingMachine
104
{
11-
private const decimal POUNDS_PER_KILOGRAM = 2.20462m;
5+
private double _weight;
126

13-
private decimal inputWeight;
7+
public WeighingMachine(int precision)
8+
{
9+
Precision = precision;
10+
}
1411

15-
public Unit Unit { get; set; } = Unit.Kilograms;
12+
public int Precision { get; }
1613

17-
public decimal InputWeight
14+
public double TareAdjustment { get; set; } = 5.0;
15+
16+
public double Weight
1817
{
1918
get
2019
{
21-
return inputWeight;
20+
return _weight;
2221
}
2322
set
2423
{
25-
if (value < 0)
26-
{
27-
throw new ArgumentOutOfRangeException("weight cannot be negative");
28-
}
29-
30-
inputWeight = value;
31-
}
32-
}
33-
34-
public decimal DisplayWeight
35-
{
36-
get
37-
{
38-
return ApplyTareAdjustment(inputWeight);
24+
if (value < 0) throw new ArgumentOutOfRangeException();
25+
_weight = value;
3926
}
4027
}
4128

42-
public USWeight USDisplayWeight
29+
public string DisplayWeight
4330
{
4431
get
4532
{
46-
return new USWeight(WeightInPounds(DisplayWeight));
47-
}
48-
}
49-
50-
public decimal TareAdjustment { set; private get; }
51-
52-
private decimal ApplyTareAdjustment(decimal weight)
53-
{
54-
return weight - TareAdjustment;
55-
}
56-
57-
private decimal WeightInPounds(decimal weight)
58-
{
59-
if (Unit == Unit.Kilograms)
60-
{
61-
return weight * POUNDS_PER_KILOGRAM;
33+
return $"{Math.Round(Weight - TareAdjustment, Precision).ToString($"F{Precision}")} kg";
6234
}
63-
64-
return weight;
6535
}
66-
}
67-
68-
class USWeight
69-
{
70-
private const decimal OUNCES_PER_POUND = 16m;
71-
72-
public USWeight(decimal displayWeightInPounds)
73-
{
74-
Pounds = (int)displayWeightInPounds;
75-
Ounces = (int)(OUNCES_PER_POUND * (displayWeightInPounds - (int)displayWeightInPounds));
76-
}
77-
78-
public int Pounds { get; }
79-
public int Ounces { get; }
80-
}
36+
}

exercises/concept/weighing-machine/.meta/config.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
"blurb": "Learn about properties by modelling a weighing machine.",
33
"contributors": [
44
"ErikSchierboom",
5-
"yzAlvin"
5+
"yzAlvin",
6+
"18-F-Cali"
67
],
78
"authors": [
89
"mikedamay"

exercises/concept/weighing-machine/.meta/design.md

+14-32
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ Note that students may choose to implement expression-bodied members.
2929
## Prerequisites
3030

3131
- `numbers`: using the `int` type and using mathematical operators and number conversions.
32-
- `floating-point-numbers`: using the `decimal` type.
3332
- `classes`: defining classes and working with members.
3433
- `enums`: working with enums.
3534
- `exceptions`: throwing an exception.
@@ -65,41 +64,24 @@ It is difficult to get the student to exercise all different aspects of
6564
properties through tests alone. We need comments to address the following
6665
practices:
6766

68-
1. If `WeighingMachine.Units` is not auto-implemented
69-
then the following comment should be made: "The appropriate form
70-
for a property such as `WeighingMachine.Units` which has no validation or other processing required is
71-
that for an auto-implemented property". - Approved with comment.
67+
1. If `WeighingMachine.Precision` is auto-implemented property set in constructor then the following comment should be made: "It is not appropriate
68+
for a property such as `WeighingMachine.Precision` to simply intializes a value with a
69+
set accessor. That should be removed.". - Approved with comment.
7270

73-
2. If `WeighingMachine.DisplayWeight` has a non-private set accessor
74-
then the following comment should be made: "It is not approprirate
75-
for a property such as `WeighingMachine.DisplayWeight` which simply returns a value
76-
to have a set accessor. That should be removed.". - Approved with comment.
77-
78-
3. If `WeighingMachine.USDisplayWeight` has a non-private set accessor
79-
then the following comment should be made: "It is not approprirate
80-
for a property such as `USWeighingMachine.DisplayWeight` which simply returns a value
81-
to have a set accessor. That should be removed.". - Approved with comment.
82-
83-
4. If `USDisplayWeight.Pounds` has a non-private set accessor
84-
then the following comment should be made: "It is not approprirate
85-
for a property such as `USDisplayWeight.Pounds` which simply returns a value
71+
2. If `WeighingMachine.Precision` has a set accessor
72+
then the following comment should be made: "It is not appropriate
73+
for a property such as `WeighingMachine.Precision` which simply returns a value
8674
to have a set accessor. That should be removed.". - Approved with comment.
8775

88-
5. If `USDisplayWeight.Ounces` has a non-private set accessor
89-
then the following comment should be made: "It is not approprirate
90-
for a property such as `USDisplayWeight.Ounces` which simply returns a value
76+
3. If `WeighingMachine.DisplayWeight` has a non-private set accessor
77+
then the following comment should be made: "It is not appropriate
78+
for a property such as `WeighingMachine.DisplayWeight` which simply returns a value
9179
to have a set accessor. That should be removed.". - Approved with comment.
92-
93-
6. If `WeighingMachine.TareAdjustement` is not an auto-implemented property
94-
then the following commen should be made: "A succinct way of implementing
95-
`WeighingMachine.TareAdjustment` is as an auto-implemented property with a
96-
`private` get accessor". - Approved with comment.
97-
98-
7. If `WeighingMachine.TareAdjustment` is an auto-implemented property
99-
but the get accessor is non-private then the following comment should be made:
100-
"A non-private set accessor is not appropriate for `WeighingMachine.TareAdjustment`
101-
as the instructions stipulate that the value must not be available outside the
102-
class". - Disapproved.
80+
81+
4. If `WeighingMachine.TareAdjustement` is not an auto-implemented property with initial value
82+
then the following comment should be made: "A succinct way of implementing
83+
`WeighingMachine.TareAdjustment` is as an auto-implemented property initialized with a
84+
value". - Approved with comment.
10385

10486
## Implementing
10587

Original file line numberDiff line numberDiff line change
@@ -1,32 +1,12 @@
11
using System;
22

3-
enum Unit
4-
{
5-
Pounds,
6-
Kilograms
7-
}
8-
93
class WeighingMachine
104
{
11-
// TODO: define the 'InputWeight' property
5+
// TODO: define the 'Precision' property
126

13-
// TODO: define the 'DisplayWeight' property
7+
// TODO: define the 'Weight' property
148

15-
// TODO: define the 'USDisplayWeight' property
9+
// TODO: define the 'DisplayWeight' property
1610

1711
// TODO: define the 'TareAdjustment' property
18-
19-
// TODO: define the 'Units' property
20-
}
21-
22-
struct USWeight
23-
{
24-
public USWeight(decimal weightInPounds)
25-
{
26-
throw new NotImplementedException("Please implement the USWeight classes' constructor");
27-
}
28-
29-
// TODO: define the 'Pounds' property
30-
31-
// TODO: define the 'Ounces' property
3212
}

0 commit comments

Comments
 (0)