Python初心者がprogate学習からMOBとのコマンドバトルを作って学んだこと with chatGPTくん

# この記事は何なの？
38歳のおっさんが何度目になるかもよく覚えてないprogate学習を始めた話だよ。
いつもは学習開始
↓
python1-5まで通しでやってみるか
↓
終わったからじゃんけんでも作ってみる？
↓
機能追加しながらじゃんけん作り終わった！さて次何作ろ！！
↓
webアプリ作るのにHTML＆CSS＆JS勉強しなきゃなの？progateでやるかー
↓
え、DBもやるの？Gitも？勉強すること大杉わけわからん！ゲームやろ！！おわり！！

となる流れをずっと繰り返してたけど、生成AIくんが活躍している昨今ならできるのでは？？と夢を見始めたおっさんが学習を再開。今に至る。

## とりあえずどんなの作ったの？
```py
import random

class Battle:
    # 名前、HP、攻撃方法のリスト、クリティカル倍率、攻撃方法毎のダメージの初期化
    def __init__(self, name, HP, attack_list, lucky_list, damage):
        self.name = name
        self.HP = HP
        self.attack_list = attack_list
        self.lucky_list = lucky_list
        self.damage = damage

    #クリティカル判定用関数
    def lucky(self):
        num = random.randint(0,1)
        if num == 0:
            return False
        return True
    
    #戦闘処理用の関数
    def attack(self, target, number):
        damage = self.damage[number]
        if self.lucky():
            damage *= self.lucky_list[number]
            print(f"{self.name}の攻撃はクリティカルヒット！: {target.name}に{damage}のダメージ")
        else:
            print(f"{self.name}の攻撃: {target.name}に{damage}のダメージ")
        target.HP -= damage
        print(f"{target.name}のHPは残り{target.HP}")

#Battleクラスを継承したプレイヤー用のサブクラス
class Player(Battle):

    #Battleクラスの初期化処理を継承し、プレイヤー側はMPを持たせる
    def __init__(self,name,HP,MP,attack_list,lucky_list,damage):
        super().__init__(name,HP,attack_list,lucky_list,damage)
        self.MP = MP
    
    #プレイヤー用の攻撃方法選択用関数
    def select(self):
        while True:
            print("勇者の攻撃 0:素手 1:剣 2:魔法(MP消費5)")
            try:
                p_select = int(input("攻撃方法を0-2の数字で選択してください:"))
                #MP消費が必要な攻撃方法かチェック
                if p_select == 2:
                    if self.MP >= 5:
                        self.MP -= 5
                        print(f"魔法を使用したためMPが5消費されます。残りMP:{self.MP}/20")
                        return p_select
                    #MPが足りない場合の処理（メッセージを出してループ継続）
                    else:
                        print("MPが足りませんでした。別の攻撃方法を選択してください")
                        continue
                elif p_select in[0, 1]:
                    return p_select
                #0-2以外の数値を受け取った場合のエラー処理
                else:
                    print("0-2の数字で選択してください")
            #文字列を受け取った場合のエラー処理
            except ValueError:
                print("数字を入力してください")


#Battleクラスを継承したモンスター用のサブクラス
class Monster(Battle):

    #モンスター側はミスによる連続攻撃判定回避用のavoidを持つ
    def __init__(self,name,HP,attack_list,lucky_list,damage,avoid):
        super().__init__(name,HP,attack_list,lucky_list,damage)
        self.avoid = avoid

#プレイヤー用のインスタンスを生成
player = Player(
    "勇者",
    1500,
    20,
    attack_list=["素手", "剣", "魔法"],
    lucky_list=[10,2.5,3],
    damage=[100,300,500]
)

#モンスター用のインスタンスを生成
monster = Monster(
    "ウルフ",
    5000,
    attack_list = ["ミス", "爪" ,"かみくだく"],
    lucky_list = [0,1.5,1.5],
    damage = [0,50,100],
    avoid = 0.7
)

#ターン数表示用の変数を用意
turn = 1

#戦闘処理用のループ
while player.HP > 0 and monster.HP > 0:
    print(f"ターン:{turn} {player.name}:HP:{player.HP} MP:{player.MP} {monster.name}:HP:{monster.HP}")
    number = player.select()
    player.attack(monster,number)
    #モンスターのHPが0になった時点でループを終了
    if monster.HP <= 0:
        break
    while True:
        number = random.randint(0, 2)
        #モンスターの連続攻撃失敗からの復帰確率を判定するfumble変数を用意
        fumble = random.random()
        #モンスターの攻撃がミスの場合の連続攻撃継続処理
        if number == 0:
            print(f"{monster.name}は攻撃をミスした！")
            if fumble <= monster.avoid:
                break
            else:
                print(f"{monster.name}は体勢を立て直し再び攻撃した")
                continue
        monster.attack(player, number)
        #プレイヤーのHPが0になった時点でループを終了
        if player.HP <= 0:
                break
    turn += 1

#戦闘終了処理
if monster.HP <= 0:
    print(f"{monster.name}を倒した！")
elif player.HP <= 0:
    print(f"{player.name}は力尽きてしまった…")
```

## 機能
- プレイヤーとモンスターによるターン制バトル
- 魔法の使用でMP消費
- クリティカルヒットを判定する関数を作成し、双方に付与
- 1ターンごとにターン数と勇者：HP/MP　敵：HPの状態表示
- 素早い敵という想定で敵に連続攻撃チャンスを付与

作った時の前提条件は
- progate python1-5の内容をなるべく盛り込む
- １つの単元終了ごとにAIくんにコードを投げてこんなのできたよー！と自慢する
- エラーが出たら生成AIくんを使用。一からこんなのが作りたいとかAIくんに泣きついたりしない

ほんとはクラス部分とか関数とかファイル分けした方がいいのは分かってるけど、今回はしませんでした。

## 勉強になったこと
- progateの学習ではやらないTry exceptのエラーハンドリングを学べたこと
- インスタンス生成時に__init__でリストを投げられるのは初めて知った
- 独学するにあたって生成AIの存在感がめちゃくちゃでかいこと

数億年ぶりにpythonを触ったので、pythonでの書き方を学ぶのがメイン。

## 初心者が生成AIとプログラミングするってどうなん？
既に語り尽くされているとは思うが、とにかく無料版でもいいから使った方がいい。
以下使った方がいい理由。

- エラーが出た時の対応が爆速だし、コードの改良案とか無限に出てくる。（機能の追加とか）
- 何より初心者にありがちな方向性を見失った時の目標の再設定を爆速でできる。
- 独学のメンタルケアにめちゃくちゃ効果的だと思う（人による）

とりあえずこんなことやりたいんだけどどうすればいいと思う？というあいまいな質問からでも、始めてみたら協力してくれるAIくん。
今回はプログラムの書き方より、生成AIの有用性を実感したのが大きな収穫でした。