22年振りのエースコンバットを存分に楽しんだ

ストーリーにはほとんど言及せず、各ミッションの感想を主に書いています。Sランク取得や機関砲縛りなどは、まとまった記事をあまり見かけないので攻略の一助になれば。

空を飛んでいる!

エースコンバットシリーズは2以来なので、実に22年振りになります。ハードもPSからPS4と四世代も飛んでいるので、グラフィックの向上がすさまじい。空を飛んでいる感覚が半端なく、VRでプレイして空の王者になりたい。
本作は架空世界ではありますが、緯度と経度が設定されており、光の角度は太陽の高さなどをもとに演算されているそうです。太陽がまぶしくて敵の機影が見えないんだ!

基本的な操作は変わっていないので、22年振りであっても戸惑うことはありませんでした。エキスパートでも問題なし。結局、難易度エースの全ミッションでSランクを獲得し、それに飽き足らずにイージーではありますが機関砲縛りを達成しました。今はノーダメージクリアを目指しています。
自分なりに考えてルートを構築するのが楽しいです。自分ができそうなことを考えて、試行錯誤するのが楽しいです。その点で、機体がたくさんあって兵装も豊富で、さらにパーツの組み合わせもあるのが本作の強みかなと思います。

ドックファイトが好きです

子どもの頃から戦闘機に憧れがあったので、戦闘機をモチーフにしたゲームにも手を出していました。SFCにもドッグファイトを題材にしたゲームがありましたが、操作性もグラフィックも今一つで、ミサイルも現実に即した本数しかもてないストイックなものが多かったです。本格的なフライトシミュレータはPCが主流でしたし。

エースコンバットはフライトは本格っぽいものの、ドッグファイトではミサイルを撃ちまくれるので爽快感があり楽しかったです。ポリゴンによる3D化の恩恵を多大に受けたゲームでしょう。2もそのままプレイし、機関砲縛りなどもやりました。
なぜか、評判の高い3はプレイしませんでした。恐らく、他のゲームが忙しかったのだろうと思います。この頃から、全般的にやり込み要素の多いゲームが増えていったように思います。舞台設定が、近未来になりストーリーを前面に押し出したのも肌に合わなかったようです。エースコンバットの世界観は2で萌芽していますが、決定付けたのは3以降でしょう。7も3につながるストーリーのようです。端的に、私はエースコンバットシリーズにストーリーを求めていませでした。7も熱い展開などもありますが、個人的には坦々とミッションをこなす方が楽しいです。なので、基本的には各ミッションの感想を中心に語っていきます。

ストーリーは特に興味は無いですが、一番好きなキャラクターはミハイです。亡国の空の王者。かっこよすぎますね。無線の掛け合いも面白く、途中からカウントがデレ始めるのはニヤニヤします。フーシェンとの掛け合い好きです。気持ちが入ってしまうのはドクター・シュローデルでしょうか。
無線でストーリーを追うのが難しいとの評判もありますが、私はミッションを何度もやり直しているので、分かりづらいと思ったことはないです。ゲームとして調整された難易度から見ても、何度もやり直すことを前提にしているように思えます。

パーツは自動回復が地味に便利

ノーマルをクリアしてマルチで遊ぼうと思っていたら、隠し機体が出現し、そいつを使ってみたくなったので、ハードを始めてしまいました。結局、隠し機体のスキンも欲しくなり、ネームド機を全て集めることに。隠し機体でハードもクリアできたので、そのままエースにも挑戦し全ミッションでSランクを獲得しちゃいました。メダル集めのために、イージーですが機関砲縛りでクリアしてしまい、現在はノーダメージクリアに挑戦中。その内、キャンペーンモードの4時間半クリアもやる予定です。

機体や兵装にパーツの選択が本作の醍醐味ですが、私はミサイルの誘導性と機体の制御系につぎ込んでいます。ただし、一番便利だったのは エースコンバット7 全ミッションSランク取得時の目安タイムとスコア(難易度ACE) - おうまさん でも述べられているように、自動回復のある「自動消火システム(DMG.RECOV+)」でした。50%までしか回復しませんが、ダメージを食らいながらも無理してごり押しができるので使い勝手が良いです。スコアを稼ぐミッションにしても、迅速に敵を倒すミッションでも有効です。防衛任務は場合によりますが、全ミッションを通じて目立たないけど陰の立て役者として機能してくれました。

兵装としてはPLSLがかなり強い。距離6000未満から攻撃でき、対空でも対地でも有効。敵機が固まっていれば、とりあえずぶっ放しとけばOK。ただし、雲の多いミッションでは無力・・・・・・。基本的にはミッションの用途に合わせて、自分の苦手な部分を補う特殊兵装を選ぶのが攻略のポイントでしょう。

防衛ミッションの防衛しどころが分かりづらい

ミッションの種類は、ターゲット撃破、スコアを稼ぐミッション、護衛ミッションに分けられるでしょう。ターゲット撃破は対空にしても対地にしても、やることが明確で、素早く撃破すれば高いランクが見込めます。ルート構築もしやすいですし、優先して相手をすべき敵も分かりやすい。
クリアに所定のスコアが必要なミッションも目的は明確ですが、スコアの稼ぎ方は自分で考える必要があり少々難易度が高いです。増援のタイミング次第で、各エリアをミッション中のどのタイミングで叩くかもポイントで、それらを考えるのが楽しみの一つです。
護衛ミッションは特定の対象を守り切れればよいので一見すると簡単そうですが、護衛に注力すべきとそうでない時のタイミングが分からず、それが難しさを助長しています。その時々ですべきことが分からなくなることがしばしありました。
基本的には護衛対象にはりつく敵を排除すればよいのですが、排除すべき時とそうでない時の落差がありすぎます。排除しなくてもいい時は、とことんほったらかしても大丈夫なのに、一度襲撃が始まると、あっという間に撃墜されます。防衛対象に残りHPゲージなどがあれば危険度が明確になるのですが、それもないので護衛対象がいつの間にかに撃墜されていることがしばしありました。しかもどの敵にやられたか分からないので対策を立てられない。また、護衛対象の移動速度が決まっているので、ミッションが長めになるのも苦手です。

初回プレイ時に戸惑ったミッション

ノーマルをプレイしていて立ちはだかった最初の壁は「06 Long Day -制限時間内に目標得点を獲得せよ」でした。スコアの稼ぎ方が分からず、何度もやり直す羽目に。地上よりも航空機の方がスコアが高いことに気がついてからは簡単になりました。どちらにせよ、空中からミサイルに追い回されると地上への対応ができないので、航空機を先に対処すべきです。その後は、難易度エースでも苦労することはありませんでした。

次は「10 Transfer Orders -マッキンゼイ司令を護衛せよ」でした。いつの間にかにマッキンゼイ司令が撃墜され、何度もゲームオーバーになりました。まぁ、こいつはむしろ死ぬべきだと思いますけど。恐らく、敵の航空機にやられていたのだと思うのですが、今となっては分かりません。SAMの場所と敵の増援タイミングを把握してしまうと、非常に楽なミッションです。

