Skip to content

「山田医師」が3人いる問題 — スタッフ名前生成を作り直しました

公開日: 2026-04-09

ユーザーさんから「職員の名字、同じのばっかり出てくるし、なんかボリューム足りなくない?」という趣旨のフィードバックをいただきました。

言われてみれば本当にその通りで、自分でも「またお前かよ山田…」と思いながらプレイしていたのに、なぜか優先度を下げて放置してしまっていた部分です。さっそく直しました。

何が起きていたか

これまでのスタッフ名前生成は、正直に言うとかなり雑な実装でした。

ts
const STAFF_NAMES_POOL = [
  '山田', '鈴木', '佐藤', '田中', '高橋', '伊藤', '渡辺', '中村',
  '小林', '加藤', '吉田', '松本', '井上', '木村', '林', '清水',
];

function generateStaffName(type, rank) {
  const last = STAFF_NAMES_POOL[Math.floor(Math.random() * STAFF_NAMES_POOL.length)];
  // ...職種ラベルを連結して返す
  return `${last}${typeLabel[type]}`;
}

問題は主に3つ。

問題1: 苗字プールが16しかない

たった16姓からランダムに選んでいるだけなので、10人も雇えばバースデーパラドックス的に重複が確実に起きます。「山田医師」「山田医師」「山田医師」が並ぶのは、不具合というより実装の必然でした。

問題2: 既存スタッフを考慮していない

毎回ただランダムに引いているので、「すでに山田さんがいるかどうか」は一切チェックされません。運が悪いと3連続で同じ苗字が出ます。

問題3: 下の名前がない

${苗字}${職種ラベル} という文字列を name に入れていたので、「山田医師」「山田看護師」のように下の名前という概念自体がない状態でした。同じ苗字・同じ職種が2人いると、もはや区別する手段がありません。

しかも UI 側(スタッフ一覧ページ)では、すでに医師ランクや診療科がバッジとして別途表示されているので、「山田医師 [研修医] [内科]」みたいに 「医師」が二重に表示される 謎の状態にもなっていました。

どう直したか

発想としてはシンプルで:

  1. 苗字プールを 16 → 100 に拡大
  2. 下の名前プールを 80名分 新規追加(性別中立寄りの名前)
  3. 雇用のたびに既存スタッフの苗字と重複しないように抽選
  4. name フィールドは "姓 名" 形式に(職種ラベルは含めない)

コードのコアはこんな感じです。

ts
function generateStaffName(existingStaff: Staff[]): string {
  // 既存スタッフの苗字をセットで持っておく
  const usedSurnames = new Set(
    existingStaff.map((s) => s.name.split(' ')[0] ?? s.name)
  );
  // まだ使っていない苗字から抽選
  const available = SURNAME_POOL.filter((n) => !usedSurnames.has(n));
  const surnamePool = available.length > 0 ? available : SURNAME_POOL;
  const surname = surnamePool[Math.floor(Math.random() * surnamePool.length)];
  const givenName = GIVEN_NAME_POOL[Math.floor(Math.random() * GIVEN_NAME_POOL.length)];
  return `${surname} ${givenName}`;
}

ポイントは「未使用の苗字だけに絞ってからランダムに引く」ところ。こうすれば、プールが枯渇しない限り100%重複を回避できます。万一 100人以上同時雇用して苗字が尽きた場合だけ、重複を許すフォールバックに落ちます(そんな病院ある?)。

苗字・名前プールの組み合わせは 100 × 80 = 8,000通り。現実的にはまず枯渇しません。

地味なおまけ: UIがちょっとスッキリした

副作用として、スタッフ一覧の表示がキレイになりました。

Before:

山田医師   [研修医] [内科]   精度×0.5   誤診率≈15%

After:

山田 太郎   [研修医] [内科]   精度×0.5   誤診率≈15%

「医師」という情報がランクバッジと name で二重化していた問題が解消して、ぱっと見で「ああ、山田太郎先生ね」と把握できるようになりました。地味ですが、プレイ中の視認性がだいぶ上がります。

性別どうするか問題

ちょっと悩んだのが 下の名前の性別 です。

最初は「男女の名前を両方プールに入れて、Staff 型に性別フィールドを追加する?」とも考えたのですが、

  • ゲーム内で性別に意味がない(能力も給料も同じ)
  • 性別フィールドを追加すると型・セーブデータ・UI全部に影響が波及する
  • 差別的な振る舞いに繋がる可能性がある

…という理由で、性別フィールドは追加しない ことにしました。名前プールは男女の名前を混ぜつつ、性別中立寄りの漢字(悠・蓮・優・遥・樹・凛・翼 など)を厚めに入れて、プレイヤーが気になるなら各自の想像で補完してもらう方針です。

あくまで「スタッフを区別するためのラベル」と割り切った設計にしました。

既存セーブはどうなる?

新しいニューゲームからは全員新形式(姓 名)で名前が付きます。

すでに遊んでいるセーブデータについては:

  • 旧スタッフの name(例: 山田医師)はそのまま 保持されます
  • 新しく雇用したスタッフだけ新形式になります
  • 既存スタッフと新形式スタッフが混在することになりますが、ゲームの動作には影響しません

一応マイグレーション(ロード時に旧名を新名に書き換える処理)も検討したのですが過剰に手を入れないというのも大事な判断だと思います。

Hospi+ — テキストベース病院経営シミュレーションゲーム