|
| 1 | +--- |
| 2 | +title: Put Together |
| 3 | +--- |
| 4 | +import { YouTube } from 'astro-embed'; |
| 5 | + |
| 6 | +## Airspeed Velocity |
| 7 | + |
| 8 | +On your journey, you encountered a strange person who mentioned something about coconuts and queries you vigorously about the airspeed velocity of unladen swallows. |
| 9 | + |
| 10 | +<div class="not-content"> |
| 11 | + <YouTube id="w8Rn_f75UHs" params="fs=1&start=104&modestbranding=1&rel=0&autoplay=1"/> |
| 12 | +</div> |
| 13 | + |
| 14 | +To answer this age old question, you can mock up the following program to calculate the airspeed velocity of these important birds. With a quick search, you find [an equation](http://www.style.org/strouhalflight) based on the Strouhal Number and some [details on swallows](http://style.org/unladenswallow/). We can use this information to create a program that can be used to calculate the airspeed velocity of African and European Swallows. |
| 15 | + |
| 16 | +From these articles we can determine that the air speed velocity of a swallow can be calculated using `Speed = Frequency * Amplitude / Strouhal`. Code this into a program and then test out the different airspeeds. |
| 17 | + |
| 18 | +- We can use two set Strouhal values - An efficient Strouhal number of 0.20 and low efficiency Strouhal of 0.40. |
| 19 | +- African Swallow: frequency 15hz, amplitude 21cm |
| 20 | +- European Swallow: frequency 14hz, amplitude 22cm |
| 21 | + |
| 22 | +To create this program, we have a few set values, and some values that we want to be able to be different each time the program runs. We can create the following building blocks to help us work with this into our program: |
| 23 | + |
| 24 | +- Two constants: |
| 25 | + - `STROUHAL_LOW_EFFICIENCY` to store 0.4 |
| 26 | + - `STROUHAL_HIGH_EFFICIENCY` to store 0.2 |
| 27 | +- Six variables: |
| 28 | + - Two strings: |
| 29 | + - `birdName` to capture the name of the bird the user enters |
| 30 | + - A `line` to store the numbers they enter, until we can convert them to a double we can use. |
| 31 | + - Four double values: |
| 32 | + - `freq` to store the frequency of the birds wing stroke, in beats per second. |
| 33 | + - `amp` to store the amplitude in meters. |
| 34 | + - `resultMax` and `resultMin` to store the two speed calculations based on the low and high efficiency Strouhal values. |
| 35 | + |
| 36 | +We will need to use `double` for these numberic values, and we will not have issues with limit of precision or accumulated rounding issues. We need the `line` to read the value, and read line returns us the text they entered. |
| 37 | + |
| 38 | +For our **algorithm**, we will need the program to step through the following actions: |
| 39 | + |
| 40 | +1. Show the start details |
| 41 | +2. Read in the name, frequency, and amplitude |
| 42 | +3. Calculate min and max speeds |
| 43 | +4. Output results |
| 44 | + |
| 45 | +Reading in the frequence and amplitude will require a few steps each: |
| 46 | + |
| 47 | +1. Show the prompt to the user (tell them what we want them to enter) |
| 48 | +2. Read in their response as a string - they enter text |
| 49 | +3. Convert the line entered to a double, and store in the variable |
| 50 | + |
| 51 | +```csharp |
| 52 | +using static System.Console; |
| 53 | +using static System.Convert; |
| 54 | + |
| 55 | +const double STROUHAL_LOW_EFFICIENCY = 0.4; |
| 56 | +const double STROUHAL_HIGH_EFFICIENCY = 0.2; |
| 57 | + |
| 58 | +string birdName, line; |
| 59 | +double freq, amp; |
| 60 | + |
| 61 | +WriteLine("Welcome to the Airspeed Calculator"); |
| 62 | +WriteLine(); |
| 63 | +WriteLine("What is the name of the bird?"); |
| 64 | +Write("Name: "); |
| 65 | + |
| 66 | +WriteLine("What is the frequency of its wing stroke? (beats per second)"); |
| 67 | +Write("Frequency: "); |
| 68 | + |
| 69 | +// Read and convert frequency to double |
| 70 | +line = ReadLine(); |
| 71 | +freq = ToDouble(line); |
| 72 | + |
| 73 | +WriteLine("What is the amplitude of its wings? (centi)"); |
| 74 | +Write("Amplitude: :"); |
| 75 | +line = ReadLine(); |
| 76 | +amp = ToDouble(line); |
| 77 | + |
| 78 | +// calculate the air speed, given a fixed Strouhal value |
| 79 | +double resultMax, resultMin; |
| 80 | +resultMax = freq * amp / STROUHAL_HIGH_EFFICIENCY; |
| 81 | +resultMin = freq * amp / STROUHAL_LOW_EFFICIENCY; |
| 82 | + |
| 83 | +// output the airspeed of the bird |
| 84 | +WriteLine($"Bird {birdName} "); |
| 85 | +WriteLine($" - f: {freq} A: {amp} Speed: {result} m/s"); |
| 86 | +WriteLine($" - f: {freq} A: {amp} Speed: {result} m/s"); |
| 87 | + |
| 88 | +``` |
| 89 | + |
| 90 | +## Water Bottle Visualiser |
| 91 | + |
| 92 | +Now we have calculated the volume of water in a bottle, let's draw it to the screen. |
| 93 | + |
| 94 | +The following program uses a whole range of constants and variables. The constants set up the dimensions of the bottle, and we let the user provide the `percentFull` so that we can calculate the water level. |
| 95 | + |
| 96 | +We can plan the **algorithm** in this program to have the following steps: |
| 97 | + |
| 98 | +1. Setup the coordinates for the water bottle |
| 99 | +2. Show a welcome message |
| 100 | +3. Read in how full the water bottle is (we can do this as a percentage) |
| 101 | +4. Calculate the height of the water |
| 102 | +5. Open the Window |
| 103 | +6. Draw the bottle |
| 104 | +7. Wait so that the user can see this |
| 105 | + |
| 106 | +For the bottle drawing we will need to capture a few dimensions. These can be constants as we wont change these in this program: |
| 107 | + |
| 108 | +- `BOTTLE_RADIUS` for the size of the circle. We can use this to draw circles at the top, bottom, and at the top of the water. |
| 109 | +- `BOTTLE_HEIGHT` the height of the water bottle cyclinder. |
| 110 | + |
| 111 | +- `BOTTLE_DIAMETER` to store the full width of the circle. We need this to draw the water. This will be a rectangle drawn on top of the middle of the circle. We can calculate this from the radius. |
| 112 | +- `BOTTLE_CENTER_X` for the position of the bottle - this is the distance from the left of the screen. We can calculate this from the width of the window to position the bottle in the middle of the screen. |
| 113 | +- `BOTTLE_LEFT_X` and `BOTTLE_RIGHT_X` to store the left and right sides of the bottle. We can use this for the position of the rectangle, and the lines for the side of the bottle. They can be calculated from the bottle's radius and center x. |
| 114 | +- `BOTTLE_BASE_Y` and `BOTTLE_TOP_Y` can be created to store the distance from the top of the screen to the top and bottom of the bottle. This will tell us where to draw the circles, lines, and rectangles. The base can be calculated from the height of the window, and the top can be calculated from the base and the bottle's height. |
| 115 | + |
| 116 | +For the water height, we need a few variables as this can change. |
| 117 | + |
| 118 | +- `percentFull` will capture how full the bottle is. This can be an integer. We can then divide this by 100 to get the proportion to apply to the bottle's height to calculate the water height. |
| 119 | +- When we know the `percentFull`, we can calculate the `waterHeight`. |
| 120 | +- We need to know where the water should be drawn. When we know its height, we can use that to calculate a `waterY` value. This will represent where the water is up to within the bottle. |
| 121 | + |
| 122 | +As with the previous program, we also need a string (we called it `line`) to store the text data from the user before we convert it to a number for us to use. |
| 123 | + |
| 124 | +:::tip[Are all programs this mathematical?] |
| 125 | + |
| 126 | +The two programs here are both very focused on mathematical calculations. This is not all we can do with computing. Most of the code in your program will not involve this level of mathematical modelling. We will soon see how we can wrap this kind of calculations into neat, reusable, packages. This is about as complex as the calculations will get in this guide. |
| 127 | + |
| 128 | +::: |
| 129 | + |
| 130 | +We need to think through the steps the computer will need to draw the water. Here are a few notes we took: |
| 131 | + |
| 132 | +- We can fill to show the water, but can draw over the top to get an outline. |
| 133 | +- We will need to draw the rectangle over the bottom circle. Then it will draw over the part of the circle that should be behind the water. |
| 134 | +- The order of drawing will need to be: |
| 135 | + - Bottom of the bottle - water and outline |
| 136 | + - Water - rectangle to water height |
| 137 | + - Side lines and top of bottle - outline |
| 138 | + |
| 139 | +To help communicate how this works, there is a comment in the code that uses ASCII art to output the bottle's shape and indicate what the different constants and variables represent. Read through the code and match up the comment with the constants, and their calculations. Notice how easy it is to resize the bottle - you can change the radius or height and the other values will all be updated to reflect this. |
| 140 | + |
| 141 | +Also, look at the drawing code. See how the constants help make it clear what is being drawn. Imagine if this were all just raw values. The code would be a jumble of numbers. Creating constants helps make it clearer what you are doing in the code. |
| 142 | + |
| 143 | +```csharp |
| 144 | +using static System.Convert; |
| 145 | +using static SplashKitSDK.SplashKit; |
| 146 | + |
| 147 | +const int WINDOW_WIDTH = 600; |
| 148 | +const int WINDOW_HEIGHT = 600; |
| 149 | + |
| 150 | +/*-------------------------------------\ |
| 151 | +| Water bottle shape... |
| 152 | +| |
| 153 | +| BOTTLE_LEFT_X BOTTLE_RIGHT_X |
| 154 | +| | | |
| 155 | +| v v |
| 156 | +| ___________ |
| 157 | +| / \ x = BOTTLE_CENTER_X |
| 158 | +| ^ | x | <-- BOTTLE_TOP_Y |
| 159 | +| | |\___________/| |
| 160 | +| | | | |
| 161 | +| | | ___________ | |
| 162 | +| | |/ \| |
| 163 | +| | | | <-- waterY |
| 164 | +| | |\___________/| ^ |
| 165 | +| | | ___________ | | waterHeight |
| 166 | +| | |/ \| v |
| 167 | +| v | | <-- BOTTLE_BASE_Y |
| 168 | +| \___________/ |
| 169 | +| BOTTLE_HEIGHT |
| 170 | +| <-----x-----> BOTTLE_RADIUS |
| 171 | +| BOTTLE_DIAMETER |
| 172 | +\-------------------------------------*/ |
| 173 | + |
| 174 | +const int BOTTLE_RADIUS = 80; |
| 175 | +const int BOTTLE_HEIGHT = 400; |
| 176 | +const int BOTTLE_DIAMETER = BOTTLE_RADIUS * 2; |
| 177 | +const int BOTTLE_CENTER_X = WINDOW_WIDTH / 2; |
| 178 | +const int BOTTLE_LEFT_X = BOTTLE_CENTER_X - BOTTLE_RADIUS; |
| 179 | +const int BOTTLE_RIGHT_X = BOTTLE_CENTER_X + BOTTLE_RADIUS; |
| 180 | +const int BOTTLE_BASE_Y = WINDOW_HEIGHT - BOTTLE_RADIUS - 5; // 5 pixel gap |
| 181 | +const int BOTTLE_TOP_Y = BOTTLE_BASE_Y - BOTTLE_HEIGHT; |
| 182 | + |
| 183 | +string line; |
| 184 | +int percentFull; |
| 185 | + |
| 186 | +WriteLine("Water Bottle Visualiser!"); |
| 187 | +WriteLine(); |
| 188 | +WriteLine("How full us your bottle? (0-100)"); |
| 189 | +WriteLine(); |
| 190 | +Write("Percent: "); |
| 191 | +line = ReadLine(); |
| 192 | + |
| 193 | +// Convert the text entered to a double |
| 194 | +percentFull = ToInt32(line); |
| 195 | + |
| 196 | +double waterHeight = BOTTLE_HEIGHT * (percentFull / 100.0); |
| 197 | +double waterY = BOTTLE_BASE_Y - waterHeight; |
| 198 | + |
| 199 | +OpenWindow("Your Water Bottle", WINDOW_WIDTH, WINDOW_HEIGHT); |
| 200 | +ClearScreen(ColorWhite()); |
| 201 | + |
| 202 | +// Draw the water |
| 203 | +// Circle at the bottom of the bottle |
| 204 | +FillCircle(ColorBlue(), BOTTLE_CENTER_X, BOTTLE_BASE_Y, BOTTLE_RADIUS); |
| 205 | +DrawCircle(ColorBlack(), BOTTLE_CENTER_X, BOTTLE_BASE_Y, BOTTLE_RADIUS); |
| 206 | + |
| 207 | +//Draw the water |
| 208 | +FillRectangle(ColorBlue(), BOTTLE_LEFT_X, waterY, BOTTLE_DIAMETER, waterHeight); |
| 209 | +DrawCircle(ColorBlack(), BOTTLE_CENTER_X, waterY, BOTTLE_RADIUS); |
| 210 | + |
| 211 | +// Outline bottle |
| 212 | +// Draw the left wall of the bottle |
| 213 | +DrawLine(ColorBlack(), BOTTLE_LEFT_X, BOTTLE_BASE_Y, BOTTLE_LEFT_X, BOTTLE_TOP_Y); |
| 214 | +// Draw the right wall of the bottle |
| 215 | +DrawLine(ColorBlack(), BOTTLE_RIGHT_X, BOTTLE_BASE_Y, BOTTLE_RIGHT_X, BOTTLE_TOP_Y); |
| 216 | +DrawCircle(ColorBlack(), BOTTLE_CENTER_X, BOTTLE_TOP_Y, BOTTLE_RADIUS); |
| 217 | +// Circle at the top of the water |
| 218 | +FillCircle(ColorBlue(), BOTTLE_CENTER_X, waterY, BOTTLE_RADIUS); |
| 219 | + |
| 220 | +RefreshScreen(); |
| 221 | +Delay(5000); |
| 222 | +``` |
| 223 | + |
| 224 | +Run this and you should see something like the following. |
| 225 | + |
| 226 | + |
| 227 | + |
| 228 | +## Wrap Up |
| 229 | + |
| 230 | +Programming with sequence and data involves two things: |
| 231 | + |
| 232 | +1. Thinking about the values you will need in your program. |
| 233 | +2. Thinking about the sequence of steps you will need to get the outcome you want. |
| 234 | + |
| 235 | +You need to think about both of these together. The data you have, and need, will help you think about the steps to acheive this. Break down your problems into small discete steps, each performing a small step toward your goal. |
| 236 | + |
| 237 | +With each piece of data, think "Does this need to change?" If the answer is yes, then use a variable. If no, use a constant. At the same time, think "What kind of value is this?" If it is a number, is it a whole number (`int`) or a real number (`double`)? This will help you make the many small decisions you need to make as you craft your code. |
0 commit comments