鯰の住処

Namazuが真面目な話を書きます

MonoGameを使ってWindows/Androidでソースコードを共有しよう

初めまして、Namazuです。 これはXamarin Advent Calendar2016の14日目の記事です。 今回はMonoGameのお話をしたいと思います。

MonoGameとは?

XNAを移植したゲームフレームワークです。使用する言語はC# XNAMicroSoftが開発したゲームエンジンで、WindowsやWindowsPhone、Xboxにおいてソースコードをほとんど共通にして動作させることが可能なフレームワークです。

ソースコードを共有!

なんか素晴らしい響きですがXNAでは対応するプラットフォームが少なすぎますよね?? そこでMonoGameの出番です。MonoGameの対応するプラットフォームは以下の通り!!

大体ゲームを作ろうとして困ることはないほどの数です。 とくに、AndroidiOSMac OS Xに対応してくれているのがとてもありがたいです。

MonoGameを最大限生かすために

さて、それではMonoGameの利点を最大化するためにはどうするか。 ズバリ、この二つを組み合わせて使うことです!

出ました!!!!Xamarin!!!!!!!!

XamarinでAPI等を提供してもらって、MonoGameの仕組みとVisual StudioのSharedProjectを活かすと…? pico1_03.png pico2_03.png piko3_03.png

複数プラットフォームでソースコードをほとんど共有化!!

やったぜ!!

さらにリソースの読み込みも共有化できちゃう!!

実際に書いてみる

流石にゲーム作るのは大変なので画像表示するだけで許してください。 今回は、WindowsAndroidで同じコードで動かしてみます。

のインストールは各自で行ってください。 (多分これ読んでる人たちプロだから大丈夫だと信じてる)

それでは、VisualStudioを起動して

 File->New->Project->Installed/Templates/Visual C#/MonoGame->MonoGame Windows Project

を作成します。 ProjectNameとSolutionNameは、 Solution ├WindowsProject ├AndroidProject └SharedProject という構造を考えて決めてください。 今回は forAdC ├forWindows ├forAndroid └SharedProject という名前をつけました。

しばらくするとエディタの準備が整うので、右側のSolutionExplorerからSolution'forAdC'を右クリックして

Add->New Project->Installed/Templates/Visual C#/MonoGame->MonoGame Android Project

からAndroid用のプロジェクトを作成して追加してください。 ここでまたプロジェクト名を決めることができます。(デフォルトはGame1) 同様に、

Add->New Project->Installed/Templates/Visual C#/Windows/SharedProject

から共有用プロジェクトを作成して追加してください。

すると、以下のような画面になるかと思います。 image まだ中身は何も弄っていません。

それでは、早速まとめましょうか。 forWindowsでは始めにProgram.csを起動しGame1.csを呼び出す形になっています。 forAndroidでは初めにActivity1.csを起動しGame1.csを呼び出す形になっています。 Game1.csの内容はほぼ同一ですので、これをまとめることができます。

Game1.csをSharedProjectに移動してそれを各プロジェクトから呼び出す形にしましょう。

forWindowsかforAndroidのどちらかからGame1.csをSharedProjectにドラッグ&ドロップでコピーしましょう。 そして、SharedProject以下のGame1.csのnamespaceを「SharedProject」(SharedProjectのプロジェクト名と同一)にします。

その後forWindowsとforAndroidのGame1.csを削除してください。

この時点でforWindowsのProgram.csを見てみると、

new Game1()

の部分でエラーが出ています。参照すべきGame1.csが見つからないからですね。 SolutionExplorerのforWindowsを右クリックし、Add ReferenceからSharedProjectを追加します。 その後SharedProjectをインポートします。

using SharedProject;

ここまで正しく書いてもSharedProjectが見つからないというエラーが出ることもありますが、一度ソリューションを閉じて再度開いてみると直ります。ソリューションファイルを読み込み直さなくても正常にビルドできます。

これで前準備が整いました。ビルドしてみてください。 青い画面が表示されたら勝ちです。

それでは、画像を追加しましょうか。

コードを書く前に、画像を準備しておかなければなりません。 MonoGameではコンテンツ(リソース)は別途ビルドする必要があります。

