ログがサービス改善の命

Meisyoでは常にログを取って、「ユーザがどこで困ってそうかな」を探し続けています。

探す方法はいたって簡単。

(何か問題があると考えて)ログを眺める

今回のアップデートでは、アイテムの購入数を選択できるようにしました。

なぜそうしたかというと、
ログを眺めていて「一人で複数回も連打してるやん・・・これ・・・」という状態に気づいたからです。

スマホゲームにはよくあるんですけどね。
1個ずつしか買えず、複数個購入したいときダルい

それは面倒なので個数の選択肢を追加しておきました。

(大手のゲーム会社になると、もともとゲーム用のソースコード群があって、それを入れ替えているだけのところも多いのでUIがなかなか改善しないのではと思います。)

カードアイテム版

監督アイテム版

※画像を加工しすぎていてよくわからない状態になっているログ

ユーザIDごと、時間(またはログNo.)ごとにORDER BYすればいいだけなんですが、
ログがないサービスも多いと思います。

とりあえずログ取っていきましょっていう。

ユーザのストレスは少しずつ蓄積していって、閾値になるとすっぱり辞めてしまうので。

ログからストレスの蓄積度合いを取りたいんだが、難しいなあ。

[Meisyo]練習難易度の不均衡是正への分析的アプローチ2

[Meisyo]練習難易度の不均衡是正への分析的アプローチから早3か月。

「練習ごとに難易度が違いすぎるんですけど!!」という不満は少しは解消されたかなー・・・

効果測定してないのにわかるの?エスパーなの?
というわけで・・・

管理画面に入れちゃいました!
これでいつでも見れるよ!

結果発表。
ポイントの分布が大きければ大きいほど、カラーバーが太くなります。

今後はこれを見て調整します。

game11がやばい。(語彙力)

game4もちょっと少ないかな?

・・・って前問題になってた練習だよねコレ・・・
回数も少ないし・・・避けないでドウゾ

というわけで、
game11はPointを2倍に、
game4は全体的にポイントを緩和+ビンゴのカウント方式を変更(簡素化)しました。

カウント方式の変更内容
以前は、
スロットで出た5つの数字をすべて比較する方式でした。

今回は、
スロットで出た5つの数字の種類を数える方式にしました。

この変更によって、以前は下記のような当たってるだろっていうのもなくなります。

例1:
11,11,12,12,13
前→1ビンゴ
今→2ビンゴ

例2:
9,9,11,11,11
前→1ビンゴ
今→3ビンゴ

詳しい計算は以下の通り。
例1:
11,11,12,12,13
↓
種類ごとに数字をまとめる(一意化)
→11,12,13
↓
[11,12,13]の配列の個数を計算
→3
↓
5-配列の個数(3)
→2ビンゴ!

例2:
9,9,9,11,11
↓
種類ごとに数字をまとめる(一意化)
→9,11
↓
[9,11]の配列の個数を計算
→2
↓
5-配列の個数(2)
→3ビンゴ!

例:完全ビンゴ
1,1,1,1,1
↓
種類ごとに数字をまとめる(一意化)
→1
↓
[1]の配列の個数を計算
→1
↓
5-配列の個数(1)
→4ビンゴ!(=完全ビンゴ)

すみません。
思いつかなくてどうにかできる方法で実装していました。(でもどうにか、、なっていない)

改善していきます。orz

後、思ったのですが・・・
SQLでだいたいのことができるので、Python要らなくね?って思ったり。

というわけで、SQLを置いていきます。何かの参考に!

