2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

モンハンのクエスト同行メンバーをランダムで決めるプログラムをPythonで作りたい

Posted at

はじめに

モンスターハンターワールド:アイスボーンの集会所は16人参加できるようになっていますが、1つのクエストに同行できるメンバーは4人までになっています。
一緒にモンハンを遊んでいる友人から、「集会所に5人以上集まったときのクエスト同行者をランダムに決められるようにしたい」との要望があったので、Pythonでプログラムを作ってみました。今回は作成したプログラムを紹介していきたいと思います。
※GUIでの実装ではなくターミナルで動作させるのみとなります。
※内容は非常に簡素なものとなっております。もっと綺麗な書き方等思いついたら修正していきます。
※自己紹介を除くと初投稿なので読んでいて違和感があるかもしれませんがご了承ください。

目次

実装したい内容

  • 集会所に参加しているメンバーの指定
  • メンバーの名前の入力
  • 集会所に参加しているメンバーから最大4人をランダムに選択する機能
  • チームカラーの指定(ランダム)
  • クエストの指定(ランダム)

実装したコード

まずは作成したコードをお見せします。

selection.py
import random
import sys
import math

# ランダムのクエストの同行者を決める関数の定義
def decision_team(members, num_members):

    # チームの数を決める(最大4チーム)
    num_teams = math.ceil(float(num_members)/4)

    # メンバーをランダムにシャッフル
    random.shuffle(members)

    # メンバーを各チームに分ける
    teams = [[] for _ in range(num_teams)]
    for i, member in enumerate(members):
        teams[i % num_teams].append(member)

    return teams

print("1~16の範囲でプレイヤー数を入力してください。終了する場合はqを入力してください。")
while True:
    num_members = input("プレイヤー数:")
    if num_members == "q":
        print("プログラムを終了します。")
        sys.exit()
    try:
        num_members = int(num_members)
    except:
        print("数字以外は入力しないでください。")
        continue
    if num_members >= 1 and num_members <= 16:
        break
    else:
        print("不正な入力です。メンバー数は1~16の範囲で入力してください。")

members = []
print("プレイヤー名を入力してください。")
for i in range(num_members):
    player = input(f"プレイヤー{i+1}の名前:")
    members.append(player)
teams = decision_team(members, num_members)

color_lst = ["", "", "", "", "黄色", ""]
quest_lst = ["ミラボレアス", "王カーナ", "激ラー", "滅日", "ベヒーモス", "アルバトリオン", "王ネロミェール", "モス", "高難易度調査クエスト", "エンシェント・レーシェン"]

print("------------")
print("    結果")
print("------------")
quest = random.choice(quest_lst)
print(f"クエスト:{quest}")
for team in teams:
    random_index = random.randint(0,len(color_lst)-1)
    color = color_lst.pop(random_index)
    print(f"{color}チーム : {team}")

コードの解説

次にコードの解説をしていきます。
かなり丁寧に解説を書いたつもりです。解説がいらない方は実行結果へどうぞ。

モジュールのインポート

import random
import sys
import math

今回作成したコードではrandomsysmathの3つのモジュールを使用しています。

decision_teamの定義

# ランダムのクエストの同行者を決める関数の定義
def decision_team(members, num_members):

    # チームの数を決める(最大4チーム)
    num_teams = math.ceil(float(num_members)/4)

    # メンバーをランダムにシャッフル
    random.shuffle(members)

    # メンバーを各チームに分ける
    teams = [[] for _ in range(num_teams)]
    for i, member in enumerate(members):
        teams[i % num_teams].append(member)

    return teams

小分けにして説明します。

decision_team
num_teams = math.ceil(float(num_members)/4)

num_teams:チームの数
num_members:メンバーの数
ここでは受け取ったnum_membersを4で割った値を切り上げすることでチーム数を決定しています。
ex) num_members=7のとき、4で割ると1.75になる。それを切り上げすると2になるのでチーム数は2になる。

(余談ですが最初はif文で場合分けしてnum_teamsを決定しましたが、この記事を書いている途中に4で割って切り上げればいいのでは...!?と天啓が降ってきたので変えてみました。)

decision_team
random.shuffle(members)

members:参加メンバーの名前が並んだリスト
書いてある通りですがメンバーリストを順番をランダムに入れ替えています。なんだかんだここが一番重要。