forWindowsのContent->Content.mgcbをエクスプローラで開きダブルクリックし、MonoGame Pipelineを起動します。 File->Newから新しいmgcbファイルを作成します。 場所は実はどこでも良いのですが、共有化してる感じを出すためにエクスプローラーでforAdCフォルダ直下にContentフォルダを作り、その下にContent.mgcbを新しく作成してください。 image その後、MonoGame Pipelineの画面が少しおかしいので引っ張って直します。 直したあとはこんな感じになります。 image その後、Add Existing Itemから追加したい画像ファイルを選択してください。 追加する際はCopy the file to the directoryを選択してください。

そしてBuildからビルドします。 ※Add Existing Item(ファイルのアイコン)、Build(歯車のアイコン)はツールバーから選択できます。 こんな感じになれば成功です。 image 成功したらMonoGame Pipelineは閉じてしまって構いません。

それでは新しく作成したContent.mgcbをforWindows,forAndroidで読み込めるようにしましょう。 まずはforWindowsについて、Content以下にあるContent.mgcbを削除してください。 そして、SourceExplorer上でContentフォルダを右クリックしてAdd->Add Existing Itemから先ほど作成したContent.mgcbを追加してください。その際、「Add」ではなく「Add as a link」を選択するようにしてください。 するとSourceExplorerにリンクとしてのContent.mgcbが表示されますので、右クリックしてPropertyのBuild ActionをMonoGameContentReferenceに設定してください。 forAndroidでも同様の作業を行ってください。

それではコードを書き換えます。 Game1.csを以下のように書き換えてください。(コピペで構いません) なお、Namazuとあるところは追加した画像のファイル名(拡張子なし)としてください。

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace SharedProject
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D texture;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";

            graphics.IsFullScreen = false;
            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 480;
            graphics.SupportedOrientations = DisplayOrientation.LandscapeLeft | DisplayOrientation.LandscapeRight;
        }

        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            texture = Content.Load<Texture2D>("Namazu");

            // TODO: use this.Content to load your game content here
        }

        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                Exit();

            // TODO: Add your update logic here

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            // TODO: Add your drawing code here

            spriteBatch.Begin();
            spriteBatch.Draw(texture, new Rectangle(0, 0, 400, 400), Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }
}

さて、ここまでで必要な作業は終了です。 実際に表示してみましょう。 forWindows image

forAndroid 5662.png

できたー!!!!!!

ということで今回やることは以上です。 お付き合いありがとうございました。

MonoGameの抱える問題

  • 日本語文献が少ない
  • Androidの文献が少ない

くらいでしょうか? XNAのdocumentを読んでも具体的な実装方法が分からず試行錯誤、なんてこともしょっちゅうです。 もう少し日本語で分かりやすくしてくれれば日本でも普及していくと思うのですが… 私も日本語文献の一助になればと思いブログを書いておりますのでよろしければそちらもご覧ください。

参考文献

git再入門

git再入門

この記事は,

  • gitを用いた共同開発をしたことがある
  • 操作ミスの直し方が分からなくて詰む
  • コマンドが色々あるらしいけど覚えきれない

くらいの方に向けたgitの解説記事です.私自身のためのメモでもあります. gitの基本的な構造に触れつつ,各コマンドが実際何をしているかを解説するのが主な目的です. また,コマンドを知らなくてもggる時の適切なキーワード選びが出来るようになれば幸いです. 第一章・第二章でgitの基本的構造,第三章でコマンド解説をします.

第一章 git repositoryの構造

git repositoryとは,所謂「ファイルやディレクトリの歴史」のことです. SourceTreeなどで目にするコミットグラフはgit repositoryを可視化したものです. 第一章では,git repositoryの構造とともに,関連する用語として

  • commit
  • branch
  • tag

を解説します.

commitはsnapshot

端的に言うとcommitは管理下にある1 ファイルやディレクトリのsnapshotです. よくある勘違いとして「commitは前のcommitからの差分」という説がありますが,違います. snapshotとは「その時の状態の複製」です.すなわち,ファイルが変更されてcommitされる度にそのコピーが作成されアーカイブされています.2

さて,このsnapshotは撮るだけでは意味がなく,参照できなくてはいけません. そのための情報をsnapshotと一緒にまとめたものがcommitです. 各commitは以下の情報を持ちます.

  • snapshot
  • commit hash (id)
  • parent commit
  • commit message

