ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

自動計画器がねこを動かす

 こんにちは、サーバーサイドエンジニアのいいだです。

 もうすぐ夏ですね。私は夏になると決まって、ある問題に直面します。毎年試行錯誤を繰り返してはいますが、いまいちしっくりくる答えにたどり着くことができません。つまり、そうめんに合うおかずとは何であろうかということです。

 ちなみに実家では目玉焼きが定番でした。いいえ、悪くはありません。今日は自動計画の話をします。

そうめんと自動計画とねこ

 自動計画とは、そうめんに合うおかずを決定することです。いわゆるAIの一分野で、周囲の環境や自身のとれる行動などから既知ないし未知の問題を解決する具体的な手順を作り出すのがその役目です。

f:id:unifa_tech:20190611175724p:plain:w300
そうめんのおかずを獲得する計画

 自動計画はロボットや産業機器などの真面目な分野でももちろん使われていますが、個人的な好みの問題からここではゲームにおける自動操作キャラクターの挙動とその計画を扱う仕組みとして紹介します。プレイヤーの体力が減った場合に攻撃を中断して回復アイテムを使ってくれる味方キャラクターという簡単なものから、アイテムを総取りしつつ崖際へ走ってプレイヤーの復帰を阻止する極悪非道のロゼッタ&チコまで、自動計画はゲームの様々なところで活用されています。

 今回は、与えられた環境で可能な限り長時間生存することを目標とするねこを作りました。(簡単な)ゴール指向の自動計画器を(それらしい)遺伝的ネットワーク計算によって学習し、横からレーザーを撃たれない限り死なないねこを目指します。

ねこについて

f:id:unifa_tech:20190611180037p:plain:w300
これはねこです

 ねこです。72頂点あります。関節は全て固定されていて動きませんが、時速40km程度で移動することができます。

 今回の設定では、ねこは最大で100の満腹度を持ちます。ねこが環境に存在する時、ねこは1秒ごとに2の満腹度を失います。これが50を下回った時、ねこは「はらへり」を認識します。その状態のまま何もせずにいると、やがて満腹度が0になり、体力を失い、死にます。

 ねこも死にたくはありませんので、何かを食べたいかと思います。もちろん、この環境には食べるものも用意されています。

f:id:unifa_tech:20190611180115p:plain:w300
これはすしです

 すしです。ねこは実際のところすしをあまり食べないそうですが、刺身にすると8頂点になりますので、ハイポリゴンなモデルを用いたリッチな体験を目指してすしにしました。16頂点あります。

 ねこはすしを「食べる」ことにより、満腹度を30回復することができます。これによって満腹度が80を上回った時、「はらへり」は解消されます。また、満腹度が50以上のとき、体力は徐々に回復します。

 つまり、すしを食べることでねこは永遠に生き続けるでしょう。大変喜ばしいことです。そのために、ねこには正しい食事を計画してもらいます。

ねこによる計画

 ゴール指向の自動計画器は、ゴールを最初に決め、それを解決する行動を求めることによって計画を作成します。たとえば冒頭のそうめんのおかずを獲得する計画においては、「食卓に並べる」がそれにあたります。おかずを食卓へ並べるには、食べる準備の整ったおかずが必要です。然るに、私はその下位のゴールとして「薬味オンリーで行く」を選択するでしょう。計画が短く、調理や洗い物等のコストも少なく、とても効率的であるからです。このように、効率的な計画器は食後の満足度をも左右します。

 海苔や小ねぎ、しょうがにも飽きましたか? いいえ、わさびがあります。茹でた小麦粉をめんつゆで食べましょう。

 ねこは行動を計画するための計画器として、有向グラフを一つ持ちます。これを計画グラフと呼びます。このグラフには「状態」「行動」の二種類の頂点が存在し、それらの接続(辺)を作成ないし変更することによって、計画器は「状態」の解消を目指します。

f:id:unifa_tech:20190611180327p:plain:w300
計画器によって作られた計画(理想)

 もし、ねことすしが十分に近ければ、ねこはすしをそのまま食べることができます。今回の設定では、ねこは2m以内のすしを0.17msで食べることができます。ちなみに、このねこは全長がおよそ1mあります。

