
クトゥルフのキャラシをランダムで作ってくれるプログラムを作ってみた
お久しぶりです。フローネのかき氷です。
新年あけましておめでとうございます。まあ、ここあまり使ってないので祝っても感ありますが。
第三回 ランダムクトゥルフキャラシ作成ー!
というわけで、この時がやってまいりました。第三回ランダムクトゥルフキャラシ作成のお時間です。
第一回では、カウガールつむぎが爆誕し大いに界隈を賑わせました。ショットガン片手に馬乗って街駆け回る死者蘇生者ですよ。どういうことですか?
先日はつむぎに並ぶ2台巨頭の一人だった四国めたんが賀屋燐羽と混ざってダークネスしょうはとして探索者デビューしました。
第二回では乗馬クラブとして乗馬技能持ち多数の探索者たちでした。目星図書館がなくて使い勝手悪いのとつむぎの二番煎じになっちゃうので没ですが。
さて、今回はどのようなキャラクターが作られてしまうのか。と言う所なんですが、なんと今回はキャラクターを自動で作ってくれるプログラムを作ってやろうということで?まじですか?
というわけで、今回はPythonを用いたクトゥルフキャラシ作成をやっていこうと思います。
コード解説
下準備
というわけで、早速ですが書いたコードを公開していこうと思います。
まあ、色々な参考文献を基に作ってるんで1から作ったわけではないということで、じゃあ頑張りをほめてもらうために公開してやろうということです。
おそらく、いあきゃらに直接打ち込ませるプログラムも書こうと思えばできそうですが、何かに触れたくないのと、直接打ち込むというちょっとした手間が楽しいんだよということでExcelを経由したプログラムを作成しました。
それと、最初に言っておきますが今回はPythonがある程度分かっている前提で話を進めていきます。要は細かい説明はしませんよーってことですね。
分からないことがあったら自分で調べてください。今やネット上にわんさかあります。私も調べた情報をまとめているだけなので。
あと、そのせいか普通に汚いです。公開はしているとはいえ他人に使われる前提ではなく、あくまで趣味としてやる用なので……
詳しい人こここうした方がいいよーとかあったら教えてください。

まず最初にこのような表を作らせてもらいました。各能力値と技能値の決め方、そして初期値ですね。
Excelファイルを読み込む
それでは、Pythonに入っていきましょう。
コードを書く前に、今回はopenpyxlとrandomとpandasを使用します。インポートしておきましょう。
まずは、今作成したExcelファイルを読み込みます。
#読み込むExcelファイルの名前とシート名を書く
excel_path = r"CoCRandom.xlsx"
test_sheet_name = "Coc"
tmp_list = []
#Excelファイルを読み込む
wb = openpyxl.load_workbook(excel_path)
sheet = wb[test_sheet_name]
for col in sheet.iter_cols():
for raw_value in col:
tmp_list.append(raw_value.value)
wb.close()
Excelファイル名をCoCRandomに、シート名をCoCにしています。
これでExcelファイルのデータがtmp_listに入りました。この名前にしたのは参考サイトそのまんまですね()
それでは、ここまでのプログラムの結果を見ていきましょう。

