From b85294b7e707345f6060c959e8a1f6374588ffc4 Mon Sep 17 00:00:00 2001 From: tetsuya-k <64536338+tetsuya-ki@users.noreply.github.com> Date: Sun, 24 Jan 2021 22:43:41 +0900 Subject: [PATCH 1/6] =?UTF-8?q?logger=E3=81=AEwarn=E3=83=A1=E3=82=BD?= =?UTF-8?q?=E3=83=83=E3=83=89=E3=82=92=E4=BD=BF=E3=81=A3=E3=81=A6=E3=81=84?= =?UTF-8?q?=E3=81=9F=E7=82=B9=E3=82=92=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assitantbot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assitantbot.py b/assitantbot.py index 943b975..c7ea32c 100644 --- a/assitantbot.py +++ b/assitantbot.py @@ -33,7 +33,7 @@ def __init__(self, command_prefix, help_command, intents): try: self.load_extension(cog) except Exception: - logger.warn("traceback:", stack_info=True) + logger.warning("traceback:", stack_info=True) # Botの準備完了時に呼び出されるイベント async def on_ready(self): From 66b4660aea6da1e632ef4b3f0e43941fe6ca84ee Mon Sep 17 00:00:00 2001 From: tetsuya-k <64536338+tetsuya-ki@users.noreply.github.com> Date: Mon, 25 Jan 2021 09:18:19 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=E3=82=B2=E3=83=BC=E3=83=A0=E3=82=AB?= =?UTF-8?q?=E3=83=86=E3=82=B4=E3=83=AA=E3=81=AB=E3=82=B3=E3=83=A8=E3=83=BC?= =?UTF-8?q?=E3=83=86=E3=82=92=E8=BF=BD=E5=8A=A0=EF=BC=88=E3=81=BE=E3=81=A0?= =?UTF-8?q?=E3=83=90=E3=82=B0=E3=81=8C=E3=81=82=E3=82=8A=E3=81=9D=E3=81=86?= =?UTF-8?q?=E3=81=A0=E3=81=91=E3=81=A9=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cogs/gamecog.py | 175 +++++++++++++++++++++++++++++++++++++++++ cogs/modules/coyote.py | 164 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 339 insertions(+) create mode 100644 cogs/modules/coyote.py diff --git a/cogs/gamecog.py b/cogs/gamecog.py index 378ff14..f81e5b3 100644 --- a/cogs/gamecog.py +++ b/cogs/gamecog.py @@ -1,7 +1,9 @@ +from cogs.modules.coyote import Coyote from discord.ext import commands # Bot Commands Frameworkのインポート from .modules.grouping import MakeTeam from .modules.readjson import ReadJson from logging import getLogger +from .modules.coyote import Coyote import asyncio import random @@ -20,6 +22,7 @@ class GameCog(commands.Cog, name='ゲーム用'): # GameCogクラスのコンストラクタ。Botを受取り、インスタンス変数として保持。 def __init__(self, bot): self.bot = bot + self.coyoteGame = Coyote() # ワードウルフ機能 @commands.command(aliases=['word','ww'], description='ワードウルフ機能(少数派のワードを与えられた人を当てるゲーム)') @@ -156,6 +159,178 @@ async def ngWordGame(self, ctx, answer_minutes=None): # NGワードゲームのネタバレメッセージを作成し、チャンネルに貼り付け await self.delayedMessage(ctx, 'NGワードゲームのネタバレです!\nそれぞれ、' + netabare_msg + 'でした!', answer_minutes * 60) + # コヨーテゲーム群 + @commands.group(aliases=['co','cog','cy','cg'], description='コヨーテするコマンド(サブコマンド必須)') + async def coyoteGame(self, ctx): + """ + コヨーテするコマンド群です。このコマンドだけでは実行できません。半角スペースの後、続けて以下のサブコマンドを入力ください。 + - コヨーテを始めたい場合は、`start`または`startAndAllMessage`を入力してください(startは説明が短く、startAndAllMessageは全てを説明します)。 + - コヨーテ中に、「コヨーテ!」をしたい場合は、`coyote`を入力してください。 + - コヨーテ中に、次の回を始めたい場合は、`deal`を入力してください。 + """ + # サブコマンドが指定されていない場合、メッセージを送信する。 + if ctx.invoked_subcommand is None: + await ctx.send('このコマンドにはサブコマンドが必要です。') + + + @coyoteGame.command(aliases=['s', 'st', 'ini', 'init'], description='コヨーテを始めるコマンド') + async def start(self, ctx): + await self.startCoyote(ctx) + await self.littleMessage(ctx) + await self.dealAndMessage() + + @coyoteGame.command(aliases=['sa', 'ina', 'inia'], description='コヨーテを始めるコマンド(全説明)') + async def startAndAllMessage(self, ctx): + await self.startCoyote(ctx) + await self.allMessage(ctx) + await self.dealAndMessage() + + @coyoteGame.command(aliases=['sn', 'no', 'inn'], description='コヨーテを始めるコマンド(説明なし)') + async def startAndNoMessage(self, ctx): + await self.startCoyote(ctx) + await self.dealAndMessage() + + @coyoteGame.command(aliases=['c', 'cy', 'done'], description='コヨーテ!(前プレイヤーの数字がコヨーテの合計数を超えたと思った場合のコマンド)') + async def coyote(self, ctx, you_id=None, number=0): + if you_id is None: + msg = '「コヨーテする相手」(@で指定)と「コヨーテを言われた人の数字」を指定してください。例:`/coyoteGame coyote @you 99`' + await ctx.send(msg) + return + if number <= 0: + msg = '「コヨーテを言われた人の数字」は「1以上の整数」(0もダメです)を指定してください。例:`/coyoteGame coyote @you 99`' + await ctx.send(msg) + return + if self.coyoteGame is None or len(self.coyoteGame.members) <= 1: + msg = ' コヨーテを始めたい場合は、`coyoteGame start`または`coyoteGame startAndAllMessage`を入力してください。' + await ctx.send(msg) + return + + you_id = re.sub(r'[<@!>]', '', you_id) + if you_id.isdecimal(): + you_id = int(you_id) + you = ctx.guild.get_member(you_id) + self.coyoteGame.coyote(ctx.author, you, number) + await ctx.send(self.coyoteGame.description) + + + @coyoteGame.command(aliases=['d', 'de', 'next'], description='ディール(次のターンを始める)') + async def deal(self, ctx): + if self.coyoteGame is None or len(self.coyoteGame.members) <= 1: + msg = 'コヨーテを始めたい場合は、`coyoteGame start`または`coyoteGame startAndAllMessage`を入力してください。' + await ctx.send(msg) + return + await self.dealAndMessage() + + @coyoteGame.command(aliases=['desc'], description='状況説明') + async def description(self, ctx): + if self.coyoteGame is None or len(self.coyoteGame.members) <= 1: + msg = 'コヨーテを始めたい場合は、`coyoteGame start`または`coyoteGame startAndAllMessage`を入力してください。' + await ctx.send(msg) + return + msg = f'ターン数:{self.coyoteGame.turn}\n' + msg += f'生き残っている人の数:{len(self.coyoteGame.members)}\n' + for member in self.coyoteGame.members: + msg += f'`{member.display_name}さん: (HP:{self.coyoteGame.members[member].HP})` ' + msg += f'山札の数:{len(self.coyoteGame.deck)}枚, ' + msg += f'捨て札:{len(self.coyoteGame.discards)}枚→' + discards_list = map(str, self.coyoteGame.discards) + discards = ','.join(discards_list) + msg += discards + await ctx.send(msg) + + @coyoteGame.command(aliases=['da','desca'], description='状況説明(全て)') + async def descriptionAll(self, ctx): + if self.coyoteGame is None or len(self.coyoteGame.members) <= 1: + msg = 'コヨーテを始めたい場合は、`coyoteGame start`または`coyoteGame startAndAllMessage`を入力してください。' + await ctx.send(msg) + return + msg = f'ターン数:{self.coyoteGame.turn}\n' + msg += f'生き残っている人の数:{len(self.coyoteGame.members)}\n' + for member in self.coyoteGame.members: + msg += f'`{member.display_name}さん: (HP:{self.coyoteGame.members[member].HP})` ' + msg += f'山札の数:{len(self.coyoteGame.deck)}枚, ' + deck_list = map(str, self.coyoteGame.deck) + deck = ','.join(deck_list) + msg += deck + '\n' + msg += f'捨て札:{len(self.coyoteGame.discards)}枚→' + discards_list = map(str, self.coyoteGame.discards) + discards = ','.join(discards_list) + msg += discards + msg += f'場のカード:{len(self.coyoteGame.hands)}枚→' + hands_list = map(str, self.coyoteGame.hands) + hands = ','.join(hands_list) + msg += f'||{hands}||' + await ctx.send(msg) + + async def startCoyote(self, ctx): + make_team = MakeTeam() + make_team.my_connected_vc_only_flg = True + await make_team.get_members(ctx) + + if make_team.mem_len < 2: + msg = f'コヨーテを楽しむには2人以上のメンバーが必要です(現在、{make_team.mem_len}人しかいません)' + await ctx.send(msg) + return + self.coyoteGame.set(make_team.vc_members) + self.coyoteGame.shuffle() + + async def dealAndMessage(self): + self.coyoteGame.deal() + dm_msg_all = '' + for player in self.coyoteGame.members: + dm_msg_all += f'{player.display_name}さん: {self.coyoteGame.members[player].card}\n' + for player in self.coyoteGame.members: + dm = await player.create_dm() + rpl_msg_del = f'{player.display_name}さん:.+\n' + dm_msg = re.sub(rpl_msg_del, '', dm_msg_all) + await dm.send(f'{player.mention}さん 他の人のコヨーテカードはこちらです!\n{dm_msg}') + + async def allMessage(self, ctx): + msg1 = 'コヨーテ:ゲーム目的\n**自分以外のプレイヤーのカード(DMに送られる)を見て、少なくとも何匹のコヨーテがこの場にいるかを推理します。**\n'\ + 'もしも宣言した数だけ居なかったら......コヨーテに命を奪われてしまいます! インディアン、嘘つかない。コヨーテだって、嘘が大キライなのです。\n'\ + 'ライフは一人3ポイントあります。3回殺されたらゲームから退場します。\n'\ + 'コヨーテの鳴き声(想像してね)が上手いプレイヤーから始めます。' + await ctx.send(msg1) + + msg2 = '最初のプレイヤーはDMに送られる他の人のカードを見て、この場に「少なくとも」何匹のコヨーテがいるか推理し、コヨーテの数を宣言します。\n'\ + '★宣言する数に上限はありませんが、1以上の整数である必要があります(つまり、0や負数はダメです)\n'\ + 'ゲームは時計回りに進行(ボイスチャンネルを下に進むこと)します。\n'\ + '次のプレイヤーは次のふたつのうち、「どちらか」の行動をとってください。\n'\ + '1: 数字を上げる → 前プレイヤーの宣言した数が実際にこの場にいるコヨーテの数**以下(オーバー)していない**と思う場合、**前プレイヤーより大きな数**を宣言します。\n'\ + '2: 「コヨーテ!」→ 前プレイヤーの宣言を疑います。つまり、前プレイヤーの宣言した数が実際にこの場にいるコヨーテの数よりも**大きい(オーバーした)**と思う場合、**「コヨーテ!」**と宣言します\n'\ + '2の場合、例:`/coyoteGame coyote @you 99`のように**Discordに書き込んで**ください!(Botが結果を判定します!)\n'\ + '**誰かが「コヨーテ!」と宣言するまで**、時計回りで順々に交代しながら宣言する数字を上げていきます\n' + await ctx.send(msg2) + + msg3 = '「コヨーテ!」と宣言された場合、直前のプレイヤーが宣言した数が当たっていたかどうか判定します。\n'\ + '★前述の通り、Botが計算します(例:`/coyoteGame coyote @you 99`のように書き込んでくださいね)\n'\ + 'まず基本カードを集計したあと、特殊カード分を計算します。\n'\ + '「コヨーテ!」を宣言された数がコヨーテの合計数をオーバーしていた場合、「コヨーテ!」を宣言した人の勝ち(数値を宣言した人の負け)\n'\ + '「コヨーテ!」を宣言された数がコヨーテの合計数以下の場合、数値を宣言した人の勝ち(「コヨーテ!」を宣言した人の負け)\n'\ + '負けたプレイヤーはダメージを受けます(ライフが減ります)。\n'\ + '使ったカードを捨て札にして、次の回を始めます(**今回負けた人から開始**します)。\n'\ + '次の回を始めるには、`/coyoteGame deal`をDiscordに書き込んでください。\n'\ + '負けたプレイヤーがその回を最後に**ゲームから脱落した場合、その回の勝者から**次の回を始めます。\n'\ + 'ライフが0になったプレイヤーはゲームから脱落します。最後まで生き残ったプレイヤーが勝利です。' + await ctx.send(msg3) + + + async def littleMessage(self, ctx): + msg = 'コヨーテ:ゲーム目的\n**自分以外のプレイヤーのカード(DMに送られる)を見て、少なくとも何匹のコヨーテがこの場にいるかを推理します。**\n'\ + 'もしも宣言した数だけ居なかったら......コヨーテに命を奪われてしまいます! インディアン、嘘つかない。コヨーテだって、嘘が大キライなのです。\n'\ + 'ライフは一人3ポイントあります。3回殺されたらゲームから退場します。\n'\ + '最初のプレイヤー:「少なくとも」何匹のコヨーテがいるか推理し、コヨーテの数を宣言(1以上の整数)します。\n'\ + 'ゲームは時計回りに進行(ボイスチャンネルを下に進むこと)\n'\ + '次のプレイヤー:は次のふたつのうち、「どちらか」の行動をとってください。\n'\ + '1: 数字を上げる → 前プレイヤーの宣言した数が実際にこの場にいるコヨーテの数**以下(オーバー)していない**と思う場合、**前プレイヤーより大きな数**を宣言します。\n'\ + '2: 「コヨーテ!」→ 前プレイヤーの宣言を疑います。つまり、前プレイヤーの宣言した数が実際にこの場にいるコヨーテの数よりも**大きい(オーバーした)**と思う場合、**「コヨーテ!」**と宣言します\n'\ + '2の場合、例:`/coyoteGame coyote @you 99`のように**Discordに書き込んで**ください!(Botが結果を判定します!)\n'\ + '**誰かが「コヨーテ!」と宣言するまで**、時計回りで順々に交代しながら宣言する数字を上げていきます\n'\ + '次の回を始めるには、`/coyoteGame deal`をDiscordに書き込んでください(**今回負けた人から開始**します)。\n'\ + '負けたプレイヤーがその回を最後に**ゲームから脱落した場合、その回の勝者から**次の回を始めます。\n'\ + 'ライフが0になったプレイヤーはゲームから脱落します。最後まで生き残ったプレイヤーが勝利です。' + await ctx.send(msg) + @wordWolf.error async def wordWolf_error(self, ctx, error): if isinstance(error, commands.CommandError): diff --git a/cogs/modules/coyote.py b/cogs/modules/coyote.py new file mode 100644 index 0000000..1e687b0 --- /dev/null +++ b/cogs/modules/coyote.py @@ -0,0 +1,164 @@ +import random +import discord +from logging import getLogger + +logger = getLogger(__name__) + +class CoyoteMember: + DEFAULT_HP = 3 + def __init__(self): + self.HP = self.DEFAULT_HP + self.card = '' + self.isDead = False + + def setCard(self, card: str): + self.card = card + + def damage(self, number: int): + self.HP = self.HP -number + if self.HP == 0: + self.isDead = True + +class Coyote: + # DEFAULT_DECK = [20, 15, 15, 10, 10, 10, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, '0(Night)', -5, -5, -10, '*2(Chief)', 'Max->0(Fox)', '?(Cave)'] + DEFAULT_DECK = [20,'Max->0(Fox)','?(Cave)','?(Cave)'] + + def __init__(self): + self.members = {} + self.body = [] + self.deck = self.DEFAULT_DECK + self.hands = [] + self.discards = [] + self.turn = 0 + self.description = '' + + def set(self, members): + for member in members: + coyoteMember = CoyoteMember() + self.members[member] = coyoteMember + + def shuffle(self): + self.deck.extend(self.discards) + self.discards = [] + random.shuffle(self.deck) + self.description += 'シャッフルしました。\n' + + def deal(self): + self.turn = self.turn + 1 + self.description = '' + self.hands = [] + + for member in self.members: + card = self.deck.pop() + self.members[member].setCard(card) + self.hands.append(card) + if len(self.deck) == 0: + self.shuffle() + + def coyote(self, me: discord.Member, you: discord.Member, number): + # 計算 + coyotes = self.calc() + + # コヨーテの結果の判定 + if number > coyotes: + self.members[you].damage(1) + self.description += f'{number} > {coyotes} → 「コヨーテ!」の勝ち({me.display_name}が正しい!)\n' + self.description += f'{you.display_name}に1点ダメージ。' + if self.members[you].isDead: + self.description += f'{you.display_name}は死にました。\n' + self.body.append(self.members.pop(you)) + else: + self.members[me].damage(1) + self.description += f'{number} <= {coyotes} → 「コヨーテ!」の負け({you.display_name}が正しい!)\n' + self.description += f'{me.display_name}に1点ダメージ。' + if self.members[me].isDead: + self.description += f'{me.display_name}は死にました。\n' + self.body.append(self.members.pop(me)) + + # 一人になったら、勝利 + if len(self.members) == 1: + for member in self.members: + self.description += f'{member.display_name}の勝ちです! おめでとうございます!!' + else: + self.description += '現在の状況:' + for member in self.members: + self.description += f'{member.display_name}さん(HP:{self.members[member].HP}) ' + + def calc(self): + # [変数名 for 変数名 in 元のリスト if 条件式] + normal_hands = [i for i in self.hands if self.is_num(i)] + special_hands = [i for i in self.hands if not self.is_num(i)] + additional_hands = [] + shuffle_flg = False + + # Caveカードの効果 + cave_hands = [i for i in special_hands if ('Cave' in str(i))] + for card in cave_hands: + while(True): + self.discards.append(card) + additional_card = self.deck.pop() + self.hands.append(additional_card) + self.description += f'{card}の効果で、1枚山札から引いた(値は{additional_card})。\n' + + # 引いたもので再計算 + normal_hands = [i for i in self.hands if self.is_num(i)] + special_hands = [i for i in self.hands if (not self.is_num(i) and not 'Cave' in str(i))] + if len(self.deck) == 0: + self.shuffle() + if not 'Cave' in str(additional_card): + break + + # Chiefカードを集計 + chief_hands = [i for i in special_hands if ('Chief' in str(i))] + special_hands = [i for i in special_hands if not 'Chief' in str(i)] + + for card in special_hands: + card = str(card) + + # Nightカードの効果 + if 'Night'in card: + self.discards.append(card) + normal_hands.append(0) + shuffle_flg = True + self.description += f'{card}の効果で、計算終了後に山札/捨て札を混ぜてシャッフルする。\n' + + # Foxカードの効果 + if 'Fox' in card: + self.discards.append(card) + num_hands = [i for i in normal_hands if self.is_num(i)] + if len(num_hands) == 0: + max_num = 0 + else: + max_num = max(num_hands) + normal_hands.append(-max_num) + self.description += f'{card}の効果で、この場で最大の値である{max_num}を0にした。\n' + + # 計算 + coyotes = 0 + self.description += '通常カードの計算:' + for card in normal_hands: + self.discards.append(card) + coyotes += card + if card >= 0: + self.description += f'+ {str(card)}' + else: + self.description += f'{str(card)}' + self.description += '\n' + + # Chiefカードの効果 + for card in chief_hands: + self.discards.append(card) + coyotes = coyotes * 2 + self.description += f'{card}の効果で、2倍にした。\n' + + if shuffle_flg: + self.shuffle() + + return coyotes + + def is_num(self, num): + try: + int(num) + except: + return False + return True \ No newline at end of file From a2f68d716cde5673091ebc4eaefa6e616496df1d Mon Sep 17 00:00:00 2001 From: tetsuya-k <64536338+tetsuya-ki@users.noreply.github.com> Date: Tue, 26 Jan 2021 00:08:19 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=E3=82=B3=E3=83=A8=E3=83=BC=E3=83=86?= =?UTF-8?q?=E6=A9=9F=E8=83=BD=E3=81=AE=E3=83=90=E3=82=B0=E3=82=92=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3(Fox=E3=81=AE=E5=8A=B9=E6=9E=9C=E3=81=A7=E6=8D=A8?= =?UTF-8?q?=E3=81=A6=E6=9C=AD=E3=81=8C=E5=A2=97=E3=81=88=E3=81=9F=E3=82=8A?= =?UTF-8?q?=E3=80=81Cave=E3=81=AE=E5=8A=B9=E6=9E=9C=E3=81=A7=E7=84=A1?= =?UTF-8?q?=E9=99=90=E3=83=AB=E3=83=BC=E3=83=97=E3=81=97=E3=81=9F=E3=82=8A?= =?UTF-8?q?=E3=80=81Cave=E3=81=8C=E5=8F=96=E3=82=8A=E9=99=A4=E3=81=8B?= =?UTF-8?q?=E3=82=8C=E3=81=9F=E3=82=8A)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cogs/gamecog.py | 154 ++++++++++++++++++++++++++++++---------- cogs/modules/coyote.py | 156 ++++++++++++++++++++++++++++++++--------- 2 files changed, 239 insertions(+), 71 deletions(-) diff --git a/cogs/gamecog.py b/cogs/gamecog.py index f81e5b3..f32b69f 100644 --- a/cogs/gamecog.py +++ b/cogs/gamecog.py @@ -22,7 +22,7 @@ class GameCog(commands.Cog, name='ゲーム用'): # GameCogクラスのコンストラクタ。Botを受取り、インスタンス変数として保持。 def __init__(self, bot): self.bot = bot - self.coyoteGame = Coyote() + self.coyoteGames = Coyote() # ワードウルフ機能 @commands.command(aliases=['word','ww'], description='ワードウルフ機能(少数派のワードを与えられた人を当てるゲーム)') @@ -167,6 +167,11 @@ async def coyoteGame(self, ctx): - コヨーテを始めたい場合は、`start`または`startAndAllMessage`を入力してください(startは説明が短く、startAndAllMessageは全てを説明します)。 - コヨーテ中に、「コヨーテ!」をしたい場合は、`coyote`を入力してください。 - コヨーテ中に、次の回を始めたい場合は、`deal`を入力してください。 + - コヨーテ中に、現在の状況を確認したい場合は、`description`を入力してください。 + 上級者向け機能 + - 説明を省略して、コヨーテを始める場合は、`startAndNoMessage`を入力してください。 + - コヨーテ中に、ネタバレありで現在の状況を確認したい場合は、`descriptionAll`を入力してください。 + - `setDeckAndStart`で自分でデッキを作成できます。詳しくは`/help coyoteGame setDeckAndStart`を入力してください。 """ # サブコマンドが指定されていない場合、メッセージを送信する。 if ctx.invoked_subcommand is None: @@ -175,23 +180,69 @@ async def coyoteGame(self, ctx): @coyoteGame.command(aliases=['s', 'st', 'ini', 'init'], description='コヨーテを始めるコマンド') async def start(self, ctx): + """ + コヨーテを始めるコマンド(説明が程よいバージョン) + - コヨーテのルールが分かる程度に省略しています。 + """ await self.startCoyote(ctx) await self.littleMessage(ctx) await self.dealAndMessage() @coyoteGame.command(aliases=['sa', 'ina', 'inia'], description='コヨーテを始めるコマンド(全説明)') async def startAndAllMessage(self, ctx): + """ + コヨーテを始めるコマンド(説明が多いバージョン) + - 初心者はこちらのコマンドを実行してください。 + - コヨーテのルールが分かるように書いてありますが、一旦説明を見ながらゲームしてみると良いと思います。 + """ await self.startCoyote(ctx) await self.allMessage(ctx) await self.dealAndMessage() @coyoteGame.command(aliases=['sn', 'no', 'inn'], description='コヨーテを始めるコマンド(説明なし)') async def startAndNoMessage(self, ctx): + """ + コヨーテを始めるコマンド(説明なし) + - 上級者向けの機能です。ルールを説明されずとも把握している場合にのみ推奨します。 + """ await self.startCoyote(ctx) await self.dealAndMessage() + @coyoteGame.command(aliases=['sds','ss', 'set'], description='デッキを指定して、コヨーテを始めるコマンド(説明なし)') + async def setDeckAndStart(self, ctx, *, deck=None): + """ + デッキを指定してコヨーテを始めるコマンド(説明なし) + - 上級者向けの機能です。ルールを説明されずとも把握している場合にのみ推奨します。 + - デッキを「,」(コンマ)で区切って指定します。二重引用符などは不要です。 + 例:`/coyoteGame setDeckAndStart 20, 15, 15, 1, 1, 1, 1, 0, 0, 0, 0(Night), -5, -5, -10, *2(Chief), Max->0(Fox), ?(Cave), ?(Cave)` + """ + make_team = MakeTeam() + make_team.my_connected_vc_only_flg = True + await make_team.get_members(ctx) + + if make_team.mem_len < 2: + msg = f'コヨーテを楽しむには2人以上のメンバーが必要です(現在、{make_team.mem_len}人しかいません)' + await ctx.send(msg) + return + if deck is None: + msg = f'deckを指定してください。\n例:`/coyoteGame setDeckAndStart 20, 15, 15, 1, 1, 1, 1, 0, 0, 0, 0(Night), -5, -5, -10, *2(Chief), Max->0(Fox), ?(Cave), ?(Cave)`' + await ctx.send(msg) + return + self.coyoteGames.set(make_team.vc_members) + self.coyoteGames.setDeck(deck) + self.coyoteGames.shuffle() + await self.dealAndMessage() + @coyoteGame.command(aliases=['c', 'cy', 'done'], description='コヨーテ!(前プレイヤーの数字がコヨーテの合計数を超えたと思った場合のコマンド)') async def coyote(self, ctx, you_id=None, number=0): + """ + コヨーテ中に実行できる行動。「コヨーテ!」を行う + - 「コヨーテ!」は前プレイヤーの宣言を疑う行動 + - 「前プレイヤーの宣言した数」が「実際にこの場にいるコヨーテの数よりも**大きい(オーバーした)**」と思う場合に実行してください + 引数は2つあり、どちらも必須です + - 1.プレイヤーのID(@マークを打つと入力しやすい) + - 2.前プレイヤーの宣言した数 + """ if you_id is None: msg = '「コヨーテする相手」(@で指定)と「コヨーテを言われた人の数字」を指定してください。例:`/coyoteGame coyote @you 99`' await ctx.send(msg) @@ -200,64 +251,87 @@ async def coyote(self, ctx, you_id=None, number=0): msg = '「コヨーテを言われた人の数字」は「1以上の整数」(0もダメです)を指定してください。例:`/coyoteGame coyote @you 99`' await ctx.send(msg) return - if self.coyoteGame is None or len(self.coyoteGame.members) <= 1: - msg = ' コヨーテを始めたい場合は、`coyoteGame start`または`coyoteGame startAndAllMessage`を入力してください。' + if self.coyoteGames is None or len(self.coyoteGames.members) <= 1: + msg = 'コヨーテを始めてから実行できます。コヨーテを始めたい場合は、`/coyoteGame start`または`/coyoteGame startAndAllMessage`を入力してください。' await ctx.send(msg) return + # コヨーテ!した相手のメンバー情報を取得。取得できない場合はエラーを返す you_id = re.sub(r'[<@!>]', '', you_id) if you_id.isdecimal(): you_id = int(you_id) + else: + msg = '「コヨーテする相手」(@で指定)と「コヨーテを言われた人の数字」を指定してください。例:`/coyoteGame coyote @you 99`' + await ctx.send(msg) + return you = ctx.guild.get_member(you_id) - self.coyoteGame.coyote(ctx.author, you, number) - await ctx.send(self.coyoteGame.description) + if you not in self.coyoteGames.members: + msg = 'ゲームに存在する相手を選び、「コヨーテ!」してください(ゲームしている相手にはいません)。' + await ctx.send(msg) + return + + self.coyoteGames.coyote(ctx.author, you, number) + await ctx.send(self.coyoteGames.description) @coyoteGame.command(aliases=['d', 'de', 'next'], description='ディール(次のターンを始める)') async def deal(self, ctx): - if self.coyoteGame is None or len(self.coyoteGame.members) <= 1: - msg = 'コヨーテを始めたい場合は、`coyoteGame start`または`coyoteGame startAndAllMessage`を入力してください。' + """ + コヨーテ中に実行できる行動。カードを引いて、プレイヤーに配ります + """ + if self.coyoteGame is None or len(self.coyoteGames.members) <= 1: + msg = 'コヨーテを始めてから実行できます。コヨーテを始めたい場合は、`/coyoteGame start`または`/coyoteGame startAndAllMessage`を入力してください。' await ctx.send(msg) return await self.dealAndMessage() - @coyoteGame.command(aliases=['desc'], description='状況説明') + @coyoteGame.command(aliases=['desc'], description='状況説明(ターン数,HP,山札の数,捨て札の数,捨て札)') async def description(self, ctx): - if self.coyoteGame is None or len(self.coyoteGame.members) <= 1: - msg = 'コヨーテを始めたい場合は、`coyoteGame start`または`coyoteGame startAndAllMessage`を入力してください。' + """ + 状況を説明します。 + - ターン数、生き残っている人の数、それぞれのHP + - 山札の数、捨て札の数、捨て札の中身 + """ + if self.coyoteGame is None or len(self.coyoteGames.members) <= 1: + msg = 'コヨーテを始めてから実行できます。コヨーテを始めたい場合は、`/coyoteGame start`または`/coyoteGame startAndAllMessage`を入力してください。' await ctx.send(msg) return - msg = f'ターン数:{self.coyoteGame.turn}\n' - msg += f'生き残っている人の数:{len(self.coyoteGame.members)}\n' - for member in self.coyoteGame.members: - msg += f'`{member.display_name}さん: (HP:{self.coyoteGame.members[member].HP})` ' - msg += f'山札の数:{len(self.coyoteGame.deck)}枚, ' - msg += f'捨て札:{len(self.coyoteGame.discards)}枚→' - discards_list = map(str, self.coyoteGame.discards) + msg = f'ターン数:{self.coyoteGames.turn}\n' + msg += f'生き残っている人の数:{len(self.coyoteGames.members)}\n' + for member in self.coyoteGames.members: + msg += f'`{member.display_name}さん: (HP:{self.coyoteGames.members[member].HP})` ' + msg += f'山札の数:{len(self.coyoteGames.deck)}枚, ' + msg += f'捨て札:{len(self.coyoteGames.discards)}枚→' + discards_list = map(str, self.coyoteGames.discards) discards = ','.join(discards_list) msg += discards await ctx.send(msg) - @coyoteGame.command(aliases=['da','desca'], description='状況説明(全て)') + @coyoteGame.command(aliases=['da','desca'], description='状況説明(全て/場のカードも分かる)') async def descriptionAll(self, ctx): - if self.coyoteGame is None or len(self.coyoteGame.members) <= 1: - msg = 'コヨーテを始めたい場合は、`coyoteGame start`または`coyoteGame startAndAllMessage`を入力してください。' + """ + 状況を全て説明します(場のカードもわかります)。 + - ターン数、生き残っている人の数、それぞれのHP + - 山札の数、山札の中身、捨て札の数、捨て札の中身、場のカード + """ + if self.coyoteGame is None or len(self.coyoteGames.members) <= 1: + msg = 'コヨーテを始めたい場合は、`/coyoteGame start`または`/coyoteGame startAndAllMessage`を入力してください。' await ctx.send(msg) return - msg = f'ターン数:{self.coyoteGame.turn}\n' - msg += f'生き残っている人の数:{len(self.coyoteGame.members)}\n' - for member in self.coyoteGame.members: - msg += f'`{member.display_name}さん: (HP:{self.coyoteGame.members[member].HP})` ' - msg += f'山札の数:{len(self.coyoteGame.deck)}枚, ' - deck_list = map(str, self.coyoteGame.deck) + msg = f'ターン数:{self.coyoteGames.turn}\n' + msg += f'生き残っている人の数:{len(self.coyoteGames.members)}\n' + for member in self.coyoteGames.members: + msg += f'`{member.display_name}さん: (HP:{self.coyoteGames.members[member].HP})` ' + msg += f'山札の数:{len(self.coyoteGames.deck)}枚, ' + deck_list = map(str, self.coyoteGames.deck) deck = ','.join(deck_list) msg += deck + '\n' - msg += f'捨て札:{len(self.coyoteGame.discards)}枚→' - discards_list = map(str, self.coyoteGame.discards) + msg += f'捨て札:{len(self.coyoteGames.discards)}枚→' + discards_list = map(str, self.coyoteGames.discards) discards = ','.join(discards_list) msg += discards - msg += f'場のカード:{len(self.coyoteGame.hands)}枚→' - hands_list = map(str, self.coyoteGame.hands) + msg += f'場のカード:{len(self.coyoteGames.hands)}枚→' + hands_list = map(str, self.coyoteGames.hands) hands = ','.join(hands_list) msg += f'||{hands}||' await ctx.send(msg) @@ -271,15 +345,15 @@ async def startCoyote(self, ctx): msg = f'コヨーテを楽しむには2人以上のメンバーが必要です(現在、{make_team.mem_len}人しかいません)' await ctx.send(msg) return - self.coyoteGame.set(make_team.vc_members) - self.coyoteGame.shuffle() + self.coyoteGames.set(make_team.vc_members) + self.coyoteGames.shuffle() async def dealAndMessage(self): - self.coyoteGame.deal() + self.coyoteGames.deal() dm_msg_all = '' - for player in self.coyoteGame.members: - dm_msg_all += f'{player.display_name}さん: {self.coyoteGame.members[player].card}\n' - for player in self.coyoteGame.members: + for player in self.coyoteGames.members: + dm_msg_all += f'{player.display_name}さん: {self.coyoteGames.members[player].card}\n' + for player in self.coyoteGames.members: dm = await player.create_dm() rpl_msg_del = f'{player.display_name}さん:.+\n' dm_msg = re.sub(rpl_msg_del, '', dm_msg_all) @@ -311,7 +385,9 @@ async def allMessage(self, ctx): '使ったカードを捨て札にして、次の回を始めます(**今回負けた人から開始**します)。\n'\ '次の回を始めるには、`/coyoteGame deal`をDiscordに書き込んでください。\n'\ '負けたプレイヤーがその回を最後に**ゲームから脱落した場合、その回の勝者から**次の回を始めます。\n'\ - 'ライフが0になったプレイヤーはゲームから脱落します。最後まで生き残ったプレイヤーが勝利です。' + 'ライフが0になったプレイヤーはゲームから脱落します。最後まで生き残ったプレイヤーが勝利です。\n'\ + 'なお、コヨーテは絶賛販売中です(1,800円くらい)。気に入った方はぜひ買って遊んでみてください(このBotは許可を得て作成したものではありません)。販売:合同会社ニューゲームズオーダー, 作者:Spartaco Albertarelli, 画:TANSANFABRIK\n'\ + 'サイト: ' await ctx.send(msg3) @@ -328,7 +404,9 @@ async def littleMessage(self, ctx): '**誰かが「コヨーテ!」と宣言するまで**、時計回りで順々に交代しながら宣言する数字を上げていきます\n'\ '次の回を始めるには、`/coyoteGame deal`をDiscordに書き込んでください(**今回負けた人から開始**します)。\n'\ '負けたプレイヤーがその回を最後に**ゲームから脱落した場合、その回の勝者から**次の回を始めます。\n'\ - 'ライフが0になったプレイヤーはゲームから脱落します。最後まで生き残ったプレイヤーが勝利です。' + 'ライフが0になったプレイヤーはゲームから脱落します。最後まで生き残ったプレイヤーが勝利です。\n'\ + 'なお、コヨーテは絶賛販売中です(1,800円くらい)。気に入った方はぜひ買って遊んでみてください(このBotは許可を得て作成したものではありません)。販売:合同会社ニューゲームズオーダー, 作者:Spartaco Albertarelli, 画:TANSANFABRIK\n'\ + 'サイト: ' await ctx.send(msg) @wordWolf.error diff --git a/cogs/modules/coyote.py b/cogs/modules/coyote.py index 1e687b0..b0a5bf9 100644 --- a/cogs/modules/coyote.py +++ b/cogs/modules/coyote.py @@ -1,5 +1,6 @@ import random import discord +import re from logging import getLogger logger = getLogger(__name__) @@ -15,13 +16,12 @@ def setCard(self, card: str): self.card = card def damage(self, number: int): - self.HP = self.HP -number + self.HP = self.HP - number if self.HP == 0: self.isDead = True class Coyote: - # DEFAULT_DECK = [20, 15, 15, 10, 10, 10, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, '0(Night)', -5, -5, -10, '*2(Chief)', 'Max->0(Fox)', '?(Cave)'] - DEFAULT_DECK = [20,'Max->0(Fox)','?(Cave)','?(Cave)'] + DEFAULT_DECK = [20, 15, 15, 10, 10, 10, 5, 5, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, '0(Night)', -5, -5, -10, '*2(Chief)', 'Max->0(Fox)', '?(Cave)'] def __init__(self): self.members = {} @@ -33,15 +33,35 @@ def __init__(self): self.description = '' def set(self, members): + self.members = {} + self.body = [] + self.deck = self.DEFAULT_DECK + self.hands = [] + self.discards = [] + self.turn = 0 + self.description = '' for member in members: coyoteMember = CoyoteMember() self.members[member] = coyoteMember + def setDeck(self, deck:str): + self.deck = [] + deck = deck.replace('"','').replace("'","").replace(' ','').replace(' ','') + card_list = deck.split(',') + + for card in card_list: + if self.is_num(card): + self.deck.append(int(card)) + else: + self.deck.append(str(card)) + def shuffle(self): self.deck.extend(self.discards) self.discards = [] random.shuffle(self.deck) - self.description += 'シャッフルしました。\n' + message = 'シャッフルしました。\n' + self.description += message + logger.info(message) def deal(self): self.turn = self.turn + 1 @@ -53,6 +73,9 @@ def deal(self): self.members[member].setCard(card) self.hands.append(card) if len(self.deck) == 0: + message = 'カードがなくなったので、' + self.description += message + logger.info(message) self.shuffle() def coyote(self, me: discord.Member, you: discord.Member, number): @@ -62,23 +85,33 @@ def coyote(self, me: discord.Member, you: discord.Member, number): # コヨーテの結果の判定 if number > coyotes: self.members[you].damage(1) - self.description += f'{number} > {coyotes} → 「コヨーテ!」の勝ち({me.display_name}が正しい!)\n' - self.description += f'{you.display_name}に1点ダメージ。' + message = f'{number} > {coyotes} → 「コヨーテ!」の勝ち({me.display_name}が正しい!)\n'\ + f'{you.display_name}に1点ダメージ。' + self.description += message + logger.info(message) if self.members[you].isDead: - self.description += f'{you.display_name}は死にました。\n' + message = f'{you.display_name}は死にました。\n' + self.description += message + logger.info(message) self.body.append(self.members.pop(you)) else: self.members[me].damage(1) - self.description += f'{number} <= {coyotes} → 「コヨーテ!」の負け({you.display_name}が正しい!)\n' - self.description += f'{me.display_name}に1点ダメージ。' + message = f'{number} <= {coyotes} → 「コヨーテ!」の負け({you.display_name}が正しい!)\n'\ + f'{me.display_name}に1点ダメージ。' + self.description += message + logger.info(message) if self.members[me].isDead: - self.description += f'{me.display_name}は死にました。\n' + message = f'{me.display_name}は死にました。\n' + self.description += message + logger.info(message) self.body.append(self.members.pop(me)) # 一人になったら、勝利 if len(self.members) == 1: for member in self.members: - self.description += f'{member.display_name}の勝ちです! おめでとうございます!!' + message = f'{member.display_name}の勝ちです! おめでとうございます!!' + self.description += message + logger.info(message) else: self.description += '現在の状況:' for member in self.members: @@ -92,46 +125,94 @@ def calc(self): shuffle_flg = False # Caveカードの効果 - cave_hands = [i for i in special_hands if ('Cave' in str(i))] + cave_hands = [i for i in special_hands if ('CAVE' in str(i).upper())] + cave_count = 0 for card in cave_hands: while(True): self.discards.append(card) - additional_card = self.deck.pop() - self.hands.append(additional_card) - self.description += f'{card}の効果で、1枚山札から引いた(値は{additional_card})。\n' - - # 引いたもので再計算 - normal_hands = [i for i in self.hands if self.is_num(i)] - special_hands = [i for i in self.hands if (not self.is_num(i) and not 'Cave' in str(i))] - if len(self.deck) == 0: + try: + additional_card = self.deck.pop() + message = f'{card}の効果で、1枚山札から引いた(値は{additional_card})。\n' + self.description += message + logger.info(message) + except IndexError: + message = 'カードがなくなったので、' + self.description += message + logger.info(message) self.shuffle() - if not 'Cave' in str(additional_card): break + deck_plus_discards_set = set(map(str, self.discards + self.deck)) + deck_plus_discards_set = {str.upper() for str in deck_plus_discards_set} + + if 'CAVE' in str(additional_card).upper(): + cave_count = cave_count + 1 + self.discards.append(additional_card) + message = f'Caveを引いたため、引き直し。\n' + self.description += message + logger.info(message) + if len(self.deck) == 0: + message = 'カードがなくなったので、' + self.description += message + logger.info(message) + self.shuffle() + + if cave_count > 2: + # 3回以上繰り返した場合は無視する + message = f'★Caveを3回以上引き続けたため、無視します。\n' + self.description += message + logger.info(message) + break + else: + if len(deck_plus_discards_set) == 1 and 'CAVE' in deck_plus_discards_set.pop(): + message = f'山札/捨て札にCaveしかない不正な状況のため、処理を終了。\n' + self.description += message + logger.info(message) + break + else: + continue + else: + self.hands.append(additional_card) + + # 引いたもので再計算 + normal_hands = [i for i in self.hands if self.is_num(i)] + special_hands = [i for i in self.hands if (not self.is_num(i) and not ('CAVE' in str(i).upper()))] + if len(self.deck) == 0: + message = 'カードがなくなったので、' + self.description += message + logger.info(message) + self.shuffle() + if not 'CAVE' in str(additional_card).upper(): + break # Chiefカードを集計 - chief_hands = [i for i in special_hands if ('Chief' in str(i))] - special_hands = [i for i in special_hands if not 'Chief' in str(i)] + chief_hands = [i for i in special_hands if ('CHIEF' in str(i).upper())] + special_hands = [i for i in special_hands if not 'CHIEF' in str(i).upper()] + fox_hands = [] for card in special_hands: card = str(card) # Nightカードの効果 - if 'Night'in card: + if 'NIGHT'in card.upper(): self.discards.append(card) normal_hands.append(0) shuffle_flg = True - self.description += f'{card}の効果で、計算終了後に山札/捨て札を混ぜてシャッフルする。\n' + message = f'{card}の効果で、計算終了後に山札/捨て札を混ぜてシャッフルする。\n' + self.description += message + logger.info(message) # Foxカードの効果 - if 'Fox' in card: + if 'FOX' in card.upper(): self.discards.append(card) num_hands = [i for i in normal_hands if self.is_num(i)] if len(num_hands) == 0: max_num = 0 else: max_num = max(num_hands) - normal_hands.append(-max_num) - self.description += f'{card}の効果で、この場で最大の値である{max_num}を0にした。\n' + fox_hands.append(-max_num) + message = f'{card}の効果で、この場で最大の値である{max_num}を0にした。\n' + self.description += message + logger.info(message) # 計算 coyotes = 0 @@ -143,13 +224,21 @@ def calc(self): self.description += f'+ {str(card)}' else: self.description += f'{str(card)}' + for fcard in fox_hands: + coyotes += fcard + if fcard >= 0: + self.description += f'+ {str(fcard)}' + else: + self.description += f'{str(fcard)}' self.description += '\n' # Chiefカードの効果 for card in chief_hands: self.discards.append(card) coyotes = coyotes * 2 - self.description += f'{card}の効果で、2倍にした。\n' + message = f'{card}の効果で、2倍にした。\n' + self.description += message + logger.info(message) if shuffle_flg: self.shuffle() @@ -157,8 +246,9 @@ def calc(self): return coyotes def is_num(self, num): - try: - int(num) - except: + num_check = re.compile(r'-?\d+') + m = re.fullmatch(num_check, str(num)) + if m is None: return False - return True \ No newline at end of file + else: + return True \ No newline at end of file From f11c60e9ffd783ec09c2d0216f9eeb17689c76c4 Mon Sep 17 00:00:00 2001 From: tetsuya-k <64536338+tetsuya-ki@users.noreply.github.com> Date: Tue, 26 Jan 2021 22:00:20 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=E3=82=B3=E3=83=A8=E3=83=BC=E3=83=86?= =?UTF-8?q?=E6=A9=9F=E8=83=BD=E3=81=AE=E3=83=90=E3=82=B0=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E3=81=A8=E8=AA=AC=E6=98=8E=E3=81=AE=E8=BF=BD=E5=8A=A0(?= =?UTF-8?q?=E6=AC=A1=E3=81=AE=E8=A1=8C=E5=8B=95=E3=81=8C=E5=88=86=E3=81=8B?= =?UTF-8?q?=E3=82=8A=E3=82=84=E3=81=99=E3=81=8F=E3=81=AA=E3=81=A3=E3=81=9F?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cogs/gamecog.py | 130 ++++++++++++++++++----------------------- cogs/modules/coyote.py | 34 ++++++++++- 2 files changed, 89 insertions(+), 75 deletions(-) diff --git a/cogs/gamecog.py b/cogs/gamecog.py index f32b69f..d5f8e0b 100644 --- a/cogs/gamecog.py +++ b/cogs/gamecog.py @@ -101,7 +101,7 @@ async def wordWolf(self, ctx, answer_minutes=None): await self.delayedMessage(ctx, netabare_msg, (answer_minutes * 60) - voting_time) # NGワードゲーム機能 - @commands.command(aliases=['ngword','ngw','ngwg', 'ngg'], description='NGワードゲーム機能(禁止された言葉を喋ってはいけないゲーム)') + @commands.command(aliases=['ngword','ngw','ngwg','ngg'], description='NGワードゲーム機能(禁止された言葉を喋ってはいけないゲーム)') async def ngWordGame(self, ctx, answer_minutes=None): """ コマンド実行者が参加しているボイスチャンネルでNGワードゲームを始めます(BOTからDMが来ますがびっくりしないでください) @@ -163,32 +163,31 @@ async def ngWordGame(self, ctx, answer_minutes=None): @commands.group(aliases=['co','cog','cy','cg'], description='コヨーテするコマンド(サブコマンド必須)') async def coyoteGame(self, ctx): """ - コヨーテするコマンド群です。このコマンドだけでは実行できません。半角スペースの後、続けて以下のサブコマンドを入力ください。 - - コヨーテを始めたい場合は、`start`または`startAndAllMessage`を入力してください(startは説明が短く、startAndAllMessageは全てを説明します)。 - - コヨーテ中に、「コヨーテ!」をしたい場合は、`coyote`を入力してください。 - - コヨーテ中に、次の回を始めたい場合は、`deal`を入力してください。 - - コヨーテ中に、現在の状況を確認したい場合は、`description`を入力してください。 + コヨーテするコマンド群です。このコマンドだけでは実行できません。**半角スペースの後、続けて以下のサブコマンドを入力**ください。 + - コヨーテを始めたい場合は、`/cy start`または`/cy startAndAllMessage`を入力してください(startは説明が短く、startAndAllMessageは全てを説明します)。 + - コヨーテ中に、「コヨーテ!」をしたい場合は、`/cy coyote`を入力してください。 + - コヨーテ中に、次の回を始めたい場合は、`/cy deal`を入力してください。 + - コヨーテ中に、現在の状況を確認したい場合は、`/cy description`を入力してください。 上級者向け機能 - - 説明を省略して、コヨーテを始める場合は、`startAndNoMessage`を入力してください。 - - コヨーテ中に、ネタバレありで現在の状況を確認したい場合は、`descriptionAll`を入力してください。 - - `setDeckAndStart`で自分でデッキを作成できます。詳しくは`/help coyoteGame setDeckAndStart`を入力してください。 + - 説明を省略して、コヨーテを始める場合は、`/cy startAndNoMessage`を入力してください。 + - コヨーテ中に、ネタバレありで現在の状況を確認したい場合は、`/cy descriptionAll`を入力してください。 + - `/cy setDeckAndStart`で自分でデッキを作成できます。詳しくは`/help coyoteGame setDeckAndStart`でヘルプを確認ください。 """ # サブコマンドが指定されていない場合、メッセージを送信する。 if ctx.invoked_subcommand is None: await ctx.send('このコマンドにはサブコマンドが必要です。') - - @coyoteGame.command(aliases=['s', 'st', 'ini', 'init'], description='コヨーテを始めるコマンド') + @coyoteGame.command(aliases=['s','st','ini','init'], description='コヨーテを始めるコマンド') async def start(self, ctx): """ コヨーテを始めるコマンド(説明が程よいバージョン) - コヨーテのルールが分かる程度に省略しています。 """ await self.startCoyote(ctx) - await self.littleMessage(ctx) - await self.dealAndMessage() + await self.coyoteLittleMessage(ctx) + await self.dealAndMessage(ctx) - @coyoteGame.command(aliases=['sa', 'ina', 'inia'], description='コヨーテを始めるコマンド(全説明)') + @coyoteGame.command(aliases=['sa','ina','inia'], description='コヨーテを始めるコマンド(全説明)') async def startAndAllMessage(self, ctx): """ コヨーテを始めるコマンド(説明が多いバージョン) @@ -196,19 +195,19 @@ async def startAndAllMessage(self, ctx): - コヨーテのルールが分かるように書いてありますが、一旦説明を見ながらゲームしてみると良いと思います。 """ await self.startCoyote(ctx) - await self.allMessage(ctx) - await self.dealAndMessage() + await self.coyoteAllMessage(ctx) + await self.dealAndMessage(ctx) - @coyoteGame.command(aliases=['sn', 'no', 'inn'], description='コヨーテを始めるコマンド(説明なし)') + @coyoteGame.command(aliases=['sn','no','inn'], description='コヨーテを始めるコマンド(説明なし)') async def startAndNoMessage(self, ctx): """ コヨーテを始めるコマンド(説明なし) - 上級者向けの機能です。ルールを説明されずとも把握している場合にのみ推奨します。 """ await self.startCoyote(ctx) - await self.dealAndMessage() + await self.dealAndMessage(ctx) - @coyoteGame.command(aliases=['sds','ss', 'set'], description='デッキを指定して、コヨーテを始めるコマンド(説明なし)') + @coyoteGame.command(aliases=['sds','ss','set'], description='デッキを指定して、コヨーテを始めるコマンド(説明なし)') async def setDeckAndStart(self, ctx, *, deck=None): """ デッキを指定してコヨーテを始めるコマンド(説明なし) @@ -231,9 +230,9 @@ async def setDeckAndStart(self, ctx, *, deck=None): self.coyoteGames.set(make_team.vc_members) self.coyoteGames.setDeck(deck) self.coyoteGames.shuffle() - await self.dealAndMessage() + await self.dealAndMessage(ctx) - @coyoteGame.command(aliases=['c', 'cy', 'done'], description='コヨーテ!(前プレイヤーの数字がコヨーテの合計数を超えたと思った場合のコマンド)') + @coyoteGame.command(aliases=['c','co','cy','done'], description='コヨーテ!(前プレイヤーの数字がコヨーテの合計数を超えたと思った場合のコマンド)') async def coyote(self, ctx, you_id=None, number=0): """ コヨーテ中に実行できる行動。「コヨーテ!」を行う @@ -251,11 +250,8 @@ async def coyote(self, ctx, you_id=None, number=0): msg = '「コヨーテを言われた人の数字」は「1以上の整数」(0もダメです)を指定してください。例:`/coyoteGame coyote @you 99`' await ctx.send(msg) return - if self.coyoteGames is None or len(self.coyoteGames.members) <= 1: - msg = 'コヨーテを始めてから実行できます。コヨーテを始めたい場合は、`/coyoteGame start`または`/coyoteGame startAndAllMessage`を入力してください。' - await ctx.send(msg) + if await self.coyoteStartCheckNG(ctx): return - # コヨーテ!した相手のメンバー情報を取得。取得できない場合はエラーを返す you_id = re.sub(r'[<@!>]', '', you_id) if you_id.isdecimal(): @@ -273,38 +269,25 @@ async def coyote(self, ctx, you_id=None, number=0): self.coyoteGames.coyote(ctx.author, you, number) await ctx.send(self.coyoteGames.description) - - @coyoteGame.command(aliases=['d', 'de', 'next'], description='ディール(次のターンを始める)') + @coyoteGame.command(aliases=['d','de','next'], description='ディール(次のターンを始める)') async def deal(self, ctx): """ コヨーテ中に実行できる行動。カードを引いて、プレイヤーに配ります """ - if self.coyoteGame is None or len(self.coyoteGames.members) <= 1: - msg = 'コヨーテを始めてから実行できます。コヨーテを始めたい場合は、`/coyoteGame start`または`/coyoteGame startAndAllMessage`を入力してください。' - await ctx.send(msg) + if await self.coyoteStartCheckNG(ctx): return - await self.dealAndMessage() + await self.dealAndMessage(ctx) - @coyoteGame.command(aliases=['desc'], description='状況説明(ターン数,HP,山札の数,捨て札の数,捨て札)') + @coyoteGame.command(aliases=['desc','setsumei'], description='状況説明(ターン数,HP,山札の数,捨て札の数,捨て札)') async def description(self, ctx): """ 状況を説明します。 - ターン数、生き残っている人の数、それぞれのHP - 山札の数、捨て札の数、捨て札の中身 """ - if self.coyoteGame is None or len(self.coyoteGames.members) <= 1: - msg = 'コヨーテを始めてから実行できます。コヨーテを始めたい場合は、`/coyoteGame start`または`/coyoteGame startAndAllMessage`を入力してください。' - await ctx.send(msg) + if await self.coyoteStartCheckNG(ctx, True): return - msg = f'ターン数:{self.coyoteGames.turn}\n' - msg += f'生き残っている人の数:{len(self.coyoteGames.members)}\n' - for member in self.coyoteGames.members: - msg += f'`{member.display_name}さん: (HP:{self.coyoteGames.members[member].HP})` ' - msg += f'山札の数:{len(self.coyoteGames.deck)}枚, ' - msg += f'捨て札:{len(self.coyoteGames.discards)}枚→' - discards_list = map(str, self.coyoteGames.discards) - discards = ','.join(discards_list) - msg += discards + msg = self.coyoteGames.create_description() await ctx.send(msg) @coyoteGame.command(aliases=['da','desca'], description='状況説明(全て/場のカードも分かる)') @@ -314,26 +297,9 @@ async def descriptionAll(self, ctx): - ターン数、生き残っている人の数、それぞれのHP - 山札の数、山札の中身、捨て札の数、捨て札の中身、場のカード """ - if self.coyoteGame is None or len(self.coyoteGames.members) <= 1: - msg = 'コヨーテを始めたい場合は、`/coyoteGame start`または`/coyoteGame startAndAllMessage`を入力してください。' - await ctx.send(msg) + if await self.coyoteStartCheckNG(ctx, True): return - msg = f'ターン数:{self.coyoteGames.turn}\n' - msg += f'生き残っている人の数:{len(self.coyoteGames.members)}\n' - for member in self.coyoteGames.members: - msg += f'`{member.display_name}さん: (HP:{self.coyoteGames.members[member].HP})` ' - msg += f'山札の数:{len(self.coyoteGames.deck)}枚, ' - deck_list = map(str, self.coyoteGames.deck) - deck = ','.join(deck_list) - msg += deck + '\n' - msg += f'捨て札:{len(self.coyoteGames.discards)}枚→' - discards_list = map(str, self.coyoteGames.discards) - discards = ','.join(discards_list) - msg += discards - msg += f'場のカード:{len(self.coyoteGames.hands)}枚→' - hands_list = map(str, self.coyoteGames.hands) - hands = ','.join(hands_list) - msg += f'||{hands}||' + msg = self.coyoteGames.create_description(True) await ctx.send(msg) async def startCoyote(self, ctx): @@ -348,18 +314,22 @@ async def startCoyote(self, ctx): self.coyoteGames.set(make_team.vc_members) self.coyoteGames.shuffle() - async def dealAndMessage(self): + async def dealAndMessage(self, ctx): self.coyoteGames.deal() dm_msg_all = '' + # 全員分のメッセージを作成 for player in self.coyoteGames.members: dm_msg_all += f'{player.display_name}さん: {self.coyoteGames.members[player].card}\n' + # DM用メッセージを作成(送付する相手の名前が記載された行を削除) for player in self.coyoteGames.members: dm = await player.create_dm() rpl_msg_del = f'{player.display_name}さん:.+\n' dm_msg = re.sub(rpl_msg_del, '', dm_msg_all) await dm.send(f'{player.mention}さん 他の人のコヨーテカードはこちらです!\n{dm_msg}') + await ctx.send(f'カードを配りました。DMをご確認ください。{self.coyoteGames.description}') + self.coyoteGames.description = '' - async def allMessage(self, ctx): + async def coyoteAllMessage(self, ctx): msg1 = 'コヨーテ:ゲーム目的\n**自分以外のプレイヤーのカード(DMに送られる)を見て、少なくとも何匹のコヨーテがこの場にいるかを推理します。**\n'\ 'もしも宣言した数だけ居なかったら......コヨーテに命を奪われてしまいます! インディアン、嘘つかない。コヨーテだって、嘘が大キライなのです。\n'\ 'ライフは一人3ポイントあります。3回殺されたらゲームから退場します。\n'\ @@ -367,7 +337,7 @@ async def allMessage(self, ctx): await ctx.send(msg1) msg2 = '最初のプレイヤーはDMに送られる他の人のカードを見て、この場に「少なくとも」何匹のコヨーテがいるか推理し、コヨーテの数を宣言します。\n'\ - '★宣言する数に上限はありませんが、1以上の整数である必要があります(つまり、0や負数はダメです)\n'\ + '★宣言する数に上限はありませんが、**1以上の整数である必要**があります(つまり、0や負数はダメです)\n'\ 'ゲームは時計回りに進行(ボイスチャンネルを下に進むこと)します。\n'\ '次のプレイヤーは次のふたつのうち、「どちらか」の行動をとってください。\n'\ '1: 数字を上げる → 前プレイヤーの宣言した数が実際にこの場にいるコヨーテの数**以下(オーバー)していない**と思う場合、**前プレイヤーより大きな数**を宣言します。\n'\ @@ -379,8 +349,8 @@ async def allMessage(self, ctx): msg3 = '「コヨーテ!」と宣言された場合、直前のプレイヤーが宣言した数が当たっていたかどうか判定します。\n'\ '★前述の通り、Botが計算します(例:`/coyoteGame coyote @you 99`のように書き込んでくださいね)\n'\ 'まず基本カードを集計したあと、特殊カード分を計算します。\n'\ - '「コヨーテ!」を宣言された数がコヨーテの合計数をオーバーしていた場合、「コヨーテ!」を宣言した人の勝ち(数値を宣言した人の負け)\n'\ - '「コヨーテ!」を宣言された数がコヨーテの合計数以下の場合、数値を宣言した人の勝ち(「コヨーテ!」を宣言した人の負け)\n'\ + '「コヨーテ!」を**宣言された数がコヨーテの合計数をオーバー**していた場合、**「コヨーテ!」を宣言した人**の勝ち(数値を宣言した人の負け)\n'\ + '「コヨーテ!」を**宣言された数がコヨーテの合計数以下**の場合、**数値を宣言**した人の勝ち(「コヨーテ!」を宣言した人の負け)\n'\ '負けたプレイヤーはダメージを受けます(ライフが減ります)。\n'\ '使ったカードを捨て札にして、次の回を始めます(**今回負けた人から開始**します)。\n'\ '次の回を始めるには、`/coyoteGame deal`をDiscordに書き込んでください。\n'\ @@ -390,18 +360,17 @@ async def allMessage(self, ctx): 'サイト: ' await ctx.send(msg3) - - async def littleMessage(self, ctx): + async def coyoteLittleMessage(self, ctx): msg = 'コヨーテ:ゲーム目的\n**自分以外のプレイヤーのカード(DMに送られる)を見て、少なくとも何匹のコヨーテがこの場にいるかを推理します。**\n'\ 'もしも宣言した数だけ居なかったら......コヨーテに命を奪われてしまいます! インディアン、嘘つかない。コヨーテだって、嘘が大キライなのです。\n'\ 'ライフは一人3ポイントあります。3回殺されたらゲームから退場します。\n'\ - '最初のプレイヤー:「少なくとも」何匹のコヨーテがいるか推理し、コヨーテの数を宣言(1以上の整数)します。\n'\ + '最初のプレイヤー:「少なくとも」何匹のコヨーテがいるか推理し、コヨーテの数を宣言(**1以上の整数**)します。\n'\ 'ゲームは時計回りに進行(ボイスチャンネルを下に進むこと)\n'\ '次のプレイヤー:は次のふたつのうち、「どちらか」の行動をとってください。\n'\ '1: 数字を上げる → 前プレイヤーの宣言した数が実際にこの場にいるコヨーテの数**以下(オーバー)していない**と思う場合、**前プレイヤーより大きな数**を宣言します。\n'\ '2: 「コヨーテ!」→ 前プレイヤーの宣言を疑います。つまり、前プレイヤーの宣言した数が実際にこの場にいるコヨーテの数よりも**大きい(オーバーした)**と思う場合、**「コヨーテ!」**と宣言します\n'\ '2の場合、例:`/coyoteGame coyote @you 99`のように**Discordに書き込んで**ください!(Botが結果を判定します!)\n'\ - '**誰かが「コヨーテ!」と宣言するまで**、時計回りで順々に交代しながら宣言する数字を上げていきます\n'\ + '**誰かが「コヨーテ!」と宣言するまで**、時計回り(ボイスチャンネルを下に進む)で順々に交代しながら宣言する**数字を上げて**いきます\n'\ '次の回を始めるには、`/coyoteGame deal`をDiscordに書き込んでください(**今回負けた人から開始**します)。\n'\ '負けたプレイヤーがその回を最後に**ゲームから脱落した場合、その回の勝者から**次の回を始めます。\n'\ 'ライフが0になったプレイヤーはゲームから脱落します。最後まで生き残ったプレイヤーが勝利です。\n'\ @@ -409,6 +378,17 @@ async def littleMessage(self, ctx): 'サイト: ' await ctx.send(msg) + async def coyoteStartCheckNG(self, ctx, desc=False): + if self.coyoteGames is None or (len(self.coyoteGames.members) <= 1 and not desc): + msg = 'コヨーテを始めてから実行できます。コヨーテを始めたい場合は、`/coyoteGame start`または`/coyoteGame startAndAllMessage`を入力してください。' + await ctx.send(msg) + return True + # 終わった後に説明が見たい場合は許す + elif len(self.coyoteGames.members) == 1 and desc: + return False + else: + return False + @wordWolf.error async def wordWolf_error(self, ctx, error): if isinstance(error, commands.CommandError): @@ -421,6 +401,12 @@ async def ngWordGame_error(self, ctx, error): logger.error(error) await ctx.send(error) + @coyoteGame.error + async def coyoteGame_error(self, ctx, error): + if isinstance(error, commands.CommandError): + logger.error(error) + await ctx.send(error) + async def delayedMessage(self, ctx, messsage, delayed_seconds=None): await asyncio.sleep(delayed_seconds) await ctx.send(messsage) diff --git a/cogs/modules/coyote.py b/cogs/modules/coyote.py index b0a5bf9..75fec69 100644 --- a/cogs/modules/coyote.py +++ b/cogs/modules/coyote.py @@ -26,7 +26,7 @@ class Coyote: def __init__(self): self.members = {} self.body = [] - self.deck = self.DEFAULT_DECK + self.deck = self.DEFAULT_DECK.copy() self.hands = [] self.discards = [] self.turn = 0 @@ -35,7 +35,7 @@ def __init__(self): def set(self, members): self.members = {} self.body = [] - self.deck = self.DEFAULT_DECK + self.deck = self.DEFAULT_DECK.copy() self.hands = [] self.discards = [] self.turn = 0 @@ -52,6 +52,8 @@ def setDeck(self, deck:str): for card in card_list: if self.is_num(card): self.deck.append(int(card)) + elif card == '': + continue else: self.deck.append(str(card)) @@ -116,6 +118,7 @@ def coyote(self, me: discord.Member, you: discord.Member, number): self.description += '現在の状況:' for member in self.members: self.description += f'{member.display_name}さん(HP:{self.members[member].HP}) ' + self.description += '\n`/coyoteGame deal`で次のターンを開始します。' def calc(self): # [変数名 for 変数名 in 元のリスト if 条件式] @@ -251,4 +254,29 @@ def is_num(self, num): if m is None: return False else: - return True \ No newline at end of file + return True + + def create_description(self, all_flg=False): + msg = f'ターン数:{self.turn}\n' + msg += f'生き残っている人の数:{len(self.members)}\n' + for member in self.members: + msg += f'`{member.display_name}さん → HP:{self.members[member].HP}`\n' + if all_flg: + msg += f'山札の数:{len(self.deck)}枚 → ' + deck_list = map(str, self.deck) + deck = ','.join(deck_list) + msg += deck + '\n' + else: + msg += f'山札の数:{len(self.deck)}枚, ' + msg += f'捨て札:{len(self.discards)}枚 → ' + discards_list = map(str, self.discards) + discards = ','.join(discards_list) + msg += discards + + if all_flg: + msg += f'\n場のカード:{len(self.hands)}枚 → ' + hands_list = map(str, self.hands) + hands = ','.join(hands_list) + msg += f'||{hands}||' + + return msg \ No newline at end of file From 23905b831046e214057dcb34efb5e861703bafb6 Mon Sep 17 00:00:00 2001 From: tetsuya-k <64536338+tetsuya-ki@users.noreply.github.com> Date: Tue, 26 Jan 2021 22:20:40 +0900 Subject: [PATCH 5/6] =?UTF-8?q?readme.md=E3=81=AB=E3=82=B3=E3=83=A8?= =?UTF-8?q?=E3=83=BC=E3=83=86=E6=A9=9F=E8=83=BD=E3=81=AE=E8=AA=AC=E6=98=8E?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- readme.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/readme.md b/readme.md index 3a49460..0591441 100644 --- a/readme.md +++ b/readme.md @@ -129,6 +129,26 @@ Discord用のBot。discord.pyのBot Commands Frameworkを使用して実装。 - BotからくるDMの様子 ![image(ngWordGame-2)](https://github.com/tetsuya-ki/images/blob/main/discord-bot-heroku/ngwordgame-2.png?raw=True) +`/coyoteGame` コヨーテを行うコマンド + +- コヨーテ開始(説明が長いですがやれば分かります!) +![image(coyoteGame_start)](https://github.com/tetsuya-ki/images/blob/main/discord-bot-heroku/coyoteGame_start.png?raw=True) + +- コヨーテ開始やディール時のDMの様子 +![image(coyoteGame_DM)](https://github.com/tetsuya-ki/images/blob/main/discord-bot-heroku/coyoteGame_DM.png?raw=True) + +- コヨーテのディール(カードを配る) +![image(coyoteGame_deal)](https://github.com/tetsuya-ki/images/blob/main/discord-bot-heroku/coyoteGame_deal.png?raw=True) + +- コヨーテ開始(自分でデッキを設定) +![image(coyoteGame_setDeckAndStart)](https://github.com/tetsuya-ki/images/blob/main/discord-bot-heroku/coyoteGame_setDeckAndStart.png?raw=True) + +- コヨーテの状況説明 +![image(coyoteGame_description)](https://github.com/tetsuya-ki/images/blob/main/discord-bot-heroku/coyoteGame_description.png?raw=True) + +- コヨーテの状況説明(ネタバレ有) +![image(coyoteGame_descriptionAll)](https://github.com/tetsuya-ki/images/blob/main/discord-bot-heroku/coyoteGame_descriptionAll.png?raw=True) + ### メッセージイベント用(onmessagecog.pyで実装) - コマンドを使って実行する訳ではない機能 From 20b851d7aece64dfa260637bf80825d7f7bbc865 Mon Sep 17 00:00:00 2001 From: tetsuya-ki <64536338+tetsuya-ki@users.noreply.github.com> Date: Tue, 26 Jan 2021 22:29:19 +0900 Subject: [PATCH 6/6] Update gamecog.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coyoteモジュールを二重でインポートしていた点を修正 --- cogs/gamecog.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cogs/gamecog.py b/cogs/gamecog.py index d5f8e0b..cfb895e 100644 --- a/cogs/gamecog.py +++ b/cogs/gamecog.py @@ -1,4 +1,3 @@ -from cogs.modules.coyote import Coyote from discord.ext import commands # Bot Commands Frameworkのインポート from .modules.grouping import MakeTeam from .modules.readjson import ReadJson @@ -412,4 +411,4 @@ async def delayedMessage(self, ctx, messsage, delayed_seconds=None): await ctx.send(messsage) def setup(bot): - bot.add_cog(GameCog(bot)) # GameCogにBotを渡してインスタンス化し、Botにコグとして登録する \ No newline at end of file + bot.add_cog(GameCog(bot)) # GameCogにBotを渡してインスタンス化し、Botにコグとして登録する