トラック
/
Swift
Swift
/
演習
/
ハイスコアボード
ハイスコアボード

ハイスコアボード

学習演習

はじめに

辞書は、Swiftの主要なコレクション型の1つです。 辞書は、一意のキーとそれに対応する値との対応関係を、順序を持たずに保持します。 辞書の中のキーはすべて同じ型でなければならず、値もすべて同じ型である必要があります。

辞書リテラルは、key: valueのペアをカンマで区切り、角括弧([])で囲んで書きます。

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<Key, Value>と、省略記法の[Key: Value]という2通りの方法で明示的に書くことができます。

空の辞書を作るには、キーと値の型を明示的に指定します。

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

値へのアクセス

値にアクセスするには、サブスクリプト記法を使います。 辞書の名前に続けて、角括弧の中にキーを書きます。 キーが辞書に存在しない可能性があるため、サブスクリプトによるアクセスはオプショナル(Value?)を返します。 キーが存在すれば、Swiftはラップされた値を返します。存在しなければ、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

オプショナルを扱わずに済むように、defaultを使ってデフォルト値を指定できます。

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"

辞書を変更する

varで宣言した可変の辞書では、サブスクリプトへの代入を使ってキーと値のペアを追加したり更新したりできます。

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

辞書の繰り返し処理

for-inループを使うと、辞書のキーと値のペアを1つずつ取り出して繰り返し処理できます。 各要素は(key, value)のタプルとして渡されます。

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

辞書を並べ替える

辞書には順序がないため、並べ替えるとキーと値のペアの配列が得られます。 sorted(by:)メソッドにクロージャーを渡すと、2つの(key, value)タプルを比較し、1つ目のタプルが2つ目より前に来るべき場合にtrueを返すようにできます。

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)

説明

この演習では、地元のゲームセンターで一番人気のゲームのハイスコアを記録する仕組みを実装します。

実装する関数は7つあり、いずれもハイスコアのデータが入った辞書を返したり、操作したりするためのものです。

1. 新しいハイスコアの辞書を定義する

newScoreBoard()という関数を作成してください。この関数は仮引数を取らず、新しいハイスコアの辞書を返します。辞書のキーにはString型の値、値にはInt型の値を使います。

2. ハイスコアの辞書にプレイヤーを追加する

ハイスコアの辞書にプレイヤーを追加するには、addPlayer(_:_:_:)を定義してください。これは3つの仮引数を取る関数です。

  • 1つ目の仮引数は、スコアの辞書です。 これはin-out仮引数にします。
  • 2つ目の仮引数は、プレイヤーの名前を表す文字列です。
  • 3つ目の仮引数は、スコアを表す整数です。 この仮引数は省略可能なので、デフォルト値の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. スコアの辞書からプレイヤーを削除する

ハイスコアの辞書からプレイヤーを削除するには、removePlayer(_:_:)を定義してください。これは2つの仮引数を取ります。

  • 1つ目の仮引数は、スコアの辞書です。 これはin-out仮引数にします。
  • 2つ目の仮引数は、プレイヤーの名前を表す文字列です。

この関数は、プレイヤーが辞書にいればそのプレイヤーを辞書から削除し、いなければ何もしません。

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. プレイヤーのスコアをリセットする

プレイヤーのスコアをリセットするには、resetPlayer(_:_:)を定義してください。これは2つの仮引数を取ります。

  • 1つ目の仮引数は、スコアの辞書です。 これはin-out仮引数にします。
  • 2つ目の仮引数は、スコアをリセットしたいプレイヤーの名前を表す文字列です。

この関数は、そのプレイヤーのスコアを0に設定します。 プレイヤーが辞書にいない場合は、何もしません。

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

5. プレイヤーのスコアを更新する

前回のスコアに加算してプレイヤーのスコアを更新するには、updateScoreを定義してください。これは3つの仮引数を取ります。

  • 1つ目の仮引数は、スコアの辞書です。これはin-out仮引数にします。
  • 2つ目の仮引数は、スコアを更新したいプレイヤーの名前を表す文字列です。
  • 3つ目の仮引数は、記録されているハイスコアに加算したいスコアです。
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. プレイヤー名で並べた、スコア付きのプレイヤーのリストを取得する

orderByPlayersという関数を定義してください。これは1つの仮引数を取ります。

  • 1つ目の仮引数は、スコアの辞書です。

この関数は、プレイヤーとそのハイスコアを組にした(String, Int)タプルの配列を返します。並び順は、プレイヤー名の昇順です。

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. プレイヤーのスコアの降順で並べたプレイヤーのリストを取得する

プレイヤーをスコアの降順で並べたリストを取得するには、orderByScoresを定義してください。これは1つの仮引数を取ります。

  • 1つ目の仮引数は、スコアの辞書です。

この関数は、プレイヤーとそのハイスコアを組にした(String, Int)タプルの配列を返します。並び順は、プレイヤーのスコアの降順です。

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)]
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
Swift Exercism

ハイスコアボードを始める準備はできましたか?

Exercismに登録すれば、35個のコンセプト116個の演習、そして本物の人間によるメンタリングとともに、Swiftを学んでマスターできます。すべて無料です。