f:id:unifa_tech:20190611180425p:plain:w300
ねことすしの間には距離があることを示す図

 しかしながら、往々にして、我々と食べ物との間には距離があります。ねこの口はねこと独立して移動できるようにはなっていないので、ねこがすしを食べるにはねこ自身がすしに近づく必要があります。つまり、すしが「食べる」の範囲内にあるかどうかを判断し、そうでない場合には「近づく」ことが求められます。

 このため、計画では「状態」が自身のとれる「行動」によって解消できるか、またそもそもその「行動」ができるかを自身で判断しなければなりません。この場合では、「はらへり」を解消するためには「食べる」必要があり、「食べる」には「近づく」必要があります。

f:id:unifa_tech:20190611180507p:plain:w300
実際の計画グラフ

 計画グラフはこのような「状態」と「行動」の接続を保持しておき、最終的に「現在すぐに実行できる行動」から「将来解消されるべき状態(課題)」までの道筋をねこに示すことができます。これによって、ねこはすしが近くにない時でも、自分ですしに近づき、それを食べることができるようになります。

ねこの提案グラフ

 計画においては、ねこは自分がどのような行動をとれば課題を解決できるかをよくよくわかっている必要があります。「はらへり」状態から「(何かを)食べる」へ至るには、「(何かを)食べる」ことが「はらへり」を解消する行動であると知っていなければいけません。

 このため、ねこは「現時点で解消できない状態」または「現時点で実行できない行動」に直面したとき、それを解消する新たな行動を探します。これにより、ねこはあらゆる問題に対して、最低限「直ちに実行できること」を見つけることができます。

 しかしながら、直ちに実行できれば何でもよいわけではありません。「はらへり」になった時、「食べる」ではなく「近づく」を選択してしまったねこは、すしに近づくことはしますがそれ以上は何もせず、いずれ死んでしまうでしょう。

 今回は、「すしは食べ物である」というのはねこにもわかっているものとして、「はらへり」→「食べる」や「食べる」→「近づく」の接続をねこ自身に発見してもらうべく、遺伝的ネットワーク計算による簡易的な学習の仕組みを用意します。これを提案グラフと呼びます。

f:id:unifa_tech:20190611180600p:plain:w300
提案グラフの例

 提案グラフは、「状態」「行動」「条件」「選択」の四つの頂点を持った有向グラフです。提案グラフはねこが持つ全ての「状態」及び「行動」と同じ数が用意され、始点となるそれによって使い分けられます。提案グラフは計画グラフが「直ちに解消できない状態ないし直ちに実行できない行動」に直面したとき、それを解決するために使われます。

 計画グラフは計画において、グラフの末端にある「状態」ないし「行動」が解決不可である場合、その時点の「状態」ないし「行動」を提案グラフに渡します。提案グラフはそれと同じ種類の「状態」ないし「行動」を始点として、別の「行動」へ辿り着くまで各頂点を辿って探索し、たどり着いた結果である「行動」を返します。もし探索中の頂点が次への接続を持っていなかった場合は、ランダムに別の頂点へ接続して探索を続けます。

頂点の種類 やること
状態 なにもしない(始点以外には選ばれない)
行動 始点でない場合、探索を終了する
条件 環境を指定の条件で検査し、trueかfalseによってそれぞれ別の頂点へ移動する
選択 その目標にターゲット(モノ、場所、時間)を設定する

 この結果得られた「行動」が実行可能であればそれを実行し、そうでなければまた提案グラフを呼ぶことによって、最終的には実行可能な「行動」にたどり着く、というのが基本的な仕組みになります。これによって、計画グラフは自分ができる全ての行動が実行不可である場合を除き、あらゆる「状態」ないし「行動」からさしあたって実行可能な行動を導くことができます。

 もちろん、それが価値ある行動かどうかは、今のところは考えません。ねこは精一杯に生きています。

ねこの天国

 提案グラフを作ることによって、ねこは実行可能な「行動」を確実に得ることができるようになりました。しかしながら、現時点では新たな問題へ直面する度にランダムで行動を選ぶおもしろ計画器であり、それが正しく機能するかは疑問です。