commit hash (id)は各commit固有の文字列です.40文字程度の英数字から成りますが,ほとんどの場合先頭7文字で識別可能です. parent commitはそのcommitの派生元となるcommitのことです.大抵parent commitは一つですが,時々0個や2個以上の場合もあります.3 commit messageはcommit時に付与された,そのcommitの説明です.commit messageは後で見る人(∋自分)のためにきちんと書きましょう.

一旦commitが作られた後は,これらの情報が変更されることは絶対にありません. commit message一つ変更するにしても,必ず新しいcommitが作成されます.

branch,tagはcommitを指すポインタ

branchやtagはどちらも「あるcommitへの参照」に他なりません. より正確に言えばcommit hashのエイリアスです. 情報の勉強をした人ならばポインタと言えばピンと来るかもしれません. 特にブランチについては「元となるブランチから分岐した時点からの歴史」と勘違いされることも多いですが,これも違います.

コミットグラフを作成するときを考えてみましょう.各commitはparent commitを知っていますので,どのcommitもやがてはroot commitに辿り着くことが出来ます.しかし,自身をparent commitとするcommitは知りませんので,各派生先の最先端のcommitを別途参照出来る必要があります.その役割を果たすのがbranchです. branchの参照先は,現在の参照先のcommitから派生するcommitが作成される度に更新されてゆきます. しかし,特定のcommitへの参照を残しておきたい場合もあります.その場合はtagを用いることで,そのcommitへの参照を普遍的に持ち続けることが出来ます. branch,tagはまとめてreferenceと呼ばれます.

第二章 commitが出来るまで

第一章では「commitが出来てから」の話をしましたが,第二章では「commitが出来るまで」の話をします. ここで解説する用語は以下の三つです.

  • worktree
  • index
  • repository

ファイルに変更を行ってからそれをcommitに含めるまでの流れを解説します.

worktreeとは,作業中のディレクトリの状態

第一章でcommitはsnapshotを持つと解説しましたが,考え方によっては現在作業中のディレクトリ自体も一つのsnapshotであると言えます.これがworktreeです. すなわち,worktreeとは作業中のディレクトリの状態そのもののことです.難しく考える必要はありません. ファイルを編集して保存すればその内容は即座にworktreeに反映されます.

indexとは,commitとしてアーカイブされる前のsnapshot

現在編集中のworktreeの状態と,アーカイブとして残したいsnapshotの状態は必ずしも一致しません.そこで,「commitとしてアーカイブされる前の,編集可能なsnapshot」としての役割をindexが担います. 例えば,機能を開発している途中にcommit間の差分が大きくなりすぎると感じた場合は現在のworktreeで行った変更を分割したいと考えます.この時,その状態まで手動でworktreeの状態を戻してしまうと二度手間になります.indexの存在はこういった状況を解決してくれます. 結果として,worktreeの一部または全部の状態をindexに反映させてゆき,indexがアーカイブしたいsnapshotになったらcommitとしてアーカイブする,という流れでcommitが作成されます.

補足,HEADについて

コミットグラフで,HEADという名前を目にしたことがあると思います. HEADはreferenceの一つで,「現在のworktreeの元となるcommit」への参照を持ちます. しかし通常HEADはいずれかのbranchと同じcommitを指すこととなっており,その場合HEADが指すものはcommit hashではなくbranchです. そうでない場合はHEADは他のreferenceと同じくcommit hashを指しますが「detached HEAD」と警告されます.

第三章 コマンドの実態

第一章,第二章ではgitの基本的な構造を解説してきました. そこでの内容を踏まえて,改めていくつかのコマンドが何をしているのかを解説したいと思います.

add

worktreeの状態をindexに反映させます. オプション等の指定により,

  • 管理下の全てのファイルをindexに反映
  • 一部のファイルをindexに反映
  • あるファイルに施した変更の一部をindexに反映

などが出来ます.

commit

現在のindexのsnapshotを持つcommitを作成します. なお,gitの文脈において「commit」という用語は

  1. 上記で説明したcommit(snapshotを持つオブジェクト)のこと
  2. commitを作成する操作のこと

と二通りで使われます. 第一章,第二章においては一回だけ2の意味で用いましたが,その他は全て1の意味で用いています.

log

