Skip to content
81 changes: 81 additions & 0 deletions src/intro-to-c/enums/enum-practice-answers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
---
title: Enums
author: Matthew Gibbons
---

@. You are a half decent farmer in a video game that received a handful of seeds in the mail. With them came a note that informed you they all take the same amount of time to grow. You decided to plant them all and nurture them to maturity. The day has come to harvest, and you need to keep track of the crops you recognize. Write a program that will keep a count of each crop you have harvested, including unknowns, and print the number harvested in order of experience gain (least to greatest). Unknown crops can be last on the list. Below are code snippets so an answer key can exist.

``` c
// Random seed
srand(24164132);
// Random number generated
1 + rand() % 13;
// Crop Values
3, 5, 6, 9, 11, 12;
```
Comment on lines +6 to +15
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it will use elements of randomness, I would explicitly write in the question that you will also need to generate random crops, and perhaps which crops are the ones that are being farmed.


**Answer:**

``` c
#include <stdio.h>
#include <stdlib.h>

typedef enum exp_value {Wheat = 5, Onion, Carrot = 3, Corn = 9, Potatoes = 12, Strawberries = 11} crop;

int main(void)
{
srand(24164132);
int wheatCounter = 0, onionCounter = 0, carrotCounter = 0, cornCounter = 0, potatoesCounter = 0, strawberriesCounter = 0, newCounter = 0;
for(int i = 0; i < 100; i++)
{
crop Mystery_crop = 1 + rand() % 13;
switch(Mystery_crop)
{
case Wheat:
wheatCounter++;
break;
case Onion:
onionCounter++;
break;
case Carrot:
carrotCounter++;
break;
case Corn:
cornCounter++;
break;
case Potatoes:
potatoesCounter++;
break;
case Strawberries:
strawberriesCounter++;
break;
default:
printf("You have found a new crop. You gained %d experience.\n", Mystery_crop);
newCounter++;
break;
}
}
printf("Carrot harvested: %d\n", carrotCounter);
printf("Wheat harvested: %d\n", wheatCounter);
printf("Onion harvested: %d\n", onionCounter);
printf("Corn harvested: %d\n", cornCounter);
printf("Strawberries harvested: %d\n", strawberriesCounter);
printf("Potatoes harvested: %d\n", potatoesCounter);
printf("New crops harvested: %d\n", newCounter);

return 0;
}
```

**Output:**
```
Carrot harvested: 9
Wheat harvested: 6
Onion harvested: 7
Corn harvested: 6
Strawberries harvested: 6
Potatoes harvested: 11
New crops harvested: 55
```

**Note:** It does not matter what you named the crops, it only matters that you get the correct output and use typedef with enums.
17 changes: 17 additions & 0 deletions src/intro-to-c/enums/enum-practice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title: Enums
author: Matthew Gibbons
---

@. You are a half decent farmer in a video game that received a handful of seeds in the mail. With them came a note that informed you they all take the same amount of time to grow. You decided to plant them all and nurture them to maturity. The day has come to harvest, and you need to keep track of the crops you recognize. Write a program that will keep a count of each crop you have harvested, including unknowns, and print the number harvested in order of experience gain (least to greatest). Unknown crops can be last on the list. Below are code snippets so an answer key can exist.

``` c
// Random seed
srand(24164132);
// Random number generated
1 + rand() % 13;
// Crop Values
3, 5, 6, 9, 11, 12;
```

**Note:** `#include <stdlib.h>` needs to be included to make the rand work.
246 changes: 246 additions & 0 deletions src/intro-to-c/enums/enum-tutorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
---
title: Enums
author: Matthew Gibbons
---

## Intro to Enums

`enum` is the keyword for the enumerator data type in C, which is a user defined data type. It is used to assign names to integer constants to make for improved readability and easy maintenance. The basic syntax is as follows:

``` c
enum name {Const1, Const2, Const3,... ConstN};
```

If no values are assigned, `Const1` will be assigned 0, `Const2` will be assigned 1, and so on. However, these values can be easily changed. It should also be noted that `name` is optional, and unnamed enumerators will not break your code.

There are some naming conventions to keep in mind while working with enums. Enum constants are either capitalized or in all caps. Name tags are lowercase.

## Enum Valuation and Adjustment