「12 Stonehenge Defensive -ストーンヘンジを防衛せよ」も苦労しました。最初は対空に注力してましたが、地上部隊も対処しなければストーンヘンジを守り切れません。そうするとミサイルが足りません。爆撃機で地上部隊を殲滅していたらなんとかなりました。ただし、その後にアーセナル・バードが控えているので特殊兵装を対地か対空のどちらかにすべきかは悩み所です。
ノーコンテニューで挑む場合はミサイルが足りなくなりがちですが、本作はコンテニューしてもSランクを狙えるのが救いです。
このミッションは開始直後に右側に見える地上部隊を減らしておくと、自軍の損耗が減り後々楽になりますね。

「14 Bunker Buster -峡谷を突破し、敵施設を接収せよ」はエースコンバットお馴染みの渓谷ミッション。最初はなかなか渓谷を抜けられませんでした。何度も繰り返して渓谷にぶつかる度に、なぜだか心が晴れやかになってきました。何度も繰り返した結果、今では2分以内に渓谷を抜けられるようになりました。

「16 Last Hope -エルジア軍将校を護衛せよ」は未だに苦手意識があります。敵を視認する作業は割と楽しいのですが、中盤の高速道路を乗ってからの護衛が苦手です。吊り橋を渡るあたりが特に辛い。

最終ミッションの「20 Lighthouse -新型兵器を撃墜せよ」ではトンネルに苦労し、最後の軌道エレベータの垂直上昇にも苦労して何度もやり直しました。垂直上昇中に加速する必要がないことに気がついてからは楽に行けるようになりましたが、未だに垂直上昇する前に軌道エレベータに侵入できず失敗することがあります。あと、出口付近のワイヤーにも当たり判定あるんですね。軌道エレベータを抜けた後にワイヤーに当たってゲームオーバーになったことがあります。

苦労したネームド機

ネームド機は条件を満たして出現させ倒す必要があります。条件を満たすのが難しいのはもちろんのこと、時間制限があると撃破にも苦労させられます。また、ミッションによってはネームド機を出現させないとランクSを取得しづらいケースもあります。

特に苦労したのは「08 Pipeline Destruction -敵港湾施設を殲滅せよ」と「13 Bunker Buster -弾道ミサイルを破壊せよ」の二つ。
「08 Pipeline Destruction -敵港湾施設を殲滅せよ」でネームド機を出現させるには、オイルタンクを全て破壊しなければなりません、これが中々難しい。対地の特殊兵装が必須だと思います。そして、ネームド機が出現するのはミッションの後半。ただし、砂嵐の中を進むトラックを追いかけながらネームド機も探す必要があります。ミッション後半にコンテニューするとネームド機は出ません。つまりオイルタンクを破壊する所からやり直しなのも辛い所・・・・・・。

「13 Bunker Buster -弾道ミサイルを破壊せよ」でのネームド機出現条件は、5分以内にミサイルサイロを全て破壊することです。ミッション毎に当たりのサイロの場所が変わりますが、リスタート時は変わらないので、何度かリスタートすれば5分以内に破壊できるようにはなります。しかし、ネームド機の出現位置が鬼畜です。弾道ミサイルが発射される後半に、最初の一発とは真逆の方向に逃げるように出現します。このミッションでは特殊兵装を利用できないので、ロングレンジのミサイルでの対処も不可能です。速度を出せる機体で挑む必要があるのですが、それでも迅速にネームド機を倒さないと弾道ミサイルの破壊が間に合いません。その上、ネームド機は固いときたもんだ。当然のようにコンテニューするとネームド機は出ませんので、前半からやり直す羽目になります。

「17 Homeward -自軍を支援せよ」はマスドライバーのレールに沿って飛ぶのが条件ですが、条件を満たしたかが分かりづらい。また、敵機に交じって出現する上に視認作業を終えてから撃破する必要があるので大変でした。ネームド機を視認した後も、時間制限のある中でネームド機を倒す必要もあります。「16 Last Hope -エルジア軍将校を護衛せよ」も視認してから撃破しないと、撃破扱いになりません。さらに、護衛しつつスコアを稼がないといけないの条件を満たすのが難しい。

「11 Fleet Destruction -敵戦力を殲滅せよ」は難しいというよりも、出現条件を満たす方法が分からなかったというのが正しい。超遠距離攻撃できる特殊兵装を使えば、割と簡単になりました。

難易度エースで別ゲーになるミッション

難易度エースになると、自機の装甲が柔らかくなり、敵は固くなります。敵はミサイルをバンバン撃ってきますし、バンバンよけます。特に無人機とミスターXことミハイのミサイルのよけ具合が半端ないです。無人機は既にトリガーの動きを学んだのではって感じのよけっぷりです!?また、スコアを稼ぐミッションではより多くのスコアを稼ぐ必要があります。ただし、エースに挑むくらいの技量があればそんなには困りません。基本的には……。

先ず苦労したのは「08 Pipeline Destruction -敵港湾施設を殲滅せよ」です。前半はスコアを稼ぐ必要がありますが、ほとんどの攻撃対象はスコアの低い地上ばかりです。オイルタンクを狙えば効率的にスコアを稼げますが、それでもスコアがギリギリになる。そして、地上ばかりを相手にしていると、難易度エースの敵航空機からミサイルを撃ちまくられます。

「07 First Contact -敵レーダー施設及び対空火砲を破壊せよ」はなんてことのないミッションです。ノーマルで始めて挑んだ際には、勝手が分からず護衛対象がAI機に打ち落とされてましたが、ハードではなんなくクリアできるようになっていました。ところが、難易度エースで変貌を遂げた無人機の洗礼を浴びることに。当たらない上に、護衛対象に容赦なく攻撃を浴びせます。何度かゲームオーバーになってしまいました。雲が多いのでロックオンしにくいのも地味につらい。

その後は、苦手なミッションなどもありましたが、Sランクでクリアしたミッションもそれなりにあったので、歯ごたえはありましたが苦労はしませんでした。「14 Bunker Buster -峡谷を突破し、敵施設を接収せよ」ではスポットライトの数が増えていたので、敵が増えているミッションもあるかもしれません。渓谷は散々抜けてきたので、難易度エースに挑める人ならスポットライトが増えても困ることは無いと思います。また敵も固くなっているようで、ミッション17のマスドライバーは三発ほど打ち込まないと撃墜できませんでした。

しかし、まさか「20 Lighthouse -新型兵器を撃墜せよ」で苦労する羽目になるとは!初回プレイではトンネルや軌道エレベータに苦しめらたものの、慣れればミスも減りました。
トンネルと垂直上昇さえできれば半ば消化試合みたいなミッションであり、ハードでは苦労しませんでした。ところが、最後にまたしても無人機が牙を剥く!
先ず、ミッション前半の二機の無人機にミサイルが当たらない!どう考えてもエンジンストールするであろう軌道でミサイルを避けていきます。さらに、小型機がレーザーで的確にミサイルを打ち落としていく。慈悲は無い。

苦労はしつつも、それなりに早いタイムで無人機を落とせるようになりました。残るはトンネルと軌道エレベータなので、楽なものだなと思ったらまたしも無人機の機動性が牙を剥く!!軌道エレベータの地下空間でデータを送信している小型機にミサイルが当たらない!?ハードまでは地下空間に入った直後にミサイルで撃ち落とせていた小型機が、狭い空間でミサイルをよけまくります。未だに安定して倒せませんが最後に信頼できるのは機関砲でした。

難易度エースでSランクに挑む

