Skip to content

Instantly share code, notes, and snippets.

@sasairc
Last active March 10, 2019 11:06
Show Gist options
  • Save sasairc/ac64327632c82d95d98ae344ced867fa to your computer and use it in GitHub Desktop.
Save sasairc/ac64327632c82d95d98ae344ced867fa to your computer and use it in GitHub Desktop.
二宮飛鳥は・・・? 2

二宮飛鳥は・・・? 2

二宮飛鳥は・・・?の続きです。 しかし二宮飛鳥要素はタイトルだけ。こいつ騙したな!

色々と変わっていますが、主な変更点はピックアップへの対応。 select_card() は今日(2/24) 修正しました。

gasha.h

/*
 * gasha.h - 二宮飛鳥?
 */

#ifndef GASHA_H
#define GASHA_H
#ifdef  __cplusplus
extern "C" {
/* __cplusplus */
#endif

#include <stdint.h> /* uint32_t */
#include <stdio.h>  /* size_t */

/*
 * レアリティの定義
 */
#define RARITY_R    3
#define RARITY_SR   4
#define RARITY_SSR  5

/*
 * レアリティに対する確率の定義
 */
#define DEFAULT_WEIGHT_R    0.85
#define DEFAULT_WEIGHT_SR   0.12
#define DEFAULT_WEIGHT_SSR  0.03

/*
 * カード(各キャラクター)
 *
 * name は暫定的 ( id と rarity だけ持たせたい )
 */
typedef struct GASHA_CARD {
    uint32_t    id;
    char*       name;
    uint32_t    rarity;
} GASHA_CARD;

/*
 * 各種設定
 */
typedef struct GASHA_PROB {
    uint32_t        id;
    float           weight;
} GASHA_PROB;

typedef struct GASHA GASHA;
typedef struct GASHA_CONF {
    float           weights[6];
    GASHA_PROB***   probs;
    int             (*change_weight_of_rarity)(GASHA** gasha, uint32_t rarity, float weight);
    void            (*normalize_weight_of_rarity)(GASHA** gasha);
    int             (*config_pickups)(GASHA** gasha, GASHA_PROB pickups[]);
    void            (*release)(GASHA** gasha);
} GASHA_CONF;

/*
 * このライブラリの要
 */
typedef struct GASHA {
    GASHA_CONF*     conf;
    GASHA_CARD**    card;
    size_t          cardc;
    int             (*join_cards)(GASHA** gasha, GASHA_CARD cards[]);
    int             (*is_ready)(GASHA* gasha);
    uint32_t        (*roll)(GASHA* gasha);
    uint32_t        (*roll10)(GASHA* gasha);
    uint32_t        (*roll100)(GASHA* gasha);
    void            (*release)(GASHA* gasha);
} GASHA;

int init_gasha(GASHA** gasha);
GASHA_CARD* id2card(GASHA* gasha, uint32_t id);

size_t count_by_rarity(GASHA* gasha, uint32_t rarity);
GASHA_CARD** filter_by_rarity(GASHA* gasha, uint32_t rarity);

#ifdef  __cplusplus
}
/* __cplusplus */
#endif
/* GASHA_H */
#endif

設定

レアリティに対する確率は以下の通りです。

SSR  0.02 %
SR   0.12 %
R    0.86 %

また、今回は「キルミーベイベー」ピックアップと題し、各レアリティにおいてキルミーベイベーのキャラクターを出現しやすくしています。元ネタは掲載誌別召喚。

	/* ピックアップ対象のカード id とその重み */
	GASHA_PROB	pickups[]	= {
		{3026, 0.3},
		{3027, 0.3},
		{3028, 0.3},
		{4019, 0.3},
		{4020, 0.3},
		{4021, 0.3},
		{5009, 0.4},
		{5010, 0.4},
		{0, 0.0},
	};

残りの割り振りは config_pickups() が宜しくやってくれます。文明的ね。

コード全景

長いのは定義部だけなので読みましょう。

/*
 * kirara_charat.c
 */
#include "./gasha.h"
#include <stdio.h>
#include <unistd.h>

#define VERBOSE
#define KMB_PICKUP  /* 「キルミーベイベー」ピックアップ */