はい、リスト内に全部入ってますね。ただ、理想としては[['STR']['3d6'],['CON']['3d6],・・・]のようにしたいのですよ。要は二次元リストと呼ばれるやつですね。多分。
というわけで、一度名称系と数値系でリストを分けてそれぞれ組み分けていきます。
#読み込んだExcelファイルを二次元リストにする
coc_lista = tmp_list[:66]
coc_listb = tmp_list[66:]
coc_list = []
for i in coc_lista:
coc_list.append([i])
for i in range(len(coc_listb)):
coc_list[i].append(coc_listb[i])
(aとbでやり方変えてる辺りほんとに汚い。)
さて、出来たリストcoc_listを見てみましょう。

先ほど書いた[['STR']['3d6'],['CON']['3d6],・・・]の形になっていますね。ちなみに、この形にした理由は最後にExcelに書き込むからです。
能力値決定
さて、能力値を決定していきましょう。
#能力値を決定する
for i in range(8):
if i <= 4:
coc_list[i][1] = rd.randint(1,6)+rd.randint(1,6)+rd.randint(1,6)
elif i <= 6:
coc_list[i][1] = rd.randint(1,6)+rd.randint(1,6)+6
else:
coc_list[i][1] = rd.randint(1,6)+rd.randint(1,6)+rd.randint(1,6)+3
forif文で回して見ました。

能力値が決まりましたね。
ついでに能力値を参照する技能の初期値も決めていきます。回避(DEX×2)と母国語(EDU×5)ですね。
ここはなんてことないのでコード書かないでおきます。どうせ後に似たようなのが出るのでそれを参考にしてください。(うまぶるな。)
で、能力値決定する前でも後でもいいのですが、能力値と技能値を一旦切り離しておきましょう。
私は技能値を決める際に必要だなと思ったので後でやりました。
切り分けもさっきコード書いたね。いっか。
それと、技能値側のリストに0,0を追加しておきます。
これが職業ポイントと興味ポイントの値になるんで。
for i in range(len(coc_skill)):
coc_skill[i].append(0)
for i in range(len(coc_skill)):
coc_skill[i].append(0)
僕、同じ文を2回繰り返すことで入れてるんですけどもっといい方法ないんかな?
これによって、[[キック,25,0,0],[組み付き,25,0,0]・・・]のようになっています。
技能値決定
さて、とても頑張ったところ、技能値決定です。
各文に説明入れてるので一気に見ていきましょう。
#職業ポイントから振り分けていく。
#職業ポイントが0以下になったらループ終了
while edu > 0:
#職業ポイントが20以下の時は余ったポイントを一つの技能にまとめたいのでif文
if edu > 20:
#技能名選択
n = rd.randint(0,len(coc_skill)-1)
#ポイント決定
l = rd.randint(1,90-(coc_skill[n][1]+coc_skill[n][2]))
#ポイントと、既に振り分けられているポイントを足した合計が90より多い場合やり直し
if l + (coc_skill[n][1]+coc_skill[n][2]) > 90:
continue
#決まったポイントが職業ポイントより多い場合、職業ポイント全部のみとする
elif edu - l <= 0:
l = edu
#ポイント決定
coc_skill[n][2] = l + coc_skill[n][2]
#職業ポイントを減らして職業ポイントが0になるので終了
edu = edu - l
else:
#上と同じ
coc_skill[n][2] = l + coc_skill[n][2]
#職業ポイントを減らしてwhileへ戻る
edu = edu - l
else:
#職業ポイントが20以下の場合ここへ行く
n = rd.randint(0,len(coc_skill)-1)
#残り職業ポイントと現在選択された技能のポイントが90より多い場合上の作業をもう一回
if edu + (coc_skill[n][1]+coc_skill[n][2]) > 90:
l = rd.randint(1,90-(coc_skill[n][1]+coc_skill[n][2]))
if l + (coc_skill[n][1]+coc_skill[n][2]) > 90:
continue
else:
coc_skill[n][2] = l + coc_skill[n][2]
edu = edu - l
#選択された技能に職業ポイントを全て振り分けて職業ポイントが0になるので終了
else:
coc_skill[n][2] = edu + coc_skill[n][2]
edu = edu-edu
#職業ポイントと同じことを興味ポイントで行う
while ints > 0:
if ints > 20:
n = rd.randint(0,len(coc_skill)-1)
#ちなみに、lを使ってるのはこの間にrandintの最大値用のmがあった名残。コンパクトにするために統合したが、mに直すのは面倒だった。
l = rd.randint(1,90-(coc_skill[n][1]+coc_skill[n][2]+coc_skill[n][3]))
if l + (coc_skill[n][1]+coc_skill[n][2]+coc_skill[n][3]) > 90:
continue
elif ints - l <= 0:
l = ints
coc_skill[n][3] = l + coc_skill[n][3]
ints = ints - l
else:
coc_skill[n][3] = l + coc_skill[n][3]
ints = ints - l
else:
n = rd.randint(0,len(coc_skill)-1)
if ints + (coc_skill[n][1]+coc_skill[n][2]+coc_skill[n][3]) > 90:
l = rd.randint(1,90-(coc_skill[n][1]+coc_skill[n][2]+coc_skill[n][3]))
if l + (coc_skill[n][1]+coc_skill[n][2]+coc_skill[n][3]) > 90:
continue
else:
coc_skill[n][3] = l + coc_skill[n][3]
ints = ints - ints
else:
coc_skill[n][3] = ints + coc_skill[n][3]
ints = ints-ints
まあ、説明はコメントに書いてある通りです。(めんどくさくなった。)
すこし長ったらしいのでコンパクトに出来ればやってください。
Excelファイルへの書き込み
最後に、分けて置いた能力値と技能値のリストを統合してExcelファイルに書き込めば完了です。新しいシートを作って書き込んでいきます。
#切り分けといたステータスと技能を統合
for i in coc_skill:
coc_status.append(i)
#あとは新しいシートを作成して終了。 名前は探索者の名前でも入れとこう。
df = pd.DataFrame(coc_status)
with pd.ExcelWriter(excel_path,engine='openpyxl', mode='a') as writer:
df.to_excel(writer, sheet_name=input("名前を入れてね! :"))
#お疲れさまでした。
print("end")
ここまでを実際に実行してみるとこうなります。

名前を入れてね!とendしか表示されませんが、この辺お好みでどうぞ。
Excelファイルからいあきゃらへ手打ち
それでは、Excelファイルを見ていきましょう。

シートが追加されていますね。
今回は三島夕映のシートを見ていきます。


なんと、技能値が割り振られています!
これで、名前を決めればワンクリックでキャラシが出来上がるプログラムが出来ました!
キャラ紹介
というわけで本題のキャラ紹介と行きましょう!
今回のキャラ名はシノビガミの命名表を用いて作りました!
No.1
豆粒小僧
https://iachara.com/view/10689317
まず特筆すべきはマーシャルアーツと拳銃の高さですね。マーシャルアーツと拳銃って合わないけど……
能力値全体的に高いですね。特にCONが最大値とショックロールにとても強いですね。小僧のくせに。
あと、豆粒小僧なのにSIZ17ですね。????
法律にも1だけ精通してます。
No.2
三島夕映
https://iachara.com/view/10689324
変装が85に医学が78…回避75にライフル65…
何してる人ですか?
戦場の救護班でもしてそうなキャラシです。
No.3
本田扇
https://iachara.com/view/10689323
目星が高いのはありがたい。ただ、跳躍に鍵開けに隠すに変装……君泥棒だね?。
N0.4
宮田油
https://iachara.com/view/10687834
隠す以外カス。(言い方ひどい)
総評
油以外何とか使えそうなキャラシで良かったです。(泥棒っていつ使うんだ?)ただ、三大技能全て持ってるキャラはいなかったので使わないかな。(おい)
〆の言葉
というわけで、第三回ランダムクトゥルフキャラシ作成でした。いかがでしたでしょうか?
プログラム化が出来たので今後はもっと気軽に開催が出来ますね。やったー(喜ぶべきなのか?)
とはいえ、この企画自体はクトゥルフのKPをやる時に一人回しする用のキャラが欲しい時にしかしませんが。
というのも、明日ついにまともな初KPをします!(ネタシだったり弟達に回したのを除いて)
で、シナリオ読んでも全体の流れが良く分からなかったので実際に一人回しをしてみようというものです。
今回作ったこの4人を使いやすいように、また、推奨に合うように小さい技能ポイントを振り直して使っていきたいと思っております。
プログラムに関してはまあ使ってみたい人いたらご自由にどうぞということで、〆の言葉とします。文書くのめんどくさくなった。言葉足りてなかったら編集するね。今咳ひどいんで寝ます。では。おつちこー!
参考文献
https://qiita.com/2019Shun/items/db0028a535297ef50184
https://www.kikagaku.co.jp/kikagaku-blog/python-while/#i-2