難易度エースでキャンペーンをクリアして、それなりにSランクを取れていたので、折角なので取れなかったミッションをフリーモードで再トライ。
本作はスコアを稼ぐだけではSランクは取れません。タイムボーナスが大きく寄与するため、スコアを稼ぎつつ短時間でクリアする必要があります。必ずしもネームド機を撃破する必要はありませんが、スコアを稼ぎにくいミッションでは出現させた方がいいでしょう。ノーダメージでもボーナスがつくので、それを狙うのもアリです(むしろ、イージーではそれを狙わないとSランクとれないかも)。
また、本作ではリスタートしても、時間を取られなければSランクは取れます。つまり、長いミッションではチェックポイント後にミサイルをリロードするためにリスタートしてもSランクを取得できるようになっています。たとえば、「12 Stonehenge Defensive -ストーンヘンジを防衛せよ」や「19 Lighthouse -アーセナルバードを破壊せよ」ではミサイルが不足しがちなので、チェックポイント通過後にリスタートした方が、ノーコンテニューよりも簡単にSランクを取得できます。

もっとも試行回数が多かったのは「09 Faceless Soldier -敵レーダー施設を破壊せよ」でした。前半は雲に隠れながら迅速にターゲットであるレーダーとそれ以外も撃破しつつネームド機を出現させ破壊し、後半は迅速に不明機を撃破する必要があります。特殊兵装としてLAGMを装備しても左回りで攻めるも上手くいかず。ミサイルに耐えられるように、装甲を厚くし自動消火システムでごり押しつつ、右回りで攻めることでネームド機を撃破しつつ迅速にターゲットを撃破できるようになりました。
右回りの方が、ターゲット以外を撃破しやすく、また比較的雲が多くて広い空間にネームド機を討てるので左回りよりは楽だと感じました。

難易度エースで苦手だった「08 Pipeline Destruction -敵港湾施設を殲滅せよ」も苦労するかと思いましたが、予想よりは苦労しませんでした。苦労させられた分、ミッションを何度も繰り返している内に攻略法が身についていたようです。

「13 Bunker Buster -弾道ミサイルを破壊せよ」は思ってたよりも大変でした。先ず、正解のサイロを探し、次に航空機を権勢もしくは撃破しつつ5分以内で破壊できるルートを構築しる必要があります。ハードくらいなら航空機を無視できますが、エースだと対応しないとミサイルを撃たれまくって結構うざいです。そのため、航空機にも対応できるルートを構築する必要があります。

「20 Lighthouse -新型兵器を撃墜せよ」は小型の無人機を忘れずに撃破しておく。新型機にミサイルを当てるためにも撃破して置いた方がいいですね。

そして機関砲縛りへ

難易度エースの全ミッションでSランクが行けてしまったので、メダルを集めるべくイージーで機関砲縛りに挑みました。
とはいうものの、クリアできる見込みもないのに挑むのは無謀でしょう。そこで、「20 Lighthouse -新型兵器を撃墜せよ」を機関砲のみでクリアできるかを先ず挑戦しました。結果的にクリアできたので、キャンペーンを周回することにしました。
「20 Lighthouse -新型兵器を撃墜せよ」は一機を撃墜すると、もう一機が発狂するので、なるべく均等にダメージを与えておきたいです。先ず無人機が軌道エレベータの方に向かうまでは一機を追い回してから、もう片方を追い回します。そうここうしていると小型機を出す際に無人機の動きが止まるので、その隙を狙って黒煙が上がるまで撃ちまくります。この時に倒さないように注意しましょう。その後は最初に攻めていた方の無人機に攻撃の手を移し撃破すれば、もう片方も割とすぐに撃破できるはず。まぁ、その後の小型無人機と、軌道エレベータの地下空間も大変なんですけどね。

機関砲縛りでは無人機の応対が大変ですが、個人的にはミハイの方が辛かったです。無人機とは違ってイベント戦でもあり、イベントが進行する前にダメージを与えても無意味です。イベント発生後に一定のダメージを与える必要があります。時間が経つにつれ、動きが鈍くなるものの、こちらも焦るのでドキドキします。「15 Battle for Farbanti -敵戦力を殲滅せよ」では残り時間2分まで粘られました。
「18 Lost Kingdom -シラージ城および周囲を制圧せよ」ではレールガンを撃つ際に隙ができるものの、機関砲が当たる距離にはいませんし、距離を詰める際に失敗するとレールガンが直撃してイージーでも一発ゲームオーバーになります。その点で、ミッション20で自機に向かってくる無人機の方が御しやすいです。

「19 Lighthouse -アーセナルバードを破壊せよ」は割となんとかなりました。アーセナルバードの下部モジュールに機関砲をやや当てにくくはありましたが、無理な体勢で打ち込む必要はありません。一方、「12 Stonehenge Defensive -ストーンヘンジを防衛せよ」ではアーセナルバードが現れた際に、ストーンヘンジを防衛しきれないことがありました。このパートでもストーンヘンジを守り切れないとゲームオーバーになるんですね。

ちなみに「13 Bunker Buster -弾道ミサイルを破壊せよ」では、誘導爆弾はつかってもOK。というか、そうでないとクリアできません。後、イージス艦を機関砲で撃破しようとすると、滅茶苦茶大変です。イージス艦、めっちゃ固い。同様に、ミッション17のマスドライバーもめっちゃ固いです。

無人機を主軸とした7

エースコンバット7は無人機を主軸としたゲームとなっており、3の到達を感じさせるつくりになっています。ゲーム全体を通しても、無人機に苦戦する構成になっています。
どの難易度でも活用できる無人機を誘導する方法として機関砲が有効です。無人機は攻撃をよけきった後に一瞬の隙があるので、そこを追撃するのがセオリーです。つまり、ミサイルを一発撃って、よけきった無人機に追撃するのが一般的な戦法でしょう。それとは別に、機関砲が届く範囲ならば、機関砲を無人機に打ち込むと、その動きを硬直させることができます。その間に、ロックオンしたミサイルを打ち込むと割と簡単にあたります。あるいは、機関砲で倒すこともできます。この戦法はミハイにも有効です。ただし、言うは易しで、機関砲で無人機を牽制できる距離まで近づくの難しいんですけどね。

ちなみに、ノーダメージクリアをイージーで始めましたが敵の機関砲がウザいです。案の定、「12 Stonehenge Defensive -ストーンヘンジを防衛せよ」はつらかったです。

おばけのアイコン遍歴

アイコンをリニューアルしました。新しくしてからも、ちょこちょこと細かなマイナーチェンジを繰り返し、現在のバージョンで落ち着きました。
昨今のサービスでは、円状にカットされたアイコンが多いので、それを利用する方向性に。二体のおばけを陰陽図っぽく配置しつつ、白いおばけは濃い藍色と円形のアイコンによって補完されるよう狙いました。輪郭がボヤッと見えてくるのが、おばけらしくて好きです。藍色の方もうっすらと顔が見える色合いて、輪郭の曖昧さが「最終防衛ライン」を表しているのです!*1

アイコンをリニューアルした旨をTwitterで告げたら「最終防衛ライン」と「おばけ」の関係が分からないとのリプライを貰いました。確かに全然関係ないので、アイコンの遍歴と合わせて説明しましょう。

f:id:lastline:20190315124010p:plain

2010年まで:ねないこだれだ