int main(void)
{
    size_t      i           = 0,
                j           = 0;

    GASHA*      gasha       = NULL;

    GASHA_CARD* result      = NULL;

    GASHA_CARD  cards[]     = {
        /*
         * ★★★
         */
        {3001, "ゆの(ナイト)",            3},
        {3002, "ゆの(アルケミスト)",      3},
        {3003, "宮子(ナイト)",            3},
        {3004, "宮子(まほうつかい)",      3},
        {3005, "ヒロ",                      3},
        {3006, "沙英",                      3},
        {3007, "乃莉",                      3},
        {3008, "なずな",                    3},
        {3009, "トオル(まほうつかい)",    3},
        {3010, "トオル(アルケミスト)",    3},
        {3011, "るん(まほうつかい)",      3},
        {3012, "るん(アルケミスト)",      3},
        {3013, "ユー子(せんし)",          3},
        {3014, "ユー子(そうりょ)",        3},
        {3015, "ナギ(そうりょ)",          3},
        {3016, "ナギ(ナイト)",            3},
        {3017, "涼風 青葉(せんし)",       3},
        {3018, "涼風 青葉(ナイト)",       3},
        {3019, "滝本 ひふみ(せんしト)",   3},
        {3020, "滝本 ひふみ(そうりょ)",   3},
        {3021, "篠田 はじめ",               3},
        {3022, "飯島 ゆん",                 3},
        {3023, "八神 コウ",                 3},
        {3024, "遠山 りん",                 3},
        {3025, "阿波根 うみこ",             3},
        {3026, "折部 やすな",               3},
        {3027, "ソーニャ",                  3},
        {3028, "呉織 あぎり",               3},
        {3029, "桜ノ宮 苺香",               3},
        {3030, "日向 夏帆",                 3},
        {3031, "星川 麻冬",                 3},
        {3032, "天野 美雨",                 3},
        {3033, "神崎 ひでり",               3},

        /*
         * ★★★★
         */
        {4001, "ゆの",                      4},
        {4002, "宮子",                      4},
        {4003, "ヒロ",                      4},
        {4004, "沙英",                      4},
        {4005, "乃莉",                      4},
        {4006, "なずな",                    4},
        {4007, "トオル",                    4},
        {4008, "るん",                      4},
        {4009, "ユー子",                    4},
        {4010, "ナギ",                      4},
        {4011, "ミホ",                      4},
        {4012, "涼風 青葉",                 4},
        {4013, "滝本 ひふみ",               4},
        {4014, "篠田 はじめ",               4},
        {4015, "八神 コウ",                 4},
        {4016, "遠山 りん",                 4},
        {4017, "阿波根 うみこ",             4},
        {4018, "星川 ほたる",               4},
        {4019, "折部 やすな",               4},
        {4020, "ソーニャ",                  4},
        {4021, "呉織 あぎり",               4},
        {4022, "桜ノ宮 苺香",               4},
        {4023, "日向 夏帆",                 4},
        {4024, "星川 麻冬",                 4},
        {4025, "天野 美雨",                 4},
        {4026, "神崎 ひでり",               4},
        {4027, "有馬 ひづめ",               4},
        {4028, "猿渡 宇希",                 4},
        {4029, "舘島 虎徹",                 4},
        {4030, "牛久 花和",                 4},

        /*
         * ★★★★★
         */
        {5001, "ゆの",                      5},
        {5002, "宮子",                      5},
        {5003, "トオル",                    5},
        {5004, "るん",                      5},
        {5005, "ユー子",                    5},
        {5006, "ナギ",                      5},
        {5007, "涼風 青葉",                 5},
        {5008, "滝本 ひふみ",               5},
        {5009, "折部 やすな",               5},
        {5010, "ソーニャ",                  5},
        {5011, "桜ノ宮 苺香",               5},
        {5012, "星川 麻冬",                 5},
        {5013, "鳩谷 こはね",               5},
        {0, NULL, 0},
    };

#ifdef  KMB_PICKUP
    /* ピックアップ対象のカード id とその重み */
    GASHA_PROB  pickups[]   = {
        {3026, 0.3},
        {3027, 0.3},
        {3028, 0.3},
        {4019, 0.3},
        {4020, 0.3},
        {4021, 0.3},
        {5009, 0.4},
        {5010, 0.4},
        {0, 0.0},
    };
/* KMB_PICKUP */
#endif

    /* gasha の初期化 */
    init_gasha(&gasha);
    /* gasha に正規化されたカードを登録 */
    gasha->join_cards(&gasha, cards);

    /*
     * 各レアリティの重み付け
     * normalize_weight_of_rarity() は 1.0 - (RARITY_R + RARITY_SSR) を設定する
     * よって change_weight_of_rarity(gasha, RARITY_R, 0.86) と等価
     */
    gasha->conf->change_weight_of_rarity(&gasha, RARITY_SR, 0.12);
    gasha->conf->change_weight_of_rarity(&gasha, RARITY_SSR, 0.02);
    gasha->conf->normalize_weight_of_rarity(&gasha);

#ifdef  KMB_PICKUP
    /* 上のピックアップ対象を登録 */
    gasha->conf->config_pickups(&gasha, pickups);
/* KMB_PICKUP */
#endif

#ifdef  VERBOSE
    /* 確認しよう */
    fprintf(stdout, "**** cards ****\n");
    for (i = 0; i < gasha->cardc; i++) {
        fprintf(stdout, "id = %d, name = %s, rarity = %d\n",
                gasha->card[i]->id, gasha->card[i]->name, gasha->card[i]->rarity);
    }
    fprintf(stdout, "\n**** probabilities 1 ****\n");
    fprintf(stdout, "\
rarity = 3, weight = %f %%\n\
rarity = 4, weight = %f %%\n\
rarity = 5, weight = %f %%\n",
           gasha->conf->weights[RARITY_R],
           gasha->conf->weights[RARITY_SR],
           gasha->conf->weights[RARITY_SSR]);
    fprintf(stdout, "\n**** probabilities 2 ****\n");
    for (i = RARITY_R; i <= RARITY_SSR; i++) {
        for (j = 0; j < count_by_rarity(gasha, i); j++) {
            fprintf(stdout, "id = %d, weight = %f %%\n",
                    gasha->conf->probs[i][j]->id, gasha->conf->probs[i][j]->weight);
        }
    }
    putchar('\n');
/* VERBOSE */
#endif

    /* gasha がレディか確認 */
    if (gasha->is_ready(gasha)) {
        /* 100回 */
        for (j = 1; j <= 100; j++) {
            if (j % 10 == 0)
                result = id2card(gasha, gasha->roll10(gasha));
            else
                result = id2card(gasha, gasha->roll(gasha));
            if (result->rarity == 5)
                fprintf(stdout, "%zu 回目の試行で 星%d の %s が当たりました。やったね!\n",
                        j, result->rarity, result->name);
            else
                fprintf(stdout, "%zu 回目の試行で 星%d の %s が当たりました。\n",
                        j, result->rarity, result->name);
            usleep(10000);
        }
    }
    /* 使った後はお片付け */
    gasha->release(gasha);

    return 0;
}