その名の通り,commitの履歴を表示します. アルゴリズム的には,現在のcommitからparent commitを辿っているに過ぎません. なお,SourceTreeのような表示にしたい場合以下のオプションとともに用いるのがおススメです. git log --oneline --graph --decorate --branches --remotes 私はこれをglとしてエイリアスを貼っています.表示結果は例えば以下のようになります.

$ git log --oneline --graph --decorate --branches --remotes
*   83c7494 (HEAD -> master) Merge branch 'develop'
|\  
| * bf290e8 (develop) poyo
* | 00c5833 just copied
|/  
* 670f4a6 yoyoyo
* 784fd6a increment
* 597fcf9 create po
* f020336 initial commit

Windowsだと「\」が「¥」になるので辛いです.

checkout

checkoutは,「worktreeの一部または全部をあるcommitの状態に変更する」コマンドです. git checkout ${brahch}という用法で最もよく目にすると思います. よく「branchを切り替える」と説明されますが,今までのことを踏まえると,この場合checkoutは「worktree全体をあるbranchの指すcommitのsnapshotに変更し,HEADをそのcommitまで変更する」という操作を行っています. また,git checkout ${commit hash} ${file}という用法もあり,これは指定したファイルを指定したcommitの状態に戻します.こちらは若干マイナーですが,むしろ定義に近い操作です.

その他,git checkout -b ${new_branch_name}という用法もあります. これは同じcommitを参照するbranchを新しく作成します.

merge

図解しているサイトを参照していただけると,merge,cherry-pick,rebaseの動作についてスムーズに理解できるかと思います. git merge ${commit hash}とすることで現在のcommitと指定したcommitの両方の状態を統合したcommitを作成します. 正確に言えば,まず現在のcommitと指定したcommitの分岐元(最も新しい共通の祖先)となるcommitを探します.分岐元のcommitと現在のcommitのdiff,分岐元のcommitと指定したcommitのdiffをそれぞれ取り,共存可能であればそれらを取り込みます. 一方,現在のcommitと指定したcommitで,あるファイルについて異なるdiffが出てしまうと競合が起こり得ます.これは手動で解決するかgit checkout --oursなどのコマンドを用いて解決するほかありません.

なお,余談ではありますがmergeによって作成されたcommit (merge commit)は親commitを二つ持ちます.

cherry-pick

図解しているサイトを参照していただけると,merge,cherry-pick,rebaseの動作についてスムーズに理解できるかと思います. git cherry-pick ${commit hash}とすることで特定のcommitの内容を現在のbranch上に適用できます.mergeとの違いを少々強引に説明すると,歴史を考慮するのがmerge,考慮しないのがcherry-pickです. cherry-pickは特定のcommitと同じsnapshotを持つcommitを現在のbranchの先頭に続けて作成しようとしますが,mergeでは上記の通り共通の祖先からのdiffを考慮した統合をしようとします.ですから,例えばあるbranchにおいてgit merge HEAD^とした場合はalready up to date.と言われ何も変更されませんが,git cherry-pick HEAD^とした場合はconflictします.また,mergeの場合は現在のcommitと指定したcommitの両方を親に持つのに対しcherry-pickの場合は現在のcommitしか親に持ちません.

rebase

図解しているサイトを参照していただけると,merge,cherry-pick,rebaseの動作についてスムーズに理解できるかと思います. git rebase ${commit hash}とすると,現在のcommitと指定したcommitの分岐元を指定したcommitに変更します. しかし,実はrebaseはcherry-pickの連続適用に過ぎません.

reset

git reset ${commit hash}とすることで,現在のbranchの参照先を指定commitに変更します. よく「git reset --hardをするとcommitが消える」といった誤解がありますが,commitは消えません.実は,ORIG_HEADというところに前にHEADが指していたcommitのhashが保存されています.ですから,git reset --hard ${any_commit_hash}をした後にgit reset --hard ORIG_HEADをすると元通りになります.

reflog

git reflogは,HEADの移動ログです.

$ git reflog
00c5833 HEAD@{0}: reset: moving to ORIG_HEAD
597fcf9 HEAD@{1}: reset: moving to 597fcf9
00c5833 HEAD@{2}: rebase finished: returning to refs/heads/master
00c5833 HEAD@{3}: rebase: poyopoyowa-i
670f4a6 HEAD@{4}: rebase: checkout 670f4a6

