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: 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.
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 was a real date or not after it.
- Limited year range: 1900 – 2099
- The program implements leap year check
- Must be able to verify 100 dates in a single run
- Dates are given in DDMMYYYY format
- NB! The symbols and the number of them have specific meanings
https://en.wikipedia.org/wiki/Date_format_by_country
- NB! The symbols and the number of them have specific meanings
- For the base task, the functions must be implemented exactly as they are described and structured in the base code.
- When presenting your program for submission, you must use stream redirection. Input file to test with is also given on this page with the test dates.
Algorithm
The algorithm is showing a higher level view of the solution and is given for you as a guideline to solve the task. It doesn’t show the information exchange between functions. Due to separating the code out to functions you will notice that also the order of some operations will change as well as some logic will be written differently.
Ste-by-step guide
To start off, we should create a text file that will contain the inputs we would have otherwise typed in from the keyboard. This way we can write the test once and then use it each time after we change something in the program to test it quicker. Depending on the program structure, you may need to have multiple test files with different scenarios.
For this task we are able to only write one test file. We need to have both valid and invalid dates to make sure our algoritm detects them correctly. E.g. 11th of December 1981 would be a valid date, however 51st of December, month number 22 etc. will would not. In addition, you need to take extra care to test the edge cases – e.g. months 0, 1, 12, 13. Also testing days and months combined, e.g. 31st of December and 32nd of December. There is some additional complexity for leap years where the month of February can have either 28 or 29 days.
Here are your dates to test. Save it as a text file to the same directory as your source code and program! You’re allowed to add your own lines to the end.
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 make a program that will start to verify these dates.
Now let’s work with the starter code.
First two functions from it be done during the class. If you weren’t in the lab, check out the lecture recording!
From this point forward, we should have 2 files:
- 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 of them:
- date – the so called 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 we run the program so that instead of writing the input from the keyboard, it will be read from the file that we’ve composed (using the stream redirection). We need to use the following structure, but replace the names with the ones for our files ./program_name < data_file
./program_name – this is how you can run a program in Linux console
< – 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: 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
- Computer 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: 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: 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/