出力

% gcc kirara_charat.c gasha.c -o kirara_charat
% ./kirara_charat
**** cards ****
id = 3001, name = ゆの(ナイト), rarity = 3
id = 3002, name = ゆの(アルケミスト), rarity = 3
id = 3003, name = 宮子(ナイト), rarity = 3
id = 3004, name = 宮子(まほうつかい), rarity = 3
id = 3005, name = ヒロ, rarity = 3
id = 3006, name = 沙英, rarity = 3
id = 3007, name = 乃莉, rarity = 3
id = 3008, name = なずな, rarity = 3
id = 3009, name = トオル(まほうつかい), rarity = 3
id = 3010, name = トオル(アルケミスト), rarity = 3
id = 3011, name = るん(まほうつかい), rarity = 3
id = 3012, name = るん(アルケミスト), rarity = 3
id = 3013, name = ユー子(せんし), rarity = 3
id = 3014, name = ユー子(そうりょ), rarity = 3
id = 3015, name = ナギ(そうりょ), rarity = 3
id = 3016, name = ナギ(ナイト), rarity = 3
id = 3017, name = 涼風 青葉(せんし), rarity = 3
id = 3018, name = 涼風 青葉(ナイト), rarity = 3
id = 3019, name = 滝本 ひふみ(せんしト), rarity = 3
id = 3020, name = 滝本 ひふみ(そうりょ), rarity = 3
id = 3021, name = 篠田 はじめ, rarity = 3
id = 3022, name = 飯島 ゆん, rarity = 3
id = 3023, name = 八神 コウ, rarity = 3
id = 3024, name = 遠山 りん, rarity = 3
id = 3025, name = 阿波根 うみこ, rarity = 3
id = 3026, name = 折部 やすな, rarity = 3
id = 3027, name = ソーニャ, rarity = 3
id = 3028, name = 呉織 あぎり, rarity = 3
id = 3029, name = 桜ノ宮 苺香, rarity = 3
id = 3030, name = 日向 夏帆, rarity = 3
id = 3031, name = 星川 麻冬, rarity = 3
id = 3032, name = 天野 美雨, rarity = 3
id = 3033, name = 神崎 ひでり, rarity = 3
id = 4001, name = ゆの, rarity = 4
id = 4002, name = 宮子, rarity = 4
id = 4003, name = ヒロ, rarity = 4
id = 4004, name = 沙英, rarity = 4
id = 4005, name = 乃莉, rarity = 4
id = 4006, name = なずな, rarity = 4
id = 4007, name = トオル, rarity = 4
id = 4008, name = るん, rarity = 4
id = 4009, name = ユー子, rarity = 4
id = 4010, name = ナギ, rarity = 4
id = 4011, name = ミホ, rarity = 4
id = 4012, name = 涼風 青葉, rarity = 4
id = 4013, name = 滝本 ひふみ, rarity = 4
id = 4014, name = 篠田 はじめ, rarity = 4
id = 4015, name = 八神 コウ, rarity = 4
id = 4016, name = 遠山 りん, rarity = 4
id = 4017, name = 阿波根 うみこ, rarity = 4
id = 4018, name = 星川 ほたる, rarity = 4
id = 4019, name = 折部 やすな, rarity = 4
id = 4020, name = ソーニャ, rarity = 4
id = 4021, name = 呉織 あぎり, rarity = 4
id = 4022, name = 桜ノ宮 苺香, rarity = 4
id = 4023, name = 日向 夏帆, rarity = 4
id = 4024, name = 星川 麻冬, rarity = 4
id = 4025, name = 天野 美雨, rarity = 4
id = 4026, name = 神崎 ひでり, rarity = 4
id = 4027, name = 有馬 ひづめ, rarity = 4
id = 4028, name = 猿渡 宇希, rarity = 4
id = 4029, name = 舘島 虎徹, rarity = 4
id = 4030, name = 牛久 花和, rarity = 4
id = 5001, name = ゆの, rarity = 5
id = 5002, name = 宮子, rarity = 5
id = 5003, name = トオル, rarity = 5
id = 5004, name = るん, rarity = 5
id = 5005, name = ユー子, rarity = 5
id = 5006, name = ナギ, rarity = 5
id = 5007, name = 涼風 青葉, rarity = 5
id = 5008, name = 滝本 ひふみ, rarity = 5
id = 5009, name = 折部 やすな, rarity = 5
id = 5010, name = ソーニャ, rarity = 5
id = 5011, name = 桜ノ宮 苺香, rarity = 5
id = 5012, name = 星川 麻冬, rarity = 5
id = 5013, name = 鳩谷 こはね, rarity = 5

**** probabilities 1 ****
rarity = 3, weight = 0.860000 %
rarity = 4, weight = 0.120000 %
rarity = 5, weight = 0.020000 %