${commit hash} HEAD@${number} ${action detail} というフォーマットで表示されていきます. ですから,例えば「git reset --hardした後に一つcommitをしてしまったけどやはりresetを取り消したい」という場合,ORIG_HEADはもはや使えませんがreflogから希望のcommit hashをたどることが出来ます.

発展編

この章の内容はgitを利用する上でほとんど必要ありませんので,こたつでみかんでも剥きながら流し読みしていただければと思います.

git object

実は,gitのcommitやsnapshotは全てgit objectと呼ばれるものから成っています.例えば,あるcommitのhashを用いてgit catfile -p ${commit hash}と打ってみてください. すると,以下のようにtreeやparentという表示とともにhash値が表示されると思います.

$ git cat-file -p 83c7494dcbf4c01cae5977ef47b08921fc7077bd
tree e8e20230a07642ef8e1d1905c4b4133f6bfce750
parent 670f4a6f2101192e5f39fe7c94a8504e374d1a55
author Namazu <${email address}> 1577514290 +0900
committer Namazu <${email address}> 1577516327 +0900

poyopoyowa-i

treeはそのgit repositoryのrootディレクトリを示すgit objectで,parentはそのcommitの親commitのhashです. treeのhash値についてgit cat-file -p ${tree hash}とするとそのディレクトリに含まれているディレクトリ(tree)やファイル(blob)が表示されます.これらにも同じようにhash値が振られています.

$ git cat-file -p e8e20230a07642ef8e1d1905c4b4133f6bfce750
100644 blob 31a6b51d9cc6fda577d58b91ba50dc8626c865e4    po.txt
100644 blob 2df961d8030ca4360795e9608c756bdbcbc190b5    yo.txt

.gitディレクト

.gitディレクトリの中にはそのrepositoryを管理するために必要な情報が全て含まれています. ls .gitとやってみると,

COMMIT_EDITMSG
HEAD
ORIG_HEAD
config
description
hooks
index
info
logs
objects
refs

といった内容が表示されます. HEADの中身やrefs/headsの中身,objectsなどを通常のcatコマンドなどで覗いてみると面白いかもしれません.

鉞の飛ばし先

鉞歓迎いたします.正確な情報を発信したいので,誤りを見つけた場合ご指摘いただけますと幸いです. こちらの記事へのコメントまたはTwitterにて@blonde_namazu宛にお願いいたします.

参考文献

基本的にGit Documentationに従いつつ,他のサイトも理解の助けとして参考にさせていただきました.


  1. 実は,「管理下にある」の定義は少々複雑です.「.gitと同じ階層かその下の階層にある」かつ「.gitignore」されていないかつ「一度でもcommitされたことがある」と言えるかと思います.

  2. しかしcommitする度に管理下の全てのファイルをコピーしていては容量が大きくなりすぎてしまいます.

  3. root commit,すなわち最初のcommitには親が存在しません.また,merge commitには2個以上のparent commitが存在します.merge commitの親が3個以上になる場合に興味を持ったあなたは「merge strategy」で検索検索ぅ↑↑🐙

gitのお話を書きました

qiita.com

研究室とかで最近gitで事故った時の直し方とかを聞かれる機会が増えたので,一度まとめておきたいなと思いちょっとだけQiitaに書いてみました. 最近アウトプットあまり出来ていないのでリハビリ程度の感覚です.

もし「gitある程度使えるようになったけど,いまだに何してるかよくわからなくて気持ち悪い」という人が居ましたら是非読んでみてください.

はてなサマーインターン2019に参加してきました

はてなサマーインターン2019に参加してきました。はてなIDid:blondenamazuです。 京都で一ヶ月間非常に濃密な時間を過ごしてきたので書きたいことはたくさんありますが、参加記なので時系列順にまとめたいと思います。 また、2020年度以降はてなサマーインターンへの参加を考えてこのブログを読んでいる方向けにカリキュラムの詳細な紹介もしています。(2019年度と異なる可能性はありますが)

はてなサマーインターン応募〜面接

私は大学院修士一年生なので、今年の夏こそはちゃんとインターン参加するぞ〜と意気込み色々な企業のインターンを探していました。 その過程で東工大で学内修士一年生向けに開催されたインターンシップ説明会ではてなサマーインターンを知りました。

