2016年7月29日金曜日

ポケモンgoの各国評価を見たら割と面白かった

ポケモンgoの人気凄いですね。
私もやっていますが、あまりやり込んではいなくてLv18, 集めたモンスターは43種ほど。

スマホゲームは、パズドラ、モンストが長年AppStore, GooglePlayの売上1位を独占し続けていた事からも分かるように、一発当てれば息が長い。果たしてポケモンgoはどうなるのか。

各国の売上ランクはAppAnnieで確認した限り1位キープという状態。パズドラやモンストが1位キープを続けたのは日本限定ですが、ポケモンgoの場合全世界(※一部地域を除く)で1位キープを(今のところ)続けているという違いがあります。

それはさておき、各国の評価を見てみると結構面白いことになっていました。

※図面+データはAppAnnie(https://www.appannie.com)から引用してます

まずは、日・米・英

だいたい同じような形です。
米英は 5 > 1 > 4 > 3 > 2 という並びに対して
日本は 5 > 1 > 3 > 4 > 2 という並び(3と4が逆)だったりと、
細かい違いはありますが。

余談ですが、これは私のアプリの評価を見ていても同じ傾向がある(日本人は3を付ける確率が他国と比べて若干多い)ような気がするので、これは国民性かな?「良い」「普通」「悪い」の選択肢で迷ったらとりあえず「普通」を選べ的な感じのアレです。

日本の評価1の指摘内容を見てみると、地域格差を指摘する声が多いので、各国だいたい同じような状況で評価1が集まっているのではないかと思います。(Ingressのポータルの情報がポケストップになっているので、Ingressが流行していた地域なら田舎でもそれなりに充実しているかもしれませんが)

ドイツ、オーストラリア、カナダ、オランダ、スウェーデン、スイスでもだいたい同じ評価分布になっています。世界各国だいたい同じような都市構造になっているんでしょうね。

しかし、イタリアは大分違う形をしている。
★1が圧倒的に多い。
これは一体・・・
Ingressポータルが全般的に少なかったとか?

逆にフランスは★1が圧倒的に少ない。
なお、フランスの評価件数が少ないのは、日本と同じく配信開始が遅かったためのようです。

世界各国で同じようにヒットしているので、評価分布は世界各国でだいたい同じ形(逆コの字型)になると推測していましたが、何故こんな差が出たのかな?色々と想像が湧いてきて面白いのですが、如何せん私はイタリアとフランスには実際に行ったことが無い(陽気なイタリア人と適当なフランス人といった漠然としたイメージぐらいしかない)ので、空想の域を出ません。

2016年7月26日火曜日

vgsdrun で ステップ実行

vgsdrun(vgs-cpu付属のデバッグ実行コマンド)にステップ実行機能を追加してみました。
これは実際に動かしてみると楽しい。
楽しい?
...いや、私だけかもしれません。
ポケモンgoの方が楽しいですね。

インストールから動かすまでの手順は下記の通り。

$ git clone https://github.com/suzukiplan/vgs-cpu.git
$ cd vgs-cpu
$ make build
$ ./vgsdrun src/test/asm_mul.asm  -s
assembling: src/test/asm_mul.asm on memory
starting debug run.
00000000: ----- start-a -----
00000000: 08 E8 03               : line#00006 > LD   A, 1000
00000003: 6F 64                  : line#00007 > MUL  A, 100
00000005: A7 A0 86 01 00         : line#00008 > CMP  A, 100000
0000000a: F8 08 03 00 00         : line#00009 > JNE  $308 (test-failed)
> h
command usage:
- h     ... help
- r     ... show registers
- q     ... quit
- other ... execute next line
> r
registers:
c->r.a = 000186A0, c->r.b = 00000000, c->r.c = 00000000, c->r.d = 00000000
c->r.p = 0000000A, c->r.s = 00000000, c->f.z = 00000000, c->f.q = 00000000
> q
$

vgsdrunを実行すると以下のようにコマンド入力待ちになります。

00000000: ----- start-a -----
00000000: 08 E8 03               : line#00006 > LD   A, 1000

上記は1行上の命令(08 E8 03)をこれから実行するという意味です。
enter キーを押せば実行して以下のように表示されます。

00000000: ----- start-a -----
00000000: 08 E8 03               : line#00006 > LD   A, 1000
00000003: 6F 64                  : line#00007 > MUL  A, 100

ちゃんとエスケープで綺麗に表示してます。
復帰(\r)や改行(\n)とかは割とよく使うかもしれませんが、1行上に戻るという中々普通に生活(プログラミング)していると使わないエスケープを使っています。
printfで書くと以下のような感じ。

printf("\033[1A");

ぐぐっても1発では出てこかなかったけど、C/C++言語で作るコマンドインタフェース(CLI)のプログラムで「1行上の行に戻りたい」みたいなニーズは少ないのだろうか。
なお、WindowsのMS-DOSプロンプトでちゃんと動くかは未確認です。

2016年7月24日日曜日

vgsdrun (デバッグ実行コマンド)

vgsasmのテスト(アセンブル+実行テスト)をもりもり実施中なのですが、アセンブリ言語自体のコーディングミスでテストがコケるというケース(=テストケースの間違い)が割と多い。

まぁ、それ自体は仕方のないことですが、どういう経路を辿ってエラーになったのかを特定するのが割とツライ。

という訳で、vgsdrun というデバッグ用コマンドを作ってみました。
https://github.com/suzukiplan/vgs-cpu/pull/10

これでアセンブリ言語のソースを実行すると、以下のように実行経過の情報をズラズラと出力していきます。

$ ./vgsdrun src/test/asm_add_a.asm 
assembling: src/test/asm_add_a.asm on memory
starting debug run.
00000000: 08 E8 03               : line#00006 > LD   A, 1000
00000003: 5D 00                  : line#00007 > ADD  A, 0
00000005: A6 E8 03               : line#00008 > CMP  A, 1000
00000008: F8 02 01 00 00         : line#00009 > JNE  $102
0000000d: F5 02 01 00 00         : line#00010 > JZ   $102
00000012: 5D FF                  : line#00011 > ADD  A, 255
00000014: A6 E7 04               : line#00012 > CMP  A, 1255
00000017: F8 02 01 00 00         : line#00013 > JNE  $102
0000001c: F5 02 01 00 00         : line#00014 > JZ   $102
00000021: 5E 00 01               : line#00015 > ADD  A, 256
00000024: A6 E7 05               : line#00016 > CMP  A, 1511
00000027: F8 02 01 00 00         : line#00017 > JNE  $102
0000002c: F5 02 01 00 00         : line#00018 > JZ   $102
00000031: 5E FF FF               : line#00019 > ADD  A, 65535
00000034: A7 E6 05 01 00         : line#00020 > CMP  A, 67046
00000039: F8 02 01 00 00         : line#00021 > JNE  $102
0000003e: F5 02 01 00 00         : line#00022 > JZ   $102
00000043: 5F 00 00 01 00         : line#00023 > ADD  A, 65536
00000048: A7 E6 05 02 00         : line#00024 > CMP  A, 132582
0000004d: F8 02 01 00 00         : line#00025 > JNE  $102
00000052: F5 02 01 00 00         : line#00026 > JZ   $102
00000057: 5F 1A FA FD FF         : line#00027 > ADD  A, -132582
0000005c: F6 02 01 00 00         : line#00028 > JNZ  $102
00000061: 09 78 56 34 12         : line#00031 > LD   A, $12345678
00000066: 12 00 00 00 00         : line#00032 > ST   A, [0]
0000006b: 07 00                  : line#00033 > LD   A, 0
0000006d: 63 00 00 00 00         : line#00034 > ADD  A, [0]O
00000072: A5 78                  : line#00035 > CMP  A, $78
00000074: F8 02 01 00 00         : line#00036 > JNE  $102
00000079: F5 02 01 00 00         : line#00037 > JZ   $102
0000007e: 5F 88 FF FF FF         : line#00038 > ADD  A, -120
00000083: F6 02 01 00 00         : line#00039 > JNZ  $102
00000088: 64 00 00 00 00         : line#00040 > ADD  A, [0]H
0000008d: A6 78 56               : line#00041 > CMP  A, $5678
00000090: F8 02 01 00 00         : line#00042 > JNE  $102
00000095: F5 02 01 00 00         : line#00043 > JZ   $102
0000009a: 5F 88 A9 FF FF         : line#00044 > ADD  A, -22136
0000009f: F6 02 01 00 00         : line#00045 > JNZ  $102
000000a4: 65 00 00 00 00         : line#00046 > ADD  A, [0]
000000a9: A7 78 56 34 12         : line#00047 > CMP  A, $12345678
000000ae: F8 02 01 00 00         : line#00048 > JNE  $102
000000b3: F5 02 01 00 00         : line#00049 > JZ   $102
000000b8: 5F 88 A9 CB ED         : line#00050 > ADD  A, -305419896
000000bd: F6 02 01 00 00         : line#00051 > JNZ  $102
000000c2: 1E 00 00 11 11         : line#00054 > LD   B, $11110000
000000c7: 32 11 11               : line#00055 > LD   C, $00001111
000000ca: 48 11 11 11 11         : line#00056 > LD   D, $11111111
000000cf: 60                     : line#00057 > ADD  A, B
000000d0: A7 00 00 11 11         : line#00058 > CMP  A, $11110000
000000d5: F8 02 01 00 00         : line#00059 > JNE  $102
000000da: F5 02 01 00 00         : line#00060 > JZ   $102
000000df: 61                     : line#00061 > ADD  A, C
000000e0: A7 11 11 11 11         : line#00062 > CMP  A, $11111111
000000e5: F8 02 01 00 00         : line#00063 > JNE  $102
000000ea: F5 02 01 00 00         : line#00064 > JZ   $102
000000ef: 62                     : line#00065 > ADD  A, D
000000f0: A7 22 22 22 22         : line#00066 > CMP  A, $22222222
000000f5: F8 02 01 00 00         : line#00067 > JNE  $102
000000fa: F5 02 01 00 00         : line#00068 > JZ   $102
000000ff: 46 01                  : line#00070 > LD   D, 1
00000101: 00                     : line#00071 > BRK 

[registers]
c->r.a = 22222222, c->r.b = 11110000, c->r.c = 00001111, c->r.d = 00000001
c->r.p = 00000101, c->r.s = 00000000, c->f.z = 00000000, c->f.q = 00000000
$

最初は、普通のgdbやxdbなどと同じようなステップ実行コマンドを用意しようと思ったのですが、それを作ろうとするとディスアセンブラを作らなければならず、ディスアセンブラ自体、後々必要になるかもしれませんが、今のところ必要になりそうな気配が無い。

という訳で、vgs-asm と vgs-cpu のコードをベースにして簡単に作ってみたのが、このvgsdrun コマンドです。

仕組みは物凄く単純で、vgs-asmは行バッファという領域にオペコードに変換したデータを持っているので、その情報をvgs-cpuの命令実行サイクル時にコールバックしてプログラムレジスタから該当する行バッファの内容を表示してあげるというもの。

ディスアセンブラをガチで作ると多分2000行の開発コストが掛かりますが、この方式ならだいたい200行ぐらいの改造(要するに労力的には1/10の作業量)で作れました。

まぁ、こういう所で削っていかないと、いつまで経ってもモノが完成しないので。

今回のCPU開発(というかVGS mk-III開発)のゴールは、
1. CPU(vgs-cpu)を自作する
2. アセンブラ(vgs-asm)を自作する
3. VGS mk-III の SDK をWindows + Mac + Linuxでザックリ使えるレベルで仕上げる
4. Invader Block を VGS mk-III で作って何処かにリリース
という風に想定していて、現在はとりあえず1と2が一区切りついた段階です。
前記事で完成したと言いましたが、アレは初期目標段階に達した(マイルストーンをクリアした)という意味で、まだまだ実際にゲームを作るのには不足した機能が割とあります。

あまり最初から完璧なモノを仕上げるより、とりあえず次フェーズに進めそうな形にしておき、次フェーズを進めながら随時細かいエンハンスを繰り返していくという開発モデル(だいたいアジャイル)です。

2016年7月18日月曜日

vgs-cpuを完成させる

昨日書いた VGS-CPU + アセンブラ (VGS-ASM) を(とりあえず)完成させた。ただし、アセンブラの方は、まだ十分にテストしていないのでまだバグがあるかもしれません。(CPUの方にはバグはありません)
https://github.com/suzukiplan/vgs-cpu

命令セットの仕様的には、8086 と 6502 がごっちゃになった感じで、尚且つ32bit CPU という、一見するとカオスな感じでありながら、実際のところかなりアセンブリ言語でのコーディングがし易い形になっているのではないかと思います。

当初VGSオペランドという特殊命令を実装するつもりでしたが、それだと VGS-CPU の用途が狭まってしまう。元々、VGS用ゲーム開発専用のCPUを開発するつもりで作っていたので、それでも目的は外れていないのですが、VGS-CPUをベースにした亜種CPUを開発し易いようにするため、8086のINT命令相当のものを実装することにしました。

INT命令といえば、MS-DOSのサービスコール INT 21h とかよく使いましたね。

INT命令で実行される命令は、以下のように簡単に(最大256個)登録できます。

int hello_world(struct vgscpu_context *c)
{
    printf("HELLO, VGS-CPU");
    return 0;
}

int main()
{
    struct vgscpu_context *c = (struct vgscpu_context *)vgscpu_create_context();
    vgscpu_regist_interrupt(c, 0, hello_world);

VGS mark-III では、この割り込みの大半が VGS-API に割り当てる形になります。
INT命令を実装したことで、VGS-CPU と VGS-ASM の責務範囲は一通り実装できたことになるので、「だいたい完成した」といって良い状態ではないかと思います。

VGS-ASMの方は、まだまだ実装したい項目が盛り沢山ですが。
とりあえず、VGS-CPUの全ての命令セットを使用したコーディングができるという状態。

テストが通っているアセンブリ言語のサンプルソース:

/*
    PUSH/POP A の テストプログラム
 */
start:
    LD      A, $deadbeef
    PUSH    A
    PUSH    AH
    PUSH    AO

    POP     AO
    CMP     A, $ef
    JNE     test-failed

    POP     AH
    CMP     A, $beef
    JNE     test-failed

    POP     A
    CMP     A, $deadbeef
    JNE     test-failed

    LD      D, 1
    BRK

test-failed:
    LD      D, -1
    BRK

中々良い感じではないでしょうか。

今は MMM; main memory mapper という、フルアセでコーディングする上で一番厄介になる主記憶のメモリマッピングをアセンブリ言語で簡潔に表現できる仕組みを脳内で設計中。(あとはテストも書かないと)

2016年7月17日日曜日

vgs-cpuがひとまず完成(cpuは...)

5月からシコシコと作り続けていた vgs-cpu がついに完成。
https://github.com/suzukiplan/vgs-cpu
まだ、VGSオペランドで実行する命令は未着状態ですが

従来のVGS(mk-II SR)では、プログラムはC/C++のネイティブコードで記述していましたが、新しいVGSでは独自の仮想CPU用のネイティブコードでプログラムを記述していくスタイルにするつもりです。

そして、無事CPUエミュレータが(ほぼ)完成した訳ですが、現状では一応プログラムを書くことはできるものの、全てハンドアセンブルしなければならない状態なので、この状態でプログラミングするのは中々キツイ(できない訳ではないけど)。

誰でもゲームを作れるようにするにはアセンブラぐらいは必要だろうということで、今度はアセンブラをシコシコ作成中。
https://github.com/suzukiplan/vgs-cpu/pull/1

コンパイラ?

コンパイラは甘え

2016年7月12日火曜日

Travis CIでC言語プロジェクトの自動ビルド+テスト

vgs-cpuのLinuxでの自動ビルド+テストにTravis CIを導入してみました。
オープンソースなのでタダ乗りです。

README.md でよく見られる下図の「build passing」というバッジをクリックすれば、vgs-cpuをTravis CIでビルドしたログとかが見れたりします。
バッジ(build: passing)
ビルド+テストログが誰でも見れる
Web版のTravis CIで、C++やclangを利用したプロジェクトの場合、コンパイラのバージョン依存が結構あると思いますが、vgs-cpuならGCCバージョン2.96という枯れ切った規格に準拠した記述をしているので全く問題ありません。

(対応するためにやったこと)
・全てのビルドとテストの手順をmakeで書く(最初からそう書いている)
・GitHub上のアカウントの設定でTravis CIのWeb hookを許可
・Travis CIでアカウント連携
・対象プロジェクト(vgs-cpu)のトグルをON
・対象プロジェクト(vgs-cpu)に .travis.yml(内容は下記) を追加

script: 
  - make --no-print-directory test

・README.mdにバッジを表示する情報を追記

# [WIP] VGS CPU [![Build Status](https://travis-ci.org/suzukiplan/vgs-cpu.svg?branch=master)](https://travis-ci.org/suzukiplan/vgs-cpu)

これだけで、あとは master へ push なり Pull Request を merge するなりすれば、Travis CIがLinux(Ubuntu)でvgs-cpuのビルド&テスト(make test)を実行してくれます。

基本的に普段はMacでビルド+テストしているので、Linuxでのビルド&テストも放っておけば(というかpushすれば)勝手にやってくれるのは中々便利。

そうそう環境依存のバグを作り込むことは無いですが、一発仕掛ければ後は勝手にやってくれるのが良いですね。どちらかといえば、環境依存バグはWindowsで作り込み易いので、Windowsの似たようなCI(Platform SDKが使える)があれば尚良いのですが...

2016年7月3日日曜日

ランダム要素+ランキングシステムが秀逸なゲーム

私が最近はまっている Nuclear Throne というゲームを紹介します。(Nuclear Throneは日本語に直訳すれば、核の玉座という感じでしょうか)

Steamで売られていて、Windows, Mac, Linux に対応してます。
http://store.steampowered.com/app/242680/
あと日本で買えるかは分かりませんが、PS4とかでも売られているらしいです。

どのぐらい面白いのかというと、ソーシャル要素の無いオフラインゲームなのに、プレイ時間が100時間を超えてもなお飽きないぐらい面白いです。

Steamだとプレイ時間が測れるから良いですね。

ゲームの内容は、ライフ制の全方向スクロール・シューティングです。
シューティングとはいっても、ゼルダの伝説みたいな感じですが。
2つの武器を持つことができるので、それらを使い分けて敵を倒していきます。

ステージ構成は、全7ステージ(15エリア)で周回ループ有りです。
奇数ステージは通常3エリア。
偶数ステージは通常1エリアのみのショートステージ(ボス無し)。
奇数ステージのエリア3にはボスがいますが、1面はエリア1でボスが出てくることが稀にあります(倒せばそのままステージ2へ)。
7-3をクリアして一定条件を満たせば2週目(ステージ0)に入ります。

全ステージクリア(1周)に掛かる時間は15〜20分ぐらいです。
1周オールに掛かる時間の例(17分24秒)
上図の場合、隠しステージに一切寄らずにストレートに15エリアクリアしていますが、隠しステージがかなり豊富にあったりします。

例えば、3-1に1つだけある金縁の車をスクリュードライバーで叩くと、ゴールデン装備が手に入る隠しステージに行けたりとか。

ゴールデン装備とは、通常ゲームスタート時はピストルを持って開始しますが、ゴールデン装備を手に入れて有効な状態にすることができれば、それを初期装備とすることができます(ただし、dailyチャレンジの場合は使用不可)。

私は近接武器(レンチ、シャベル、ハンマーあたり)をメインに使っているので、ゴールデン・レンチが取れるまで結構粘りました。
ちなみに、このゲームで近接武器をメインで使う人は少数派かもしれません。マウス+キーボードでプレイする場合は飛び道具メインでプレイした方が面白いので。ただ、ゲームパッドでプレイする場合、飛び道具が使い難いので近接メインでプレイせざるを得ないかも。(攻撃をする時の入力が進行方向と逆に入れる必要があるというかなりクセのあるものなので)
このゲームの最大の特徴は、とにかくランダム要素が多いことです。

ステージの形状や敵の配置がランダム
どういう武器が拾えるかもランダム
回復アイテムが拾えるかどうかもランダム

近接武器をメインに使う私の場合、ステージ4に入るまで(3-3まで)にシャベルが拾えるか拾えないかで、難易度がかなり揺れます。
もっとも、私が初めて1周オールした時は、ハンマーもシャベルも拾えず、ゴールデン・レンチで Nuclear Throne を殴り壊しましたが。
初回クリア時のスクショ
ゴールデンレンチで殴り壊しました
1周目なら、装備よりもどちらかというと進化の方が重要かも。

一定量の緑のアイテムを集めてレベルが上がると特殊能力を追加できるのですが、これもどれが来るかはランダムです。
近接メインで攻める場合の最重要進化は、LONG ARMS(射程が伸びる)とGAMMA GUTS(体当たりでダメージを与える)で、ステージ4までにこれらの進化が出来たか出来なかったかで難易度がかなり変わってきます。
LONG ARMS
(最重要進化)
GAMMA GUTS
(下手な内は)結構重要な進化
更に、デスエンカみたいな敵も稀に出ます。
1面の黄色いサソリとか5面の黄色いロボとか。
黄色いサソリは良いですが、黄色いロボはヤバイ。
黄色いロボ
(恐らく1周目最恐のデスエンカ)
上図のように壁に隠れながら、EYESの敵を引き付ける特殊能力で誘導しつつ、近接武器(※近接武器の場合、壁を貫通して敵を攻撃できる)で殴り壊せば怖くないですが、そういう風にできるかどうかも運ですね。
やや広い地形に3体黄色いロボが居て、ハンマーヘッド(壁を壊せるようになる進化)も無かった時は、「あ、死んだな」って感じになります。

このゲームのランダム要素以外の特徴としては、日々クリアされるデイリーランキングでしょうか。

iOSとかのゲームセンターを使った事がある人なら分かると思いますが、有名どころのゲームのランキングというのは、一部の馬鹿な人がクラッキングして出した不正なスコアで上位ランキングが埋め尽くされているので、何も面白くありません。そんなクソランキングは、むしろ無い方が良いというのが、真にゲームを楽しみたい人にとっての共通認識ではないかと思います。

このNuclear Throneのランキングですが、1日1回しか挑戦できず、しかも毎日クリアされます。
在りし日のデイリーランキング(Global)
1日1回しか挑戦できないという成約は上手いですね。
継続プレイ率をかなり上げることが出来るのではないかと思います。
実際、毎日数千人のプレイヤーが競いあっています。
更に、デイリーでクリアされることから、チートでランキングを荒らす馬鹿も湧きにくいし、仮に湧いてもすぐにクリアされます。(まぁ、ボットで毎日送り続けるようにする阿呆も湧いてくるかもしれませんが、ゲームセンターと違って毎日送り続ける必要があるから、それは相当リスキーでしょう)

総括すると、Nuclear Throneは、
・適度なランダム要素で得られる新鮮なゲームプレイ
・チート対策で純粋にゲームで競いたい人にとって嬉しいランキングシステム
あたりが秀逸なゲームという感じでしょうか。

ちなみに、難易度は結構高めです。
近接メインでクリアするのは中級者向けで、あまりゲームが上手くない人は飛び道具メイン(キーボード+マウス)でプレイした方が無難です。飛び道具メインでプレイする人向けに参考になりそうな実況動画がニコニコ動画に上がってました。
http://www.nicovideo.jp/watch/sm27848106