<Lua> おみくじ/複数の文字列の内の1つを無作為に選択する

Last modified: 2019-07-21

ここではLuaでおみくじ、つまり複数用意した文字列の中のいずれかを無作為に選択して表示するプログラムを作成する。

解説

配列としてのテーブル型とその初期化

Luaには “テーブル型” という多目的のデータ型があり、複数のデータを並べて1つのテーブル型変数に入れることができる。テーブル型は文字列と値を組にして値を出し入れする形(“連想配列” や “辞書” などと呼ばれる型)でも使えるが、ここでは単純に値を並べる “配列” としての使い方をする。

テーブル型を配列として初期化するには

t = {1, 2, 3}

のようにコンマ区切りの値を波括弧で囲った形をとる。

おみくじのプログラムを作る際には吉凶の文字列をまとめて用意することになり

omikuji = {'大吉', '中吉', '小吉', '吉', '末吉', '凶', '大凶'}

のように並べて記述する。

ランダムな数値を出力

ランダムな数値を出力するには一般的に言語を問わず

  1. ランダムな数値の元(seed:種)となるデータを与える
  2. ランダムな数値を(中の計算によって)得る操作を行う

という複数の段階がとられる。ただしこれは(他の言語と同様に)厳密なランダム値が得られるものではなく疑似乱数と呼ばれるものとなる。

ランダムな数値の元となるデータを与える部分では現在のシステム日時を数値として取得したものが一般的に使われる。これをLuaで記述すると

math.randomseed(os.time())

となる。

値を得る操作は

-- 0から1の範囲で取得する場合
math.random()

-- 1から指定値の範囲で取得する場合
math.random([最大値])

-- 最小値と最大値を指定する場合
math.random([最小値], [最大値])

のいずれかとなる。ここでは2番目の形が使いやすい。

下のコマンドを繰り返し実行すると、 “1” から “5” までのいずれかの数字が表示される。ただしシステム時刻の “秒” 部分が変わるまでは何度繰り返し実行しても同じ値が出る。

$ lua -e "math.randomseed(os.time()); print(math.random(5))"
(1から5までのいずれかの数字が表示される)

os.time()は秒単位よりも細かい単位での時刻情報を返さないため、1秒以内に繰り返し実行しても異なる値が得られるようにすることはできず、Luaの標準機能としては他に秒単位よりも細かい単位での時刻を取得する方法は提供されていない。Luaを自作プログラムの中で使えるようにしている場合、Luaから呼び出し可能な関数を用意してその中でOS依存の方法(POSIX準拠OSのgettimeofday()やWindowsのGetSystemTime()など)で得られた値を用いて乱数の種を設定するといった方法も考えられるが、実際にはそこまでしなくても多くの場合において(秒単位でも)問題にはならないと思われる。

配列としてのテーブル型の要素数を取得

配列としてのテーブル型の中に含まれるデータ(要素)の数は#[テーブル変数]で得られる。

下の例では要素数が3つなので “3” が出力される。

$ lua -e "t = {12, 34, 56}; print(#t)"
3

配列としてのテーブル型から個別の要素を取り出す

配列としてのテーブル型変数から個別の要素を取り出すには、角括弧の中に “何番目の要素か” を示す番号を入れる。最初の番号は1で最後の番号は#[テーブル変数]になる。

$ lua -e "omikuji = {'大吉', '中吉', '小吉', '吉', '末吉', '凶', '大凶'}; print(omikuji[1])"
大吉
$ lua -e "omikuji = {'大吉', '中吉', '小吉', '吉', '末吉', '凶', '大凶'}; print(omikuji[2])"
中吉
$ lua -e "omikuji = {'大吉', '中吉', '小吉', '吉', '末吉', '凶', '大凶'}; print(omikuji[#omikuji])"
大凶

コード例

以上の内容を踏まえておみくじのプログラムを記述すると下のようになる。

[任意]ファイル名:004_omikuji.lua エンコーディング:UTF-8

#! /usr/bin/lua
-- -*- coding: utf-8 -*-

--[[--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
動作確認バージョン: 5.3, JIT2.1
--  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --]]

-----
----- おみくじ (複数の文字列の内の1つを無作為に選択して表示)
-----

do
    -- 複数のデータを入れることのできる「テーブル」という型
    -- ここでは結果の文字列(後でいずれかを取り出す)を格納して配列として用いる
    -- 要素の番号は0ではなく1からとなる
    local omikuji = {'大吉', '中吉', '小吉', '吉', '末吉', '凶', '大凶'}

    -- math.randomseed()にos.time()の結果(現在のシステム日時)を入れ
    -- math.random()でランダムな値が得られるようにする
    -- (他の言語でもよく用いられる手法)
    math.randomseed(os.time())

    -- ランダムな値を得る
    -- math.random()は値の取得方法が幾つかあり、引数の付け方で変わる
    -- 1つの整数を指定すると1からその値までの整数が得られる
    -- 「#omikuji」はomikujiの長さ(要素数)でこの場合は「7」
    local num = math.random(#omikuji)

    -- ランダムな値を「何番目を参照するか」の部分に用いて
    -- それに対応する文字列を表示
    print(('結果は %s (値は %d)'):format(omikuji[num], num))
end

-- 終了

下は実行例。結果はシステム時刻の “秒” が変わるまでは繰り返し実行しても変わらない。

$ lua [004_omikuji.luaの場所]
結果は 大凶 (値は 7)

$ lua [004_omikuji.luaの場所]
結果は 末吉 (値は 5)

$ lua [004_omikuji.luaの場所]
結果は 吉 (値は 4)
  • 使用したバージョン
    • Lua 5.3.3
    • LuaJIT 2.1.0 Beta 3