このエントリーは、KLab Advent Calendar 2016 18日目の記事です。
はじめに
今年の10月、SHENZHEN I/O というインディゲームがリリースされました。この SHENZHEN I/O、中国の深センにある電子機器の企業で働くエンジニアとして、基板に電子部品を乗せて組み合わせアセンブリでプログラムを書いて要求仕様に適した回路を作るという、現実のエンジニアがやっていることそのものがゲームになっています。
このゲームをリリースした会社は、同じようにアセンブリによるプログラム自体をゲームにした TIS-100 や、オートメーションなライン工場を作る infinifactory というゲームをリリースしていたりしています。工場といえばこちらも今年にリリースされた惑星上に巨大なオートメイション生産システムを設計する factorio というものもありました。エンジニアは、今やゲームも中でもエンジニアとして働くことができる時代になったのです!
そんな時代が訪れたことに感化され、私もエンジニアとして働くことができるゲームを世に出したい!ということで、エンジニアリングするネットゲームを作ってみました。
このゲームは、異なるネットワークの間にあるネットワークデバイスのコンフィグレーションを仕様に沿って行い、ネットワーク疎通を成功させるというものです。
ネットワーク設定は専用のコンソールを使ってコマンドベースで行っていきます。仕様書に書かれた内容に適したネットワーク設定を行って「Verify Network」ボタンで疎通を確認することができればクリアです。
提示される仕様書は毎回異なるものが要求される上、クリアしても次の仕様書がすぐにやってきます。エンジニアとして働く環境としては仕事が多いものの大変やりがいのある内容となっているはずです。
是非ともあなたのゲームライフにエンジニアリングを!
以上、エンジニア in ゲームな時代の到来をご紹介しました。
ここから先は、このゲーム制作に伴う過程や成果、感想などをご紹介します。
問題(クエスト)について
ネットワーク設定ゲームを作ろうと決めた際、ゲームの中でプレイヤーが要求される問題をどのようなものにするかを考える必要がありました。すなわち、プレイヤーがクリアのためにやらなければならないことは何か、なにかが欠落していてそれを見つけて直す?ジレンマやストレスなどは用意することができる?
それらを考えて項目として挙げた問題例は以下のようなものでした。
- インターフェースが落ちている
- IP アドレスを適切に付与する
- ルーティングテーブルに適切な経路情報を乗せる
- どのインターフェースの先に目的のネットワークが繋がるのかわからない
- 仕様の情報不足(欠落)
- 仕様に嘘が書いてる(誤植)
- ...
一見無理そうだけども問題パターンを厳選して組み合わせることで自ずと正解が導けるのではと考えて項目を挙げていきましたが、実装時間の都合もあり結局複雑なルーティング情報やクリアのための情報が不足している、情報に嘘があるといった問題はやめることにしました。特に後半の情報の不足や嘘は、「総当たりで Go が答えです」に近いような話で、ゲームとしての面白さには欠けるかなと思ったことも理由です。
問題クリアのための情報を提示する手段として
プレイヤーがゲームの中でやることは「コンソールを使って要求されるネットワークデバイスの設定を行う」というものになっていて、別途その要求される情報をプレイヤーへ伝える手段が必要になります。こちらは、コンソールが表示されているターミナルウインドウとは別に Web ブラウザを開いてもらって、そこに問題クリアのためのデバイスやネットワークの情報を提示することにしました。
ゲームが起動されて問題が用意された時点で問題データを HTML のページとして閲覧可能なようにしてプレイヤーにそれを見てもらうようにします。したがって、ネットワーク設定用コンソールとは別に HTML コンテンツの出力を行う Web サーバを立てるようにしました。
実装に使った言語と技術
- Go
- websocket
今回のシチュエーションのように、プログラムを起動したターミナルにはネットワークデバイスのコンソール画面を表示しつつ、裏では別に問題表示用の Web サーバを立ち上げて、コンソール〜Web サーバ間の情報共有も同一プロセス内で行うといったことが GO では容易にできます。
プレイヤーに見てもらう問題表示用のブラウザと Go の Web サーバ間との通信は websocket を使って行うことにしました。こちらの採用には特別大きな理由はなく Go における websocket の実例を持っておこうと思った程度のものでした。
「今の問題」という情報が Web サーバ側にありますので、それをクライアント(ブラウザ)へ websocket で送ってページレンダリングさせます。ゲーム進行と共に問題が変わった際には再び websocket で送って次の問題という形で処理させています。通常の Web のようにクライアント側からのイベント発火だけでなくサーバ側からのイベント発火と変化発生を容易にできるようにしておいた方が、ゲーム進行における情報同期や更新はやりやすいなと感じました。
ターミナルを支える技術 github.com/chzyer/readline
REPL で情報入力を行うゲームのターミナル部分には https://github.com/chzyer/readline を使っています。このライブラリは先日公開された terraform 0.8 で追加された console を見て知りました。
簡単に使うことができる上、コマンドの suggestion と completion による入力支援機能を提供することができます。このゲームの UX として高いレベルのものを用意できたのもこのライブラリのおかげです。
ライブラリ自体はあくまで REPL の機能提供と役割に特化しており、入力された内容に対してどの処理を実行するかといったコマンドプロキシ的な機能はありません。実装を進めていく上で、コンソール上のコマンドの入力支援 (Completion) に対する処理への接続に漏れがあった、あるいは逆に処理は用意したものの入力支援の定義に漏れがあったという誤りが起きそうという懸念があります。
そこで、コマンド+処理の定義リストを元にして、実際に実行される処理となる Action ツリーと、補完のための Completion ツリーのエントリを自動的に生成するような仕組みを用意しました。
Action ツリーは独自で、Completion ツリーは readline ライブラリが用意してくれる形式になります。
これを用意したことで、実装の際はコマンド名に対する処理をフラットにつらつらと書くだけで同じプレフィックスを持ったコマンドの補完もコマンド解釈後の末端の処理の実行も適切に行われ大変楽に進めることができました。
別の機会に CLI ベースのツールを作る際にも改めて使ってみて、REPL を採用した格好良いコンソールアプリケーションという形で実装を進めてみたいところです。
まとめ
エンジニアとして働いているような、ネットワークコンフィグレーションを成功させるゲームを作りました。
何をするゲームでどうすればクリアなのか、そして遊ぶたびに変化が出るような内容となるよう考えながら進めていきました。設定のためのコンソールに REPL を採用して使いやすさを持ったインターフェースを実現しつつ、そのコマンド自体の作りやすさも考慮した設計と実装を行いました。小さな規模で行った中でも得られたものが色々あって、大変良い経験だったと思っています。
最後にこのゲーム、このままだとゲームとして面白いかどうかというと、なかなか厳しいところがあります…。現状だと教育用や働くエンジニアの体験ソフトくらいならなんとかという感じでしょうか。
もう少し頑張るならば、拡張して GUI 込みでどのポートにどのケーブルをつないでルートを作ったりとか、ルーティングプロトコルのようなものを組み込んだ上でルートが切り替わっても疎通できる状態を継続させるとか…。なにより、「ゲームをキャッチーな見た目に」したほうが良さそうです。