人狼BBS:G の更新時間について

再検討して下さいという旨のメールがきたので再検討しました。
アンケートとかはどう落し込むかで結局悩むので「えいや」でいきます。
インターバルはどう組んでも微妙だったのでちょっと極端になりました。

村番号の下1桁 更新時間
0 12:45
1 06:15
2 23:15
3 00:45
4 06:45
5 22:45
6 01:15
7 18:15
8 00:15
9 02:15

G173からの適用となります。
動かしてみて、あまりにもあんまりだったらまた検討します。

人狼BBS:G また構成の変更など

13人村の狂人が復活しました。13人村はいろいろ悩ましいのでまた変わるかもです。

10人 狼狼占霊村村村村村楽
11人 狼狼狂占霊狩村村村村楽
12人 狼狼狂占霊狩村村村村村楽
13人 狼狼狼狂占霊狩村村村村村楽
14人 狼狼狼狂占霊狩村村村村村村楽

役職希望も復活しました。ただし30%の確率でおまかせにされます。初参加時は村人希望ですが、これもおなじく30%の確率でおまかせになります。以下実装。

  size = wolf_live_person.size
  max = {
    'werewolf'   => (13 <= size ? 3 : 6 <= size ? 2 : 1),
    'seer'       => 1,
    'medium'     => ( 9 <= size ? 1 : 0),
    'possessed'  => (11 <= size ? 1 : 0),
    'bodyguard'  => (11 <= size ? 1 : 0),
    'freemasons' => (16 <= size ? 0 : 0),
  }
  sum = 0
  max.values.each{|i| sum += i}
  max['villagers'] = size - sum
  wolf_live_person.each do |i|
    if i['user_id'] != 'master'
      i['skill'] = '' if !max.keys.index(i['skill']) # 不正な文字列ならおまかせ
      i['skill'] = '' if rand(100) < 30 # 30%の確率でおまかせ
    end
  end
  max.each do |k, v|
    # 希望が多すぎる場合はランダムで選ばれた人(ゲルト以外)がおまかせ
    wolf_skill_rand(k)['skill'] = '' while v < wolf_skill_person(k).size
  end
  max.each do |k, v|
    # 足りない役はおまかせの人からランダムで割り当て
    wolf_skill_rand('')['skill'] = k while wolf_skill_person(k).size < v
  end

人狼BBS:G 構成の変更

10人から開始、14人まで参加可能に変更しました。10人村では狂人と狩人がおらず、13人では狂人のかわりに人狼が増え、14人では人狼3匹の構成になります。

以下のような構成になります。

10人 狼狼占霊村村村村村楽
11人 狼狼狂占霊狩村村村村楽
12人 狼狼狂占霊狩村村村村村楽
13人 狼狼狼占霊狩村村村村村村楽
14人 狼狼狼狂占霊狩村村村村村村楽

狩人の護衛履歴はなくなりました。

依存関係によるメモリ管理

今更このご時世にC言語C++でなく)におけるメモリ管理の話なんぞしてもという気はするが、かれこれ数年ほど使ってきてわりと便利だったので公開してみる。

要求される仕様は以下のような感じ。

  1. 開放忘れを防ぎたい
  2. 後処理などの手間を軽減したい
  3. 単純で癖のない仕様
  4. 削除するタイミングは管理したい

そんなわけで、こんなのを使っている。

void *DP_Malloc(size_t size, void *owner);
void DP_Free(void *p);

第2パラメータのownerに同じくDP_Mallocで得られたポインタを渡すと、そいつが親になる。親がDP_Freeされると、子も自動でDP_Freeされる。もちろん、子だけをDP_Freeで開放してもよいし、その場合は管理下から外れる。

Field *field = DP_Malloc(sizeof(Field), null);
Monster *monsterA = DP_Malloc(sizeof(Monster), field);
Monster *monsterB = DP_Malloc(sizeof(Monster), field);
monsterA->texture = DP_Malloc(sizeof(Texture), monsterA);
monsterB->texture = DP_Malloc(sizeof(Texture), monsterB);

DP_Free(monsterA); // monsterA->textureも一緒に開放される
DP_Free(field); // 残りのmonsterBとそのtextureが開放される

こんな感じ。ownerにNULLを指定したポインタは、自分でDP_Freeする。

各環境のAPIなどから得られたポインタをこの依存関係に組み入れることもできる。それには以下の関数を使う。

typedef void (*DP_Func)(void*);
void *DP_Link(void *p, DP_Func del_func, void *owner);

こんな感じで使う。

static void *FCloseFunc(void *p) {
    fclose(p);
}
FILE *fp = DP_Link(fopen("boo.dat", "rb"), FCloseFunc, null);
FileHeader *header = DP_Malloc(sizeof(FileHeader), fp);

/* ヘッダのデータを読んでなんかしたりする */

DP_Free(fp); // headerも開放される&freeの代わりにFCloseFuncが呼ばれる

削除の前にやりたい処理がある場合は以下で関数を登録する。デストラクタ的な。

void *DP_SetFinalize(void *p, DP_Func final_func)

ざっとこんな感じ。ソースは以下。

ゆるトーク

http://yull-talk.jp/

このご時世、どうでもいい相手とどうでもいい話をする機会というのは、人によっちゃとても得難いもので、でもきっと必要なことなんじゃないかって思ったのです。

という具合のものです。