f:id:unifa_tech:20190611181403p:plain:w300
執拗にレーザーを出すねこ

 死にそうだからといってみだりにレーザーを撃つべきではありません。空腹ならばなおさらです。ねこは正しくない行動をした時にそれを知り、正す必要があります。少なくとも来世では。

f:id:unifa_tech:20190611181431p:plain:w300
空腹に打ち震えているねこ

 環境はねこの天国を持ちます。ねこの天国はまたたびの香りのフォグに包まれ、すしと比べて頂点数に優れる缶詰の山と、リアルタイム流体シミュレーションで流れるおやつの川、そして物理演算の宿った荒ぶるおもちゃの大地があります。さておき、全てのねこは死んだとき、その生存時間と自身が持っている提案グラフを天国に送ります。

f:id:unifa_tech:20190611181524p:plain:w300
天国が管理する情報

 天国は直近100件のねこの平均生存時間と、最大で100件の提案グラフを持っています。新しいねこが環境に生まれるとき、天国はねこに自身が持つ提案グラフをランダムで一つ与えます。ねこは天啓を受け、生まれた瞬間から比較的賢いかもしれない状態になります。

f:id:unifa_tech:20190611181548p:plain:w300
天国が持っている中で最もマシな提案グラフ

 これにより、ねこは賢かったり、そうでなかったりする状態で人生を送ります。生きるうちに新たな発見をし、提案グラフに変更が加わるかもしれません。そうして大往生を迎えると、提案グラフと生存時間がまた天国に蓄積されていきます。

 この繰り返しによって提案グラフが100件集まると、天国は「進化」を行います。世代を一つ送り、100件集まった提案グラフを長生きした順に並べ、以下の処理を行います。

範囲 やること
上位10件 そのまま残す
次の20件 ランダムな2件ずつでペアを作る
双方にある辺を残す
片方にしかない辺は30%の確率で残す
次の5件 全ての辺を10%の確率で消す
そのほか 削除する

 この結果、残った提案グラフが次世代のねこたちに与えられます。これらは概ね前世代のご長寿ランキング上位勢ということになりますので、次世代のねこは比較的賢いことが期待できそうな状態から人生をスタートします。そしてそのねこがより長く生き、優秀な提案グラフを次世代に残し続けることによって、提案グラフが改善され、計画器がより適切な計画を立てられるようになります。

 全てのねこが永遠に生きるようになったとき、天国はその役目を終えるでしょう。

f:id:unifa_tech:20190611181846p:plain:w300
まだ天国を必要とするねこ

おわりに

 簡単なものではありますが、ゴール指向の自動計画器と遺伝的ネットワーク計算の学習装置を作ることができました。AIについては全くの門外漢なので調べていてもなるほどわからん状態でしたが、さしあたってねこが動いているので私は満足しています。

 計画器やその学習には様々な手法がありますので、それらを参考に今後も改善を重ねつつ、より賢いねこになってもらえればと思っています。

時間帯被るかどうかから長方形の衝突検知

こんにちは、午睡チェックサーバーエンドエンジニアのちょうです。最近開発で見つかったちょっと難しい問題について話したいです。それは時間帯が被ってるかどうかのチェックです。

時間帯

例えば

  • 午後3時から午後4時
  • 午後5時から午後6時

という2つの時間帯は被らないとし、

  • 午前10時から午後4時
  • 午後3時から午後5時

が被るとしたら、どうやって時間帯が被るかをチェックしますか。

時間帯を表記しやすいために、[15:00, 16:00] は午後3時から午後4時の意味をします。なお、[15:00, 16:00][16:00, 17:00] は被らないとします。

個別のケースを考えるより、すべて可能なケースをここにリストアップしました。

f:id:unifa_tech:20190603190445p:plain

2つの時間帯の関係は全部6ケースあります。以下金色の時間帯1は[S1, E1]、水色の時間帯2は[S2, E2]とします。

  1. 被らない、E1 <= S2
  2. 被る、S1 < S2 < E1
  3. 被る、S2 <= S1 < E1 <= E2
  4. 被る、S1 <= S2 < E2 <= E1
  5. 被る、S1 < E2 < E1
  6. 被らない、E2 <= S1

