2021年2・3月の振り返り

先月、先々月の振り返りです。

42Tokyoでやったこと

以下の2つの課題をクリアしました。

  1. Kubernetesの課題
  2. bash再実装の課題

また、課題外ではWebhook URLの作成をしました。

Kubernetesの課題

Kubernetesを使って7つのアプリケーション(FTPSサーバ、phpMyAdminMySQLなど)を立ち上げる課題です。

大変だったこと

レビューでの環境差異

現在リモートで課題を進めていることもあり、環境に差異が出ないよう、この課題はVMでレビューを行います(校舎だと違うかもしれません)。

しかし、レビューいただく際に以前レビューした時の設定が残っていて動作しなかったり、共有ディレクトリ内で実行するとパーミッションが上手く設定されなかったりといったことがありました。原因を突き止めるのが難しかったです。

各種アプリケーションの設定

特に印象に残っていることは以下の2つです。

  1. vsftpdがPID 1の時にSIGSEGVでクラッシュする挙動

    Alpine 3.12で起きた問題。おそらく、この GitHubのcommitログ に書かれている原因で発生しているのだと思います。

    他の生徒に教えていただき、ラッパースクリプトを使ってPIDを1以外にすることで対処しました。聞かなかったら絶対分からなかったです。

  2. phpMyAdmin 5.0.4でテーブルのドラッグ時にJavaScriptのエラーが発生(5.1.0で修正)

    エラーを確認した数日前に Issue が上がっていました。Issueが上がってなかったら解決方法が分からなかったと思います。

学んだこと

公式ドキュメントとIssueを参照することの大切さと、諦めない心を学びました。

bash再実装の課題

機能が制限されたbashの再実装をしました。bashの仕様や構文解析について知れて楽しかったです。

詳細については以下の記事にまとめています。

nafuka.hatenablog.com

Webhook URLの作成

42ではAPIを使って様々なデータを取得できるのですが、Webhookを設定することもできると聞き、Webhookのデータを受け取るURLを作成しました。

現在は42で開催されるイベントが作成されたら、Discordサーバに通知が行くようになっています。

画像は通知例です。

f:id:nafuka11:20210404195338p:plain:w400

AWS LambdaとAPI Gatewayを使って作りました。デプロイにはServerless Frameworkを使っています。

42Tokyoのコミット時間

合計 1日平均
2月 175時間41分 6.3時間
3月 213時間18分 6.9時間

bash再実装が楽しくて、3月は1日平均が少し増えました。

今後やること

以下の課題を進める予定です。

bash再実装の課題振り返り

42 Tokyo の課題でbashの再実装に取り組みました。本記事ではその振り返りをします。

課題の概要

機能が制限されたbashを再実装する課題です。