decision_team
teams = [[] for _ in range(num_teams)]
    for i, member in enumerate(members):
        teams[i % num_teams].append(member)

    return teams

teams:各チームのメンバーリストが格納されているリスト
ここでは各チームにメンバーを振り分けています。teamsという二重の空リストを内包表記で定義しています。appendする際には余りを使ってindexを指定することで、メンバーの振り分けを動的に行っています。また、振り分ける際は各チームのメンバー数が大きく離れないようにしています(詳しくは最後の実行結果にて)。最後に出来上がったteamsをreturnします。

プレイヤー数の入力

print("1~16の範囲でプレイヤー数を入力してください。終了する場合はqを入力してください。")
while True:
    num_members = input("プレイヤー数:")
    if num_members == "q":
        print("プログラムを終了します。")
        sys.exit()
    try:
        num_members = int(num_members)
    except:
        print("数字以外は入力しないでください。")
        continue
    if num_members >= 1 and num_members <= 16:
        break
    else:
        print("不正な入力です。メンバー数は1~16の範囲で入力してください。")

まずはinputを使ってnum_membersを決定します。
この時「q」を入力したらsys.exit()でプログラムを強制的に停止させるようにしています。正直これくらいのプログラムなら実装しなくてもよさそうだけど

続いてtryで数値以外をはじきます。intに変換できない=数値ではないを利用し、数値でなければ再入力させます。
入力された数値が1~16の範囲に入っていれば合格です。範囲外なら再入力になります。

余談ですが大学のC言語の授業の課題で、毎回のように不正入力を無限ループでチェックすることをやっていたので、不正入力検知が習慣化してしまいました。

チームの決定と諸設定

members = []
print("プレイヤー名を入力してください。")
for i in range(num_members):
    player = input(f"プレイヤー{i+1}の名前:")
    members.append(player)
teams = decision_team(members, num_members)

color_lst = ["", "", "", "", "黄色", ""]
quest_lst = ["ミラボレアス", "王カーナ", "激ラー", "滅日", 
             "ベヒーモス", "アルバトリオン", "王ネロミェール", 
             "モス", "高難易度調査クエスト", "エンシェント・レーシェン"
            ]

ここでは先ほど入力したメンバーの数だけメンバーの名前を入力していきます。入力結果が見やすいようにf文字列を使って整形しています(詳しくは最後の実行結果にて)。入力したメンバーの名前をmembersに追加していきます。
出来上がったmembersnum_membersdecision_teamの引数に入れ、チームを決定します。

また、チームカラーを指定するためのcolor_lstや、quest_lstを定義しています。この2つはお好みで決められます。

結果の表示

print("------------")
print("    結果")
print("------------")
quest = random.choice(quest_lst)
print(f"クエスト:{quest}")
for team in teams:
    random_index = random.randint(0,len(color_lst)-1)
    color = color_lst.pop(random_index)
    print(f"{color}チーム : {team}")

最後に結果の表示を行います。
先ほど定義したquest_lstからランダムに1つクエストを選択します。
※ここではどのチームも同じクエストに出発する前提です。ただチーム分けするだけならクエスト選択部分はいらないですね。
チーム、及びチームカラーの表示はfor文で行います。
チームカラーの選択ではrandint.popを使用することでcolor_lstの中から被ることなく色を取り出すことができます。

実行結果

Pythonのバージョンは3.12.5で、正常動作を確認しています。

実行結果1

image.png
プレイヤー数5で実行した場合、このような結果画面になります。

実行結果2

image.png
プレイヤー数の入力のときに実装した厳格な不正入力検知もしっかり機能しています。

さいごに

今回はモンスターハンターワールド:アイスボーンにおけるクエスト同行メンバーをランダムで決めるプログラムを作りました。今でも友人たちとモンハンをする際、5人以上メンバーが集まったときはこのプログラムを使ってチーム分けを行っています。

モンハンがメインになっていますが、このプログラムのほとんどは基礎的なことしか使っていません(内包表記はちょっと難しいかも?)。そういう意味ではPythonの基礎の確認として使うこともできるかもしれません。

長々とした記事でしたが、ここまで読んでくださった皆様、ありがとうございました。
ワイルズが待ち遠しい!!

参考

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?