プログラムの文法は一通り学んだんだけど
どうやってプログラム書けばいいか分からないと言う方
朗報です。

ドラクエのシミュレーターを通じて
プログラムの作り方を学んでいきましょう。

解説動画はこちら







さてまず考えることは
小さなところからコツコツとです。

まずは1行から
慣れてきたら複数行
有る程度できるようになったら数千行の奴へ挑戦

と言うようにステップを踏んで
プログラムに慣れていきましょう。

最初はコピペからで十分です。
有る程度コードが打てるようになったら
次の段階へ進みましょう。

プログラムを考える時のコツですが

プログラムに基本は
1.入力 , 2.計算 , 3.出力 を考える
です。

1.入力させるデータ(構造) が何で
2.何をどう計算させるか(アルゴリズム)がどうなってて 
3.最終的に何を出すか(結果)

と言うことを考えます。

これは1行1行にも当てはまります。
全ての行で入力 , 計算 , 出力が行われているはずです。

一体何をどうしているのかを
把握しながらコードを書くのが
プログラムを書くコツになります。

ドラクエのシミュレーションを考えてみましょう。

想定されるシーンは
ドラクエ1

勇者 vs スライム
1対1の対決です。

ここではキャラクターとしては2体。
ステータスは共通のものを使うとします。

次に何をするかと言うと

お互いに攻撃しあってHPを減らしていき
HPが0になったら戦闘は終了しますので
それまで戦いを続けます。

最終的にはどちらかが勝つことになり
これが結果となります。

さて入力データを考えていきましょう。

2体のキャラクターですが
プログラムの入力データとしては
1つのクラスにまとめることができます。

次のようなクラスでまとめられます。

class character():

    def __init__(self,name,hp,attack,defence,agility):
        self.name = name
        self.hp = hp
        self.attack = attack
        self.defence = defence
        self.agility = agility

これを呼び出してみると
c1 = character('勇者',150,60,40,60)
c2 = character('スライム',100,50,30,56)

for k,v in c1.__dict__.items():
    print(k,v)
    
for k,v in c2.__dict__.items():
    print(k,v)
name 勇者
hp 150
attack 60
defence 40
agility 60
name スライム
hp 100
attack 50
defence 30
agility 56

こんな感じで勇者とスライム君ができました。

次はアルゴリズムを考えていきます。

アルゴリズム
1.ダメージ計算

攻撃力÷2-守備力÷4=ダメージ基礎値
ランダム値(ダメージ基礎値 ÷16+1)
ダメージ = ダメージ基礎値 プラスマイナス ランダム値

2.先頭順序
素早さ乱数の多い方が先に行動する
素早さ乱数 = 素早さ プラスマイナス10%のランダム値
例:400 = 360から440の間のランダム値

3.戦闘シーン
ダメージを算出してお互いのHPを削って
どちらかが0になったら終了


まずはダメージ計算です。
基礎値を算出してプラマイランダム値と言うのが
公式的な算出方法なようです。

シリーズによって多少の違いはありますが
基本的な考え方は一緒なのでこれを踏襲します。
import numpy as np

# ダメージ計算
def damage_calc(c1,c2):
    base = c1.attack //2 - c2.defence//4
    rand = base//16+1
    tmp = np.random.randint(0,rand*2+1)-rand
    damage = base + tmp
    return damage

次に先頭順序の計算です。

これを考えるには素早さ乱数がわからないとダメなので
先にこれを計算しておきます。
# 素早さ計算
def agility_calc(c):
    base = c.agility
    tmp = base//10
    result = np.random.randint(base-tmp,base+tmp+1)
    return result

# 先頭順序の計算
def turn_calc(c1,c2):
    a1 = agility_calc(c1)
    a2 = agility_calc(c2)
    if a1>=a2:
        return True
    else:
        return False

最後に先頭シーンを考えます。
お互いのHPを削って行って
HPが0になったら先頭終了です。

ターン中の計算と
先頭シーンの制御の部分で分けてみます。
# ターン中の計算
def turn(c1,c2):
    damage = damage_calc(c1,c2)
    c2.hp = c2.hp - damage if c2.hp - damage>=0 else 0
    print('{0}の攻撃 : {1}に{2}のダメージ'.format(c1.name,c2.name,damage))
    print('{0}のHP : {1}'.format(c2.name,c2.hp))
    if c2.hp<=0:
        print('{0}は力尽きた'.format(c2.name))
        return (c1,c2,0)
    damage = damage_calc(c2,c1)
    c1.hp = c1.hp - damage if c1.hp - damage>=0 else 0
    print('{0}の攻撃 : {1}に{2}のダメージ'.format(c2.name,c1.name,damage))
    print('{0}のHP : {1}'.format(c1.name,c1.hp))
    if c1.hp<=0:
        print('{0}は力尽きた'.format(c1.name))
        return (c1,c2,1)
    return (c1,c2,9)

# 戦闘
def battle(c1,c2):
    while True:
        # 勇者が先のターン
        if turn_calc(c1,c2):        
            c1,c2,flg = turn(c1,c2)
            if flg==0:
                print('終了 : {0}の勝ち'.format(c1.name))
                break
            elif flg==1:
                print('終了 : {0}の勝ち'.format(c2.name))
                break
        # モンスターが先のターン
        else:
            c2,c1,flg = turn(c2,c1)
            if flg==0:
                print('終了 : {0}の勝ち'.format(c2.name))
                break
            elif flg==1:
                print('終了 : {0}の勝ち'.format(c1.name))
                break


これで出来ました。

さてシミュレーションしてみましょう。
c1 = character('勇者',100,80,40,66)
c2 = character('スライム',180,80,30,66)

# 戦闘開始
battle(c1,c2)
勇者の攻撃 : スライムに33のダメージ
スライムのHP : 147
スライムの攻撃 : 勇者に31のダメージ
勇者のHP : 69
勇者の攻撃 : スライムに35のダメージ
スライムのHP : 112
スライムの攻撃 : 勇者に29のダメージ
勇者のHP : 40
スライムの攻撃 : 勇者に31のダメージ
勇者のHP : 9
勇者の攻撃 : スライムに34のダメージ
スライムのHP : 78
勇者の攻撃 : スライムに33のダメージ
スライムのHP : 45
スライムの攻撃 : 勇者に28のダメージ
勇者のHP : 0
勇者は力尽きた
終了 : スライムの勝ち

スライムが強すぎて勝てる気がしませんね。

アプリケーションは小さなプログラムの集合体です。
小さなプログラムは数行のコードだったりします。

何が入力で、何を計算させれば良いのかを
少しづつ考えていけば、次第に大きなものを
作れるようになってくと思います。

ドラクエのシミュレーションは
プログラムの初心者がプログラムの作り方を学ぶ
題材としてはうってつけだと思います。

まずは最低限の機能を実装していき
次第に大きくしていきます。

昔作った
ドラクエモンスターライトの
シミュレーターは複数 vs 複数のバトルなので
心折れそうでしたがアンドロイドアプリにすることができました。
(今は公開していませんが)

目標を決めるとそれに向かって努力するので
小さめの目標から初めて
達成を繰り返していくと言う過程を経ることで
大きな目標達成に繋げることができるのではないかと思います。

今回はここまでです。
それでは。