具体的には、

  • Simple command
  • いくつかのbuiltin command
    • cd, echo など。env など本来builtinでないコマンドも含みます
  • 構文解釈( ; | "" ''
  • リダイレクト(< > >>
  • 環境変数の展開

を実装します。
課題は2人の生徒で取り組む必要があります。

この課題をこなすことで、以下のことが学べたと思います。

  • bashの仕様
  • 構文解析(LexerとParser)
  • プロセスの作成、任意のプログラム実行
  • パイプ、リダイレクション
  • シグナルハンドリング

成果物

f:id:nafuka11:20210329023115g:plain

github.com

取り組み方

42 Tokyoの生徒、 ToYeah さんと課題に取り組みました。

調査

まずは bash で何を実装すべきか調べました。

The Architecture of Open Source Applications というオープンソースアプリケーションの設計について書かれた本の 日本語訳 を読みました。
この本にはbashアーキテクチャについて載っていました。

本を読んだところ、bashのメイン部分の実装は以下の4工程に分けられそうでした。

  1. Lexer(単語分割)
  2. Parser(構文解析
  3. Expansion(変数展開)
  4. Command execution(コマンド実行)

開発方法

開発は GitHub 上で行いました。

コードに変更を加える場合は基本的に Issue を立てた後、Issue に紐づくPullRequest を出し、相手にレビューしていただきました。

プロジェクト管理は Jootoガントチャートを作り、進捗を確認していました。
自分の進捗はこんな感じでした。課題着手から完了まで、おおよそ37日かかったようです。

f:id:nafuka11:20210328164757p:plain

ドキュメントは HackMD を使いました。議事録を残したり、参考URLを共有していました。

実装

1. Lexer(単語分割)

Lexerでは入力文字列を構文解析しやすいよう、単語に分割します。

例えば、

echo "hello w"'orld'; cat<file|wc

という入力文字列が渡された場合、

echo
"hello w"'orld'
;
cat
<
file
|
wc

に分割します。

状態の更新

入力文字列を先頭から1文字ずつ見ていって、状態を更新していきます。

状態は以下の3つのいずれかです。

  1. 通常
  2. シングルクォートの中
  3. ダブルクォートの中

今見ている文字が ' なら状態をシングルクォートの中に、 " なら状態をダブルクォートの中に更新します。
対応するクォートが現れたら、状態を通常に戻します。

単語分割

状態が通常の時にスペース、 ; | > など、単語を分割すべき文字を見つけたら、そこで単語を分割します。

Lexerの段階では、まだ " ' は残ったままです。" ' は 3. Expansion で除去します。

2. Parser(構文解析

Parserでは、分割された単語を先頭から1つずつ見て構文解析し、抽象構文木を作ります。

抽象構文木

抽象構文木とは、構文解析した結果をプログラムで処理しやすいよう木構造にしたデータです。

構文解析はリストでも実現できるようですが、木の方が文法の追加に柔軟に対応できそうなのでこちらを採用しました。

私たちの実装では、この入力文字列は、

cat < file1 | grep a | wc -l > file2 > file3 ; echo a | grep a; echo b

以下の図のようなデータ構造になります。

f:id:nafuka11:20210328170655p:plain

木の左下から右上にたどると、入力文字列と対応するようになっています。
コマンドノードには引数のリスト、リダイレクトのリストを持つようにしています。

構文解析方法

シェルの文法に関しては POSIXの規格 に載っている「Shell Grammar Rules」を参考にしました。バッカス・ナウア記法を理解するために、Railroad Diagram Generator で可視化して文法を確認しました。

規格を見たところ、今回の課題では ;|command の順に解釈していけば良さそうでした。

  • ; の解釈では、| の解釈の後、; の解釈と | の解釈のループに入ります。; がなくなったらループを抜けます。
  • | の解釈では、 command の解釈の後、 | の解釈と command の解釈のループに入ります。 | がなくなったらループを抜けます。
  • command の解釈では、リダイレクト(< > >> )が来たら次の単語をファイル名とし、それ以外はコマンド文字列とします。|; が来たり、単語がなくなったらループを抜けます。

……と文章で書いても難しいかもしれません。先ほどの抽象構文木の図に番号を振ってみました。

f:id:nafuka11:20210328171032p:plain

番号順に木が作られます。左下の末端からコマンドの子ノードを作り、親ノードに繋げていきます。

構文解析の方法は以下のURLを参考に作成しました。

エラー処理

; の前にコマンドがない場合、|> の後に単語がない場合は構文解析エラーになります。

echo > のような入力は構文解析エラーになります。一方で > file; は許容されます。

3. Expansion(変数展開)

Expansionは、コマンド実行前に呼び出され、コマンドの引数とリダイレクトの単語を処理します。
単語に含まれる $USER のような変数を展開し、" ' の除去も行います。

変数展開によって単語が分割されるため、ここで再度Lexerを実行します。
例えば、VAR="echo hello" という変数があり、$VAR という1つの単語が与えられたら、 2つの単語 echo , hello に分割されます。

4. Command execution(コマンド実行)

抽象構文木の左下まで降りて、右上に向かってコマンドを実行していきます。

パイプ

パイプするためには、木を登って降りてコマンドノードを見ていく必要があります。今回は木を登らず、構文解析時にコマンドノードをポインタで繋ぐことにしました。

f:id:nafuka11:20210328171309p:plain

パイプの実行方法

パイプが1つの場合

a | b のような場合は、1つパイプを作って、それぞれのプロセスの標準入出力を繋ぎます。

パイプが複数の場合

a | b | c のようにパイプが複数になった場合、少し複雑になります。コマンド b を実行する時には 入力側のパイプ、出力側のパイプ、2つのパイプが必要です。

これはパイプの最初、中間、最後と3つの状態で場合分けして考えられます。
パイプが増えると中間状態のコマンドが増えます。

  1. パイプの最初
    • パイプを作成し、パイプの片側を閉じ、片側を標準出力に繋ぎます。
  2. パイプの中間
    • 1で作成したパイプの片側を閉じ、片側を標準入力に繋ぎます。
    • パイプを作成し、パイプの片側を閉じ、片側を標準出力を繋ぎます。
  3. パイプの最後
    • 2で作成したパイプの片側を閉じ、片側を標準入力に繋ぎます。

私たちは pipe_state というenumで状態を持たせました。bitで read, writeのフラグを管理しても良かったかもしれません。

パイプの処理を図にするとこんな感じになります。

f:id:nafuka11:20210328171443p:plain

注意点として、使い終わったパイプは親、子プロセスともに閉じないといけません。そうしないと、パイプがずっと入力を待ち続けてしまいます。

リダイレクト

リダイレクトはパイプの後に行います。パイプする前にファイルを開いておき、パイプ後にファイルディスクリプタを上書きします。

builtinコマンドでの注意点

パイプで繋がれていないbuiltinコマンドの場合、子プロセスでなく親プロセスで実行されます。子プロセスにしてしまうとexportなど環境変数の設定が親プロセスに反映されないためです。

親プロセスでリダイレクトすると、親の標準入力、標準出力などが書き換わり、その後のコマンド実行に影響が出ます。
このため、上書きする前にファイルディスクリプタdup してバックアップし、リダイレクトが完了したら dup2 して復元する必要があります。

工夫したこと

データ構造の可視化

デバッグ時に、抽象構文木をdotファイルに出力、単語リストを標準出力するようにしました。

画像の左側が単語リスト、右側がdotファイルです。

f:id:nafuka11:20210328171544p:plain

dotファイルは Graphviz などのツールを使うと画像を生成できます。本記事の抽象構文木の図はdotファイルを Graphviz で生成したものです。

可視化により、不具合がどこで起こっているのか突き止めやすくなったと思います。また、図示すると説明もしやすかったです。

テスターの作成

早い段階から テスター を作り、リグレッションが起きていないか、メモリリークが起きていないか確認するようにしました。

このおかげで比較的少ない不具合数(cファイル, ヘッダファイルの行数およそ4300行に対し、不具合数23)で済んだように思います。

感想

楽しかったこと

チーム開発の楽しさ

一人と違って、相手から反応があり楽しかったです。相手からどんなレビューが来るか、コードが来るか、楽しみにしていました。

チームメイトの ToYeah さんは実装力があり、レビューでは特にメモリリークについて指摘いただき、頼もしかったです。

構文解析の面白さ

資料を参考に実装したら、こんなに綺麗に作れるのかと感動しました。

大変だったこと

bashの仕様の把握

特にbuiltinコマンドはソースコードを読まないと分からない挙動が多かったです。bashは長い歴史があり、ソースコードも歴史を感じさせるものとなっています(そんなに読みやすくないという意味です)。

以下はbashの面白い挙動の一例です。

  • cdは、カレントディレクトリが存在しない場合、cdするディレクトリをPWDにjoinしてcdを試みます。

    • この挙動については ToYeah さんが詳しく解説されています。 qiita.com
  • exitは、複数の引数が与えられた場合、exitしません。そして ; 以降のコマンドは無視されます。

    • 例えば、 exit 0 0; echo hello というコマンドの場合、 echo hello は実行されません。
  • シェルがどのくらいの深さで実行されているか確認できる変数、 SHLVL は1000以上になると bash: warning: shell level (1000) too high, resetting to 1 と表示され、1にリセットされます。
    • ちなみにbash4.4以前では、SHLVL=999 の時にbashを起動すると SHLVL が空文字になるバグがあります。

終わりに

課題を見て、始めはどう実装すればいいか全く分からなかったのですが、資料を読んで協力してなんとか実装できました。

bashの仕様や構文解析、プログラムの実行など学ぶことが多く、面白かったです。

時間があれば、コマンドのHistory機能など実装してみたいと思います。

2021年1月の振り返り

42Tokyoのコミット時間

f:id:nafuka11:20210204212655p:plain

1月のコミット時間は161時間37分でした。

内訳としては、半分が課題、残り半分がレビュー、イベント、AWS Academyなどになっています。

42Tokyoでやったこと

Kubernetesの課題

2020年12月からKubernetesで複数のアプリケーションをデプロイする課題に取り組んでいます。

課題はほぼ完了して、これからレビューを受ける予定です。

今回はレビューで説明するためのスライドを作成しました。

f:id:nafuka11:20210204212914p:plain

課題の規模が大きい場合、スライドを作るようにしています。理由としては、

  • 説明に再現性を持たせるため。
    • 全て口頭だとその時々で説明が違ってしまう、説明を忘れてしまう、などの問題があるため。
  • 聴覚だけでなく、視覚、言語で理解させたいため。
    • 人によって理解しやすい情報が異なるため。

があります。

AWS Academy

AWS Academy とはAWSが提供している学生向けカリキュラムです。

42TokyoはAWS Academyに加盟しており、生徒は無料でカリキュラムを受講できます。

現在私はAWS Academy Cloud Foundationsを受講しています。これはAWSの入門にあたるコースです。

ラボという、制限付きのAWSの環境にアクセスできるのが楽しいです。マネジメントコンソール、AWS CLIなどが使えます。

Yahooのペアプロ・TDDワークショップに参加

Yahooさんが主催する42Tokyoの生徒向けのペアプロ・TDDワークショップに参加しました。

nafuka.hatenablog.com

コードゴルフのイベントに参加

内容はBit逆転、FizzBuzzでした。

感想

良かったこと

  • Togglで時間をつけ始めました。
    • 何にどれくらい時間を使っているのか可視化されて良いです。
  • スライドを以前よりも短い時間で作れました。
    • 以下の記事を参考に、スケルトンという資料の設計図を作ってみました。手戻りが少なくなり良かったです。 diamond.jp

課題

  • ブログを書くのに時間がかかりすぎてしまう。
    • 書き慣れていない、自分の中で型を持っていない、といくつか原因があると思うので解消していきたいです。

今後やること

  • 引き続きKubernetesの課題を進め、課題が終わったらシェルの再実装の課題に移りたいです。
  • Discord Botは軽微な修正しかしていないので、そろそろ何か新しいことをしたいです。

Yahooのペアプロ・TDDワークショップに参加しました

2021年1月28日にYahooさんが42Tokyoの生徒向けに主催してくださった、ペアプロ・TDDワークショップに参加しました。

本記事はその参加レポートです。

そもそもペアプロ、TDDとは

ペアプロ、TDD、どちらもXPのプラクティスの一つです。

XPとは、

Wikipedia より

エクストリーム・プログラミング、XPは、 ソフトウェア品質 を向上させ、変化する顧客の要求への対応力を高めることを目的としたソフトウェア開発プロセスである。

ペアプロは、ペアプログラミングの略で、2人のプログラマがドライバーとナビゲーターの役割に分かれ、1つの画面でプログラミングを行う開発方法です。

TDDは、テスト駆動開発(Test-Driven Development)の略で、テスト→実装→リファクタリングのサイクルを繰り返していく開発方法です。

内容

Zoom上でワークショップが行われました。このワークショップはもともと8時間の内容を2時間にぎゅっと凝縮したものとなっていました。

ワークショップでは以下の3つが行われました。

  1. XPの説明
  2. Yahoo社員のライブコーディング
  3. 生徒同士のペアプログラミング

XPの説明

XPの説明では、XPがなかった頃の課題、XPについて、5つの価値と主要プラクティス13個について知ることができました。

ライブコーディング

ライブコーディングでは、ペアプログラミングで行うお題のデモンストレーションを見ました。この時、開発サイクルの説明を交えつつライブコーディングをされていました。

開発サイクルは、

  • PMから与えられたストーリーをじゃんけん見積もり
  • 実装
  • 受け入れテスト

という流れだそうです。

ペアプログラミング

その後、生徒同士でペアプログラミングを行いました。

内容は、Node.jsとVue.jsでじゃんけんゲーム、電子書籍アプリの実装を行うことになりました。しかし、私たちのペアは時間が足りず、電子書籍アプリの実装まではたどり着くことができませんでした。

オンラインでペアプログラミングをするにあたり、Zoomの画面共有 + 遠隔操作機能を使いました。Zoomの遠隔操作機能はVSCodeと相性が悪いらしく、キー入力を受け付けなくなるトラブルがありました。それでも、2人でプログラミングをする楽しさは体験できたと感じます。

感想

ライブコーディング時に、開発サイクルの説明がなされ、実際の業務のイメージがつきました。

ペアプログラミングは、42のP2Pラーニングと親和性が高く、チームプロジェクトで使ってみたいと思いました。

TDDは、大規模なプロジェクト、長期間開発するプロジェクトで特に役に立ちそうだと思いました。 これまでのプロジェクトで、新機能を追加したものの既存機能にバグを埋め込んでしまい再度修正……ということがありました。最初にテストを書いておくと安心して機能追加できそうです。

ワークショップで学んだことを生かして生徒たちと開発していきたいと思います。

2020年振り返り

今年は一言で表すと42Tokyoとコロナな1年でした。

要約

1月に42Tokyoの入学試験Piscineを受験、新型コロナウィルスの影響で開校が延期。4月からオンラインの特別カリキュラム開始、6月から42Tokyoが開校し本来のカリキュラムを進めています。

出来事

42Tokyo

去年42Tokyoの存在を知り、1月に入学試験Piscineを受験、合格しました。

その後、新型コロナウィルスの影響で42Tokyoの開校が延期。代わりに4月から1ヶ月間特別カリキュラムがありました。特別カリキュラムについては以下の記事を参照ください。

nafuka.hatenablog.com

6月から開校し、本来のカリキュラムが始まりました。カリキュラムは基本オンラインで進めています。

カリキュラム

42Tokyoのカリキュラムでは以下の課題に取り組みました。

  • 標準Cライブラリの再実装
  • 指定ファイルディスクリプタから1行ずつ文字列を読み込む関数の実装
  • ネットワークに関するクイズ問題
  • printfの再実装
  • Wolfenstein 3Dのような、Ray castingを使ったゲームの製作
  • DockerでWebサーバ、DBなど全部入りのコンテナを立てる*1
  • 過去作成したC言語の関数をアセンブリで再実装

現在は、Kubernetesで各種サービスを立ち上げる課題、bashの再実装に着手しています。

イベント

42Tokyoでは時々イベントが行われます。運営側が主催することもあれば、生徒が主催することもあります。以下のようなことをしています。

コードゴルフのお題はBrainf*ckの実装や以前の課題などです。終わった後、皆で実装を見せ合うのが勉強になります。

ラジオ体操は、毎日2-3回、決まった時間に皆とやっています。体操をするだけでなく、定期的に雑談や進捗を報告する場になっていて、モチベーション維持に役立っています。

オンラインで変わったこと

  1. 文章を書く機会が増え、積極的にコミュニティへアウトプットをするようになりました。

    オンラインだと暗黙知が形成されにくいこともあり、なるべく課題で学んだこと、躓いたことは文章に残すよう心がけています。

  2. レビューで説明するため様々なツールを使うようになりました。

    Googleスライド、HackMD、Notion、A Web Whiteboardなど。オフラインの時は紙に書いて説明していました。

42Tokyoに入ってみて

  • 多様な生徒に出会うことができました。
    • 42Tokyoは学歴や職業などに関わらず、人を受け入れています。それまで交流関係が狭かったのですが、42Tokyoに入学してから様々な生徒と出会い、刺激を得ています。
  • 生徒の役に立つツールを作るのが楽しいです。
    • 多数の生徒が在籍しているので、ツールを作るとフィードバックが得られ嬉しいです。
  • データを分析する楽しさに気づきました。
    • 42ではAPIが提供されており、生徒たちが成績などのデータにアクセスできます。他国のキャンパスのデータも取得できます。
    • データから予測を立て提示すると人を動かしやすく、楽しいです。

その他

42のカリキュラム外で作ったもの

  1. AtCoderのスコアをSlackに投稿するツール

    nafuka.hatenablog.com

  2. Discord Bot

    42TokyoのDiscordサーバでBotを稼動させています。

    nafuka.hatenablog.com

    42Tokyo用のBot以外に、ロール・チャンネル管理Botも作成して、時々使っています。

    f:id:nafuka11:20201231185640p:plain:h400

  3. 生徒の進捗で表示するGoogleスプレッドシート

    日別で各課題に合格(validated)、提出(submitted)、登録(subscribed)した人数を表示してみたり

    f:id:nafuka11:20200727171817p:plain

    入学時期別で成績分布をグラフにしてみたりしています(画像はダミーデータです)。

    f:id:nafuka11:20201231194442p:plain

    データの取得にはGASやPythonを使っています。

スマートホームはじめました

Google Home Miniを家族に貰ってから、Nature Remo mini、Switch Botカーテンを買って部屋で使っています。

Nature Remo miniと連携した音声でのリモコン操作は、リモコンを探す必要がなく快適です。Switch Botカーテンは、朝カーテンを自動で開けてくれるので目覚めがよくなりました。

読んだ本

  • スッキリわかるC言語入門
  • Head First C
    • C言語を勉強するために読みました。
  • すべてがFになる
    • Piscinerに教えてもらい読んだ本。1996年にこの本が書かれたのすごいです。
  • 銀河ヒッチハイク・ガイド
    • 42の元ネタの本。「42」が出てくるのは意外と後の方です。
  • Discord Bot運営実践入門
    • Discord Bot開発の知見の宝庫でした。
  • カイゼン・ジャーニー
    • 勇気がもらえる本でした。タスク管理、振り返りのやり方、とても参考になりました。
  • 個人Webサービスシステム構成事典
    • これを読んでHeroku + Papertrailを導入してみました。
  • 数学ガールの秘密ノート/丸い三角関数
  • 数学ガールの秘密ノート/ベクトルの真実
  • 数学ガールの秘密ノート/行列が描くもの
    • Ray castingの課題で数学の知識が必要になり読みました。数学が好きになれる本だと思います。
  • Discord Bot開発実践入門
    • 『Discord Bot運営実践入門』より初心者向けな本。初心者の布教用に購入。
  • 失敗プログラマー
    • 落ち込んでる時に読んで元気が出ました。
  • プログラマのためのDocker教科書 第2版
    • Dockerの課題があり購入。インフラの教科書 + Dockerな感じです。
  • 15Stepで習得 Dockerから入るKubernetes

他、読みきってはないですが、『人を動かす』が集団の中で上手くやっていく方法が書いてあり勉強になりました。立ち回りが上手い方はこの本に書かれていることを実践されてるように思います。

来年の抱負

  • 42Tokyoの除籍システム、通称ブラックホールに吸い込まれることなく、来年中に基礎的な学習を終え、インターンに参加できるレベルに到達したいです。
  • 42Tokyoに入って、便利なツールを作ったり、データを集め眺めて分析のようなことをするのが好きと気づきました。今の環境でできることをやっていきたいです。

来年もよろしくお願いします。

*1:Dockerの課題は、本来は各プロセスを別コンテナにするべきでしょうが、分離された環境で環境構築の練習をするのが目的なのかなと思います。

Discord Botで42Tokyoの課題を解決しようとした話

この記事は 42tokyo Advent Calendar 2020 の4日目の記事です。

Discord Botを通じて42Tokyoというエンジニア養成機関に存在する課題を解決しようとした話です。

そもそも42Tokyoとは

フランス発のエンジニア養成機関です。今年から開校しました。

学費無料、教師不在、生徒同士が教え合うP2Pラーニング、課題解決型学習が特徴です。

42tokyo.jp

42Tokyoは生徒主体の組織なため、カリキュラムで与えられた課題だけではなく組織に存在する課題も、基本的に生徒たちによる解決が求められます(少なくとも私自身はそう感じています)。

この記事では、Discord Botを使って組織に存在する課題を解決しようとした事例を紹介します。

Discord Bot作成の経緯

42Tokyoは、コロナウィルスの影響により、現在オンラインでカリキュラムを実施しています。Discordがメインの学習の場です。

学習にあたり、Discordでは不便なことがありました。

  1. イベントの登録呼びかけが手動

    42Tokyoでは時々イベントが開催されます。登録しないとイベントには参加できません。その登録を手動で呼びかけていました。手動だとたまに忘れてしまうので自動化したいと思いました。

  2. メッセージのブックマーク機能がない

    Discordにはメッセージのブックマーク機能がありません。このため、ブックマークの代わりに、有益なメッセージのURLを自分専用のテキストチャンネルに貼っておく習慣がありました。クリックしないと内容が分からず不便でした。

  3. 現在のチャンネル数を知る手段がない

    Discordのチャンネル数上限は500。上限に達するとチャンネルを新規作成できなくなります。

    42TokyoのDiscordサーバは生徒が自由にテキスト・ボイスチャンネルを作れるため、チャンネル数が多くなっていました。現状を把握するために、チャンネル数を知る必要がありました。

  4. 欲しいコマンドがない

    猫画像を貼って癒されたいのにコマンドがありませんでした。

42TokyoのDiscordサーバでは、申請すれば自分の作ったBotを動かせます。そこでBotを作ってみることにしました。

技術構成

言語はPython、ライブラリは discord.py を使い、Heroku 上でBotを動かしています。

言語をPythonにしたのは、使ったことがある言語だったため。デプロイ先をHerokuにしたのは、参考となる記事が多かったためです。

機能紹介

スクリーンショットはテスト用のサーバで撮ったものです。

イベント通知機能

f:id:nafuka11:20201125235331p:plain:w540

毎日決まった時刻に、翌日開催されるイベントを通知する機能です。

メッセージのブックマーク機能

f:id:nafuka11:20201125233058p:plain

メッセージに特定のスタンプ(🌟)を押すと、スタンプを押したユーザ宛にメッセージの内容をDMする機能です。

R. Danny というBotのstarboard(サーバ全体のブックマーク機能)を参考に作成しました。 R. Dannyはdiscord.pyの作者が作っており、他の機能やモジュール構成など参考になります。オススメです。

メッセージ送信先をDMにしたのは、他のDiscordサーバでstarboardが面白ネタの共有として使われていることが多かったからです。

ブックマークに使うスタンプの選定基準は以下としました。

  • 普段から使われなさそうなもの(誤って押されない)
  • プレミアム感のあるもの(押されて嬉しい)

チャンネル数を表示するコマンド

f:id:nafuka11:20201125235823p:plain:w300

チャンネル数上限の問題を知った時、まず類似の問題が他のサーバで発生していないか見て回りました。そして他のDiscordサーバではどうやって解決しようとしているかを探しました。探す中、Discord Bot Portal JPというDiscordサーバを見つけました。

Discord Bot Portal JPは、Discord Botの開発者・利用者が集まるDiscordサーバです。質問ごとにテキストチャンネルを自動生成するシステムがあります。そのシステム故にチャンネル数が多いです。

そのサーバにあるBot、Echidnaにチャンネル数を表示するコマンドがあり、それを参考に作成しました。

お遊び的コマンド

f:id:nafuka11:20201125235443p:plain:w380

猫画像を投稿するコマンド。TheCatAPI から画像のURLを取得しています。

Discord Botを導入した効果

  1. イベントの登録呼びかけが手動

    → Discord Botにより、自動でイベント登録を呼びかけるようになり、呼びかけの手間が無くなりました。

  2. メッセージのブックマーク機能がない

    → ブックマーク機能により、気になるメッセージのURLを貼ることなく、DMへ保存できるようになりました。この機能は1日平均16.9回使われているようです。

  3. 現在のチャンネル数を知る手段がない

    → チャンネル数を把握できるようになり、現在のチャンネル数から今後どのようなチャンネル構成にするか話し合いが行われるようになりました。

  4. 欲しいコマンドがない

    → 猫画像が貼れるようになり、手軽に癒しが得られるようになりました。このコマンドは1日平均2.7回使われているようです。

学んだこと

  • API, ライブラリ(discord.py)の更新情報をキャッチアップすることの大切さ。
    • APIの仕様変更に伴ってライブラリも定期的な更新が必要となります。以下のDiscordサーバで情報収集するようにしています。
      • Discord Developers
      • Discord API
      • discord.py
  • エラー通知の大切さ。
    • 以前、APIの仕様変更にライブラリ側が対応できず、一時的にBotが動作しなくなりました。その時すぐに気づくことができなかった反省から、エラー通知の大切さを学びました。
    • 現在は、エラーが発生したらテスト用のDiscordサーバに通知が行くようにしています。
  • 問題解決の楽しさ。
    • 生徒からダイレクトに反応が得られるので、やりがいがあります。

参考になった書籍・サイト

Discord Bot作成にあたり、以下の書籍・サイトが参考になりました。

今後の展望

  • イベント通知の強化
    • イベント開始1日前だけでなく、開始前・終了後にも通知するように。
  • ブックマークの週間ランキング
    • 1週間にどんなメッセージがブックマークされたかをランキングにします。
    • ブックマーク数が可視化されると楽しいし、モチベが上がるはず。
  • メッセージのコピー機
    • チャンネル数が増えたときチャンネルを統合したり、メッセージを共有しやすくしたいです。
  • テストを書く
    • お恥ずかしながらテストをあまり書けていないので、ちゃんと書きたいです。

終わりに

Discord Botで42Tokyoの学習環境が少し便利になったかなと思います。

これからも何か課題を見つけたら、Discord Botや他の方法を使って解決していきたいです。

CodinGame Fall Challenge 2020 参加記録

2020/11/13〜11/23にCodinGameで開催されたコンテスト、Fall Challenge 2020 に参加しました。

Goldリーグまで進めました。順位は世界209位、日本59位でした。 f:id:nafuka11:20201123223823p:plain

ルール

ツカモさんの記事に詳しく載っています。呪文を唱えて素材を変換し、素材からポーションを作ってお金を稼ぎ、より多くのお金を稼いだプレイヤーが勝つゲームです。

tsukammo.hatenablog.com

実装

Wood 2

作れるポーションの中でもっとも価値が高いポーションBREWするようにしました。

Wood 1

  • BREWできるならする。
  • BREWできないならCASTする。
    • 最短手で作れるポーションを求める。
    • 上位の素材を生成する呪文から見て、唱えられる & ポーション製造に必要な素材ならCASTする。
  • CASTできなかったらREST。

としました。

Bronze

3手先まで、BREW, CASTをDFSで全探索して、最も評価値の高いコマンドを選ぶようにしました。

Silver

再帰関数を使ったDFSからBFSにしたり、高速化する方法をググって実装して、4手先まで読めるようにしました。

repeatableも見て1ターンで複数回呪文を唱えるようにしました。

Gold

最初10ターンはLEARN固定。

その後はchokudaiサーチを使って7手先まで読んでコマンドを探索しました。

探索するコマンドはBREW, CAST, RESTのみ。

評価方法は、素材の数とBREWするポーションのprice, tomeIndexから計算。6個目に作るポーションはターンが早いほどボーナスをつけるようにしました。

chokudaiサーチを実装するまではビームサーチにしていて、7手先上位100手を見ていました。どちらのサーチも、実装にあたりツカモさんの記事がとても参考になりました。

qiita.com

反省点

  • 初回100ms与えられるので、最初探索をして時間を有効に使うべきのだったかもしれません。

  • LEARNを探索に含めたバージョンも作ったのですが、あまり強くならず……。その調整にかなり時間を使ってしまったので、思い切って捨てる覚悟が必要だったかもしれません。

感想

以前、CodinGame上で行われた、42の学校間コンテスト では、シミュレートが難しく1ターンの最善手を探索することしかできませんでした。

今回は数手先まで探索できて楽しかったです。DFS, BFS, ビームサーチ, chokudaiサーチといろいろな実装を試せました。

次回参加するときはチーム内5位以上に入りたいです(今回6位)。