A common example is an enumeration of the days of the week, which may look like this:

``` c
enum days_of_the_week {Sunday = 1, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday};
```

This assigns `Sunday` the value of 1, and the following value will be 1 greater. In this example, the compiler assigns value to the constants based on the defined value in the form previous + 1. You can define any number of values in an enumerated list and this rule will be followed. For example, we can define the value for each enumerated constant if we choose like this:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This assigns `Sunday` the value of 1, and the following value will be 1 greater. In this example, the compiler assigns value to the constants based on the defined value in the form previous + 1. You can define any number of values in an enumerated list and this rule will be followed. For example, we can define the value for each enumerated constant if we choose like this:
This assigns `Sunday` the value of 1, and the following value will be 1 greater. In this example, the compiler assigns value to the constants based on the defined value in the form "previous + 1." You can define any number of values in an enumerated list and this rule will be followed. For example, we can define the value for each enumerated constant if we choose like this:


``` c
enum game_difficulty {Cookie_Clicker = 1, Gungeon = 6, ARK = 7, Dark_Souls = 10};
```

or we can define some of them like this:

``` c
enum exp_value {Wheat = 2, Onion, Carrot, Corn = 7, Potatoes, Strawberries = 11};
```

In this case, the assigned values would look like this:

```
Wheat = 2
Onion = 3
Carrot = 4
Corn = 7
Potatoes = 8
Strawberries = 11
```

This is in line with the "previous + 1" rule stated earlier. `Onion`, `Carrot`, and `Potatoes` will all follow this rule because they were not explicitly defined.

Values in the same list can have the same values. If we look back at our `game_difficulty` example, we can add a few more titles that have equivalent difficulty.

``` c
enum game_difficulty {Cookie_Clicker = 1, Gungeon = 6, ARK = 7, Dark_Souls = 10, Super_Meat_Boy = 10, House_Flipper = 1, Bloodborne = 10};
```

As you can see, Dark Souls, Bloodborne, and Super Meat Boy are all rated at the same level of difficulty, as well as House Flipper and Cookie Clicker. These will not cause any errors, they just happen to hold the same value, as if they were any regular `int` variable.

## Using Enums in Code

When using enums, we must define a variable type. This can be done in one of two ways. Here is a general example:

Comment thread
ZThatWhiteGuyZ marked this conversation as resolved.
```c
enum enum_name {Const1, Const2, Const3, ..., ConstN};
enum enum_name variable_name;

// or

enum enum_name {Const1, Const2, Const3, ..., ConstN} variable_name;
```

We can even define multiple variables of type `enum_name` like this:

```c
enum enum_name {Const1, Const2, Const3, ..., ConstN} different_variable_name;
enum enum_name variable_name, another_one;

// or

enum enum_name {Const1, Const2, Const3, ..., ConstN} different_variable_name, variable_name, another_one;
```

**Note:** Splitting the variable type up looks a bit strange. This is only done for the sake of example. The second option is nicer and cleaner.


Now we can assign and use our enumerated values in code. Lets look at something simple using the `exp_value` example. You'll notice the enum variables are not declared on the same line that the enum is defined. That is because it is best practice not to declare global variables.

``` {.c #dirt-growers}
#include <stdio.h>

enum exp_value {Wheat = 2, Onion, Carrot, Corn = 7, Potatoes, Strawberries = 11};

int main(void)
{
enum exp_value crops, plants, dirt_growers;

crops = Onion;
plants = Corn;
dirt_growers = Potatoes;
printf("Onion Experience Gain: %d\n", crops);
printf("Corn Experience Gain: %d\n", plants);
printf("Potatoes Experience Gain: %d\n", dirt_growers);

return 0;
}
```

Here we assign the value of `Onion` to `crops`, which we know is 3. The expected output would be as follows:

```
Onion Experience Gain: 3
Corn Experience Gain: 7
Potatoes Experience Gain: 8
```

But what if we don't want to use the enum keyword explicitly?

### Using `typedef` With Enums

We can use the `typedef` keyword to make our enumerated list a bit more versatile. The basic syntax would look something like this:

``` c
// 1)
typedef enum {Const1, Const2, Const3,... ConstN} variable_name;

// or

// 2)
typedef enum name {Const1, Const2, Const3,... ConstN} variable_name;

// or

// 3)
enum name {Const1, Const2, Const3,... ConstN};
typedef enum name variable_name
```
Comment on lines +122 to +136
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small thought. Since this already has the "#)" numbering, I would either take out the "// or"s or take out the numbering, since they are both saying the same thing.

Suggested change
``` c
// 1)
typedef enum {Const1, Const2, Const3,... ConstN} variable_name;
// or
// 2)
typedef enum name {Const1, Const2, Const3,... ConstN} variable_name;
// or
// 3)
enum name {Const1, Const2, Const3,... ConstN};
typedef enum name variable_name
```
``` c
// Variation 1
typedef enum {Const1, Const2, Const3,... ConstN} variable_name;
// Variation 2
typedef enum name {Const1, Const2, Const3,... ConstN} variable_name;
// Variation 3
enum name {Const1, Const2, Const3,... ConstN};
typedef enum name variable_name


In the first syntax example, the enumerator is not named, but it is type defined to the variable name. In the second example, the enumerator is both named and type defined on the same line. In the third example, the enumerator is named on one line and then type defined on the next. The second and third example have the same meaning, and allow us to call our enumerator with the `enum` keyword or with the type defined variable name, like this:

``` c
enum name constant_1 = Const1;
variable_name constant_2 = Const2;
```

With this, we will be able to create an enum variable, rather than being restricted to the constants in the enumerated list. Let's look at this example where we use option 3.

``` {.c #mystery-example}
#include <stdio.h>

enum exp_value {Wheat = 2, Onion, Carrot, Corn = 7, Potatoes, Strawberries = 11};

int main(void)
{
int x = 9;
typedef enum exp_value crop_experience;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we already talked about this but I believe typedef statements should be written next to where the enum was defined, since it is globally-defined.

crop_experience Mystery_crop = x;

switch(Mystery_crop)
{
case Wheat:
printf("It is wheat.\n");
break;
case Onion:
...
default:
printf("You have found a new crop. You gained %d experience.\n", Mystery_crop);
break;
}
return 0;
}
```

In this case `x = 9` is hard coded, but you could also take in an input and check if it is a crop you've encountered before.

## Enum Errors

Enumerated constants can only appear in one enumerated list. For example, this code would produce a `replication of enumerator` error:

``` c
#include <stdio.h>

enum days_of_the_week {Sun = 1, Mon, Tues, Wed, Thur, Fri, Sat};
enum celsetial_bodies {Sun, Moon, Jupiter};

int main(void)
{
enum celestial_bodies body;
enum days_of_the_week day;

day = mon;
printf("%d\n", mon);
body = sun;
printf("%d\n", sun);
return 0;
}
```

In this case, `Sun` appears in two enumerated lists, thus the error. You will also get an error if you use non-integer values.

## Bad-Practice Uses of Enums

In general, you shouldn't have global variables. However, enums provide a lot of versatility and wiggle room for things that will work. You may notice this being very similar to the [dirt grower example](#dirt-grower). The only difference is that `crops`, `plants`, and `dirt_growers` are now globally defined.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link doesn't work 😩


``` C
#include <stdio.h>

enum exp_value {Wheat = 2, Onion, Carrot, Corn = 7, Potatoes, Strawberries = 11} crops, plants, dirt_growers;

int main(void)
{
crops = Onion;
plants = Corn;
dirt_growers = Potatoes;
printf("Onion Experience Gain: %d\n", crops);
printf("Corn Experience Gain: %d\n", plants);
printf("Potatoes Experience Gain: %d\n", dirt_growers);
return 0;
}
```

If you recall the [Mystery Crop example](#mystery-example) we looked at, you'll notice this is that example with a global definition and `typedef` of `crop_experience`.

``` c
#include <stdio.h>

typedef enum exp_value {Wheat = 2, Onion, Carrot, Corn = 7, Potatoes, Strawberries = 11} crop_experience;

int main(void)
{
int x = 9;
crop_experience Mystery_crop = x;

switch(Mystery_crop)
{
case Wheat:
printf("It is wheat.\n");
break;
case Onion:
...
default:
printf("You have found a new crop. You gained %d experience.\n", Mystery_crop);
break;
}
return 0;
}
```