SELECT
  s.action_no
  ,SUM(s.count_uu) AS total_uu
  ,CEIL(SUM(s.point * count_uu) / SUM(s.count_uu)) AS ave_point
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 0 THEN count_uu ELSE 0 END) AS point_00
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 1 THEN count_uu ELSE 0 END) AS point_01
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 2 THEN count_uu ELSE 0 END) AS point_02
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 3 THEN count_uu ELSE 0 END) AS point_03
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 4 THEN count_uu ELSE 0 END) AS point_04
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 5 THEN count_uu ELSE 0 END) AS point_05
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 6 THEN count_uu ELSE 0 END) AS point_06
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 7 THEN count_uu ELSE 0 END) AS point_07
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 8 THEN count_uu ELSE 0 END) AS point_08
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 9 THEN count_uu ELSE 0 END) AS point_09
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 10 THEN count_uu ELSE 0 END) AS point_10
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 11 THEN count_uu ELSE 0 END) AS point_11
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 12 THEN count_uu ELSE 0 END) AS point_12
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 13 THEN count_uu ELSE 0 END) AS point_13
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 14 THEN count_uu ELSE 0 END) AS point_14
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 15 THEN count_uu ELSE 0 END) AS point_15
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 16 THEN count_uu ELSE 0 END) AS point_16
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 17 THEN count_uu ELSE 0 END) AS point_17
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 18 THEN count_uu ELSE 0 END) AS point_18
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 19 THEN count_uu ELSE 0 END) AS point_19
  ,SUM(CASE WHEN FLOOR(s.point / 10) = 20 THEN count_uu ELSE 0 END) AS point_20

# 全体集計
FROM
  (
    SELECT
      SUBSTRING_INDEX(action, ',', 1) AS action_no
      ,CEIL(SUBSTRING_INDEX(action, ',', -1)) AS point
      ,COUNT(action) AS count_uu
    FROM
      acts
    WHERE
      sub = 'practice'
    AND
      time >= '$date 00:00:00'
    AND
      LENGTH(SUBSTRING_INDEX(action, ',', 1)) > 0
    AND
      CEIL(SUBSTRING_INDEX(action, ',', -1)) BETWEEN 0 AND 200
    GROUP BY
      action_no
      ,point DIV 10
    ORDER BY
      action_no
  ) AS s
GROUP BY
  s.action_no;

DIV要らない気もするけど気にしてはいけない(戒め)

[SQL]URLから正規表現でホストの抽出

他のサイトの説明が釈然としなかったので投稿。

以下のref0~2番のホストを抽出したいとする。

ref[0] = "http://www.other.com/path1/index.php?k1=v1&k2=v2#Ref1"
ref[1] = "http://www.other.net/path1/index.php?k1=v1&k2=v2#Ref1"
ref[2] = "https://www.other.com/"

*ホスト名 0 = www.other.com

SQLでは以下の通り。

substring(ref from 'https?://([^/]*)')

出力は[0] = www.other.com

関数:
 substring(抽出文字列, 開始桁, 切り取り文字数)

正規表現:
(1)https?
「?」の使い方:「X?」=Xを0or1文字
httpの後に「sを1文字」または「何もつけない」という意味。
[http|https]と同義。
基本SSL準拠でないと警告が出る仕組みになったので、今後はhttpsが増えてくると思います。

(2)([^/]*)
分解して考えると、[^/]に*が付いて、その外側に()。
手順1. [^/]は「^ = ではない」「/」を[](1文字)なので、
「/」ではない「1文字」と読み替える。
手順2. *は直前の文字の0回以上の繰り返し(最長一致)なので、
「/」ではない文字が出てくるまでの文字列が出力される。
手順3. そこに() = フォーカスする。
ということで、0ではwww.other.comが出力される。

手順3をなしにしてみると・・・

substring(ref from 'https?://[^/]*')

[0] = http://www.other.com が出力される。

さらに、変な位置に()をつけると、

substring(ref from 'https?://([^/])*')

「/ではないの文字列の最後の一文字」を出力できる。
つまり、0の場合comの最後のmだ。意味があるのかは置いといて。

[^/]を[^.]に変えると、

substring(ref from 'https?://([^.]*)')

最初の「.」までのwwwが出力される。

とまあ、こんな感じで分解して考えるといいだろう。