初めに
DiscordBotの引継ぎ候補という圧力がサークル内に蔓延している。
Pythonでプログラムを書くのにもだいぶ慣れてきたので、せっかくだし作ることにした。
開発記録・リファレンスとして、記事を投稿していく予定。
!st (種族値/実数値表示)
!st ポケモン名[*] [レベル]
レベルを指定しなかった場合、Lv50の実数値を返します。
レベルを指定した場合、入力したレベルでの実数値を返します。
レベルに-1に指定した場合、そのポケモンの種族値を返します。
名前の後ろに半角の * をつけると、名前の部分一致で検索できます。
使用例
種族値を実数値に変換するプログラム
3値(種族値・個体値・努力値)に関しては、以下の記事を参照。
実数値の表を作成するには?
まずは、変数の定義から説明する。
bst…あるポケモンの種族値リスト(Base Status)
ex. ライチュウの場合
bst=[H,A,B,C,D,S]=[60, 90, 55, 90, 80, 110]
Hの実数値は、bst_1=H=100と表現する。
この種族値リストから、以下の表を作成したい。
ast…あるポケモンの実数値(Actually Status)
i\j | H | A | B | C | D | S |
---|---|---|---|---|---|---|
最高 | 167 | 156 | 117 | 156 | 145 | 178 |
準 | 167 | 142 | 107 | 142 | 132 | 162 |
無振 | 135 | 110 | 75 | 110 | 100 | 130 |
最低 | 120 | 85 | 54 | 85 | 76 | 103 |
この表は、Pythonの辞書の形式で表すと、以下のようになる。
astdict={ '最高': [167, 156, 117, 156, 145, 178], ' 準': [167, 142, 107, 142, 132, 162], '無振': [135, 110, 75, 110, 100, 130], '最低': [120, 85, 54, 85, 76, 103] }
astdictは4×6の行列になっている。この辞書が作れればok
astdict['最高']=[167, 156, 117, 156, 145, 178]
の行を例に挙げて説明する。
これは1行目の実数値リストなので、ast_1と表現する。
(Pythonでは、配列aの1番目の要素をa[0]と表現するが、ややこしいのでa_1=a[0]ということにする。一般に、第i行=ast_i)
よって、ast_1=[167, 156, 117, 156, 145, 178]
ast_1のj列の要素は、ast_1jと表現する。
つまり、ast_11=167
ようやく、実数値 ast_ijを計算する準備が整った。
第i行を計算する
種族値と実数値の関係式は以下の通り。
計算式
最大HP
実数値=(種族値×2+個体値+努力値÷4)×レベル÷100+レベル+10
こうげき・ぼうぎょ・とくこう・とくぼう・すばやさ
実数値={(種族値×2+個体値+努力値÷4)×レベル÷100+5}×せいかく補正
(ただし、小数はすべて切り捨て)
この式から、j=1とj≠1のときでast_ijの計算式が異なることがわかる。
第i行のast_iを計算するために必要な変数は、
- iに依存しないもの
bst_j = 種族値のj列のステータス
(j=1,2,3,4,5,6 に対し、H,A,B,C,D,Sが対応する)
lv=レベル(=デフォルト:50)
- iに依存するもの
iv_ij = i行j列のステータスの個体値
ev_ij = i行j列のステータスの努力値
ncor_ij = i行j列のステータスの性格補正
iに依存する変数はまとめて、b2a_iと定義する。(bst_j to ast_ij)
b2a_i=[iv_i,ev_i,ncor_i]
そして、lambda式で関数fを次のように定義する
(intで小数から整数に型変換して切り捨てを行っている)
f=lambda bst_j,iv,ev,lv:int(int((int(bst_j*2+iv+ev/4)*lv/100+5
このfを使って、ast_ijは次のように計算できる
ast_j=f(bst[j],iv,ev,lv)+lv+5
(j=1)
ast_j=int((f(bst[j],iv,ev,lv))*ncor[j])
(j≠1)
以上をPythonの関数として記述するとこうなる。
#ある同じ値orgをjに関して繰り返すリストを定義(original copied list) cplist=lambda org:[org,org,org,org,org,org] def bst2ast(bst,lv,iv,ev,ncor): ast_i=[] #実数値を格納するリスト for j in range(6): f=lambda st,iv,ev,lv:int(int(st*2+iv+ev/4)*lv/100)+5 if j==0: ast_j=f(bst[j],iv[j],ev[j],lv)+lv+5 else: ast_j=int((f(bst[j],iv[j],ev[j],lv))*ncor[j]) ast_i.append(ast_j) return ast_i #ライチュウの種族値リスト bst=[60,90,55,90,80,110] #デフォルトのLv lv=50 #個体値リスト iv_1=cplist(31) #努力値リスト ev_1=cplist(252) #性格補正リスト ncor_1=cplist(1.1) b2a_1=[iv_1,ev_1,ncor_1] ast_1=bst2ast(bst,lv,*b2a_1) print(ast_1) #出力:[167, 156, 117, 156, 145, 178]
これで、Lv50のときの各ステータスの最大値が求められた。
同じように、第i行目に関してast_iを計算するには、上の関数bst2astをiについてループすればよい。
def bst2astdict(bst,lv): #lv=-1とした場合、種族値をそのまま返す if lv==-1: return {"種族値":bst} else: #個体値・努力値・性格補正の行列 b2a=[ [cplist(31),cplist(252),cplist(1.1)], [cplist(31),cplist(252),cplist(1)], [cplist(31),cplist(0),cplist(1)], [cplist(0),cplist(0),cplist(0.9)] ] #結果を格納するリスト astlist=[] for i in range(4): ast_i=bst2ast(bst,lv,*b2a[i]) astlist.append(ast_i) keys=["最高"," 準","無振","最低"] astdict=dict(zip(keys,astlist)) return astdict bst=[60,90,55,90,80,110] #ライチュウの種族値リスト lv=50 #デフォルトのLv astdict=bst2astdict(bst,lv) print(astdict) """出力 {'最高': [167, 156, 117, 156, 145, 178], ' 準': [167, 142, 107, 142, 132, 162], '無振': [135, 110, 75, 110, 100, 130], '最低': [120, 85, 54, 85, 76, 103]} """
あとはこれを出力すればOK!
#リスト[167, 156, 117, 156, 145, 178]を #文字列 167-156-117-156-145-178 に変換する関数 l2s=lambda s,l:s.join(map(str,l)) msg="" for item in astdict.items(): msg+=f"> {item[0]}: {l2s('-',item[1])}\n" print(msg)
> 最高: 167-156-117-156-145-178
> 準: 167-142-107-142-132-162
> 無振: 135-110-75-110-100-130
> 最低: 120-85-54-85-76-103
PostgreSQLから種族値データを取得する
あいまい検索かそうでないかで場合分けして結果を出力する。
import psycopg2 import numpy as np import re from dotenv import load_dotenv import os load_dotenv() DATABASE_URL=os.environ["DATABASE_URL"] #list to str l2s=lambda s,l:s.join(map(str,l))
def st(name,lv=50): #出力用関数を定義 def fetch_bst(name,lv): #アイコンを生成 cur.execute( f"select icon from pokedex where name='{name}'" ) icon=cur.fetchone()[0] print(icon) cur.execute( f"select h,a,b,c,d,s from pokedex where name ='{name}'" ) bst=cur.fetchone() astdict=bst2astdict(bst,lv) msg="" for item in astdict.items(): msg+=f"> {item[0]}: {l2s('-',item[1])}\n" print(msg) conn=psycopg2.connect(DATABASE_URL) with conn: with conn.cursor() as cur: #名前の最後に"*"をつけるとあいまい検索になる #あいまい検索している場合 if re.findall(r'\*',name): name=name.strip('\*') #DBから名前をあいまい検索 cur.execute( f"select name from pokedex where name like '%{name}%'" ) #ヒットしたすべての結果:fnames fnames=np.array(cur.fetchall()).flatten() for fname in fnames: seek_bst(fname,lv) #あいまい検索でない場合 else: seek_bst(name,lv) st("ライチュウ*")
> 最高: 167-156-117-156-145-178
> 準: 167-142-107-142-132-162
> 無振: 135-110-75-110-100-130
> 最低: 120-85-54-85-76-103
> 最高: 167-150-112-161-150-178
> 準: 167-137-102-147-137-162
> 無振: 135-105-70-115-105-130
> 最低: 120-81-49-90-81-103
これで完成!