mikanbox55's diary

AdventCalenderのために作りました。中の人のやる気しだいで記事が増えるかも

AtCoder ABC 118 D Match Matching

私的にやってるatcoderですが先日ABCのC埋めがやっと終わりました。Dからは1問あたりのボリュームが増えるので詰まった問題とかについて出来るだけアウトプットを残していきたいと思い記事を書くことにしました。

人によってはAB問題は簡単だから埋めるまでも無いって意見の人もいますが、AB埋めする時にc++でやると、STLの各コンテナ型やtemplateの復習にもなるので大抵の方にはお勧めします。

では本題。 問題リンク

問題概要

  • N本のマッチ棒をぴったり使って出来るだけ大きな数を作る
  • 1-9までの数字のうちM種類の使える数字がA_{i}  (1 \leq i  \leq M) で与えられる

制約条件

  •  N \leq  10^4

考察

最初に上の桁から貪欲に決めていく方法を考えた。基本的には桁数が大きいほど良いので、提示された全ての数字 A_{i} のうち、必要なマッチの数が一番小さいA_{i}ものA_{min}を選択し、必要なマッチの最小数で割ればN /  M( A_{min} )、大体の桁数は出せる。

ここで問題になるのは、ちょうどN本使う必要があるため、適当なA_{i}を組み合わせて使用マッチの数をNにする必要があるということである。一番下の桁から探索し、マッチの数がぴったりかつ、桁数が最大で数字が最大になる組み合わせを探す。

....というような考え方でやってたが、マッチの数がぴったりかつ、桁数が最大で数字が最大になる組み合わせを探す この部分の探索が結局難しくて諦めた。なんかいけそうな気もするが考慮すべき制約の数や組み合わせが膨大になってきた時点で他の解法を検討すべきだったと今になって思う

以下に想定した解法でACした記事が載ってた。制約じゃなくてある桁数まで全探索でいけるっぽい。今度試してみるかー。 qiita.com

想定解法

想定解法はDPらしい。確かに制約条件が  N  \leq   10 ^4 なので、DPは選択肢に入れといた方がよかった。 DPの形式は以下
dp_{i} = マッチ棒をi本使って作れる整数の最大値