被るケースが4個あるので、4ケースの一つに当てはまれば被ります。とはいえ、4つのケースに共通点あまりないし、そのままコードにするのは分かりにくいです。

ここで一つのテクニックは被るケース以外のケース、つまり被らないケース、の逆にすれば簡単にできます。

  ALL CASES - <CASE 1> - <CASE 6>
=!<CASE 1>   && !<CASE 6>
=!(E1 <= S2) && !(E2 <= S1)
= (E1 > S2)  &&  (E2 > S1)

実際、↑の条件で被る4つのケース一つ一つチェックしてみれば、すべて合ってることが分かります。もし数学が強い人がちゃんと4つの被るケースの共通点を見つければ、たぶん同じ結果になるでしょう。我々一般人にとって、同じ結果に辿り着けるには、逆思考がキーになります。

長方形の衝突検知

もうひとつ自分が興味を持っていた問題を紹介します。長方形の衝突検知。

f:id:unifa_tech:20190604113432p:plain

長方形の衝突検知はよくゲームで使われるらしいです。例えば、2つのオブジェクトがぶつかるかによってダメージを受けるかなどを決めます。

方法1

時間帯と同じ方法を使えます。金色長方形を長方形1とし、水色長方形は長方形2とする。X軸に長方形1と長方形2が被るかつY軸に長方形1と長方形2が被れば長方形1と長方形2が被る。つまり

長方形1: (x1, y1), (x2, y2)
長方形2: (x3, y3), (x4, y4)
[x1, x2] と [x3, x4] 被る -> (x2 > x3) && (x4 > x1)
[y1, y2] と [y3, y4] 被る -> (y2 > y3) && (y4 > y1)
よって衝突の条件は
(x2 > x3) && (x4 > x1) && (y2 > y3) && (y4 > y1)
方法2

↑以外に、もう一つ方法があります。2つの円が被るかどうかの条件を考えてみましょう。円でしたら中心と中心の距離が2つの円の半径の和より大きいでしたら被らない、小さいでしたら被るということになります。同じように、長方形の中心と中心のX軸の距離が2つの長方形の高さの半分より小さいかつY軸の距離も2つの長方形の幅の半分より小さいでしたら2つの長方形が被る。つまり

f:id:unifa_tech:20190604140657p:plain

長方形1: (x1, y1), (x2, y2)
長方形2: (x3, y3), (x4, y4)
w1 = (x2 - x1), h1 = (y2 - y1)
w2 = (x4 - x3), h2 = (y4 - y3)
中心1 ((x2 + x1) / 2, (y2 + y1) / 2)
中心2 ((x4 + x3) / 2, (y4 + y3) / 2)
ABSは絶対値関数
中心の距離: (
    ABS((x4 + x3) / 2 - (x2 + x1) / 2), 
    ABS((y4 + y3) / 2 - (y2 + y1) / 2)
)
衝突の条件
ABS((x4 + x3) / 2 - (x2 + x1) / 2) < (w1 + w2) / 2 && 
    ABS((y4 + y3) / 2 - (y2 + y1) / 2)) < (h1 + h2) / 2
ABS((x4 + x3) - (x2 + x1)) < (w1 + w2) && 
    ABS((y4 + y3) - (y2 + y1))) < (h1 + h2)
ABS((x4 + x3) - (x2 + x1)) < ((x2 - x1) + (x4 - x3)) && 
    ABS((y4 + y3) - (y2 + y1))) < ((y2 - y1) + (y4 - y3))

条件は2つに減りました。

方法1と方法2が同じなのかは私が答えられないですが、中心の距離で判断するのを理解すればいいと思います。

さいご

いかがでしょうか。たまにこういう数学っぽい問題を解いてみましょうか。普段の開発ではあまりこういう問題が出ないですが、気分転換としていい勉強になると思います。

Vue.jsで複数ページにまたがるフォームをVuexを使わずに実装してみる