おばけのアイコンを最初に使ったのは、恐らくはてなブックマークです。サービス開始頃から使っていると思うので、2005年頃からでしょうか。
アイコンを設定する際に「ねないこだれだ」がすっと頭に浮かびました。印象に残ってずっと心に留まっていた絵本だったからでしょう。また、ふたば☆ちゃんねるの二次元裏板である虹裏でコラージュがたくさん作られており、ネットミームとしても強いのもアイコンとしてふさわしいと考えたのかも知れません。まぁ少々ミーム力が強すぎましたが。

2007年頃からTwitterを始めましたが、その際も特に何も考えずに「ねないこだれだ」を使っていました。夜中に「ねないこだれだ」ともつぶやいてネタにもしてました。

はてなだけの頃は特にオフ会などには参加しなかったのですが、Twitterを始めからちょくちょく参加するようになります。DMのおかげかな。幸いにも、はてなブックマークなどでホットエントリーになる記事もあり、はてな界隈のオフ会が多かったのっで、割と認識されていたように思います。
ID よりも「ねないこだれだ」のアイコンが強烈だったようで、アイコンを覚えてる方が多かった気がします。そのせいか、次第に「おばけ」と呼ばれる機会が増えていきました。
lastline は ID であり、ハンドルネームとして意識したことはないです。個人的に名前は識別できればなんでよく、特にこだわりはないので呼びたいように呼ばれていたら、「おばけ」が定着していました。

2010年にドミニオンが流行ってまして

2010年にマイナーチェンジして「抑留の最終防衛線(ラストライン)」を入れ込みました。アイコンとしてはごちゃごちゃしてデキは良くないですね。
「抑留の」と二つ名みたいのを付けていたのは、当時ドミニオンの海辺が出た頃で、「抑留」が好きだったから。また、「とある魔術の禁書目録」っぽいロコが作れるジェネレーターが流行っていたので、それに影響されたのもあります。

ちなみに、「抑留」のコストは2コイン。効果は+2コインで廃棄する際にサプライの山札に抑留トークンを配置でき、プレイヤーがカードを購入する際に山札にある抑留トークンの枚数に応じて呪いを獲得するというもの。相手の邪魔をするカードであり、使い切りで自分の手数が遅くなるので、あまり使い勝手の良いカードではないと思います。先手番で3ターン目の打てれば効果は高いです。尚、私は1, 2ターン目で購入したカードが埋まって5ターン目に引くタイプです。

2011年にドット絵化

長らく「ねないこだれだ」を利用してましたが、著作権的にはよろしくないので、自分で描くことにしました。2011年に、単純明快なデザインとしてドット絵で「ねないこだれだ」を作ってみました。ドット絵ですが「抑留の最終防衛線(ラストライン)」が残ってるので、アイコン全体としてはごちゃごちゃしたままですけども。ドットにアールがついているので、タイル絵風になっているのが小さなこだわりです。

2012年にアイコンをから二つ名を省きました。斜め視点の3Dドッド絵風で質感がガラスブロックっぽいので、今から見ると Minecraft っぽいですね。

2013年にマテリアルデザインっぽく

2013年頃から、マテリアルデザインなどが叫ばれるようになり、アイコンをシンプルにしたいなと考えていました。Windows 8マテリアルデザインを参考にし、ドット絵を踏襲しながらシンプル化を図りました。斜めを維持したのは、Windowsのスタートボタンを参考にしたからです。ドットの格子も、Windowsのタイル状アイコンっぽくて気に入っています。

このアイコンを長らく使っていたのですが、2016年にマイナーチェンジしました。おばけを正面に向け、格子をなくしてフラット化を図りました。ただし、このアイコンは縮小すると潰れてしまうので、はてなブックマークとは相性が良くなかったです。

2018年に円形への対応

2017年にTwitterのアイコンが円形になりました。この頃からFacebookを倣ってアイコンを円形にするサービスが増えたように思います。同じ頃に、はてなのアイコンも円形になりました。

正方形からなるドット絵は、円形のアイコンと微妙にマッチしていません。おばけの曲線化は、ドット絵の頃からずっと考えてはいましたが実行には移しませんでしました。そこで一念発起し、2018年にドット絵から曲線によるおばけに変更。楕円を切り取って口にしたら、スマイルマークっぽくなりました。
曲線にしたものの、ずっとおばけの手が気になっていました。手はドット絵の頃から納得のいく仕上がりではなく、アイコンとしてバランスが取りづらいなと感じていました。縮小表示すると、しばし手が潰れてしまうのもアイコンとして具合が悪い。
邪魔になるのなら、いっそのこと取り除いてみようと思い立ち再デザインしたのが現在のアイコンです。手を省くと、よりフラットにスリムになりました。当初は白い一体だけでしたが、余白にもおばけがいることに気がつきうっすらと目と口を入れてみました。結果的に陰陽図っぽくなりました。円形なら、いっそのこと白い方は余白でみせようと思い立ち、現在のバージョンに落ち着きました。

f:id:lastline:20190316131713p:plain

最新版のリニューアルにも紆余曲折がありました。おばけの輪郭や目と口の形状とその位置で表情が変わってきます。顔のベースは表情に富んだ以前のアイコンを引き継ぎました。当初は、白色と藍色ともに輪郭がありましたが、ふと藍色の方を背景色と同じすることを思いつきました。バランスは悪くないのですが、縮小すると白の方が潰れてしまいます。そうならばと正立のしてる方を藍色にして、逆側と透過色にしてみるといい具合です。ただ、それならば逆向きの方が良さそうだと回転させ、現在のバージョンに至っています。白色というよりも、実は透過色として設定しているので、背景色によっては溶け込むのが面白い点です。

*1:ということに今しました

Pokémon Shirt が届いた!!

www.pokemon.co.jp

先行で注文販売していたPokémon Shirtが届きました!
第一世代のポケモンを元にしたデザインのシャツをオーダーできます。

カジュアル、ドレス、アロハを選べ、ドレスは首回りやゆき丈を指定可能。
シャツ全体のデザインはもちろん、襟、袖口、ポケットなども変更できます。
それぞれのパーツに好きなポケモンをあしらうことができます。ヒトカゲリザードリザードンと進化先のポケモンに統一したり、なんてことも。ニョロゾ系が統一感があります。
ドレスシャツでも、袖口や襟の裏のみで目立たないようにできるので、フォーマルでも行けるかも。

私は、とりあえずドレスシャツで定番のピカチュウにしました。全体は白いシャツですが、ポケットと襟の裏、袖口の裏などにピカチュウを隠してみました。

f:id:lastline:20190301182702j:plain
箱のデザインもいいですね。

f:id:lastline:20190301182721j:plain
先行特典として、ハンカチを頂けました。ペイズリー型のコクーンはセンスありますよね。

f:id:lastline:20190301182740j:plain
オーダー通りに、ワンポイントでピカチュウが入っているので、フォーマルでも行ける!

ゆるドミで遊んだボドゲの感想

主催のしんざきさんが週の初めから体調が悪そうで心配しておりましたが、やはり働きながら風邪を治すのは無理だったようで、ゆるドミ途中でのリタイアとなりました。会場設営くらいしか手伝ってないのに、名前が挙がっており恐縮です。息子さんがドミニオンスイスドローに参加できず残念がったおりました。
ドミニオン以外にも色々なボードゲームで遊べるのも、ゆるドミの魅力だと思います。あと、くるりんパニック世界大会。
自分的な心残りは、ブラフが一回したできなかったことですね。自分のを持ってくるべきでした。