企業ごとにインターンシップのプログラムは様々ですが、全体一ヶ月間で前半二週間講義/後半二週間開発というカリキュラムを組んでいるのは私の知る限りはてなだけでした。 特に講義パートを設けている点が非常に珍しく、内容もWeb開発やインフラ、デザイン、企画など様々なテーマが充実しているのが特色だと思います。 私はWeb系の開発をしてみたかったものの自分では取り組めていなかったので、この機会にと思い応募を決めました。

そうして技術課題選考、その後面接という形でした。 面接では私がサークルで取り組んできたゲーム制作や競技プログラミングなどの話に耳を傾けていただきました。 いくつかのインターンシップの選考面接を受けた中で、最も話しやすく緊張もせずに受けられた面接でした。

午前中に面接が終了し、正午ごろには合格の連絡が来ました。 ICPC国内予選が午後にあったのでバタバタしている中でしたが、嬉しくてめっちゃテンションが上がったのを覚えています。 おかげで国内予選も頑張れました。

前半講義パート

前半の講義パートでは、毎日社員の方々が持ち回りで講義をしてくださいます。 前半のスケジュールは基本的に

時刻 内容
10:30-11:00 出社・アンケート記入
11:00-13:00 講義
13:00-14:00 昼休み
14:00-19:00 課題
19:00 退社

でした。

一週目の講義内容はGo言語によるWebアプリケーション開発、DBについて、セキュリティについてなどWeb開発全般について必要な知識を身に付けるものです。 一週目の課題は事前に与えられた最低限の機能を備えたWebアプリケーションに対して、その日の講義に関連した提示された変更を加えていくというものです。課題は毎日与えられて、翌日11時までにPRで提出するというものです。

二週目の講義はインフラやデザイン、企画などの内容です。 二週目は毎日与えられる課題はなく、金曜日の成果発表に向けて各自で機能開発をしていきます。

元々のアプリケーションはシンプルなダイアリーでしたが、私は小説投稿サイトに改造しました。 UXを意識した開発をし、ほたて*1では14票で3位を獲得しました!

後半チーム開発パート

後半の三、四週目の配属チームは前半過程の最後に決まります。 二週目の木曜日にid:motemenさんより無事全員前半過程審査通過の連絡があり、金曜日の面談でid:taira1999120さんとともにアプリチームへの配属が決定しました。

後半過程のスケジュールもほとんど前半過程と似ていて、

時刻 内容
10:30 出社
10:30-13:00 チーム開発
13:00-14:00 昼休み
14:00-19:00 チーム開発
19:00 退社

初日は同期のid:taira1999120さん、メンターのid:kouki_danさん、デザイナーのid:n-sugaさんとともに後半二週間での目標設定についてずっと話し合っていました。 結果、私がAndroidid:taira1999120さんがiOSで同じ機能を実装することにしました。インターンで両OS開発するのは初めてらしいですが、実際かなり大変でした。

二日目から本格的に開発に取り掛かったのですが、マルチモジュール開発についてあまり詳しくなかったので変なところにコードを書いて怒られていたりしました。それはそう。 また、NavigatorやData Binding、Injectionなど自分でAndroid開発をするときに逃げてきたところと真面目に向き合いました。 あとMVPからMVVMへの移行中で両方の実装が見比べられたりしたのは面白かったです。

四週目前半までわからん〜って言いながらずっとid:kouki_danさんやid:takuji31さんに泣きつく仕事をしていました。 最後の二日間くらいは最終成果発表に向けてまだやることが無限にあることに気づいて絶望しつつ、作業には慣れてきたので割とノリノリで作業していました。この二日間は一番大変でしたが、一番楽しい時間でもありました。

しかし最終成果発表にリリースが間に合わず、Androidはクライアント企業様の動作確認待ち、iOSAppleの審査待ちでした。

…となる予定でしたが、アプリチームの発表開始5分前くらいにクライアント企業様からOKが来てAndroidは100%リリースされました。あの瞬間だけは多分私を中心に世界が回っていたと思います。

ほたてによる投票の結果は5チーム中4位でした. やはり機能がきちんとリリースできてユーザーからのフィードバックまで受けられたチームと比較すると見劣りしてしまいましたが,票数で見ると30票以上も獲得できたのはとても嬉しいです.

成果物

前半過程成果物 