**** probabilities 2 ****
id = 3026, weight = 0.300000 %
id = 3027, weight = 0.300000 %
id = 3028, weight = 0.300000 %
id = 3001, weight = 0.003333 %
id = 3002, weight = 0.003333 %
id = 3003, weight = 0.003333 %
id = 3004, weight = 0.003333 %
id = 3005, weight = 0.003333 %
id = 3006, weight = 0.003333 %
id = 3007, weight = 0.003333 %
id = 3008, weight = 0.003333 %
id = 3009, weight = 0.003333 %
id = 3010, weight = 0.003333 %
id = 3011, weight = 0.003333 %
id = 3012, weight = 0.003333 %
id = 3013, weight = 0.003333 %
id = 3014, weight = 0.003333 %
id = 3015, weight = 0.003333 %
id = 3016, weight = 0.003333 %
id = 3017, weight = 0.003333 %
id = 3018, weight = 0.003333 %
id = 3019, weight = 0.003333 %
id = 3020, weight = 0.003333 %
id = 3021, weight = 0.003333 %
id = 3022, weight = 0.003333 %
id = 3023, weight = 0.003333 %
id = 3024, weight = 0.003333 %
id = 3025, weight = 0.003333 %
id = 3029, weight = 0.003333 %
id = 3030, weight = 0.003333 %
id = 3031, weight = 0.003333 %
id = 3032, weight = 0.003333 %
id = 3033, weight = 0.003333 %
id = 4019, weight = 0.300000 %
id = 4020, weight = 0.300000 %
id = 4021, weight = 0.300000 %
id = 4001, weight = 0.003704 %
id = 4002, weight = 0.003704 %
id = 4003, weight = 0.003704 %
id = 4004, weight = 0.003704 %
id = 4005, weight = 0.003704 %
id = 4006, weight = 0.003704 %
id = 4007, weight = 0.003704 %
id = 4008, weight = 0.003704 %
id = 4009, weight = 0.003704 %
id = 4010, weight = 0.003704 %
id = 4011, weight = 0.003704 %
id = 4012, weight = 0.003704 %
id = 4013, weight = 0.003704 %
id = 4014, weight = 0.003704 %
id = 4015, weight = 0.003704 %
id = 4016, weight = 0.003704 %
id = 4017, weight = 0.003704 %
id = 4018, weight = 0.003704 %
id = 4022, weight = 0.003704 %
id = 4023, weight = 0.003704 %
id = 4024, weight = 0.003704 %
id = 4025, weight = 0.003704 %
id = 4026, weight = 0.003704 %
id = 4027, weight = 0.003704 %
id = 4028, weight = 0.003704 %
id = 4029, weight = 0.003704 %
id = 4030, weight = 0.003704 %
id = 5009, weight = 0.400000 %
id = 5010, weight = 0.400000 %
id = 5001, weight = 0.018182 %
id = 5002, weight = 0.018182 %
id = 5003, weight = 0.018182 %
id = 5004, weight = 0.018182 %
id = 5005, weight = 0.018182 %
id = 5006, weight = 0.018182 %
id = 5007, weight = 0.018182 %
id = 5008, weight = 0.018182 %
id = 5011, weight = 0.018182 %
id = 5012, weight = 0.018182 %
id = 5013, weight = 0.018182 %

