Lab material
- Slides: Pseudo-random numbers
- Slides: Standard streams
- Reading: stream redirection guide
Lab tasks
In this lab you have two tasks. Both of the tasks have an extra task available.
Task 1 [W08-1]: Date validation
The purpose of this task is to check given numerical dates and check if the date is valid or not. In this task, we’ll also introduce stream redirection and return value of the scanf() statement.
Download the starter code: https://blue.pri.ee/ttu/files/iax0583/aluskoodid/8_1_date_base.c
Requirements
- The program checks each date and prints if it is a real date or not
- Year rage for the date to be considered valid: 1900 – 2099
- Program must must support leap years correctly
- Must be able to verify 100 dates in a single run
- Dates are given in
DDMMYYYY format
- NB! The characters and the number of characters have specific meanings
https://en.wikipedia.org/wiki/Date_format_by_country
- NB! The characters and the number of characters have specific meanings
- For the base task, the functions must be implemented exactly as they are described and structured in the starter code
- When presenting your program, you must use stream redirection. Test data is given on this page
Algorithm
The algorithm is limited to validating the date. The starter code also requires use of arrays, which is not depicted in the algorithm. This also causes variance in the order of operations.
Reminder: Activity diagrams do not show calling functions or data flow between functions.
Ste-by-step guide
To start off, we should create a text file that will contain the inputs we would otherwise have typed from the keyboard. This way we can write the test once and use it every time we update the source code. Depending on the program structure, you may need to have multiple test files to cover different scenarios.
You need to plan your testing in a way, that all possible options for your program would be tested. You need to have both realistic and unrealistic dates. I.e. 11th of December, 1981; 51st of December; month nr 22, month “abc” etc. Special attention should be put into edge cases – e.g. 29th of February. This time we have created the inputs for you. If you wish, you can add more dates in the end.
Save the following file with test inputs into the same directory you stored your program.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
14041805 26052100 31012015 30092011 01012001 31062011 32011999 00012011 01002023 01132033 29022022 28022022 28022000 29022000 29022004 29021900 |
Next you’ll need to create a program that will test these dates.
Now let’s start working with the starter code. First two functions will be completed together in the class. If you were absent, watch the lecture recording!
From this point forward, we should have 2 files, both in the same directory
- Program code (e.g. date.c )
- Text file with the dates (e.g. input or input.txt )
Next up, we need to compile the program. One option would be to use Geany or any other IDE that you’ve used so far. You can do that if that’s what you feel the most comfortable with. Just don’t forget to recompile after changing the code!
Let’s verify that everything is where it should by by using the command ls -l :
|
1 2 3 4 5 |
INTRA\risto.heinsar@lx27:~/P/date> ls -l total 18 -rwxr-xr-x 1 INTRA\risto.heinsar INTRA\domain users 12732 Oct 6 14:11 date -rwxr-xr-x 1 INTRA\risto.heinsar INTRA\domain users 536 Oct 5 15:50 date.c -rwxr-xr-x 1 INTRA\risto.heinsar INTRA\domain users 73 Oct 6 14:11 input.txt |
Before we had 2 files, now we should have 3
- date – binary file, that we produced by compiling our program. Can be executed.
- date.c – source code. This is the file we wrote our code in. Cannot be executed.
- input.txt – text file, that contains dates (test data).
Now you need to run the program in such a way, that instead of typing the dates from the keyboard, we use stream redirection on the operating system level (our program is not reading the input file, it doesn’t even know how to do it). For this, we would formulate the command using the structure ./program_name < data_file
./program_name – this is how you can run a program in Linux or MacOS, on the command line
< – a symbol denoting that the input stream will be redirected for this program
data_file – the file it will use to stream the input from
This is how the output will look like after we finish the part of the code done together and you will start your individual work
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
INTRA\risto.heinsar@lx27:~/P/date> ./date < input Dates read: 16 14.04.1805 26.05.2100 31.01.2015 30.09.2011 01.01.2001 31.06.2011 32.01.1999 00.01.2011 01.00.2023 01.13.2033 29.02.2022 28.02.2022 28.02.2000 29.02.2000 29.02.2004 29.02.1900 |
Testing: completed solution
After implementing the date validation, Your output should look something like this:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
INTRA\risto.heinsar@lx27:~/P/kp> ./date < input Dates read: 16 14.04.1805 < Invalid date! 26.05.2100 < Invalid date! 31.01.2015 < OK 30.09.2011 < OK 01.01.2001 < OK 31.06.2011 < Invalid date! 32.01.1999 < Invalid date! 00.01.2011 < Invalid date! 01.00.2023 < Invalid date! 01.13.2033 < Invalid date! 29.02.2022 < Invalid date! 28.02.2022 < OK 28.02.2000 < OK 29.02.2000 < OK 29.02.2004 < OK 29.02.1900 < Invalid date! |
Task 2 [W08-2]: Lottery
Start by downloading the starter code
- With Estonian comments: https://blue.pri.ee/ttu/files/iax0583/aluskoodid/8_2_loto_base.c
- With English comments: https://blue.pri.ee/ttu/files/iax0583/aluskoodid/8_2_loto_base_en.c
Requirements
- Lab task must be built on the starter code. It contains a list of functions with comments that you need to implement and use.
- Lottery numbers can be from 1 to 25 (ends inclusive)
- User is asked to enter 6 numbers
- Program will randomly generate 10 lottery numbers
- Program will print out both the user and the randomly generated numbers
- Check and show how many and which numbers matched (won)
- There is no number uniqueness requirement for the base task
- Every user number can win only once
- If all numbers won, congratulate on jackpot. If none of the numbers won, give your condolences.
Testing
NB! The nature of a lottery is to be random, however testing this program without knowing that numbers to expect is not possible. Due to this, we will fix the random seed (srand function parameter) to be the same on every run. Then generate the lottery numbers once and remember them / write them down so you can test the program!
Test 1: Random numbers, some may win, no errors on input
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
Enter lottery number [1 ... 25] (1 / 6): 1 Enter lottery number [1 ... 25] (2 / 6): 3 Enter lottery number [1 ... 25] (3 / 6): 5 Enter lottery number [1 ... 25] (4 / 6): 13 Enter lottery number [1 ... 25] (5 / 6): 14 Enter lottery number [1 ... 25] (6 / 6): 15 User numbers are 1 3 5 13 14 15 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Winning number: 1 Winning number: 13 Winning number: 15 Matched 3 out of 6! |
Test 2: No winning numbers
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
Enter lottery number [1 ... 25] (1 / 6): 11 Enter lottery number [1 ... 25] (2 / 6): 12 Enter lottery number [1 ... 25] (3 / 6): 14 Enter lottery number [1 ... 25] (4 / 6): 21 Enter lottery number [1 ... 25] (5 / 6): 22 Enter lottery number [1 ... 25] (6 / 6): 23 User numbers are 11 12 14 21 22 23 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Matched 0 out of 6! None of the numbers matched. Better luck next time! |
Test 3: Jackpot
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
Enter lottery number [1 ... 25] (1 / 6): 17 Enter lottery number [1 ... 25] (2 / 6): 18 Enter lottery number [1 ... 25] (3 / 6): 10 Enter lottery number [1 ... 25] (4 / 6): 1 Enter lottery number [1 ... 25] (5 / 6): 20 Enter lottery number [1 ... 25] (6 / 6): 25 User numbers are 17 18 10 1 20 25 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Winning number: 17 Winning number: 18 Winning number: 10 Winning number: 1 Winning number: 20 Winning number: 25 Matched 6 out of 6! Congratulations! You won the jackpot! |
Test 4: Invalid user input
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
Enter lottery number [1 ... 25] (1 / 6): -5 Invalid number! Retry: 5 Enter lottery number [1 ... 25] (2 / 6): 26 Invalid number! Retry: 27 Invalid number! Retry: -4 Invalid number! Retry: 6 Enter lottery number [1 ... 25] (3 / 6): 7 Enter lottery number [1 ... 25] (4 / 6): 8 Enter lottery number [1 ... 25] (5 / 6): 9 Enter lottery number [1 ... 25] (6 / 6): 10 User numbers are 5 6 7 8 9 10 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Winning number: 9 Winning number: 10 Matched 2 out of 6! |
Test 5: Every user number can win only once (sanity check)
In this test, we will change the specification for the constants. This will help us test that every user number can only win once. This is also called a sanity check type of test.
NB! This test will only work if you haven’t yet solved the extra task where all numbers are checked to be unique. Repetition of numbers must be allowed for this!
|
1 |
#define MAX_LOTTO 1 |
After changing the constant, check for 2 things:
- How many numbers match! Should be Matched 6 out of 6!)
- Check the numbers generated by the program. They can only be ones! (0 or 2 would mean that you have a mistake in the formula for limiting random numbers)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Enter lottery number [1 ... 1] (1 / 6): 1 Enter lottery number [1 ... 1] (2 / 6): 1 Enter lottery number [1 ... 1] (3 / 6): 1 Enter lottery number [1 ... 1] (4 / 6): 1 Enter lottery number [1 ... 1] (5 / 6): 1 Enter lottery number [1 ... 1] (6 / 6): 1 User numbers are 1 1 1 1 1 1 Lottery numbers are 1 1 1 1 1 1 1 1 1 1 Winning number: 1 Winning number: 1 Winning number: 1 Winning number: 1 Winning number: 1 Winning number: 1 Matched 6 out of 6! Congratulations! You won the jackpot! |
Extra task 1 [W08-3]: reason for validation failure (date validation)
Lets improve our program to make it more clear why a date failed our validation.
Requirements
- Extend your program in a way that it will give a reason for why the date didn’t validate
- At minimum, you must be able to differentiate
- Invalid year
- Invalid month
- Invalid day. You must differentiate between dates lower and higher than the allowed range for a specific month
- Non-leap year 29th of February.
- You are allowed to add functions and modify the existing structure of the program within reason.
- Reminder! Avoid magical numbers! Define your constants
Testing
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
INTRA\risto.heinsar@lx27:~/P/kp> ./date_adv < input Dates read: 16 14.04.1805 < Year out of range! 26.05.2100 < Year out of range! 31.01.2015 < OK 30.09.2011 < OK 01.01.2001 < OK 31.06.2011 < Day exceeds maximum days for given month! 32.01.1999 < Day exceeds maximum days for given month! 00.01.2011 < Day before first of month! 01.00.2023 < No such month exists! 01.13.2033 < No such month exists! 29.02.2022 < 29th of February only exists on leap year! 28.02.2022 < OK 28.02.2000 < OK 29.02.2000 < OK 29.02.2004 < OK 29.02.1900 < 29th of February only exists on leap year! |
Extra task 2 [W08-4]: unique numbers for lottery
By completing this task, you will make your program more realistic. For this we need to only solve 1 more function CheckIfNumInArray() and start using it
Requirements
- Enforce a requirement for the user entered numbers to be unique. If a user enters a number that they already entered before, immediately ask them for a different number.
- Enforce the same requirement for the lottery machine.
- Do not chagne the implementations of GetUserNumbInRange() and GenerateRandomNum() functions. There is a better suited place for this.
- Comment in and solve the function
CheckIfNumInArray() . You need to start using it in three different places
- During user input to make sure that the values are unique
- During generation of lottery numbers to make sure that they are unique
- To count how many user numbers matched with the winning number in the function FindMatchCount()
Testing
Test 1: Check the uniqueness requirement for the user
NB! Use the exact same sequence to test!
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
Enter lottery number [1 ... 25] (1 / 6): 1 Enter lottery number [1 ... 25] (2 / 6): 2 Enter lottery number [1 ... 25] (3 / 6): 3 Enter lottery number [1 ... 25] (4 / 6): 4 Enter lottery number [1 ... 25] (5 / 6): 3 You've already entered this number! Retry: 2 You've already entered this number! Retry: 1 You've already entered this number! Retry: 5 Enter lottery number [1 ... 25] (6 / 6): 6 User numbers are 1 2 3 4 5 6 Lottery numbers are 17 18 10 1 20 25 4 9 13 15 Winning number: 1 Winning number: 4 Matched 2 out of 6! |
Test 2: Check the uniqueness requirement for generated lottery numbers
To test the random numbers, we need to manipulate one of the constants
|
1 |
#define MAX_LOTTO 10 |
We will force the amount of numbers the computer is generating to be exactly as many unique numbers can be generated based on our lower and upper bounds for the numbers. We should get all numbers from 1 – 10 and none of them can repeat.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
Enter lottery number [1 ... 10] (1 / 6): 1 Enter lottery number [1 ... 10] (2 / 6): 2 Enter lottery number [1 ... 10] (3 / 6): 3 Enter lottery number [1 ... 10] (4 / 6): 4 Enter lottery number [1 ... 10] (5 / 6): 5 Enter lottery number [1 ... 10] (6 / 6): 6 User numbers are 1 3 4 5 6 Lottery numbers are 2 8 5 1 10 9 3 6 7 4 Winning number: 1 Winning number: 2 Winning number: 3 Winning number: 4 Winning number: 5 Winning number: 6 Matched 6 out of 6! Congratulations! You won the jackpot! |
Think and answer the question: What would happen if we would have made the constant to be 9?
After the class, you should
- Know which standard streams exist
- Know how to use stream redirection on different platforms
- Know how to execute the programs you create on Linux command line
- Be able to use Boolean values
- Be able to split up input
- Know how to use the return value of scanf
- Know how and when to omit curly braces. Also when not to.
- Know what a dangling else statement is.
- Be able to generate pseudo-random numbers
- … within a specific range
- … while fixing the seed for testing
- … while making them dependent on the current time
- Know the difference between pseudorandom and random
- Know how UNIX time works and what’s the importance of 1st of January, 1970.
Additional content
- Boolean type support library
https://en.cppreference.com/w/c/types/boolean - What is a leap year
https://www.timeanddate.com/date/leapyear.html - Standard streams
https://en.wikipedia.org/wiki/Standard_streams - Redirection
https://en.wikipedia.org/wiki/Redirection_(computing) - Pseudorandomness
https://en.wikipedia.org/wiki/Pseudorandomness - Why does Cloudflare use lava lamps to help with encryption? (üks võimalik lahendus pseudojuhuslikkuse probleemile)
https://www.cloudflare.com/learning/ssl/lava-lamp-encryption/ - Unix time
https://en.wikipedia.org/wiki/Unix_time - Unixi praegune kellaaeg ja selle teisendi
https://www.unixtimestamp.com - rand() and srand() in C/C++
https://www.geeksforgeeks.org/rand-and-srand-in-ccpp/ - time.h library in C
https://www.cplusplus.com/reference/ctime/