f:id:blondenamazu:20190913163824p:plain
前半過程成果物

小説投稿サイトを作りました。 画面間の移動が自然に行えることや書き手が困らないようなUIを目指しました。 また、ログイン情報を監視して記事の作成の可否を決めたりしました。

小説を書く/読むときに左に他のエピソードの一覧が見えるようにしたのがこだわりポイントです。

後半過程成果物

f:id:blondenamazu:20190913165513p:plain:w600

f:id:blondenamazu:20190913164909p:plain:w300f:id:blondenamazu:20190913164932p:plain:w300

コミックDAYSのアプリの布教機能を強化しました。

布教(シェア)された数に応じてユーザーにリコメンドする機能などを考案し、実装を行いました。 本当はこれ以降のアップデートも考案していてクライアント企業様からもOKが出ていたのですが実装が間に合わず無念でした。 id:kouki_danさんやid:takuji31さん、id:n-sugaさんなどが実装してくださることを楽しみにしています!!

最後に

私は普段東京暮らしなのでインターン参加前は京都で一ヶ月過ごすのに不安もありましたが、インターン最終日の今となってはもはや東京に帰りたくないくらい快適に過ごせました。 これも長きに渡る準備の末暖かくインターン生として受け入れてくださった社員の方々のおかげだと思います。

この記事の読者にははてなサマーインターンへの参加を検討している方もいると思いますが、インターンを大事にしていただける社風や社員の方々からのサポートの手厚さなど魅力的な点は非常に多いです。逆にデメリットは頑張って考えても思いつかないくらいなので、一ヶ月間京都に来られるならば是非応募してみてください!

P.S.