滑り込みで東京オリンピックの抽選申し込みを済ませました、Webエンジニアの本間です。 どの日でもよいので抽選に当たって欲しいのですが、全部当たると困ってしまう、なかなか悩ましい気持ちになりました。

さて弊社では、現在開発中のプロジェクトのフロントエンドの実装において Vue.js を使っています。 今回、Vue.jsを使った実装をしている中で、複数ページにまたがるフォームの実装で調査した内容を紹介しようと思います。

続きを読む

sudo実行時のカレントディレクトリや環境変数などの挙動について

おはこんにちばんわ! ひさびさなユニファのインフラのすずきです。

最近八王子から、都心に引っ越してきました。
やはり通勤時間が短いと快適ですよね。
そして先日AWSのRe:Inventのチケット申込みが始まりましたね。
今年は行きたい…い゛ぎたい!!!!

と前置きはおいて今回は2度めのsudo関連のブログです。

前回のsudoの記事はこちら、

tech.unifa-e.com

なんかそこそこ見てもらえてるみたいで、関連記事かけという強いプレッシャーの元今回書くことにしました。

では本題

続きを読む

Core Imageをつかって画像処理はじめました

こんにちはiOSエンジニアのしだです。
写真の画像補正をiOS上でOpenCVを使って実装したらメモリの消費やCPU使用率が激しくつらい気持ちになりました。 CIFilterいいよって教えてもらって、Core Image をあまり真面目に使ったことがなかったのですが使い始めてみました。

はじめは ビルトインの CIFilter と CI Kernel Language を見ていたのですが、 CIKernel(source string: String) のAPIが非推奨になっていたため調べてみたら Metal Shading Language が使えるようになっていました。 WWDC2018によると今後はCI Kernel Language は非推奨になってくようです。

CI Kernel Language は実行時にコンパイルされるのに対して、Metal Shading のほうはアプリのビルド時にコンパイルされるのでシンタックスエラーもすぐわかるので便利です。 CIKernel 向けの Metal Shading Language を使ってみたので、いくつかサンプルを上げておきます。

続きを読む

UniFa Developer's MeetUp&LT会 #1を開催しました。

こんにちは。ユニファエンジニアの田渕です。

長かったGWも終わりましたが、みなさまどのようにお過ごしでしたでしょうか??

今日は、少々前のお話になってしまいますが、4月に開催した「UniFa Developer's MeetUp&LT会 #1」について お話していこうと思います。 合わせて、同じイベントについてPodcastでも話しておりますので、ご興味ありましたら聞いてみてください。

UniFa Developer's Podcast

続きを読む

スクラムとは何なのか?

はじめまして。認定スクラムマスター(なりたてほやほや)の渡部です。

スクラムには、必須とも言えるスクラムイベントや、定義された様々なルールが存在します。

多くの場合、まずは教科書のやり方に倣って導入されるチームがほとんどだと思います(実際、それをオススメします)が、 ただ書いてある通りに運用しているだけだと、「う〜ん、こんな場合はどうするんだっけ?」「そもそも何のためにやってるんだっけ?」「うまくいってる実感が無いけどどうすれば…」という疑問が出てくるときがあると思います。ありますよね?

そんなとき、「そもそもスクラムとは何なのか?」を理解しておくことで、最適な判断を行えるようになりますし、現状のやり方は何がイケてないのか?どうするべきなのか?を考えることができるようになります。

そこで今回は、下記2点について解説していきたいと思います。

本記事で解説する内容
  • スクラムってそもそも何なのか?
  • スクラムイベントって実のところ何をしてるの?
想定読者
  • スクラムを勉強中の方
  • スクラムを導入したが、いまいち各種イベントがしっくりこない方
  • スクラムを自分のチームなりにアレンジしたい(or アレンジしたは良いが、これで良いか分からない)方

スクラムってそもそも何?

まずスクラムガイドを参照してみると、以下のように記載されています。

複雑で変化の激しい問題に対応するためのフレームワークであり、可能な限り価値の高いプロダクトを生産的かつ創造的に届けるためのものである。

https://www.scrumguides.org/docs/scrumguide/v2017/2017-Scrum-Guide-Japanese.pdf

