LoginSignup
33
16

More than 3 years have passed since last update.

ElixirでDiscordのbotを作る

Last updated at Posted at 2019-05-24

ElixirでDiscordのbot作るの楽しい~って思ったので書きました。
Elixir自体のインストールはこちらからどうぞ。
Discord botアカウントの作成等はこちらの記事が参考になります。

作るもの

  • !dice 2d6と送信するとダイスを振ってくれる
  • 結果は[(,区切りの各ダイス値)] 合計:(ダイスの合計値)のような形式で返ってくる

こんな感じのダイスロールbotを作ります。

作る

mix new discord_bot --sup

で新しいプロジェクトを作成します。
discord_botの部分は適宜変更してください。

ライブラリを導入する

今回はdiscord_alchemyを使用します。
Discord APIのラッパーライブラリです。

mix.exsを開き、depsを以下のように変更してください。

mix.exs
defp deps do
  [
    {:alchemy, "~> 0.6.1", hex: :discord_alchemy}
  ]
end

変更後、

mix deps.get

を実行することで、パッケージが取り込まれます。

pingされたら返事する

とりあえずbot界のHello, world!(?)を作りましょう。

最初に、config.exsにbotのトークンを書きます。

config/config.exs
config :discord_bot,
  discord_token: "bot token"

次に、botの処理を書きます。
lib/discord_bot/application.exを書き換えます。

lib/discord_bot/application.ex
defmodule DiscordBot.Application do
  use Application

  defmodule Commands do
    use Alchemy.Cogs

    Cogs.def ping do
      Cogs.say "pong!"
    end
  end

  def start(_, _) do
    token = Application.get_env(:discord_bot, :discord_token)
    run = Alchemy.Client.start(token)
    use Commands
    run
  end
end

これで!pingを送信したらpong!と返ってくるbotが完成しました!

mix run --no-halt

を実行することで、botが動作します。

ダイスを振る

さて、ついにダイスを振るコマンドを実装していきます。

Commandsモジュールで

Cogs.def コマンド名(引数) do
  # 処理
end

とすることでコマンドを定義できます。

まずは6面ダイスを2個振った結果を返すコマンドCommands内に定義してみます。

Cogs.def dice do
  dices = 1..2 |> Enum.map(fn _ -> 1..6 |> Enum.random end)
  result = dices |> Enum.sum
  Cogs.say("[#{dices |> Enum.join(",")}] 合計:#{result}")
end

2019-05-25_025646.png

できました!
やっていることは単純で、リスト[1, 2]のそれぞれにリスト[1, 2, ..., 6]からランダムに選ばれた値を突っ込んでるだけです。

Elixirのパイプライン演算子|>は、左の式の結果を右の式の第一引数に渡すものです。とてもべんりです。

m面ダイスをn個振る

最後に、!dice ndmの形式でダイスの個数、面数を指定できるようにします。
ついでに

  • 個数は1~100
  • 面数は1~1000

という制限もつけます。

Cogs.def コマンド名(引数)引数にはコマンド後の文字列が入ってくるので、それを利用してダイスの個数と面数を取得します。

後は、固定値だった26個数面数に置き換えるだけです。

Cogs.def dice(roll) do
  case Regex.run(~r/\A(\d|[1-9]\d+)d(\d|[1-9]\d+)\z/, roll) do
    [_, n, m] ->
      num = n |> String.to_integer
      face = m |> String.to_integer

      cond do
        num <= 0 || num > 100 ->
          Cogs.say("個数は1以上、100以下にしてください")
        face <= 0 || face > 1000 ->
          Cogs.say("面数は1以上、1000以下にしてください")
        true ->
          dices = 1..num |> Enum.map(fn _ -> 1..face |> Enum.random end)
          result = dices |> Enum.sum
          Cogs.say("[#{dices |> Enum.join(",")}] 合計:#{result}")
      end
    _ ->
      Cogs.say("ndmの形式で入力してください")
  end
end

2019-05-25_065253.png

これでダイスロールbotのできあがりです!

引数なしの!diceコマンドを残しておくと、!diceした時は2d6を振り、!dice ndmした時はm面ダイスをn個振ってくれるのでべんりかもしれません。

さいごに

Elixirたのしい~~~!!!
文章を書くのは苦手なのでとてもつかれた。

おまけ

完成したlib/discord_bot/application.exの全文です。

lib/discord_bot/application.ex
defmodule DiscordBot.Application do
  use Application

  defmodule Commands do
    use Alchemy.Cogs

    Cogs.def dice do
      dices = 1..2 |> Enum.map(fn _ -> 1..6 |> Enum.random end)
      result = dices |> Enum.sum
      Cogs.say("[#{dices |> Enum.join(",")}] 合計:#{result}")
    end

    Cogs.def dice(roll) do
      case Regex.run(~r/\A(\d|[1-9]\d+)d(\d|[1-9]\d+)\z/, roll) do
        [_, n, m] ->
          num = n |> String.to_integer
          face = m |> String.to_integer

          cond do
            num <= 0 || num > 100 ->
              Cogs.say("個数は1以上、100以下にしてください")
            face <= 0 || face > 1000 ->
              Cogs.say("面数は1以上、1000以下にしてください")
            true ->
              dices = 1..num |> Enum.map(fn _ -> 1..face |> Enum.random end)
              result = dices |> Enum.sum
              Cogs.say("[#{dices |> Enum.join(",")}] 合計:#{result}")
          end
        _ ->
          Cogs.say("ndmの形式で入力してください")
      end
    end
  end

  def start(_, _) do
    token = Application.get_env(:discord_bot, :discord_token)
    run = Alchemy.Client.start(token)
    use Commands
    run
  end
end
33
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
16