はじめに
この記事は東京高専プロコンゼミ Advent Calendar①1日目の記事です。
https://adventar.org/calendars/5509
Discordとは?
ゲーマー向けの無料ボイスチャットアプリ。SlackやTeamsと同じように1つのサーバーと複数のチャンネルを使ったコミュニケーションツールです。
Discordのいいところを適当に箇条書きで挙げておきます。
- フレンドが今やっているゲームがわかる(マルチプレイに誘いやすい)
- 役職(ロール)という概念があり、かなり細かく権限の設定ができる(ネッ友とリア友が混ざってるサーバーだとすごく便利です)
- ユーザーが多い
- 無料で音声通話が25人まで、ビデオ通話が10人までできる
- Bot開発者にやさしい(Botについては次の章で詳しく説明します)
みんなDiscord、使おう!!(宣伝)
Discord Botとは?
Discordは色々なAPIを無料で提供しています。これを使ってbotを作ることで、音声通話で音楽を流したり、おみくじを作ったり、色々な機能を実現することができます。
APIの公式ドキュメントを1から見て自分でAPIを叩くのは面倒ですが、素晴らしいことに有志のユーザーがAPIのWrapperを作ってくれているので、botを作って動かすのはそう難しいことではありません。(プログラミングの基礎を知っていれば簡単に作れると思います)
現在メジャーなWrapperには、
・JavaScriptで実装されている discord.js
・Pythonで実装されている discord.py
の2つがあります。
この記事では discord.py を使って簡単なbotを実装し動かすところまでを説明していきたいと思います!
簡単なbotを作ってみよう!!
というわけで、ようやく本題に入ります。今回は、じゃんけんができるbotを1から作っていきます。
準備
まずは、環境構築を済ませましょう。
今回は入れると長くなってしまうのでpythonとpipの環境構築は省いて、API Tokenの取得とサーバーへのbotの導入,discord.pyのダウンロードを説明します。
tokenの取得
Discordにログインした状態で https://discord.com/developers/applications にアクセスします。すると、このような画面が出てくるので右上の"New Application"ボタンを押します。
出てきたポップアップのNAME欄にbotの名前を入力します.今回は"jyankenbot"と入力しました.これは読者の方が自由に変更しても大丈夫ですのでお好きな名前をつけてあげてください!
名前を入力したら"Create"ボタンを押します.
作成が終わると,この画面に遷移するので左のメニューにある"Bot"の部分をクリックしてください.
右上にある"Add Bot"ボタンを押してbotを追加します.
このようなポップアップが出てきますが,"Yes, do it!"を押してください.
作成に成功するとこのような表示がでてくるので,青い"Click to Reveal Token"をクリックしてください.Tokenが表示されます.
次の章ではプログラムにこのTokenを使うので,コピーするなりしてとっておいてください.(何度でも確認できるので個別に保存等はしなくて大丈夫です)
サーバーへのbotの導入
まずは新しくテスト用のサーバーを作りましょう!
サーバー名は適当で大丈夫ですし,アイコン画像もアップロードしなくてもサーバーを作ることができます.新規作成を押したらサーバーが作成されます!
次にbotの招待リンクを取得しましょう!
https://discord.com/developers/applications にアクセスして,先ほど作成したjyankenbotを選択したのち遷移されるページで,左のメニューの"OAuth2"の部分をクリックしてください.
クリックするとこのページに移るので,真ん中の"bot"のチェックボックスを選択してください.
少し下にスクロールすると"BOT PERMISSIONS"という欄があるので,"Administrator"を選択して下さい.これを選ぶとbotがサーバーに対してすべての行為を行えてしまうので,本当は良くないのですが今回はお試しで作るだけなので見逃してください.(ちゃんとしたbotを作るときはちゃんと権限を設定するようにしてください!!!!)
選択できたら画面中央にあるURLをコピーして,アクセスしてください.
アクセスするとbotをサーバーに追加する管理画面が表示されるので,先ほど作ったサーバーを選択して"はい"を押します.
認証ボタンを押す前にしっかり"管理者"にチェックがついていることを確認してください.
先ほど作ったサーバーのページに戻り,jyankenbotが追加されていれば成功です.お疲れさまでした.
discord.pyのダウンロード
ターミナルで以下のコマンドを実行するだけです、簡単!
$ pip install discord.py
プログラムを書く
環境構築が終わったら、さっそくコードを書いていきましょう!
まずはbot.pyファイルを作って,botのベースを書き込んでいきます。
from discord.ext import commands
TOKEN = "ここにさっき取得したトークンを入れる"
# botの初期化(command_prefixはコマンドの先頭につく文字を示している)
bot = commands.Bot(command_prefix="/")
# "/test"とメッセージが送られて来たらこの関数を実行する
@bot.command()
async def test(ctx): # 関数名がそのままコマンドになる
# メッセージが送られたチャンネルに"hello world"と送る
await ctx.send("hello world!!") # ctx.send()はctx.channel.send()のショートカット
if __name__ == "__main__":
# botを起動
bot.run(TOKEN)
これは,チャットに"/test"と送られると"hello world!!"と返すbotです.
また,このコードではdiscord.pyのコマンドフレームワークというものを使っており,botのコマンド関連のコードをスマートに書くことができています.
次のようなコードでも同じ機能を実装できますが、明らかに前述のコードの方がコードの量が短くきれいですし、コマンドが10個、20個と増えたときもスパゲッティコードにならずに済む実装です。
import discord
TOKEN = "ここにさっき取得したトークンを入れる"
bot = discord.Client()
# メッセージが送られて来たらこの関数を実行する
@bot.event
async def on_message(message):
# 文字列が"/"から始まっているかどうかを判定
if message.content.startswith("/"):
# 文字列の1文字目を切り捨てる
command = message.content[1:]
if command == "test":
# メッセージが送られたチャンネルに"hello world"と送る
await message.channel.send("hello world!!")
if __name__ == "__main__":
# botを起動
bot.run(TOKEN)
では実際にこのbotを動かしてテストしてみましょう!terminalでこのコマンドを実行してください.
$ python bot.py
このように"/test"と入力して"hello world!!"と返ってきたら成功です!
これでbotの基本的な部分が完成しました!
次はじゃんけんコマンドを作ります!!
from discord.ext import commands
from random import randint
TOKEN = "ここにさっき取得したトークンを入れる"
# botの初期化(command_prefixはコマンドの先頭につく文字を示している)
bot = commands.Bot(command_prefix="/")
# "/test"とメッセージが送られて来たらこの関数を実行する
@bot.command()
async def test(ctx): # 関数名がそのままコマンドになる
# メッセージが送られたチャンネルに"hello world"と送る
await ctx.send("hello world!!") # ctx.send()はctx.channel.send()のショートカット
def hand_to_int(hand):
"""
グー: 0, チョキ: 1, パー: 2 とする
handはカタカナ,ひらがな表記,数字に対応する
"""
hand_int = None
if hand in ["グー", "ぐー", "0"]:
hand_int = 0
elif hand in ["チョキ", "ちょき", "1"]:
hand_int = 1
elif hand in ["パー", "ぱー", "2"]:
hand_int = 2
return hand_int
def get_player_result(player_hand, bot_hand):
"""
勝利: 1, 敗北: 0, ひきわけ: 2 とする
result_table[player_hand][bot_hand]で結果がわかるようにする
"""
result_table = [
[2, 1, 0],
[0, 2, 1],
[1, 0, 2]
]
return result_table[player_hand][bot_hand]
@bot.command()
async def jyanken(ctx, hand):
hand_emoji_list = [":fist:", ":v:", ":hand_splayed:"]
player_hand = hand_to_int(hand)
if player_hand is None:
await ctx.send("不正な手です!もう一度やり直してください!!")
return
bot_hand = randint(0, 2)
await ctx.send(
f"あなた: {hand_emoji_list[player_hand]}\n"
f"Bot: {hand_emoji_list[bot_hand]}"
)
result = get_player_result(player_hand, bot_hand)
if result == 0:
await ctx.send("残念,あなたの負けです!!")
elif result == 1:
await ctx.send("おめでとうございます!!,あなたの勝ちです:tada:")
else:
await ctx.send("あいこ!")
if __name__ == "__main__":
# botを起動
bot.run(TOKEN)
これでbotとじゃんけんができるようになりました!
これから上記のコードの解説をしていきます.
まずこの部分ですが,コマンドフレームワークの恩恵でコマンド関数に引数を追加するだけで簡単に
/jyanken ぱー
のようなコマンドの後ろの値を取得することができます!
@bot.command()
async def jyanken(ctx, hand):
上の部分でとった手を表すテキストをプログラムで扱いやすいように,この関数を使って変換します.
hand
が手を表すテキストであれば対応する数字を返します.
def hand_to_int(hand):
"""
グー: 0, チョキ: 1, パー: 2 とする
handはカタカナ,ひらがな表記,数字に対応する
"""
hand_int = None
if hand in ["グー", "ぐー", "0"]:
hand_int = 0
elif hand in ["チョキ", "ちょき", "1"]:
hand_int = 1
elif hand in ["パー", "ぱー", "2"]:
hand_int = 2
return hand_int
先ほどのように手を数字化したので,事前に勝ち負けを計算した表(2次元配列)を利用して,数字化されたじゃんけん結果を簡単に得ることができます.
def get_player_result(player_hand, bot_hand):
"""
勝利: 1, 敗北: 0, ひきわけ: 2 とする
result_table[player_hand][bot_hand]で結果がわかるようにする
"""
result_table = [
[2, 1, 0],
[0, 2, 1],
[1, 0, 2]
]
return result_table[player_hand][bot_hand]
最後に結果ごとにメッセージを送ります.
result = get_player_result(player_hand, bot_hand)
if result == 0:
await ctx.send("残念,あなたの負けです!!")
elif result == 1:
await ctx.send("おめでとうございます!!,あなたの勝ちです:tada:")
else:
await ctx.send("あいこ!")
コードが書けたら実行して試してみましょう!!
先ほどと同じようにターミナルで以下のコマンドを実行するだけです!
$ python bot.py
このようにじゃんけんができれば成功です!!(僕は勝ててませんが,みなさんは勝てましたか?)
最後に
こんな感じでDiscord Botは簡単に作ることができます!今回はじゃんけんbotを作りましたが,Discord Botは本当に色々なことができるので是非皆さんもオリジナルbotを作って遊んでみてください!!
本当はもっとコードについて詳しく解説したり,botをクラウドにデプロイするところまで書きたかったのですが,さすがにめんどくさい記事が長くなってしまうのでこのぐらいにしておきます.(デプロイに関してはカレンダーの担当日がもう一日あるので,もしかしたらそこで書くかも?)
最後になりますが,拙い文章にここまでお付き合いいただきありがとうございました!!