忘れない内にプレイしたボードゲームの感想を書いて起きます。

デクリプト

今回一番面白いと思ったボードゲーム。チームに分かれて、相手のキーワードを推理するゲームが、キーワードそのものを当てる必要がないのが面白いと感じました。ゲーム終了後にキーワードの当てっこをするのも楽しみの一つかも。
インストを聞いていると、いまひとつイメージが掴めませんが、実際にプレイしてみるとルールは単純だと分かります。

f:id:lastline:20190223162920j:plain
デクリプトのキーワード表示板。コンソールみたいでかっこいい!

それぞれのチームに4つのキーワードが指定されます。自分のチームのキーワードはみることができますが、相手のキーワードは見ることができません。キーワードは以下のように番号と紐付けられます。

1番「うさぎ」
2番「大会」
3番「司会」
4番「コンビニ」

各チームで一人ずつ暗号作成者が3つの番号が書かれたカードを引きます。たとえば「1、2、4」など。この番号の順番を正確に味方チームへ伝える必要があります。伝達に二回失敗すると負けです。そして、相手チームはその順番を二回当てると勝ちです。
暗号作成者は、この3つの番号の順番を味方チームだけにわかるようなキーワードで伝えます。例えば、「跳ねる」、「ゲーム」、「街」など。キーワードを知っていれば「跳ねる」は1番の「うさぎ」、「ゲーム」は2番の「大会」、「街」は4番の「コンビニ」と連想できるでしょう。相手チームは、このキーワードを元に番号の順番を推測するのですが、1ターン目は手掛かりがないので無理です。キーワードがどの番号に相当したかメモっておきましょう。勝負は2ターン目からです。
2ターン目が「3、4、1」で暗号作成者が「声」、「店」、「月」と伝達します。味方チームなら暗号を解読できますが、相手チームは推測する必要があります。たとえば次のように推測したとします。「声」は動作なので「跳ねる」と関連していそうだ。「店」は街中にあるので「街」と関連があるだろう。「月」は良く分からないので、まだ出ていない3番目に相当しそうだ。以上の推測をまとめると以下の通り。

一番「跳ねる」「声」
二番「ゲーム」
三番「月」
四番「街」「店」

「1,3,4」と推測しましたが、残念ながら不正解で暗号解読には至りませんでした。キーワードが溜まっていくと推測しやすくなります。つまり、暗号作成者は推測されにくいキーワードを考える必要がでてきます。しかし、あまりにも突飛なキーワードでは味方チームに伝わりません。相手チームのキーワードの推測や、推測されにくいキーワードを考えるのが肝ですが、暗号作成者の変化球なキーワードを推測するのも楽しみの一つでしょう。
実際のルールではキーワードを考える時間、解読する時間に制限があるのですが、今回は初回プレイなのもあって時間は測りませんでした。制限時間がないと、相手チームにばれにくいキーワードを考えられるため、必然的にプレ時間も長引きます。ある場合は、キーワードが類推しやすくなるでしょうし、伝達ミスも増えるので、ゲーム性が異なってくるでしょう。

面白さが伝わったがあまり自身はありませんが、結構盛り上がっていましたし、プレイする人にっよって連想されるキーワードも異なるので、何度もプレイしたくなるゲームです。

タイムボム

時空警察とボマーに振り分けられ、お互いの役割は伏せたまま、それぞれの陣営の目標を達成するゲーム。時空警察は時空爆弾の解除を目指し、ボマーは爆発を狙う。インストでは人狼系と言われて納得。

プレイヤーに「解除」、「しーん」、「爆発」と書かれたカードが所定の枚数配られます。プレイヤーはカードの内容を把握して、その後にシャッフルして目の前に伏せます。つまり、自分が持ってるカードの種類は把握できるけど、どの位置かは分からない状態です。ニッパーを持ったプレイヤーが自分以外の伏せカードを選び表にします。「解除」なら爆弾を解除でき、全ての爆弾を解除できれば時空警察の勝ち。「爆発」を引いたらボマーの勝ち。「しーん」は何も起きません。ここは運要素ですが爆弾解除というフレーバーが活きてますね。
「爆発」以外なら、カードをめくられた人が次のニッパー係で、それぞれのプレイヤーが一枚ずつめくられるまで続けます。一巡したら、そカードを一旦集めて配り、仕切り直します。

パーティーゲームとして、みんなでワイワイやるのに向いてると思います。デザインやフレーバーからしても子どもと一緒に遊ぶのに丁度良いでしょう。

レールロード・インク

地図ボードに線路と道路を引くゲーム。
線路と道路の書かれたサイコロを振って、その出目に応じた路線を地図ボードに書き込んでいきます。ルールに沿ってマスを埋めて高得点を狙うパズルゲームです。実質的にはソロプレイですが、出来上がった路線を見ると引き方や書き方に個性がでて面白いです。

シンプルで気軽に遊べ、サイコロによるランダム要素があるので毎回異なる展開になるので長く遊べそうです。拡張ルールとしては、ボードの地形が変化し線路を引けないマス目などが生じるようです。

ボードゲームFallout

Falloutの世界観やゲーム性が、ボードゲームで再現されていました。マップを探索し、敵と戦ったり回避しながら建物を漁り、ジャンクを売りを繰り返しながらシナリオを進めていくのはまさにFallout。デスクローも徘徊しているぞ!!もともと、TPRGっぽいので相性がよいのでしょう。奴隷商人やレールロードなどのFallout 3や4のシナリオが再現されています。
ゲームの目的はイベントを進めてポイントを獲得すること。誰かが8点かせげば終了。終了時に特定の条件を達成していると追加のポイントが貰えるため、8点に到達したプレイヤーが勝利するとは限りません。

戦闘やイベントなどは、基本的にはサイコロの出目で判定を行います。特定のSPECIALを有しているとサイコロの振り直しができます。例えば、交渉ではCharismaであるCが、ロボットやコンソールの操作ではIntelligenceのIがあるとサイコロを振り直せます。装備がSPECIALを補ったり、サイコロを振り直すなど、特定の効果を有しています。
武器としては銃がやはり強いです。弾切れの心配はありません。まぁ実際のゲームでも弾切れすることはほぼないですけど。防具としては、パワーアーマーがあればほぼ死にません。ユニーク装備として所有しているキャラクターもいますが、移動力が下がるので一長一短。強力なパワーアーマーが手に入るイベントもありますが、それを達成するのは時間も手間もかかります。

Perkも用意されているのですが、今回のプレイではみんなでイベントこなすのに一直線だったのでPerkを利用する機会はありませんでした。ゲームの終了条件である8点に到達するのが難しかったので、もうちょっと敵と戦ったり、建物を漁ったりすべきだったのかな?

プレイヤー同士でアイテムの交換もできるので、ある意味でマルチプレイFalloutであり、76っぽくあります。およそ3,4時間くらいで終わるので、この手のゲームとしては早い方かと思います。他のシナリオもプレイしてみたいです。

紫禁城