後ほどインターンシップにまつわる話のうち、ここに書ききれなかった部分を書きたいと思います(生活面など

*1:はてなで日常的に用いられている社内投票システム

ICPC 2019国内予選参加記

7/12 (金) に開催されたICPC 2019国内予選に参加してきました.

チーム

P IS NPというチームで出てきました. チームメンバーは,

の三人です. 全員AtCoderのレートは水色です.

同じくらいのレートで組めたら楽しいよねって感じで私が二人を誘いました.

結果

  • 全体で58位/458チーム
  • 東工大内で7位/22チーム

でした!!

f:id:blondenamazu:20190715225902p:plain

自分たちの実力を鑑みればかなり力を出し切れた方だと思います.

順位表を見ると,今回は3完のチームが100チーム以上あったみたいですね.ミスもなく,実装も早く出来たという点で満足しています.

戦略

言語は私がC++,ぱるまとPolyがKotlinでした. ICPCのルールでは事前にソースコードを準備してはいけないため,私がC++用のテンプレートを書き始めるところからスタートしました.

問題の解き方については,B問題以降はなるべく全員で考察してノーミスを目指しました.

また,私は実装にそこそこ自信があったので主に実装を担当することにしました.

私たちの実際の競技中の立ち回りは以下の通りでした.

  • Namazuが印刷してきたC++のテンプレートを写経開始.同時に,ぱるまとPolyがA問題を考察開始
  • ぱるまとPolyがA問題の解法を確認した後,Polyが印刷された問題文をもらいに行く.
  • Namazuの写経が終わり,ぱるまに言われるままにA問題を実装開始.
  • Polyが印刷された問題文を手に帰還.PolyがB問題を考察し始める.
  • A問題をAC (7:12).
  • Polyが「自明」と言いつつB問題の解法をNamazu,ぱるまと共有.問題無さそうだったのでNamazuがB問題を続けて実装し,ぱるまとPolyはC問題を考察することに
  • B問題をAC (17:26).
  • ぱるまとPolyのC問題考察がほぼ終了したらしく,ぱるまにC問題の実装を任せてNamazuとPolyがD問題を考察開始.
  • C問題をAC (1:04:53).
  • D問題が分からない.ぱるまも含めて考察をするが,解法が生えない.
  • 残り一時間の時点でPolyが「E問題は実装重いけどやるだけだからやれ」と言ってきたので珈琲飲んで気合いを入れて*1NamazuがE問題実装開始.
  • Namazu,先ほど飲んだ珈琲のせいでトイレに行きたくなりつつE問題を実装するが辛くなってきてギブアップ.
  • Polyが「多分嘘解法だけど一旦Dを実装して」というのでNamazuがDの実装を始める.
  • 実装したDを投げる.当然WA.
  • 絶望感に包まれながら競技終了.Namazuはトイレに行く.

このような感じで大体うまく分担して回せていたと思います.

反省

DのDP解法は頑張って思いつきたかった気がします. 実装したのは左から順番に決めていくみたいな手法だったので,その決め方をもう少し賢く出来れば…

Eは気合いが足りなかったと反省しています.

さいごに

チームで競プロやるのめっちゃ楽しいですね. 今回を持って私はICPCの出場権を失いますが,もっと前からこの楽しさに気づいておけば…なんて思ってしまいます. これからも競プロは続けていくつもりなので,その中でまたチームを組んで出られる機会があれば挑戦したいですね.

以上,ICPC参加記でした.

蛇足

P IS NPチーム名はメンバー三人の頭文字であるP,N,PからP≠NP問題を絡めることとBaba Is Youネタで作りました. 本当はeiyatonariみたいな感じでチームメンバーの名前を上手く組み合わせたかったのですが,私が考えた案が悉くpolyにダメ出しされ,ぱるまも凄く気を遣って無理やりフォロー入れてくれるような感じだったのでボツにしました.

参考文献:ダメ出しに容赦がないPoly

悔しかったので客観的な意見を聞いてみようと思い,(誰の案かは伏せて)不採用になった案でアンケート取ってみました.

それぞれの発案者は以下の通りです.

  • Npp:Poly案
  • ParNaPoly:Namazu
  • PolyNaruma:Namazu

対戦ありがとうございました.

*1:ごちうさ二期第6羽参考

最近,競技プログラミングが楽しい

こんにちは,Namazuです. 最近私は競技プログラミングにハマっています. この記事は現状を簡単に書くだけですが,競プロカテゴリを作って時々知見をまとめておきたいななどと考えています.

AtCoder

f:id:blondenamazu:20190613231024p:plain

現在主にAtCoderのコンテストに参加しています. ユーザーページはこちらです. 現在は水色レートの中盤近くです.今年中に青色レートになれたら良いな…などと考えています.

今年5月からABCの問題数が増えましたが,未だにE,F問題がコンテスト中に解けていません. まずはそこからですね…

Google Code Jam 2019

皆参加していると聞いて参加してみました.

  • Round 1A:無回答(恥ずかしながら回答できず)
  • Round 1B:2160th
  • Round 1C:985th (通過!)
  • Round 2 :2443th (惨敗!)

ギリギリでRound 2に進むことが出来ましたがRound 2は全然解けませんでした. 来年はRound 2でもう少しまともに戦えるように勉強したいと思います.

GitHub

こちらにテンプレートとかまとめています. 新しいアルゴリズム覚えたりすると多分増えていきます.

TypingWar

TypingWar

traPにおいて、チームで制作したリアルタイム通信対戦型のタイピングゲームです。

ブラウザゲームなので、こちらからすぐに遊べます。

概要

  • 人と対戦できるMultiモードとAIと対戦できるSingleモードがあります。
  • 1単語打つごとに相手に攻撃が入り、自軍の前線を押し上げます。
  • 語群は3つありますので、好きなものを打ってください。単語が長いほど攻撃力が高いです。
  • ノーミスで同じ語群の単語を5つ打つと、ボーナススキルが発動します。(詳細は以下
  • 相手を押し切るか、60秒経過時点でより前線を押していた方が勝ちです。

詳細なルール等はtraPの公式ブログに上げています。 trapti.tech

制作のお話

TypingWarプロジェクトには第一期、第二期があります。

第一期

この時はMultiモードのみで、Singleモードはありませんでした。

私はチームリーダー件デザイナーとして - ゲーム案の考案 - プロジェクトの運営・方針の決定 - デザインの考案・素材制作

等を行いました。 プログラムには全く触っていません。 当時はまだプログラミング勉強していなかったので…

第二期

この時期に以下の変更がを行いました。 - Singleモードの追加実装 - Twitter投稿機能の実装 - 語群の追加 - BGMの制作(一部をフリーBGMからtraPで制作したBGMへ

私が携わったのは上の三つです。 この時初めてTypingWarのプログラムに触りました。 SingleモードもほとんどMultiモードのコピペでしたが…