1 回目の試行で 星3 の ソーニャ が当たりました。
2 回目の試行で 星3 の 呉織 あぎり が当たりました。
3 回目の試行で 星3 の ソーニャ が当たりました。
4 回目の試行で 星4 の 呉織 あぎり が当たりました。
5 回目の試行で 星3 の 折部 やすな が当たりました。
6 回目の試行で 星3 の ソーニャ が当たりました。
7 回目の試行で 星3 の 呉織 あぎり が当たりました。
8 回目の試行で 星3 の ソーニャ が当たりました。
9 回目の試行で 星3 の 折部 やすな が当たりました。
10 回目の試行で 星4 の ソーニャ が当たりました。
11 回目の試行で 星3 の ソーニャ が当たりました。
12 回目の試行で 星3 の 呉織 あぎり が当たりました。
13 回目の試行で 星3 の 折部 やすな が当たりました。
14 回目の試行で 星3 の ソーニャ が当たりました。
15 回目の試行で 星3 の ソーニャ が当たりました。
16 回目の試行で 星3 の 折部 やすな が当たりました。
17 回目の試行で 星3 の 折部 やすな が当たりました。
18 回目の試行で 星3 の ソーニャ が当たりました。
19 回目の試行で 星3 の 折部 やすな が当たりました。
20 回目の試行で 星4 の 猿渡 宇希 が当たりました。
21 回目の試行で 星3 の 呉織 あぎり が当たりました。
22 回目の試行で 星3 の ソーニャ が当たりました。
23 回目の試行で 星3 の 折部 やすな が当たりました。
24 回目の試行で 星3 の 桜ノ宮 苺香 が当たりました。
25 回目の試行で 星3 の 呉織 あぎり が当たりました。
26 回目の試行で 星3 の 折部 やすな が当たりました。
27 回目の試行で 星3 の 折部 やすな が当たりました。
28 回目の試行で 星3 の ソーニャ が当たりました。
29 回目の試行で 星3 の 呉織 あぎり が当たりました。
30 回目の試行で 星4 の ソーニャ が当たりました。
31 回目の試行で 星3 の 折部 やすな が当たりました。
32 回目の試行で 星3 の 折部 やすな が当たりました。
33 回目の試行で 星3 の ソーニャ が当たりました。
34 回目の試行で 星3 の 折部 やすな が当たりました。
35 回目の試行で 星3 の ソーニャ が当たりました。
36 回目の試行で 星3 の ソーニャ が当たりました。
37 回目の試行で 星3 の ソーニャ が当たりました。
38 回目の試行で 星4 の 折部 やすな が当たりました。
39 回目の試行で 星3 の ソーニャ が当たりました。
40 回目の試行で 星4 の 折部 やすな が当たりました。
41 回目の試行で 星3 の 涼風 青葉(ナイト) が当たりました。
42 回目の試行で 星3 の ソーニャ が当たりました。
43 回目の試行で 星4 の 呉織 あぎり が当たりました。
44 回目の試行で 星3 の 折部 やすな が当たりました。
45 回目の試行で 星3 の ソーニャ が当たりました。
46 回目の試行で 星3 の ソーニャ が当たりました。
47 回目の試行で 星3 の 折部 やすな が当たりました。
48 回目の試行で 星3 の ソーニャ が当たりました。
49 回目の試行で 星3 の 折部 やすな が当たりました。
50 回目の試行で 星4 の ソーニャ が当たりました。
51 回目の試行で 星4 の 呉織 あぎり が当たりました。
52 回目の試行で 星3 の 呉織 あぎり が当たりました。
53 回目の試行で 星3 の 折部 やすな が当たりました。
54 回目の試行で 星3 の 呉織 あぎり が当たりました。
55 回目の試行で 星4 の 呉織 あぎり が当たりました。
56 回目の試行で 星3 の トオル(まほうつかい) が当たりました。
57 回目の試行で 星3 の ソーニャ が当たりました。
58 回目の試行で 星3 の 折部 やすな が当たりました。
59 回目の試行で 星3 の ソーニャ が当たりました。
60 回目の試行で 星4 の ナギ が当たりました。
61 回目の試行で 星3 の 八神 コウ が当たりました。
62 回目の試行で 星3 の 折部 やすな が当たりました。
63 回目の試行で 星3 の 折部 やすな が当たりました。
64 回目の試行で 星3 の ソーニャ が当たりました。
65 回目の試行で 星3 の 折部 やすな が当たりました。
66 回目の試行で 星3 の 折部 やすな が当たりました。
67 回目の試行で 星3 の ソーニャ が当たりました。
68 回目の試行で 星5 の ソーニャ が当たりました。やったね!
69 回目の試行で 星3 の 折部 やすな が当たりました。
70 回目の試行で 星4 の ソーニャ が当たりました。
71 回目の試行で 星3 の 折部 やすな が当たりました。
72 回目の試行で 星3 の ソーニャ が当たりました。
73 回目の試行で 星3 の 呉織 あぎり が当たりました。
74 回目の試行で 星3 の 折部 やすな が当たりました。
75 回目の試行で 星3 の ソーニャ が当たりました。
76 回目の試行で 星3 の ソーニャ が当たりました。
77 回目の試行で 星3 の 折部 やすな が当たりました。
78 回目の試行で 星3 の 折部 やすな が当たりました。
79 回目の試行で 星3 の 折部 やすな が当たりました。
80 回目の試行で 星5 の 折部 やすな が当たりました。やったね!
81 回目の試行で 星3 の 宮子(ナイト) が当たりました。
82 回目の試行で 星3 の 折部 やすな が当たりました。
83 回目の試行で 星3 の 神崎 ひでり が当たりました。
84 回目の試行で 星3 の 折部 やすな が当たりました。
85 回目の試行で 星3 の ソーニャ が当たりました。
86 回目の試行で 星3 の 折部 やすな が当たりました。
87 回目の試行で 星3 の 折部 やすな が当たりました。
88 回目の試行で 星4 の 折部 やすな が当たりました。
89 回目の試行で 星3 の ユー子(そうりょ) が当たりました。
90 回目の試行で 星5 の 折部 やすな が当たりました。やったね!
91 回目の試行で 星3 の ソーニャ が当たりました。
92 回目の試行で 星3 の 呉織 あぎり が当たりました。
93 回目の試行で 星3 の ソーニャ が当たりました。
94 回目の試行で 星3 の ソーニャ が当たりました。
95 回目の試行で 星3 の 呉織 あぎり が当たりました。
96 回目の試行で 星3 の 呉織 あぎり が当たりました。
97 回目の試行で 星3 の 呉織 あぎり が当たりました。
98 回目の試行で 星3 の 折部 やすな が当たりました。
99 回目の試行で 星3 の 呉織 あぎり が当たりました。
100 回目の試行で 星4 の ソーニャ が当たりました。

ナイスですねーナイスですねー