BMマガジンにおまけでついていた陣取りゲームです。赤、青、緑、黄と4種類のカードがあり、プレイヤーはそれぞれ一色を選び、そのカードセットのみを使用します。
一枚ずつカードをめくり皇帝の部屋につなげていきます。部屋のタイルは、赤、白、青の三色でつなげられるのは同じ色のタイルのカードのみです。カードには、タイルの色と壁や門の他、点数がアップする龍や、各プレイヤーの色に対応した宦官などが描かれています。
壁で仕切られた部屋ができたら、その度に点数計算をします。宦官を最も多く配置した人がその部屋の主となり得点を得ます。たとえば、赤の宦官が3人、青の宦官が1人なら、赤のプレイヤーが得点を得られます。タイルの枚数ごとに1点、また龍がいると3点です。さらに、その出来上がった部屋に門で繋がっている部屋のタイルも点数に含まれます。広い部屋を作りつつ、門でつながる部屋を作るのが大量得点の秘訣です。ただし、門を作りすぎると相手に大量得点のチャンスを与えることにも鳴るので難しい所です。
例えば、完成した大きな部屋に門があり、そこに1タイルだけで部屋を完成させることができる3方向が壁のカードを配置すると、完成した部屋の点数は1点ですが、大きな部屋の得点も加算されるので大量に得点が得られます。

カードを一枚ずつめくり、それを置くしかできないため運要素が強いと感じました。もともとが惑星開拓をモチーフにしたゲームなので出たとこ勝負なのでしょうが、皇帝と宦官なら調略要素が欲しいところ。カードを2から3枚まで保持できるとか、1枚だけ表を向けて保持できるとか、ルールのアレンジをしてみも良いかも。
ルールをアレンジするのは楽しむとして、不満点としては得点チップが1,2,10,20点と5点がないので、点数を配分するときに面倒でした。

AZUL

綺麗なタイルを作るゲーム。新版が出ているのを知り、ちょっと悲しい。

f:id:lastline:20190223185117j:plain
AZULの装飾スペースに配置されたタイル

5色のタイルを集めて、5×5のボードに装飾していきます。各タイルとは所定の位置に配置しなければなりません。それぞれの行と列には一色しか同じ色を配置できません。列をつなげたり、色を揃えることで点数を獲得できます。横一行に揃えたプレイヤーが出たらゲーム終了です。
プレイヤー人数に応じた枚数の皿を用意し、袋から4枚ずつタイルを取り出し乗せます。各プレイヤーは一つの皿から一色だけをめとめて取ることができます。そのタイルをボードに配置し、残ったりタイルは中央にまとめます。中央にまとめられたタイルも取ることができます。場が進むにつれて皿に盛られていないタイルが増えます。
ボードには、皿から取ってきた複数枚のタイルを置く確保スペースと、装飾スペースがあります。確保スペースには上から行に応じて1、2、3、4、5枚の空きの行があり、手番で取ったタイルを特定の行に配置します。たとえば、赤を2枚取った手番で1行目に1枚、2行目に1枚と置くことはできません。
2行目ならば、2枚置けます。1行目に置く場合は余るので、その場合はペナルティとしてボードの一番下にある行に配置します。一番下はマイナス行で、置くと減点となります。手番が進むと、お皿に盛られていないタイルがどんどん増えていきます。4枚や5枚のタイルを確保できるチャンスですが、徐々に確保スペースがなくなるため、後半ほどマイナスが嵩みやすい。
取れるタイルがなくなったら、確保スペースのタイルを装飾スペースに配置します。1行目なら1枚、2行目なら2枚と、行に応じた枚数を置いていれば、装飾スペースの各色のスペースに配置できます。足りない場合は、そのまま残します。例えば、4行目に3枚しか無い場合などですね。
装飾スペースに置ければ1点を確保できます。タイルが連続すると、連続した枚数に応じて点数が入ります。最後に、マイナス点に配置されたタイルに応じて減点します。
タイルと配置したら、残ったタイルは箱などに待避させておいて、袋が空になったら入れます。
2巡目以降は、装飾スペースにタイルが配置されています。装飾スペースにあるのと同色のタイルを確保スペースの行に置くことはできません。例えば、黄色のタイルが既に3行目の装飾スペースにあったら、3行目の確保スペースに置くことはできません。つまり、徐々に確保スペースにおけるタイルの色が限定されていきます。つまり、減点になる可能性が増えていきます。

タイルの出方はランダムですが、それ以外は公開情報なので目的が筒抜けです。他のプレイヤーがやりたいことが類推しやすいので、その点を考えて立ち回る必要があります。ちょうどよい複雑さになっていると思います。タイルの質感がよく、ずっと触っていたくなり、また見た目も綺麗なゲームです。

ラーメン屋は何曜日に休みが多いのかAPIを利用して調べた

きっかけはツイート

ラーメン屋は何曜日に休みのお店が多いのかを調べてみようと思ったきっかけは、フォロワーのツイートだった。調べることは好きだけど、これまでは人力で調べてばかりだった。Pythonを勉強してから、ずっとウェブスクレイピングやWeb APIに興味があったので、折角なので挑戦してみた。

ラーメン屋は月曜日が休みが多い

HOT PEPPERぐるなびAPIを提供しているので、そこからラーメン店の情報を取得し、定休日を集計した。

データは2019年2月21日に取得し、HOT PEPPERからは2212件、ぐるなびからは4767件の店舗情報が集められた。これを元に、定休日を集計した。データはJSON形式で、定休日もキーとして割り振られているので、抽出は簡単だった。

HOT PEPPERぐるなびともに、年中無休がもっと多く全体の30%から40%を占めている。曜日としては、月曜日が休みの店が多くHOT PEPPERでは15%、ぐるなびでは11%であった。次いで、火曜、水曜、日曜が10%前後である。金土休みの店はほとんどなく、0.5%程度である。それを除けば、木曜休みが5%と、他の曜日に比べて半分程度であった。
無休と曜日別の定休日はそれぞれのサービスで似たような傾向にあったが、その他は異なる結果になった。それぞれのサービスに登録する店舗の傾向を反映しているのだろう。たとえば、不定休の店はHOT PEPPERでは6%だが、ぐるなびでは14%と倍近い違いがある。一方で、HOT PEPPERでは祝日前が定休日の店舗が2%程度なのに、ぐるなびには殆どなかった。

f:id:lastline:20190222121019p:plain
HOT PEPPER ラーメン屋 定休日

f:id:lastline:20190222121057p:plain
ぐるなび ラーメン屋 定休日

曜日別でも割合を算出した。何曜日に休みが多いのかは、こちらの方が適当だろう。月曜日が定休日の店が25%から30%で、火曜、水曜、日曜が大体20%くらいとなる。月曜休みの未成は多いが、突出して多いわけではない。火、水、日はHOT PEPPERぐるなびとでばらつきがあったので、月曜日の次に多い曜日を特定するのは難しい。一方で、木曜日は10%と下がる。金土は稼ぎ時のためか、定休日のお店は1%くらいである。むしろ、数%でも存在していることが意外であった。
日曜日が休みの店舗はオフィス街などにあるのだろう。平日に休む場合は、月曜日が多く、次いで火曜日と水曜日となる。月曜日が休みなのは多客日の後に休みたい心理的な面と、日曜に市場が開いていないため食材調達上の問題もありそうだ。木曜日が定休の店が少ないのは、金曜日の仕込みなどがあるからだろうか。

f:id:lastline:20190222121128p:plain
HOT PEPPER ラーメン店 曜日別定休日

