Tracks
/
Swift
Swift
/
Exercises
/
High Score Board
High Score Board

High Score Board

Learning Exercise

Introduction

Dictionaries are one of Swift's three primary collection types. Dictionaries store mappings between keys which are elements of one type and values which are elements of another type (possibly the same type as that of the keys).

Dictionary literals are written as a series of key: value pairs, separated by commas, enclosed in square brackets. Empty dictionaries can be written by following the type name of the dictionary by a pair of parenthesis, e.g. [Int: String](), or, if the type can be determined from the context, as just a pair of square brackets surrounding a colon, [:]. Type names for dictionaries are written in one of two ways: Dictionary<K, V> or [K: V] where K is the type of the keys in the dictionary and V is the type of the values. When creating an empty array, the type must be specified.

var addresses: Dictionary<String, String> = ["The Munsters": "1313 Mockingbird Lane", "The Simpsons": "742 Evergreen Terrace", "Buffy Summers": "1630 Revello Drive"]
var sequences: [String: [Int]] = ["Euler's totient": [1, 1, 2, 2, 4, 2, 6, 4], "Lazy caterer": [1, 2, 4, 7, 11, 16, 22, 29, 37], "Carmichael": [561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841]]
let constants = ["pi": 3.14159, "e": 2.71828, "phi": 1.618033, "avogadro": 6.02214076e22]
var emptyDict1: [Int: Int] = [:]
var emptyDict2 = [Character: String]()
var emptyDict3 = Dictionary<Int, Double>()

Elements of a dictionary can be accessed using subscript notation, where the name of the dictionary is followed by square brackets which enclose the key for which we want the corresponding value.

Note, however, that the value returned is not of type Value, but rather of optional type, Value?. This is because one can supply a key that is not present in the dictionary. In these cases, Swift chooses to return nil rather than throw an error.

let munster: String? = addresses["The Munsters"]
// => "1313 Mockingbird Lane"
let carmichael = sequences["Carmichael"]
// => [561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841]
let planck = constants["planck"]
// => nil

To avoid the optional type of the return, one can supply a default value to return if the key if not found in the dictionary.

let e: Double = constants["e", default: 0]
// => 2.71828
let hoagie: [Int] = sequences["Hoagie", default: []]
// => []
let betty = addresses["Betty Cooper", default: "Address unknown"]
// => "Address unknown"

This subscript notation can be used to retrieve the value associated with that key as well as to set the value associated with that key, provided the dictionary was defined as a variable (i.e. using var). This can be used to update the value associated with a key or to add a new key: value pair to the dictionary.

sequence["Euler's totient"]?.append(contentsOf: [6,4])
sequence["Euler's totient"]
// => [1, 1, 2, 2, 4, 2, 6, 4, 6, 4]
addresses["Betty Cooper"] = "111 Queens Ave."
addresses["Betty Cooper", default: "Address unknown"]
// => "111 Queens Ave."
constants["Gelfond's"] = 23.140692
// compiler error: "Cannot assign through subscript: 'constants' is a 'let' constant"

Like arrays, the key: value pairs of a dictionary can be stepped through one at a time using a for-in loop. This type of loop takes each key: value pair of the dictionary and binds the pair to a specified name for further processing inside the loop body. The pair is represented as a tuple and can be decomposed like other tuples to assign each element to a name. For example, to print out the address book, on can write:

for (name, address) in addresses {
  print("\(name) lives at \(address)")
}

// prints out:
// Betty Cooper lives at 111 Queens Ave.
// The Munsters lives at 1313 Mockingbird Lane
// The Simpsons lives at 742 Evergreen Terrace
// Buffy Summers lives at 1630 Revello Drive

Like the other collection types, dictionaries can be sorted according to arbitrary sorting functions. To do so, one must first define a function that takes two key: value pairs, represented as tuples and returns a Bool such that the return value is true if the first key: value pair should appear in the sorted result before the second key: value pair.

This function can then be passed into the dictionary's sorted(by:) method which will return a sorted array of key: value pairs. E.g. to sort the constants dictionary by the value of the constant plus the number of characters in the constant's name we could write:

func weirdSort(_ lhs: (String, Double), _ rhs: (String, Double)) -> Bool {
  let left = lhs.1 + Double(lhs.0.count)
  let right = rhs.1 + Double(rhs.0.count)
  return left < right
}

let sortedConstants = constants.sorted(by: weirdSort)
// => [(key "e", value 2.71828), (key "phi", value 1.618033), (key "pi", value 3.14159), (key "avogadro", value 6.02214076e+22)]

Instructions

In this exercise, you're implementing a way to keep track of the high scores for the most popular game in your local arcade hall.

You have 7 functions to implement, all related to returning and manipulating a dictionary of high score data.

1. Define a new high score dictionary

Create a function newScoreBoard() that takes no parameters and returns a new high score dictionary which uses values of type String for the keys and values of type Int as the values.

2. Add players to the high score dictionary

To add a player to the high score dictionary, define addPlayer, which is a function which takes 3 parameters:

  • The first parameter is the dictionary of scores. This should be an in-out parameter.
  • The second parameter is the name of a player as a string.
  • The third parameter is the score as an integer. The parameter is optional, implement the third parameter with a default value of 0.
addPlayer(&highScores, "Dave Thomas")
// Adds "Dave Thomas" to the dictionary with a high score of 0.
addPlayer(&highScores, "José Valim", 486_373)
// Adds "José Valim" to the dictionary with a high score of 486_373.

3. Remove players from the score dictionary

To remove a player from the high score dictionary, define removePlayer, which takes 2 parameters:

  • The first parameter is the dictionary of scores. This should be an in-out parameter.
  • The second parameter is the name of the player as a string.

This function should remove the player from the dictionary if they are in it and do nothing otherwise.

removePlayer(&highScores, "Dave Thomas")
// Removes "Dave Thomas" from thee dictionary
removePlayer(&highScores, "Rose Fanaras")
// Doesn't alter the dictionary as "Rose Fanaras" is not in the dictionary.

4. Reset a player's score

To reset a player's score, define resetPlayer, which takes 2 parameters:

  • The first parameter is the dictionary of scores. This should be an in-out parameter.
  • The second parameter is the name of the player as a string, whose score you wish to reset.

The function will set the score of the player to 0. If the player is not in the dictionary, then nothing should happen.

resetScore(&highScores, "Dave Thomas")
// High score for "Dave Thomas" set to 0

5. Update a player's score

To update a players score by adding to the previous score, define updateScore, which takes 3 parameters:

  • The first parameter is the dictionary of scores. This should be an in-out parameter.
  • The second parameter is the name of the player as a string, whose score you wish to update.
  • The third parameter is the score that you wish to add to the stored high score.
addPlayer(&highScores, "Freyja Ćirić", 12_771_008)
updateScore(&highscores, "Freyja Ćirić", 73)
// Score for "Freyja Ćirić" updated to 12_771_081

6. Get a list of players with scores ordered by player name

Define the function orderByPlayers, which takes 1 parameter:

  • The first parameter is the dictionary of scores.

The function will return an array of (String, Int) tuples that are the players and their high scores sorted in ascending order by the player's name.

orderByPlayers(highScores)
// => [("Dave Thomas", 0), ("Freyja Ćirić", 12_771_091), ("José Valim", 486_373)]

7. Get a list of players ordered by player score in decreasing order

To get a list of players ordered by scores in decreasing order, define orderByScores, which takes 1 parameter:

  • The first parameter is the dictionary of scores.

The function will return an array of (String, Int) tuples that are the players and their high scores sorted in descending order by the player's score.

orderByScores(highScores)
# => [("Freyja Ćirić", 12_771_091), ("José Valim", 486_373), ("Dave Thomas", 0)]
Edit via GitHub The link opens in a new window or tab
Swift Exercism

Ready to start High Score Board?

Sign up to Exercism to learn and master Swift with 35 concepts, 100 exercises, and real human mentoring, all for free.