と、アジャイル開発のフレームワークの1つであることがわかりますね。

さらに読み進めていくと、スクラムの3本の柱について記載されています。
僕なりにスーパーラフに説明すると次のようになります。

スクラムの3本の柱ってなぁに?

  • 【透明性】
    • あらゆるもの・ことが見える化されてることだよ!
      タスクはもちろん、作業の進捗、プロセス、メンバーの幸福度、困ってることなど、本当にありとあらゆるものだよ!
  • 【検査】
    • 見える化されたあらゆるもの・ことをチェックすることだよ!
  • 【適応】
    • 検査されたものの中で、悪いものは良い方向に、良いものはもっと良くなるよう、変更・調整をかけることだよ!

スクラムのあらゆるイベント・ルールは上記「3本の柱」の上になりたっていますので、 一言で、スクラムとは「あらゆる作業を見える化し、問題を特定し、着実にカイゼンを積み重ねるフレームワーク」と言えます。

上記を理解せずに運用してしまうと、せっかくのイベント、1つ1つのプロセスに価値を見いだせなくなってしまうでしょう。

スクラムを行ううえでは、(スクラムマスターは特にですが)チーム全員が上記を理解することが大切です。

そして当然の事ながら、スクラムマスターはチームが上記を理解できるよう、支援をすることが必要になります。

スクラムイベントで行なっていること

この章では、スクラムイベントで行なっていることを、上記「3本の柱」に当てはめて見ていきます。
激しくラフにまとめていますが、ざっくりイメージを掴んでいただければよろしいかと思います。

そうすることで、各スクラムイベントの目的とは何なのか?何をしているのか?の理解の助けになるなぁと個人的に思っています。

また、これは経験談ですが、自分のチームなりにアレンジする際にどう調整すれば良いのかも判断しやすくなると考えています(というかなりました)。

※各イベントで具体的に何をすべきか、どうするのが良いか等は、また別の機会にお話できればと思います。

スプリントプランニング

【透明性】スプリントで成し遂げることを決定し、
【検査】成し遂げると決めたことが、確実に完了できるかを詳細に確認し、
【適応】完了を阻害する要因がある場合、確実に完了できるよう調整・変更を加える

上記を行うことで、 確実にスプリントで完了できる計画をたてることが可能となります。

デイリースクラム(朝会)

【透明性】チームで毎日集まって、やったこと、これからやること、困ってることを話し合うことで
【検査】作業の進捗、問題、他チームメンバーの作業への影響などを把握する
【適応】-

上記を行うことで、 大きな問題になる前に気付くことができたり、困っているメンバーのフォローをすることができるようになります。

※デイリースクラムの場では状況の把握までを目的としています。 問題がある場合は、デイリースクラム終了後に時間をとり、必要な人のみで議論します。

スプリントレビュー

【透明性】スプリントで完成したもののデモや、最新のスケジュールを共有することで、
【検査】関係者の適切な確認・フィードバックを得ることができ、
【適応】必要に応じて、バックログの修正やスケジュールの調整、開発計画の見直しを行う

上記を行うことで、 スプリントごとに正しい方向性を都度確認しながら、手戻りの少ない開発を進めることが可能となります。

スプリントレトロスペクティブ(ふりかえり)

【透明性】次のスプリントを始める前にチームで、人 / 関係 / プロセス / ツールの観点でふりかえることで
【検査】良かったこと・改善が必要なことを特定、整理でき、
【適応】次のスプリントで実施すべきカイゼン計画を行える

上記を行うことで、 スプリントを経るごとに、一歩ずつですが着実に生産性を向上させることが可能となります。

おわりに

上記のように、スクラムでは【透明性】【検査】【適応】の「3本の柱」がいたるところに組み込まれており、(これがまた難しいのですが、)しっかりと理解し適切に運用することができれば、着実に生産性を上げられるようになっています。

これが、スクラムで生産性が向上する秘密というか仕組みです。

  • スクラムとは何なのか?
  • スクラムイベントでは何をやっているのか?

拙い文章ではありますが、上記を理解する上での一助となれば幸いです。