トラック
/
Elixir
Elixir
/
演習
/
ハイスコア
ハイスコア

ハイスコア

学習演習

はじめに

マップ

マップは、Elixirで情報をキーと値のペアで保存するためのデータ構造です。他の言語では、連想配列(PHP)、ハッシュ(Perl 5、Raku)、辞書(Python)と呼ばれることもあります。

キーと値にはどんなデータ型でも使えますが、キーがアトムのときは省略した書き方を使えます。マップは、アクセスや返却のときにエントリの順序を保証しません。

リテラルの書き方

空のマップは、単に%{}と書いて宣言します。マップリテラルに要素を追加したいときは、2つの書き方があります。

# If the key is an atom:
%{atom_key: 1}

# If the key is a different type:
%{1 => :atom_value}

# You can even mix these if the atom form comes second:
%{"first_form" => :a, atom_form: :b}

決まった書き方が定められているわけではありませんが、キーと値のリテラルのペアは一貫した書き方で表すようにしましょう。

Mapモジュールの関数

Elixirには、マップを扱うための関数が_Mapモジュール_にたくさん用意されています。_Mapモジュール_の関数の中には、マップの変換を助けるために、_無名関数_を引数として渡す必要があるものもあります。

定数としてのモジュール属性

Elixirでは、モジュール属性を定義して、関数の中で定数として使うことができます。

defmodule Example do
  # Defines the attribute as the value 1
  @constant_number 1

  def example_value() do
    # Returns the value 1
    @constant_number
  end
end

モジュールの定数を定義するために使う場合、属性にはコンパイル時に評価できる任意の式を書けます。コンパイル後は、モジュール属性はコンパイル中に展開されてしまうため、アクセスできません。これは、Cなどの言語で定義するマクロに似ています。

説明

この演習では、地元のゲームセンターで一番人気のゲームのハイスコアを記録しておく方法を実装します。

1. 新しいハイスコアのマップを定義する

新しいハイスコアのマップを作るには、HighScore.new/0関数を定義します。この関数は引数を取らず、新しい空のハイスコアのマップを返します。

HighScore.new()
# => %{}

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

ハイスコアのマップにプレイヤーを追加するには、HighScore.add_player/3を定義します。これは3つの引数を取る関数です。

  • 1つ目の引数は、スコアのマップです。
  • 2つ目の引数は、プレイヤーの名前を表す文字列です。
  • 3つ目の引数は、整数のスコアです。この引数は省略可能で、デフォルト値0で実装します。

デフォルトの初期スコアは、モジュール属性に保存します。あとでもう一度必要になります。

score_map = HighScore.new()
# => %{}
score_map = HighScore.add_player(score_map, "Dave Thomas")
# => %{"Dave Thomas" => 0}
score_map = HighScore.add_player(score_map, "José Valim", 486_373)
# => %{"Dave Thomas" => 0, "José Valim"=> 486_373}

3. スコアのマップからプレイヤーを削除する

スコアのマップからプレイヤーを削除するには、HighScore.remove_player/2を定義します。これは2つの引数を取ります。

  • 1つ目の引数は、スコアのマップです。
  • 2つ目の引数は、プレイヤーの名前を表す文字列です。
score_map = HighScore.new()
# => %{}
score_map = HighScore.add_player(score_map, "Dave Thomas")
# => %{"Dave Thomas" => 0}
score_map = HighScore.remove_player(score_map, "Dave Thomas")
# => %{}

4. プレイヤーのスコアをリセットする

プレイヤーのスコアをリセットするには、HighScore.reset_score/2を定義します。これは2つの引数を取ります。

  • 1つ目の引数は、スコアのマップです。
  • 2つ目の引数は、スコアをリセットしたいプレイヤーの名前を表す文字列です。

この関数は、プレイヤーがスコアを持っていない場合でも動作する必要があります。

score_map = HighScore.new()
# => %{}
score_map = HighScore.add_player(score_map, "José Valim", 486_373)
# => %{"José Valim"=> 486_373}
score_map = HighScore.reset_score(score_map, "José Valim")
# => %{"José Valim"=> 0}

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

以前のスコアに加算してプレイヤーのスコアを更新するには、HighScore.update_score/3を定義します。これは3つの引数を取ります。

  • 1つ目の引数は、スコアのマップです。
  • 2つ目の引数は、スコアを更新したいプレイヤーの名前を表す文字列です。
  • 3つ目の引数は、保存されているハイスコアに加算したいスコアです。

この関数は、プレイヤーが以前のスコアを持っていない場合でも動作する必要があります。その場合は、以前のスコアが0であるとみなします。

score_map = HighScore.new()
# => %{}
score_map = HighScore.add_player(score_map, "José Valim", 486_373)
# => %{"José Valim"=> 486_373}
score_map = HighScore.update_score(score_map, "José Valim", 5)
# => %{"José Valim"=> 486_378}

6. プレイヤーの配列を取得する

プレイヤーの配列を取得するには、HighScore.get_players/1を定義します。これは1つの引数を取ります。

  • 1つ目の引数は、スコアのマップです。
score_map = HighScore.new()
# => %{}
score_map = HighScore.add_player(score_map, "Dave Thomas", 2_374)
# => %{"Dave Thomas" => 2_374}
score_map = HighScore.add_player(score_map, "José Valim", 486_373)
# => %{"Dave Thomas" => 2_374, "José Valim"=> 486_373}
HighScore.get_players(score_map)
# => ["Dave Thomas", "José Valim"]
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
Elixir Exercism

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

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