遷移式
dp_{i} = funcmax(dp ( i ) ,dp (  i  -  M ( A_{j} )   )

確かに、この定義だと dpの添字i*に対して局所最適性 ( i_{1}  \leq   i_{2}  → dp_{1} \leq dp_{2}   )は成り立っていることがわかる。

あとは整数の最大値をどうやって保存するかである。
条件より生成される整数は10^4桁までで、到底long long などに収まらない。初見ではvectorを使って一つひとつ各桁を保存することを考えたが、いくつかの記事でstring型に保存するのを見た。確かにこれならいちいちpushする代わりに 足し算で処理できるし、桁数はsize()で取れて比較もcharを取り出して比較すれば良いので非常にあっている.

あとはfunc_maxの部分を正確に定義すれば良い。ifとかで書かずにちゃんと外部に関数で書こう。
今回重要なのは桁数なので、最初に桁数を比較。次に各桁の数を見ていって比較をすることで正確に比較ができる。

以上。

オフショルニーハイ女子(ユニティちゃん)に森を走らせようと思った理由とか

自己紹介

はじめましてこんにちは。2013年度阪大OLC入学のあっきー@popolocrois55です!雑に自己紹介すると、香川出身、トレは続かない、遠征好き、雨オリエン比較的好き(ただし寒さには弱い)って感じです。最近だと、Bucho Orienteering ChampionshipsのIT media Directorをやってたりしました。諸事情により競技者としてはほぼ引退し、最近は趣味としてゆるーく阪大の練習会や大会に参加しています。

あんまり記事を書くのとは得意ではないですが、書いては消し書いては消しを繰り返し泥沼にハマりました。ブログどうやって書けばええんや......誰か教えてください(土下座)。TwitterオリエンティアAdvent Calender2018の募集を見て、「記事書くなら今年しかない!」と思い筆を執ることにしました。


以下、ユニティちゃんに森を走らせるに至った理由について、オタク向けな内容(Ocadから出力されたDXFファイルの仕様について)も含みつつ話をしていきたいと思いますので宜しくお願いします。

ゲーム紹介

この記事を見ている人はほぼ知ってるとは思いますが、一応宣伝のためゲームページへのリンクを貼っておきます。まだやったことない人はぜひダウンロードしてね!

ユニティちゃんとオリエンテーリング
ユニティちゃんとオリエンテーリング
開発元:Shuhei Akiyama
無料
posted withアプリーチ

ゲーム開発に至ったきっかけ

「これだっ!」
っていう出来事があるというよりかは、前々から色々と頭のなかで考えていることが色々絡まり合った結果生じたという感じです。なんでこの時期に作ったの?って言われたら現役卒業して夏休みとかがヒマになったってのが大きいですね。そのほかの理由についてはこれから書いていきたい思います。

机上練習(地図読み) の限界

1つ目の理由としては、地図読み(机上で行う読図練習全般)に限界を感じていて、効果的な補助ツールを作りたかったってのがあります。まず僕は他の人を出し抜いてる感を得ることに喜びを覚えるタイプなので、練習に限らず練習を工夫することが大好きです。過去のAdvent Calenderにも色々な工夫を紹介した記事があり、そのうち好きな記事のリンクを貼っておきます(以下)。

orien-advent.hatenablog.com

orien-advent.hatenablog.com

orien-advent.hatenablog.com

僕も個人的に練習とか対策とかを色々工夫してきたのですが、地図を使った机上練習だと伸びない能力があるなーと当時から感じていました。どういう能力かというと、ちょうどリンク貼った記事のうち三番目僕の言いたいことが書いてあったので引用させていただきます。

地図に描かれた等高線の表現や、地形のイメージなどは、やはり山に入った回数がものをいいます。

これですね。更に言うと、去年とか僕がコーチの時はコンタ線から風景を書いてもらうような地図読み会もやったりして、多少は机上でもこっちの能力を伸ばす練習を考案したりしたのですが、コンタから地形を読む能力の逆


実際の風景からコンタを想像する能力≒ナビゲーション力?


これらを机上の練習で伸ばすのはほぼ無理じゃないかなと、色々地図読みとか対策しているうちに思うようになりました。

というかそもそも、実際の風景からコンタ線(地図記号)を意識している人って多いんですかね。僕のこれまでの経験だとやっぱり地図読みとかの机上練習では地図から地形をイメージする機会が多く反対はほぼなかった記憶ですが、個人的に見えた風景からコンタをイメージする力ってめちゃくちゃ重要だと思うんですよね。なんで重要かというと文章では説明が難しいので以下に図でまとめました。謎のパワポが出来上がりました。今見るとよくわかんないですね。まとまってないです。

f:id:mikanbox55:20181201225727p:plain
風景からコンタを想像するメリット

まず、そもそもの話として、オリエンで迷いがちな人は上の図の黒い矢印、つまりコンタ線から地形を立体的にイメージするという作業が出来ていないのではないかなーと思います。その場合、地図と現地を対応させるにはわかりやすい点(人特、道の分岐、わかりやすい岩等)しかなく、テレイン内ではっきりと今自分はここにいる!と分かる場所が少ないため迷いやすいのではと思います。実際自分も新人の時はこんな感じで、ある点まで走って、ついたなーと思ったら地図を見て、、、の繰り返しだったのでよく迷ってました。
で次。コンタ線から地形をイメージできる場合。この場合、正しいルートを通れば自分のイメージした地形が現れ、間違えていてもイメージと違い違和感を感じ、そこで立て直すことも出来るため、それなりに迷わずにレース出来ると思います。しかし、自分のイメージがずれて間違っているのに気づけないまま進んでしまいうこともあり、この場合かなり大きいミスに繋がります。
個人的になんですけど、これ(地形からのイメージが現地とずれる)って結構な頻度で起きうると思うんですよね。焦って地図読む時間が足りなかったり、一つ特徴を見落としていたり、自分のイメージ力が足りなかったり....etcと色々理由はあるんですけどまあレース中のミスの大半はイメージと現地のズレかなと思います。
で、このズレを軽減する手段の一つとして、実際の風景からコンタ線(地図記号)を意識、つまり現地からのフィードバックがあると思うんですよね。地図と現地の双方からの情報を頭に入れることで、正しいルートをたどっている時は確信度が高まることによるスピードアップが期待でき、逆に正しいルートから逸れそうになったときに即座に気づくことが可能になると思います。そもそもにんげんにミスはつきものなので、自分の頭に入れる情報のソースを増やし地形イメージのダブルチェックを行うことは直感的にも理にかなってるかなーと思います。..........




このままいくと、無限に話がそれていきそうなのでまとめると


実際の風景からコンタ線(地図記号)を意識する力は重要だけど、机上だと難しいから練習出来るツールがほしいかったから


ってのが理由の一つです。

作ったゲームを遊んでもらいたい

これはまあ強い衝動とかじゃなくて、出来たらいいな〜って感じの願望に分類されるやつです。元々中学ぐらいにポポロクロイス物語とか黄金の太陽とかのRPGに嵌ったのをきっかけにゲーム作りをはじめました。当時ゲームを作るといえばRPGツクールというゲームを作るためのソフトウェアが大正義だったのですが、残念ながら中学生の僕は親にも恥ずかしくて言えず結局HSPというインタプリタ言語を手がかりにごにょごにょ製作してました。(今思うとC++とかやっとけばもっと楽になれたのに...という思いもあるけど当時の自分には難しすぎた)。当時はまだスマホもなかったし、特に公開する場所もないのでモチベもそこまで高くなく、暇な時にぼちぼちコード書いたりドット打ったりしてました。

で、大学2年くらい?になんかのきっかけでUnityに出会いました。この時期になるとスマホガラケーをほぼ駆逐していたので、Unityを使って開発すれば多くの人に遊んでもらえるゲーム作れるなってのはすぐわかりました。大体この時期くらいからUnityを使ったモバイルゲームを公開するって具体的な目標が定まったかなと思います。しかし当時は生活をオリエンに8割振りくらいしていたので如何せん時間が足りず、思い立ってから作るまでに結構時間がかかっちゃいましたね。


ちなみに、Twitter黒歴史ノート晒してた方がいらっしゃいましたが、中学くらいのRPG作ろうと思った時のメモとかは個人的に黒歴史です。ちゃんと廃棄しましたが。

インカレ対策でツール作った経験とか

このツールの製作過程で作成するオリエンゲームの方向性とかが大体定まったので、ツール作成もきっかけの一つになります。現役時に僕はインカレ対策で他の人より凝ったことがしたいってのと、自分のコーディングスキル上げたいってのが動機で現役時は地図から大まかなテレインの3D模型作るツールを作ってました。これはインカレとかの旧図から茶色(コンタ線)だけ抜いて来たあと、人力で高さごとに色塗りしその画像に従ってOpenCVを使ってモデルを表示するってツールです。これは大学3年終わりくらいから使ってるのですが、この頃から地図を3D化する発想はあって、人力じゃなくOcadデータとかから作れたらゲームできそうやなーってのは思ってました。

f:id:mikanbox55:20181201222205j:plain
当時インカレ対策で作ってたツール

OcadからMapデータを作る

オリエンのゲームを作るに当たってテレインは当然たくさん必要なんですけど、これをペイントとかで人力で作るのって正気の沙汰じゃないのでどうにかOcadのデータを使えるようにしたかったんですよね。これが可能ってわかったあとにゲーム作りを始めたので最後の、直接のきっかけになります。


まずOcadから何かしら使えるデータを作ろうとした時に、最初にOcadから出力したBitMapからテレインのマップデータ(マップを離散的に分割し、どこに何があるかを二次元配列等で表現したやつ)作ろうと考えました。が、数時間くらいで速攻で止めました。理由は簡単で画像から得られるのは色情報だけなので、同じ色で違う意味を持つ特徴を区別して取得するのが難しからです。
次にOcadが保存する.ocdファイルを直接読み込むことを考えました。正直バイナリデータとか分からんけどなんとかなるかなーと思ってはじめましたが、案の定挫折しました。一応Ocad11のファイルフォーマットとかのWikiもあるんで超頑張ればいけるかもしれませんが。あと、OpenOrienteeringのMapperとかも見たのは見たんですが結局分からん!ってなって挫折しました。分かるかたいらっしゃればコメントよろです。
で、Ocad触ってたら、エクスポートの項目に.DXFってのがあるのを発見しました。よく考えたら国土地理院からデータをインポートする時に使ってたしこれはワンチャンあるかなーと思ってテキストエディタとか見ながら中身を見ていったら見事ビンゴ。これによってOcadデータから意味の分かるテキストデータが出力可能になりました。ちょうどこれを発見したのが、2017年の3月とかで時間があったのと、これまでに述べた動機により、モチベーションが高まったので開発をはじめました。

最後に

動機について書いていただけなのに、気づいたらかなりの文字数になってました。なんだかんだいって自分もオリエンに対して力を入れていたんだなーと記事を書いていて思いました。前ほど全力で向き合うことはもうないかなとは思いますが、今後もゆるーくながーく付き合っていけたらと思っています。

最初はゲームの中身とか今後についても述べる予定だったのですが、流石に記事が長すぎるのでここで簡単に触れておきます。

ゲーム作成で使っているサービス一覧

  • フロント(Unity C#
  • バックエンド (nifty mobile cloud もしくはAWS)
  • Python,PILOpenCV (DXFデータからゲームで使うデータへの変換)
  • Blender (3Dモデルの調整とか)
  • 任意のドットエディタ、ドローソフト(UI作成)


今後のアプデの予定

  • 操作方法の改善、追加
  • 貧弱なチュートリアルの強化
  • 色々パラメータがあるモードの実装
  • ランキング実装(来年春とかになりそう)
  • 通信対戦とか(いつになることやら)
  • キャラクターの衣装とか、キャラ変更とか(めちゃくちゃ先)

やりたいことは色々あるんですが、現在僕が卒業間近ということもあり開発にほぼ時間が割けないのでアンインストールせずに気長にお待ちいただけると幸いです。今後もゆるーくながーく更新する予定なので皆さんのオリエン力向上や新歓の際の説明とか、色々な場面で使ってもらえると開発者としては冥利に尽きます。

余談

以下マニアックな内容とかオリエンとは関係ない部分もあるので読みたい人はどうぞ。

DXFファイルの仕様

せっかくなので、解析したDXFファイルの手がかりを雑に記載します。僕も完全に理解したわけじゃなく必要なところだけ理解した感じなので、参考程度でお願いします。


まずDXFファイルに関する概要はWikipediaに記載があるので全体の概要はこちらで確認をお願いします。 DXF - Wikipedia

で、Wikipediaに記載があるように、Cad向けのフォーマットなんですがOcadが吐く形式がこれに準拠しているかはよくわかりません。なんとなく準拠してない気がしますが。 次に基本的な部分に解説してきます。Ocadが吐くDXFファイルはテキスト形式で以下のように基本的に2行セットで1つの意味を持ちます。僕が見たところ、2行のうち上の行には明確に意味があるのですが下の行はよくわかんなかったです。なので、とりあえず2行セットで見て上の行だけ見ておけば大丈夫かなと思います。

VERTEX
  8


そして下のコードは、実際のDXFファイルの先頭部分(ヘッダー)で、ここではDXTMINから始まる6行でxy座標の最小値、EXTMAXから始まる6行でxy座標の最大値が記述されています。これによりOcadファイルに記述された地図の最大サイズを計算することが可能です。下のコードの場合だと、幅が(-262 ~ 258.8) 高さが(-188 ~ 239)となります。

DXFファイルの例(ヘッダー)

  0
SECTION
  2
HEADER
  9
$EXTMIN
 10
-262.00
 20
-188.00
  9
$EXTMAX
 10
258.80
 20
239.00
  0
ENDSEC
  0
SECTION
  2
ENTITIES
  0


このヘッダーの下に、Ocadで書いた記号の位置情報が全てテキストで記述されています。Ocadの記号は以下2種類のブロック(POLYLINE or POINT)ごとに分類され、保存されます。

  • POLYLINE (折れ線の特徴:コンタ線とか、多角形とか、曲線とかも全部これ)
    • VERTEX (折れ線や閉路上にある点の数だけVERTEXが存在)
      • 記号id
      • x座標
      • y座標
    • VERTEX
    • VERTEX
    • ....
  • SEQEND

ここまで

  • POINT (点特徴物)
    • 記号id
    • x座標
    • y座標


実際の例(ここで)

  0
VERTEX
  8
3060
 10
-96.30
 20
-175.35
  0
SEQEND
  0
POINT
  8
1160
 10
-23.25
 20
-88.65
 50
0.0
POINT

あと、上に記述した記号idですが、これ実はオリエンの地図図式規定にある記号idと一致します。まさかのまさかですよね。ちなみに、上の例だとPOINTの記号idは1160なので図式規定に従うと「穴」になります。 つまり、(-23.25,-88.65)の位置に穴が存在することを示しています。



上の手がかりより、テキストを上から読み込んで最初のヘッダで地図のサイズを取得し、その後特徴を読み込んで構造体を再構築することで、どの特徴がマップのどの位置にあるかをプログラム上で扱えるようになりました。 自分としてはこれで満足したのでこれ以上調べてませんが、国土地理院から取得してVector Map Maker とかで処理したDXFファイルがどうなっているかとかが分かれば、作図の方にも活かせそうな感じはします。(Vector Map MakerからのデータをOcadで読み込む時に特徴変換せずに最初から任意の特徴に変換とかできそう)

あと、ぜんぜん関係ないですけどこの記事はMarkdown記法で書いてます。知ってる人は今更なに言ってんだって感じにはなると思いますが、Markdownいいですよ。はてなはデフォで対応してるし。