/*
* gasha.c - 二宮飛鳥?
*/
#include "./gasha.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#ifdef LIBRARY_VERBOSE
#define print_error() fprintf(stderr, "%s: %d: %s\n",\
__FILE__, __LINE__, strerror(errno))
/* LIBRARY_VERBOSE */
#endif
static int create_config(GASHA** gasha);
static int config_probs(GASHA** gasha);
static int change_weight_of_rarity(GASHA** gasha, uint32_t rarity, float weight);
static void normalize_weight_of_rarity(GASHA** gasha);
static int config_pickups(GASHA** gasha, GASHA_PROB pickups[]);
static int sort_probs(GASHA** gasha, uint32_t rarity);
static int normalize_probs(GASHA** gasha, uint32_t rarity);
static int join_cards(GASHA** gasha, GASHA_CARD cards[]);
static int is_ready(GASHA* gasha);
static uint32_t roll(GASHA* gasha);
static uint32_t roll10(GASHA* gasha);
static uint32_t roll100(GASHA* gasha);
static uint32_t select_card(GASHA* gasha, uint32_t rarity);
static void release_conf(GASHA** gasha);
static void release_conf_probs(GASHA** gasha);
static void release_card(GASHA** gasha);
static void release(GASHA* gasha);
static float gen_rval(void);
int init_gasha(GASHA** gasha)
{
GASHA* gs = NULL;
if ((gs = (GASHA*)
malloc(sizeof(GASHA))) == NULL) {
#ifdef LIBRARY_VERBOSE
print_error();
/* LIBRARY_VERBOSE */
#endif
goto ERR;
} else {
gs->conf = NULL;
gs->card = NULL;
gs->cardc = 0;
gs->join_cards = join_cards;
gs->is_ready = is_ready;
gs->roll = roll;
gs->roll10 = roll10;
gs->roll100 = roll100;
gs->release = release;
}
if (create_config(&gs) < 0)
goto ERR;
*gasha = gs;
return 0;
ERR:
release(gs);
return -1;
}
/*
* id2card()
*
* roll() から返却された ID からカードの情報を得る
*/
GASHA_CARD*
id2card(GASHA* gasha, uint32_t id)
{
size_t i = 0;
for (i = 0; i < gasha->cardc; i++) {
if (gasha->card[i]->id == id)
return gasha->card[i];
}
return NULL;
}
/*
* count_by_rarity()
* filter_by_rarity()
*
* レアリティ別のリストを返す
*/
size_t
count_by_rarity(GASHA* gasha, uint32_t rarity)
{
size_t i = 0,
n = 0;
for (i = 0; i < gasha->cardc; i++)
if (gasha->card[i]->rarity == rarity)
n++;
return n;
}
GASHA_CARD**
filter_by_rarity(GASHA* gasha, uint32_t rarity)
{
size_t i = 0,
n = 0;
GASHA_CARD** dest = NULL;
if ((dest = (GASHA_CARD**)
malloc(sizeof(GASHA_CARD*) * (count_by_rarity(gasha, rarity) + 1))) == NULL) {
#ifdef LIBRARY_VERBOSE
print_error();
/* LIBRARY_VERBOSE */
#endif
return NULL;
}
for (i = 0; i < gasha->cardc; i++) {
if (gasha->card[i]->rarity == rarity) {
dest[n] = gasha->card[i];
n++;
}
}
dest[n] = NULL;
return dest;
}
/*
* create_config()
*
* レアリティに対する既定の確率を設定する
*/
static
int create_config(GASHA** gasha)
{
if ((*gasha)->conf != NULL)
release_conf(gasha);
if (((*gasha)->conf = (GASHA_CONF*)
malloc(sizeof(GASHA_CONF))) == NULL) {
#ifdef LIBRARY_VERBOSE
print_error();
/* LIBRARY_VERBOSE */
#endif
return -1;
} else {
(*gasha)->conf->weights[RARITY_R] = DEFAULT_WEIGHT_R;
(*gasha)->conf->weights[RARITY_SR] = DEFAULT_WEIGHT_SR;
(*gasha)->conf->weights[RARITY_SSR] = DEFAULT_WEIGHT_SSR;
(*gasha)->conf->change_weight_of_rarity = change_weight_of_rarity;
(*gasha)->conf->normalize_weight_of_rarity = normalize_weight_of_rarity;
(*gasha)->conf->config_pickups = config_pickups;
(*gasha)->conf->release = release_conf;
}
return 0;
}
static
int config_probs(GASHA** gasha)
{
size_t i = 0;
uint32_t rarity = 0;
GASHA_CARD** cards = NULL;
if ((*gasha)->conf->probs != NULL)
release_conf_probs(gasha);
if (((*gasha)->conf->probs = (GASHA_PROB***)
malloc(sizeof(GASHA_PROB**) * 6)) == NULL) {
#ifdef LIBRARY_VERBOSE
print_error();
/* LIBRARY_VERBOSE */
#endif
return -1;
}
for (rarity = RARITY_R; rarity <= RARITY_SSR; rarity++) {
if (((*gasha)->conf->probs[rarity] = (GASHA_PROB**)
malloc(sizeof(GASHA_PROB*) * (count_by_rarity(*gasha, rarity) + 1))) == NULL) {
#ifdef LIBRARY_VERBOSE
print_error();
/* LIBRARY_VERBOSE */
#endif
goto ERR;
}
cards = filter_by_rarity(*gasha, rarity);
for (i = 0; i < count_by_rarity(*gasha, rarity); i++) {
if (((*gasha)->conf->probs[rarity][i] = (GASHA_PROB*)
malloc(sizeof(GASHA_PROB))) == NULL) {
#ifdef LIBRARY_VERBOSE
print_error();
/* LIBRARY_VERBOSE */
#endif
goto ERR;
}
(*gasha)->conf->probs[rarity][i]->id = cards[i]->id;
(*gasha)->conf->probs[rarity][i]->weight = 1.0 / (float)count_by_rarity(*gasha, rarity);
}
(*gasha)->conf->probs[rarity][i] = NULL;
}
return 0;
ERR:
release_conf_probs(gasha);
return -1;
}
/*
* gasha->conf->config_pickups();
*
* ピックアップを設定する
*/
static
int config_pickups(GASHA** gasha, GASHA_PROB pickups[])
{
size_t i = 0,
j = 0;
GASHA_CARD* card = NULL;
for (i = 0; pickups[i].id != 0; i++) {
if ((card = id2card(*gasha, pickups[i].id)) == NULL)
return -1;
for (j = 0; (*gasha)->conf->probs[card->rarity] != NULL &&
pickups[i].id != (*gasha)->conf->probs[card->rarity][j]->id; j++);
if ((*gasha)->conf->probs[card->rarity] == NULL)
return -1;
(*gasha)->conf->probs[card->rarity][j]->weight = pickups[i].weight;
}
for (i = RARITY_R; i <= RARITY_SSR; i++) {
sort_probs(gasha, i);
normalize_probs(gasha, i);
}
return 0;
}
/*
* sort_probs()
*
* テーブルをピックアップ用にソートする
*/
static
int sort_probs(GASHA** gasha, uint32_t rarity)
{
size_t i = 0,
j = 0;
GASHA_PROB p;
for (i = 0; i < count_by_rarity(*gasha, rarity); i++) {
for (j = count_by_rarity(*gasha, rarity) - 1; j > i; j--) {
if ((*gasha)->conf->probs[rarity][j - 1]->weight <
(*gasha)->conf->probs[rarity][j]->weight) {
p = *((*gasha)->conf->probs[rarity][j - 1]);
*((*gasha)->conf->probs[rarity][j - 1]) = *((*gasha)->conf->probs[rarity][j]);
*((*gasha)->conf->probs[rarity][j]) = p;
}
}
}
return 0;
}
/*
* normalize_probs()
*
* ピックアップ外の確率を設定する
*/
static
int normalize_probs(GASHA** gasha, uint32_t rarity)
{
size_t i = 0;
float pw = 0.0,
npw = 0.0;
npw = (*gasha)->conf->probs[rarity][count_by_rarity(*gasha, rarity) - 1]->weight;
while ((*gasha)->conf->probs[rarity][i]->weight != npw) {
pw += (*gasha)->conf->probs[rarity][i]->weight;
i++;
}
npw = (1.0 - pw) / ((float)count_by_rarity(*gasha, rarity) - i);
while (i < count_by_rarity(*gasha, rarity)) {
(*gasha)->conf->probs[rarity][i]->weight = npw;
i++;
}
return 0;
}
/*
* gasha->conf->change_weight_of_rarity()
*
* レアリティ別の確率を設定する
*/
static
int change_weight_of_rarity(GASHA** gasha, uint32_t rarity, float weight)
{
if ((*gasha)->conf == NULL) {
if (create_config(gasha) < 0)
return -1;
}
(*gasha)->conf->weights[rarity] = weight;
return 0;
}
/*
* gasha->conf->normalize_weight_of_rarity()
*
* レアリティ別の確率を正規化する
*/
static
void normalize_weight_of_rarity(GASHA** gasha)
{
(*gasha)->conf->weights[RARITY_R] = 1.0 -
((*gasha)->conf->weights[RARITY_SR] + (*gasha)->conf->weights[RARITY_SSR]);
return;
}
/*
* gasha->join_cards()
*
* gasha にカードを登録する
*/
static
int join_cards(GASHA** gasha, GASHA_CARD cards[])
{
size_t i = 0;
if ((*gasha)->card != NULL)
release_card(gasha);
for ((*gasha)->cardc = 0;
cards[(*gasha)->cardc].name != NULL; ((*gasha)->cardc)++);
if (((*gasha)->card = (GASHA_CARD**)
malloc(sizeof(GASHA_CARD) * (*gasha)->cardc)) == NULL) {
#ifdef LIBRARY_VERBOSE
print_error();
/* LIBRARY_VERBOSE */
#endif
goto ERR;
}
for (i = 0; i < (*gasha)->cardc; i++) {
if (((*gasha)->card[i] = (GASHA_CARD*)
malloc(sizeof(GASHA_CARD))) == NULL) {
#ifdef LIBRARY_VERBOSE
print_error();
/* LIBRARY_VERBOSE */
#endif
goto ERR;
} else {
(*gasha)->card[i]->id = cards[i].id;
(*gasha)->card[i]->rarity = cards[i].rarity;
if (((*gasha)->card[i]->name = strdup(cards[i].name)) == NULL) {
#ifdef LIBRARY_VERBOSE
print_error();
/* LIBRARY_VERBOSE */
#endif
goto ERR;
}
}
}
config_probs(gasha);
return 0;
ERR:
release_card(gasha);
return -1;
}
/*
* select_card()
*
* 確定したレアリティのカードを一枚抽選する
*
* 2019/02/24 - 全て重みベースで抽選するよう変更
*
* こんな感じ
*
* +---+---+-+-+-+-+
* | 3 | 3 |1|1|1|1|
* +---+---+-+-+-+-+
* total weight = 1.0
*/
static
uint32_t select_card(GASHA* gasha, uint32_t rarity)
{
size_t i = 0;
uint32_t id = 0;
float rval = 0;
/*
* rval = 0.615385 はやすなちゃん
* rval = 0.692308 はソーニャちゃん
*/
rval = gen_rval();
for (i = 0; i < count_by_rarity(gasha, rarity); i++) {
if (rval <= gasha->conf->probs[rarity][i]->weight) {
id = gasha->conf->probs[rarity][i]->id;
break;
}
rval -= gasha->conf->probs[rarity][i]->weight;
}
return id;
}
/*
* gasha->is_ready()
*
* roll()/roll10() できる状態であるかチェックする
*/
static
int is_ready(GASHA* gasha)
{
if (gasha->conf != NULL &&
gasha->card != NULL &&
gasha->cardc > 0)
return 1;
return 0;
}
/*
* gasha->roll()
*
* 所謂「単発」
*/
static
uint32_t roll(GASHA* gasha)
{
float rval = gen_rval();
if (rval < gasha->conf->weights[RARITY_SSR])
return select_card(gasha, RARITY_SSR);
if (rval < gasha->conf->weights[RARITY_SR])
return select_card(gasha, RARITY_SR);
return select_card(gasha, RARITY_R);
}
/*
* gasha->roll10()
*
* 10連ガシャにおいて SR 以上を確定させる
* この関数が10連する訳ではなく、上記の roll() を組み合わせて使う
*/
static
uint32_t roll10(GASHA* gasha)
{
float rval = gen_rval();
if (rval < gasha->conf->weights[RARITY_SSR])
return select_card(gasha, RARITY_SSR);
return select_card(gasha, RARITY_SR);
}
/*
* gasha->roll100()
*
* SSR 確定
*/
static
uint32_t roll100(GASHA* gasha)
{
return select_card(gasha, RARITY_SSR);
}
/*
* 以下はリソースの解放
* release() で全て呼ばれる
*/
static
void release_conf(GASHA** gasha)
{
if ((*gasha)->conf == NULL)
return;
free((*gasha)->conf);
(*gasha)->conf = NULL;
return;
}
static
void release_conf_probs(GASHA** gasha)
{
size_t i = 0,
j = 0;
if ((*gasha)->conf->probs == NULL)
return;
for (i = RARITY_R; i <= RARITY_SSR; i++) {
if ((*gasha)->conf->probs[i] != NULL) {
for (j = 0; (*gasha)->conf->probs[i][j] != NULL; j++) {
free((*gasha)->conf->probs[i][j]);
(*gasha)->conf->probs[i][j] = NULL;
}
free((*gasha)->conf->probs[i]);
(*gasha)->conf->probs[i] = NULL;
}
}
free((*gasha)->conf->probs);
(*gasha)->conf->probs = NULL;
return;
}
static
void release_card(GASHA** gasha)
{
size_t i = 0;
if ((*gasha)->card == NULL)
return;
for (i = 0; i < (*gasha)->cardc; i++) {
if ((*gasha)->card[i] != NULL) {
if ((*gasha)->card[i]->name != NULL) {
free((*gasha)->card[i]->name);
(*gasha)->card[i]->name = NULL;
}
free((*gasha)->card[i]);
(*gasha)->card[i] = NULL;
}
}
free((*gasha)->card);
(*gasha)->card = NULL;
(*gasha)->cardc = 0;
return;
}
static
void release(GASHA* gasha)
{
if (gasha != NULL) {
gasha->conf->release(&gasha);
release_conf(&gasha);
release_card(&gasha);
free(gasha);
}
return;
}
/*
* gen_rval()
*
* 乱数生成
*/
static
float gen_rval(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
srand(tv.tv_usec);
return (float)rand() / (float)RAND_MAX;
}
/*
* gasha.h - 二宮飛鳥?
*/
#ifndef GASHA_H
#define GASHA_H
#ifdef __cplusplus
extern "C" {
/* __cplusplus */
#endif
#include <stdint.h> /* uint32_t */
#include <stdio.h> /* size_t */
/*
* レアリティの定義
*/
#define RARITY_R 3
#define RARITY_SR 4
#define RARITY_SSR 5
/*
* レアリティに対する確率の定義
*/
#define DEFAULT_WEIGHT_R 0.85
#define DEFAULT_WEIGHT_SR 0.12
#define DEFAULT_WEIGHT_SSR 0.03
/*
* カード(各キャラクター)
*
* name は暫定的 ( id と rarity だけ持たせたい )
*/
typedef struct GASHA_CARD {
uint32_t id;
char* name;
uint32_t rarity;
} GASHA_CARD;
/*
* 各種設定
*/
typedef struct GASHA_PROB {
uint32_t id;
float weight;
} GASHA_PROB;
typedef struct GASHA GASHA;
typedef struct GASHA_CONF {
float weights[6];
GASHA_PROB*** probs;
int (*change_weight_of_rarity)(GASHA** gasha, uint32_t rarity, float weight);
void (*normalize_weight_of_rarity)(GASHA** gasha);
int (*config_pickups)(GASHA** gasha, GASHA_PROB pickups[]);
void (*release)(GASHA** gasha);
} GASHA_CONF;
/*
* このライブラリの要
*/
typedef struct GASHA {
GASHA_CONF* conf;
GASHA_CARD** card;
size_t cardc;
int (*join_cards)(GASHA** gasha, GASHA_CARD cards[]);
int (*is_ready)(GASHA* gasha);
uint32_t (*roll)(GASHA* gasha);
uint32_t (*roll10)(GASHA* gasha);
uint32_t (*roll100)(GASHA* gasha);
void (*release)(GASHA* gasha);
} GASHA;
int init_gasha(GASHA** gasha);
GASHA_CARD* id2card(GASHA* gasha, uint32_t id);
size_t count_by_rarity(GASHA* gasha, uint32_t rarity);
GASHA_CARD** filter_by_rarity(GASHA* gasha, uint32_t rarity);
#ifdef __cplusplus
}
/* __cplusplus */
#endif
/* GASHA_H */
#endif
@844196
Copy link

844196 commented Mar 10, 2019

1499683496790

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment