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

High Score Board

Learning Exercise

Introduction

Dictionaries are one of Swift's primary collection types. A dictionary stores unordered associations between unique keys and corresponding values. All keys in a dictionary must be of the same type, and all values must also share the same type.

Dictionary literals are written as comma-separated key: value pairs enclosed in square brackets:

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.02214076e23
]

Dictionary types can be written explicitly in two ways: Dictionary<Key, Value> or the shorthand syntax [Key: Value].

To create an empty dictionary, specify its key and value types explicitly:

var emptyDict1: [Int: Int] = [:]
var emptyDict2 = [Character: String]()
var emptyDict3 = Dictionary<Int, Double>()

Accessing Values

You can access values using subscript notation: place the key inside square brackets after the dictionary name. Because a key might not exist in the dictionary, subscript access returns an optional (Value?). If the key is present, Swift returns the wrapped value; if not, it returns nil:

let munster: String? = addresses["The Munsters"]
// Returns Optional("1313 Mockingbird Lane")

let carmichael = sequences["Carmichael"]
// Returns Optional([561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841])

let planck = constants["planck"]
// Returns nil

To avoid working with optionals, you can provide a default value using the default parameter:

let e: Double = constants["e", default: 0]
// Returns 2.71828

let hoagie: [Int] = sequences["Hoagie", default: []]
// Returns []

let betty = addresses["Betty Cooper", default: "Address unknown"]
// Returns "Address unknown"

Modifying Dictionaries

For mutable dictionaries declared with var, you can add or update key-value pairs using subscript assignment:

sequences["Euler's totient"]?.append(contentsOf: [6, 4])
// sequences["Euler's totient"] is now [1, 1, 2, 2, 4, 2, 6, 4, 6, 4]

addresses["Betty Cooper"] = "111 Queens Ave."
addresses["Betty Cooper", default: "Address unknown"]
// Returns "111 Queens Ave."

constants["Gelfond's"] = 23.140692
// Compiler error: Cannot assign through subscript: 'constants' is a 'let' constant

Iterating Over a Dictionary

You can iterate through each key-value pair of a dictionary using a for-in loop. Each item is provided as a (key, value) tuple:

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

Sorting Dictionaries

Because dictionaries are unordered, sorting them produces an array of key-value pairs. You can pass a closure to the sorted(by:) method that compares two (key, value) tuples and returns true if the first tuple should appear before the second:

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

let sortedConstants = constants.sorted(by: sortByNameLengthThenValue)

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.
var highScores = newScoreBoard()
addPlayer(&highScores, "Dave Thomas")
// Returns ["Dave Thomas": 0]
addPlayer(&highScores, "José Valim", 486_373)
// Returns ["Dave Thomas": 0, "José Valim": 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.

var highScores = ["Dave Thomas": 0, "José Valim": 486_373]
removePlayer(&highScores, "Dave Thomas")
// Returns ["José Valim": 486_373]
removePlayer(&highScores, "Rose Fanaras")
// Returns ["José Valim": 486_373]

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.

var highScores = ["Dave Thomas": 486_373, "José Valim": 10]
resetScore(&highScores, "Dave Thomas")
// Returns ["Dave Thomas": 0, "José Valim": 10]

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.
var highScores = ["Dave Thomas": 0, "José Valim": 486_373]
addPlayer(&highScores, "Freyja Ćirić", 12_771_008)
updateScore(&highScores, "Freyja Ćirić", 73)
// Returns ["Dave Thomas": 0, "José Valim": 486_373, "Freyja Ćirić": 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.

var highScores = ["Dave Thomas": 0, "José Valim": 486_373, "Freyja Ćirić": 12_771_091]
orderByPlayers(highScores)
// Returns [("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.

var highScores = ["Dave Thomas": 0, "José Valim": 486_373, "Freyja Ćirić": 12_771_091]
orderByScores(highScores)
// Returns [("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 concepts116 exercises, and real human mentoring, all for free.