Tutorial 12

πŸ’Ύ

Records

9618 A-Level


Often we want to store data related to a particular entity as a single object - for example, rather than creating separate variables for a person's name, date of birth, gender, hobbies etc, we could store them all as a single record

While individual records are good, arrays of records are often even more useful - e.g. creating an array of a custom Person record that we created

Paper 2 theory questions often ask about the benefit of records - you can say:

  • Keeps code organised/easier to understand/makes properties easy to access, since they're stored as a single object
  • More flexible - can easily add/remove properties

If talking about arrays of records, as well as the above points, you can also say:

  • Easier to add/remove instances by changing the array size - typing out creating 10 variables like Person1Name, Person2Name etc is very tedious
  • Can loop through all records - e.g. to populate with them values from a file, search, sort them etc. You can't do this with individual variables
  • Less code duplication - since we can access elements based on their index/in a loop, rather than having to have different statements for each item if using individual variables

Let's see some examples

1

Record Syntax

Records are defined with the TYPE keyword, followed by the record name, a list of declarations and finally the ENDTYPE keyword

In the example below, we will define a custom Person record with 4 fields/properties/attributes

We then need to declare an instance of the Person record which we call walter

To access individual fields, we use the dot e.g. walter.name

TYPE Person DECLARE name : STRING DECLARE dob : DATE DECLARE isAlive : BOOLEAN DECLARE hobbies : ARRAY[1:2] OF STRING DECLARE icon : CHAR ENDTYPE DECLARE walter : Person walter.name ← "Walter White" walter.dob ← 07/09/1958 walter.isAlive ← FALSE walter.hobbies[1] ← "Chemistry" walter.hobbies[2] ← "Business" walter.icon ← 'πŸ§‘β€πŸ”¬' OUTPUT walter.icon, " ", walter.name, " was born on ", walter.dob, " - they enjoy ", walter.hobbies[1], " and ", walter.hobbies[2], ". They are ", getLivingWord(walter.isAlive), "." FUNCTION getLivingWord(isAlive : BOOLEAN) RETURNS STRING IF isAlive = TRUE THEN RETURN "alive" ELSE RETURN "dead" ENDIF ENDFUNCTION

2

People

Use the Person example above to create an array of 3 people and assign relevant values to each of the fields - you should then create a procedure to output all of the people's details

CONSTANT NUM_PEOPLE = 3 TYPE Person DECLARE name : STRING DECLARE dob : DATE DECLARE isAlive : BOOLEAN DECLARE hobbies : ARRAY[1:2] OF STRING DECLARE icon : CHAR ENDTYPE DECLARE people : ARRAY[1:NUM_PEOPLE] OF Person people[1].name ← "Walter White" people[1].dob ← 07/09/1958 people[1].isAlive ← FALSE people[1].hobbies[1] ← "Chemistry" people[1].hobbies[2] ← "Business" people[1].icon ← 'πŸ§‘β€πŸ”¬' people[2].name ← "Sherlock Holmes" people[2].dob ← 01/06/1854 people[2].isAlive ← FALSE people[2].hobbies[1] ← "Boxing" people[2].hobbies[2] ← "Violin" people[2].icon ← 'πŸ•΅οΈβ€β™‚οΈ' people[3].name ← "Tom Riddle" people[3].dob ← 31/12/1936 people[3].isAlive ← FALSE people[3].hobbies[1] ← "Snakes" people[3].hobbies[2] ← "Artifacts" people[3].icon ← 'πŸ§™β€β™‚οΈ' CALL OutputPeople() PROCEDURE OutputPeople() DECLARE index : INTEGER FOR index ← 1 TO 3 OUTPUT people[index].icon, " ", people[index].name, " was born on ", people[index].dob, " - they enjoy ", people[index].hobbies[1], " and ", people[index].hobbies[2], ". They are ", getLivingWord(people[index].isAlive), "." NEXT index ENDPROCEDURE FUNCTION getLivingWord(isAlive : BOOLEAN) RETURNS STRING IF isAlive = TRUE THEN RETURN "alive" ELSE RETURN "dead" ENDIF ENDFUNCTION

3

Flight Booking

Create a program that can store the following information about 3 flights:

  • Airline
  • Departure city
  • Destination city
  • Date
  • Price
  • Number of seats available

You can either pre-populate the records, or have the user input them as the program runs

The main functionality is that the user should be able to specify the departure city, destination city, date and number of tickets they would like to buy - if a suitable flight is available, they should be notified of their successful booking, otherwise a relevant error message should be displayed

There should be some way of allowing the user to continue buying tickets, until they choose to quit

CONSTANT NUM_FLIGHTS = 3 TYPE Flight DECLARE airline, departureCity, destinationCity : STRING DECLARE flightDate : DATE DECLARE seatsRemaining : INTEGER DECLARE price : REAL ENDTYPE DECLARE flights : ARRAY[1:NUM_FLIGHTS] OF Flight DECLARE departureCityChoice, destinationCityChoice : STRING DECLARE flightDateChoice : DATE DECLARE menuChoice : CHAR DECLARE flightIndex, ticketNumChoice : INTEGER DECLARE foundFlight : BOOLEAN flights[1].airline ← "Latam" flights[1].departureCity ← "Buenos Aires" flights[1].destinationCity ← "Sao Paolo" flights[1].flightDate ← 15/04/2025 flights[1].seatsRemaining ← 3 flights[1].price ← 150 flights[2].airline ← "British Airways" flights[2].departureCity ← "Sydney" flights[2].destinationCity ← "London" flights[2].flightDate ← 22/06/2025 flights[2].seatsRemaining ← 75 flights[2].price ← 1000 flights[3].airline ← "NASA" flights[3].departureCity ← "Earth" flights[3].destinationCity ← "Mars" flights[3].flightDate ← 01/01/2040 flights[3].seatsRemaining ← 1 flights[3].price ← 0 REPEAT OUTPUT "Where would you like to depart from:" INPUT departureCityChoice OUTPUT "Where would you like to fly to:" INPUT destinationCityChoice OUTPUT "What date would you like to fly:" INPUT flightDateChoice OUTPUT "How many tickets would you like:" INPUT ticketNumChoice flightIndex ← 0 foundFlight ← FALSE WHILE foundFlight = FALSE AND flightIndex < NUM_FLIGHTS DO flightIndex ← flightIndex + 1 IF departureCityChoice = flights[flightIndex].departureCity AND destinationCityChoice = flights[flightIndex].destinationCity AND flightDateChoice = flights[flightIndex].flightDate THEN foundFlight ← TRUE ENDIF ENDWHILE IF foundFlight = TRUE THEN IF ticketNumChoice <= flights[flightIndex].seatsRemaining THEN OUTPUT "Purchased ", ticketNumChoice, " tickets for ", flights[flightIndex].airline, " flight from ", flights[flightIndex].departureCity, " to ", flights[flightIndex].destinationCity, " on ", flights[flightIndex].flightDate, " for πŸͺ™", (flights[flightIndex].price * ticketNumChoice) ELSE OUTPUT "Couldn't book ", ticketNumChoice, " tickets - only ", flights[flightIndex].seatsRemaining, " seats available" ENDIF ELSE OUTPUT "No flight for this route on that date is available" ENDIF OUTPUT "Would you like to book another flight? (y/n)" INPUT menuChoice UNTIL LCASE(menuChoice) = 'n' OUTPUT "Have a safe flight!"

4

Football Clubs

Use the 20 Premier League FootballClubs.txt file - note that club details are grouped together in the form:

  • Team name
  • Year founded
  • Stadium name
  • Stadium capacity
  • Yearly wage bill (GBP)
  • Team captain

Create a program to read all the clubs into an array of records, then provide the user with a menu and implement the functionality to:

  • Output club details
  • Find club with a given captain
  • Output all clubs founded in the 1800s
  • Order the clubs in descending order of stadium capacity
  • Show wage stats (min, max, average, total and range of yearly wages)
  • Quit
TYPE FootballClub DECLARE name, stadium, captain : STRING DECLARE founded, capacity, wageBill : INTEGER ENDTYPE CONSTANT NUM_CLUBS = 20 DECLARE clubs : ARRAY[1:NUM_CLUBS] OF FootballClub DECLARE line : STRING DECLARE index, menuChoice : INTEGER OPENFILE FootballClubs.txt FOR READ WHILE NOT EOF(FootballClubs.txt) DO index ← index + 1 READFILE FootballClubs.txt, clubs[index].name READFILE FootballClubs.txt, line clubs[index].founded ← STR_TO_NUM(line) READFILE FootballClubs.txt, clubs[index].stadium READFILE FootballClubs.txt, line clubs[index].capacity ← STR_TO_NUM(line) READFILE FootballClubs.txt, line clubs[index].wageBill ← STR_TO_NUM(line) READFILE FootballClubs.txt, clubs[index].captain READFILE FootballClubs.txt, line ENDWHILE CLOSEFILE FootballClubs.txt REPEAT //
  • Output club details
  • //
  • Find club with a given captain
  • //
  • Output all clubs founded in the 1800s
  • //
  • Order the clubs in descending order of stadium capacity
  • //
  • Quit
  • OUTPUT "--- Menu --- 1) Output club details 2) Search club by captain 3) Show 1800s clubs 4) Order by stadium capacity 5) Show wage stats 6) Quit Please choose an option:" INPUT menuChoice CASE OF menuChoice 1: CALL OutputAllClubs() 2: CALL SearchClubByCaptain() 3: CALL Show1800sClubs() 4: CALL OrderByStadiumCapacity() 5: CALL ShowWageStats() ENDCASE UNTIL menuChoice = 6 OUTPUT "Goodbye..." PROCEDURE OutputAllClubs() DECLARE n : INTEGER FOR n ← 1 TO NUM_CLUBS OUTPUT n CALL OutputClub(clubs[n]) OUTPUT "" NEXT n ENDPROCEDURE PROCEDURE OutputClub(c : FootballClub) OUTPUT c.name, " was founded in ", c.founded, " plays at the ", c.stadium, " with a capacity of ", c.capacity, ". Their yearly wage bill is Β£", c.wageBill, " and their captain is ", c.captain ENDPROCEDURE PROCEDURE SearchClubByCaptain() DECLARE n : INTEGER DECLARE found : BOOLEAN DECLARE captain : STRING found ← FALSE n ← 1 OUTPUT "Enter captain to search for:" INPUT captain WHILE found = FALSE AND n <= NUM_CLUBS IF clubs[n].captain = captain THEN CALL OutputClub(clubs[n]) found ← TRUE ENDIF n ← n + 1 ENDWHILE IF found = FALSE THEN OUTPUT "No club with captain named ", captain ENDIF ENDPROCEDURE PROCEDURE Show1800sClubs() DECLARE n : INTEGER FOR n ← 1 TO NUM_CLUBS IF clubs[n].founded < 1900 THEN CALL OutputClub(clubs[n]) OUTPUT "" ENDIF NEXT n ENDPROCEDURE PROCEDURE OrderByStadiumCapacity() DECLARE isSorted : BOOLEAN DECLARE endIndex, n : INTEGER isSorted ← FALSE endIndex ← NUM_CLUBS - 1 WHILE isSorted = FALSE DO isSorted ← TRUE FOR n ← 1 TO endIndex IF clubs[n].capacity < clubs[n + 1].capacity THEN DECLARE tempClub : FootballClub tempClub ← clubs[n] clubs[n] ← clubs[n + 1] clubs[n + 1] ← tempClub isSorted ← FALSE ENDIF NEXT n endIndex ← endIndex - 1 ENDWHILE FOR n ← 1 TO NUM_CLUBS CALL OutputClub(clubs[n]) OUTPUT "" NEXT n ENDPROCEDURE PROCEDURE ShowWageStats() DECLARE n, min, max, total : INTEGER min ← clubs[1].wageBill max ← clubs[1].wageBill total ← 0 FOR n ← 1 TO NUM_CLUBS IF clubs[n].wageBill < min THEN min ← clubs[n].wageBill ENDIF IF clubs[n].wageBill > max THEN max ← clubs[n].wageBill ENDIF total ← total + clubs[n].wageBill NEXT n OUTPUT "--- Yearly Wage Stats ---" OUTPUT "Min: ", min OUTPUT "Max: ", max OUTPUT "Total: ", total OUTPUT "Average: ", total / NUM_CLUBS OUTPUT "Range: ", max - min ENDPROCEDURE

    The following are some example files you can use throughout these challenges - you may also want to use a list of English words to try some interesting tasks too