4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

pythonで作るDiscordでHit&Blowゲームbot

Last updated at Posted at 2019-09-08

##開発環境

  • Windows10
  • discord.py 1.2.3
  • Python3.7.4

#作成したHit&Blowゲームのルール

  1. 4桁の重複していない数字をCPUが隠し持ち、桁一致を表すHitと数値のみ一致を表すBlowの数をヒントに設定された数字を当てる
  2. 対戦中にゲームを始めることはできない。CPUといえど2窓行為はしないのだ
  3. ニックネーム機能によるなりすまし代打が可能

参考:@Smoothie1023さん

#コード

コード全文
main.py
import discord 
import asyncio
import random
import re

client = discord.Client()
start = time = name = correct = 0

# 起動時に動作する処理。今回のbotには無関係
@client.event
async def on_ready():
	CHANNEL_ID = # 起動確認に使っても良いチャンネルのID
	channel = client.get_channel(CHANNEL_ID)
	await channel.send('ハローワールド!')
	print('Logged in as')
	print(client.user.name)
	print(client.user.id)
	print('------')

# なるべくニックネームで呼ぶようにする処理
def callnick(message):
	nick = message.author.nick
	if nick is None:
		return message.author.name
	else:
		return nick

# 今回のbotの本体
@client.event
async def on_message(message):
	if message.author != client.user:
		global start,name,time,correct,answer,ans,hit,blow,t
		if message.content == "/hb" and start == 0: # ゲーム開始
			start = time = 1
			name = callnick(message)
			await message.channel.send("Let's enjoy Hit & Blow!")
			print(f"{name}がゲームを開始しました。")
			correct = random.sample(list(range(10)),4) # 正解決め
			print(f"correct")
			await message.channel.send(f"{name}さん4桁の数字を入力してください。")

		if re.match(r'[0-9]{4}',message.content) and name == callnick(message):
			time += 1
			answer = message.content[:]
			ans = list(map(int, answer))
			hit = blow = 0
			for num in range(len(ans)):
				t = "x"
				try:
					t = correct.index(ans[num])
				except ValueError:
					pass
				if t != "x":
					if t == num:
						hit += 1
					else:
						blow += 1
			print(f"{ans} {hit} Hit / {blow} Blow {correct}")
			await message.channel.send(f"{hit} Hit / {blow} Blow")
			if hit == 4: # クリア時の処理
				start = 2

		if start == 2:
			await message.channel.send(f"{correct} : Correct! 挑戦回数:{time-1}")
			print("ゲーム終了")
			start = time = name = correct = 0

		if message.content == "/reset" and start > 0 and callnick(message) == name: # エラーした場合のリセット
				await message.channel.send(f"ゲームをリセットします。正解:{correct}")
				print("ゲームがリセットされました。")
				start,time,name= 0,0,""

client.run("TOKEN")

#解説

###ニックネーム

def callnick(message):
	nick = message.author.nick
	if nick is None:
		return message.author.name
	else:
		return nick

ニックネームを持たない発言者にまでmessage.author.nickのまま返事をしてしまうと、無い物は文字列として取得できずNoneになり返答文が崩壊するため返事を行わないエラーを起こす。
そのため、ニックネームが無い発言者の場合は代わりに本名を返す処理を行った。
面倒なものは関数(def)化する。

###正解決め

correct = random.sample(list(range(10)),4) # 正解決め

重複なしの4桁の数字にしなければゲームが成立しないため、sampleによる非復元抽出でリストから取り出す。
0-9の10文字からなるリストの作成にrangeを使用。
桁数の指定4を変数にすれば、ゲーム開始時に任意の桁数にする拡張を行えそう。

###解答受付
正規表現により、4桁の数字であれば0000から9999まで解答として認識する。
同じ数字の重複を弾く処理はカット。ゲームプレイヤーの良心に委ねる。
誤記例if message.content == "[0-9]{4}":

###なりすまし代打可能

if re.match(r'[0-9]{4}',message.content) and name == callnick(message):

and条件で追加したname == callnick(message)での判定により、ゲームを開始した者と同じニックネームの者の解答を拾う。

#その他忘備録

トライ&エラー中は鬱陶しいので5行目だけでもコメントアウトした方が良さそう
@client.event
async def on_ready():
	CHANNEL_ID = # 起動確認に使っても良いチャンネルのID
	channel = client.get_channel(CHANNEL_ID)
	await channel.send('ハローワールド!')
インデントの数を間違えると大変な事になる部分
if t != "x":
	if t == num:
		hit += 1
	else:
		blow += 1

本体であるif message.content == "/hb" and start == 0: # ゲーム開始以下も@client.eventの外に出して処理すれば、他の機能を持たせたbotにHit&Blowの機能を追加することも可能なはず。
実証が済んだら更新する。

4
2
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
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?