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

ハイスコア

初級

説明

ゲームプレイヤーのハイスコアリストを管理します。

古典的なアーケードゲームであるFroggerのハイスコアを扱うコンポーネントを作ることが課題です。Froggerは、史上最も売れた、そして最も中毒性の高いゲームのひとつであり、アーケード時代の名作です。 さらに、リストから最高スコア、最後に追加されたスコア、上位3つのスコアを返すメソッドを書くことも課題です。

AWKでの並べ替え

この演習では、出力を特定の方法で並べ替える必要があります。 多くのプログラミング言語と同様に、配列を繰り返し処理するときの順序は実装に依存し、一見ランダムに見えることがあります。 たいていの場合、これは人間が望む並びではありません。 GNU awkには、並べ替えのための機能がいくつか用意されています。

  1. asort:配列の_値_に基づいて、数値でインデックス付けされた配列を並べ替えます。

    #!gawk 
    BEGIN {
        for (i = 1; i <= 5; i++)
            nums[i] = int(100 * rand())
    
        # returns the array size
        n = asort(nums, sorted)
    
        for (i = 1; i <= n; i++)
            print i, nums[i], sorted[i]
    }
    

    この出力は次のようになります。

    1 92 30
    2 59 57
    3 30 59
    4 57 74
    5 74 92
    

    n = asort(array)という書き方では、指定した配列をその場で並べ替えます。

    これは、数値でインデックス付けされた配列で特に役立ちます。 sorted配列を埋める処理では、元の配列のインデックスは破棄されます。 sorted配列のインデックスは1からnまでになります。

  2. asorti:配列の_インデックス_に基づいて配列を並べ替えます。

    asorti関数は、「元」の配列のインデックスを並べ替えたものを格納した「出力先」の配列を用意します。

    #!gawk
    BEGIN {
        nums["foo"] = int(100 * rand())
        nums["bar"] = int(100 * rand())
        nums["qux"] = int(100 * rand())
    
        print "unordered"
        for (i in nums)
            print i, nums[i]
    
        print "ordered by index"
        n = asorti(nums, sorted)
        for (i = 1; i <= n; i++)
            print sorted[i], nums[sorted[i]]
    }
    

    この出力は次のようになります。

    unordered
    foo 92
    qux 30
    bar 59
    ordered by index
    bar 59
    foo 92
    qux 30
    
  3. PROCINFO["sorted_in"]:配列を指定した順序でたどります。

    組み込みのPROCINFO配列には、実行中のawkプロセスに関する多くの情報が含まれています。 この配列の興味深い要素の1つがsorted_inです。 この配列のキーの値は、for (indx in array)ループで配列のインデックスが処理される順序を制御する関数の名前です。

    この関数には、自分で定義した関数の名前を指定することもできますし、あらかじめ用意されている便利な並べ替え関数を使うこともできます。たとえば、次のようなものがあります。

    • "@ind_str_asc"、"@ind_str_desc":配列をインデックスで並べ替えます。アルファベット順で、昇順または降順に並べ替えます。
    • "@ind_num_asc"、"@ind_num_desc":配列をインデックスで並べ替えます。数値として、昇順または降順に並べ替えます。
    • "@val_str_asc"、"@val_str_desc":配列を値で並べ替えます。アルファベット順で、昇順または降順に並べ替えます。
    • "@val_num_asc"、"@val_num_desc":配列を値で並べ替えます。数値として、昇順または降順に並べ替えます。

    先ほどのasortの例は、次のように書けます。

    PROCINFO["sorted_in"] = "@val_num_asc"
    for (idx in nums)
        print idx, nums[idx]
    
    3 30
    4 57
    2 59
    5 74
    1 92
    

    asortiの例は、次のように書けます。

    PROCINFO["sorted_in"] = "@ind_str_asc"
    for (idx in nums)
        print idx, nums[idx]
    
    bar 59
    foo 92
    qux 30
    

    この方法なら、一時的なsorted配列と戻り値のnを使わずに済みます。 すっきりと、無駄がありません。

ユーザー定義の並べ替え関数

ユーザー定義の並べ替え関数は、4つの仮引数を受け取ります。 ある配列要素のインデックスと値、そしてもう1つの配列要素のインデックスと値です。

function compare(idx1, val1, idx2, val2) {...}

戻り値は次のとおりです。

  • 0より小さい場合:idx1がidx2より前に来ます。
  • 0より大きい場合:idx1がidx2より後に来ます。
  • 0の場合:両方のインデックスの並べ替えの優先順位は同じですが、どちらが先になるかは決まっていません。

for (idx in array)の順序を制御するPROCINFO["sorted_in"]に加えて、asortとasortiはどちらも、比較関数の名前を3番目の仮引数として受け取ることができます。

参考リンク


出典

80年代のアーケードゲームFroggerへのオマージュ
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
AWK Exercism

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

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