f:id:lastline:20190222121202p:plain
ぐるなび ラーメン屋 曜日別定休日

他の業態の飲食店と比較すべきだが、今回は本筋ではないのでやらない。恐らく、他の飲食店でも似たような傾向になるだろう。

Pythonによる定休日の集計方法

HOT PEPPERぐるなびAPIを利用し、Pythonにてラーメン店の情報を取得しJSONとして保存した。そのデータから定休日の情報を抜き出し、集計を行った。
取得したJSONデータから直接定休日を集計した方が手順は省けるが、定休日以外の統計処理を見据えて店舗情報を保存することにした。

APIの叩き方は経験が無かったので少々戸惑ったけども、一度取得できれば試行錯誤は用意だった。むしろ、JSONデータや定休日を集計しCSV形式で保存したデータが文字化けしまくって四苦八苦した。

HOT PEPPERぐるなびAPI仕様の所感

食べログAPIがあると便利そうだと思ってググったら、残念ながらかなり前に廃止されていることを知った。そこで、食べログAPI提供終了していたので代わりのAPIを探した(一覧) - エンジニアステップ を参考に、HOT PEPPERぐるなびAPIを使うことにした。それぞれに一長一短がある。

HOT PEPPER はメールアドレスのみでAPIキー取得でき、お試しにはもってこいだ。検索できる店舗数に上限がないのも扱いやすい。また、店舗のジャンルコードとして「ラーメン店」を指定できるため、今回の用途と相性もよい。ただし、ぐるなびと比較すると登録店舗数が圧倒的に少ない。
データ形式XMLがデフォルトだが、JSONJSONPも選択できる。

ぐるなびは、APIを取得するために氏名などを入力する必要があるため、お試しで使う身としてはちょっと敷居が高い。一方で、自身でサービスを立ち上げる際にはぐるなびの方が案内がしっかりしており信頼感が高い。データはJSON形式で出力される。

業態コードとして「ラーメン」が用意されているものの、それを指定して叩いても居酒屋のようなラーメン専門店以外もひっかかる。特定の業態を抽出するには工夫が必要となる。
一方でテストツールをウェブから利用でき、お試しで結果を得やすい。また登録店舗数が圧倒的に多い。たとえば、ラーメン店で検索するとHOT PEPPERでは2,600店しかヒットしないが、ぐるなびだとその10倍の26,000店もヒットする。統計を取りたいならぐるなびの方に分があるだろう。ただし、取得上限が1,000件までのため、必要な情報を網羅的に得るのにも工夫が必要となる。

PythonAPIを叩いてみれば

Python の requests を用いて API を叩き、JSON形式で店舗情報を取得した。先にも述べたが、ラーメン店を絞り込むのにやや工夫が必要である。

HOT PEPPER はラーメン店のジャンルコードが G013 と指定されており、絞りこみが楽である。約2,600店がヒットした。取得上限はないが1ページ当たり100店舗までしか表示できないので、26回叩いて全店舗の情報をJSONとして出力した。

ぐるなびにもラーメン店の業態コードがあるものの、それだけではラーメン店以外もヒットする。お好み焼きやしゃぶしゃぶ店なども引っかかるため、ぐるなびの分類方法は難がありすぎに思う。対処は比較的簡単で、フリーワードに「ラーメン」を入れることでほぼラーメン店のみに絞れた。
ぐるなびでは約26,000件ものラーメン店がヒットした。取得上限が1,000件なので、それ以上の店舗情報を得るには叩き方に工夫が必要となる。今回は、都道府県毎に取得した。
東京には3,000店舗以上、都市圏では1,000店舗以上のラーメン店が登録されている。 1,000件以上ある都道府県では上限の1,000件を取得するように設定した。ぐるなびの掲載順に取得すると、ラーメン店以外は検索結果の後ろの方に表示される。上位1,000件を取得した方が、ラーメン店以外を除外しやすい。

APIの叩き方に少々手間取ったが、それ以上に四苦八苦したのがJSONデータの保存である。エンコードUTF-8を指定しているのに、なぜか日本語がASCIIで描き込まれ uXXXXなどど保存される。それを回避するには、open() ではなく codecs.open() で開き、dumps() の引数に ensure_ascii=False と指定する必要があった。

# HOT PEPPER のラーメン店情報をJSON形式で取得する
import requests
import json
import codecs
 
# APIキーの指定
apikey = ”{個々人のAPIKEYを入力する}”
 
# APIのURL
api = 'http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?key={key}&order=3&genre={genre}&count={count}&start={start}&format=json'
 
# APIにリクエストを送信して店舗数を取得する
url = api.format(key=apikey, count=1, start=1, genre='G013')
response = requests.get(url)
response.raise_for_status()
data = json.loads(response.text)
count_range = data['results']["results_available"]
 
# ラーメン店の検索結果をJSON形式で取得する
ramen_json = []
 
# 100件ごとにAPIにリクエストを送信して店舗情報を取得する
for i in range(0, count_range, 100):
    url = api.format(key=apikey, count=100, start=i, genre='G013')
 
    response = requests.get(url)
    response.raise_for_status()
 
    data = json.loads(response.text)
    data = data['results']['shop']
    ramen_json += data
 
# 取得したラーメン店のJSONデータを保存
with codecs.open('ramen_hot.json', 'w', 'utf-8') as obj:
    dump = json.dumps(ramen_json, indent=4, ensure_ascii=False)
    obj.write(dump)
# ぐるなびのラーメン店情報をJSON形式で取得する
import requests
import json
import codecs
 
# APIキーの指定
apikey = ”{個々人のAPIKEYを入力する}”
 
# APIのURL
api = 'https://api.gnavi.co.jp/RestSearchAPI/v3/?keyid={key}&category_s={categoly}&freeword={freeword}&offset={start}&hit_per_page={count}&pref={pref_code}'
 
# 業態コードとフリーワードの指定
w_ramen = '%e3%83%a9%e3%83%bc%e3%83%a1%e3%83%b3' # ラーメン
c_ramen = 'RSFST08008' # ラーメン
 
# 都道府県毎に店舗情報を取得する
for num in range(1, 48):
    num = str(num).zfill(2)
    pref_num = 'PREF' + num
 
    # APIにリクエストを送信して店舗数を取得する
    url = api.format(key=apikey, count=1, start=1, freeword=w_ramen, categoly=c_ramen, pref_code=pref_num)
    response = requests.get(url)
    response.raise_for_status()
    data = json.loads(response.text)
    count_range = data['total_hit_count']
 
    # 上限が1000件なので、1000を超える場合は count_range を1000に書き換える
    if count_range > 1000:
        count_range = 1000
 
    # ラーメン店の検索結果をJSON形式で取得する
    ramen_json = []
 
    # 100件ごとにAPIにリクエストを送信して店舗情報を取得する
    for i in range(1, count_range, 100):
        url = api.format(key=apikey, count=100, start=i, freeword=w_ramen, categoly=c_ramen, pref_code=pref_num)
 
        # 実際にAPIにリクエストを送信して結果を取得する
        response = requests.get(url)
        response.raise_for_status()
 
        data = json.loads(response.text)
        data = data['rest']
        ramen_json += data
 
    # 取得したラーメン店のJSONデータを保存
    with codecs.open('ramen_guru' + pref_num + '.json', 'w', 'utf-8') as obj:
        dump = json.dumps(ramen_json, indent=4, ensure_ascii=False)
        obj.write(dump)
定休日を抽出する

HOT PEPPERぐるなびともに定休日がそれぞれ close や holiday としてキー登録されているので定休日の抽出は非常に簡単だ。
また、ラーメン専門店を抽出できているかを確認するため、店舗業態も抽出した。都道府県毎の傾向を見ようと思い都道府県も抽出したが、今回はそこまでやらなかった。
ぐるなびの定休日情報は細かく書かれており、たとえば「毎週月曜日、*元日は休み」など備考が含まれている。今回は定期的な休業日を知りたかったので備考を省くように処理した。
ちなみに、ぐるなびの店舗形態を確認すると「こだわりラーメン」に分類されているラーメン店があった。気になって調べてみると、北海道を拠点する山岡家が用いている業態名称である。チェーン店なのにこだわりラーメンと銘打つのは強気すぎないか。

結果を、1列目に都道府県、2列目に店舗業態、3列目に定休日となるCSVファイルとして保存した。
ぐるなび都道府県毎にCSVファイルを出力した後に結合したファイルを作成した。
ちなみに、CSVファイルを結合する時にもエンコードの問題が発生。結合したファイルを出力する際に encoding='utf-8' と指定しているにも拘わらず、なぜかJIS形式で保存されるため、UTF-8で開こうとして文字化けした。結合するファイルを開く際に、engine='python' と指定することで文字化けを回避した。

# HOT PEPPERとぐるなびの店舗データから定休日を抽出しCSVとして出力
import os
import glob
import json
import codecs
import csv
 
def holiday_pickup_hot(path):
    # HOT PEPPERのJSONデータを処理する関数
    # 指定したpath内のJSONファイルを取得
    # 地域、店舗ジャンル、定休日を抽出
    # CSV形式で保存
 
    # フォルダ中のパスを取得
    All_Files = glob.glob('{}*.json'.format(path))
 
    for file in All_Files:
        #JSON ファイルを開く
        with codecs.open(file, 'r', 'utf-8') as obj:
            df = json.load(obj)
 
        # 地域、店舗ジャンル、定休日を抽出する
        ramen_csv = []
        for i in range(len(df)):
            holiday_list = []
            area = df[i]['large_area']['name']
            genre =  df[i]['genre']['name']
            holiday = df[i]['close']
            holiday_list = [area, genre, holiday]
            ramen_csv.append(holiday_list)
 
        # 抽出した地域、店舗ジャンル、定休日のデータをCSV形式で保存
        name = file.rstrip('.json')
        with open(name + '_holiday.csv', 'w') as obj:
            writer = csv.writer(obj, lineterminator='\n')
            writer.writerows(ramen_csv)
 
def holiday_pickup_guru(path):
    # ぐるなびのJSONデータを処理する関数
    # 指定したpath内のJSONファイルを取得
    # 地域、店舗ジャンル、定休日を抽出
    # CSV形式で保存
 
    # フォルダ中のパスを取得
    All_Files = glob.glob('{}*.json'.format(path))
 
    for file in All_Files:
        #JSON ファイルを開く
        with codecs.open(file, 'r', 'utf-8') as obj:
            df = json.load(obj)
 
        # 地域、店舗ジャンル、定休日を抽出する
        ramen_csv = []
        for i in range(len(df)):
            holiday_list = []
            area = df[i]['category']
            genre =  df[i]['code']['prefname']
            holiday = repr(df[i]['holiday']) #repr()
            holiday = holiday.split(r'\n')
            holiday = holiday[0].split("'")
            holiday_list = [area, genre, holiday[1]]
            ramen_csv.append(holiday_list)
 
        # 取得した地域、店舗ジャンル、定休日のデータをCSV形式で保存
        name = file.rstrip('.json')
        with open(name + '_holiday.csv', 'w') as obj:
            writer = csv.writer(obj, lineterminator='\n')
            writer.writerows(ramen_csv)
 
 
holiday_pickup_hot(path='./ramen_hot/')
holiday_pickup_guru(path='./ramen_guru/')
# フォルダ内にあるCSVファイルを結合し出力
import os
import glob
import csv
import pandas as pd
 
# フォルダ中のパスを取得
DATA_PATH = "./ramen_guru/"
All_Files = glob.glob('{}*.csv'.format(DATA_PATH))
 
# フォルダ中の全csvをマージ
list = []
for file in All_Files:
    list.append(pd.read_csv(file, engine='python', header=None))
 
df = pd.concat(list, sort=False)
 
# 結合しcsvを出力
df.to_csv('ramen_guruPREF01to47_holiday.csv', encoding='utf-8')
定休日を集計する

EXCELでもできそうだが、折角なのでPythonを使って集計した。CSVファイルの3列目を読み込み、定休日をキーとする辞書形式でカウントした。定休日と頻出数のセットとしたリストを作り、それをソートした後に、結果をCSVファイルとした出力した。
曜日は意図通りに集計されるが、「無」、「無休」などは別々に集計される。また、週に二日以上定休日がある場合も、異なるキーとなる。そのため、出力されたデータを手動で再集計した。集計方法には工夫の余地があるものの、結果としては大きな差異はないと思われる。

ぐるなびは定休日が記載されていない店舗が多かった。約20,000店舗の情報を取得したが、その内約16,000件は定休日の情報が「記載無し」であった。これは「null」や「nan」の意味での「記載無し」である。定休日がなく年中無休なのか、そもそも情報が記載されていないのか判断できない。「記載無し」の店舗は省き、残った4,000店舗から定休日を集計した。

# CSVファイル内の指定した列にある単語の出現数をカウントする
import pandas as pd
 
def counter(file_name, read_column):
    # CSVファイルの指定した列の単語の出現数をカウントする関数
    # file_name でCSVファイルを指定
    # read_column で列を指定
 
    df =  pd.read_csv(file_name, engine='python', header=None)
    data = df.iloc[:, read_column]
 
    # 単語を辞書のキーとしてカウントする
    words = {}
    for word in data:
        words[word] = words.get(word, 0) + 1
 
    # 単語と出現数をタプルとしてリスト化しソートする
    dic = [(v,k) for k,v in words.items()]
    dic.sort()
    dic.reverse()
 
    # 結果をCSV形式で保存
    # utf-8 を指定しない
    with open(file_name.strip('.csv') + '_count.csv', 'w') as obj:
        for count, word in dic:
            obj.write(str(count) + ',' + str(word) + '\n')
 
counter(file_name='ramen_holiday_hot.csv', read_column=2)
counter(file_name='ramen_guruPREF01to47_en.csv', read_column=2)

APIを叩いて集計してみた感想

ブログに内容をまとめるのに、コードを書いて結果を得るまでと同じくらいの労力がかかってしまった。

APIそのものは簡単に取り扱えるので、欲しい情報を絞り込むのに検索力が必要に感じた。データを取得でにさえすれば、集計自体も難しくない。エンコードには苦しめられたが……。
最終的に人力で集計した部分もあるが、今回はそこを自動化するのに労力かかりそうだったので、自動化するメリーはないだろう。より多くのデータを集計するならより自動化をすべきだろう。自然言語系の処理は面倒そうだ。

コードを他人に見せることを意識すると、コメントやプログラミングのロジックなどを他の人が読んでもわかりやすいようにしようと自然に思えたので、勉強に向いてるなと感じた。