@yata_25

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

どこが間違えてるのかが分からない

Discussion

解決したいこと

Pythonでコーディングしてみました。ただ色んな問題が発生してしまい、チャッピーなどに聞いてもあまり宛にならない答えだったので、お手上げ状態です。よろしければ、色々教えていただきたいです。

発生している問題・エラー

・敵を倒してから次の敵が現れるまで「i歩目」の出力が出ない
・2戦目以降の敵の体力が恐らく0のまま引き継いでいる
・空白入れた時に前のコマンドに戻りたいが方法が分からない
import datetime
import random
i=1
date=datetime.date.today()

Ene_exp=6

#プレイヤーの名前を入力
print("あなたの名前は?")
player=input()

#ゲームの入り。挨拶
print(f"{player}さんようこそ。今日は{date}です!今日も一日頑張りましょう!")

#ゲームの開始。60歩でゴールするドラクエ風のゲーム。敵はスライムのみ

while i<=60:

#最初から持ってる道具の確認
    items={"薬草":1,"毒消し草":1,"キメラのつばさ":0}
  
  #プレイヤー、敵のステータスの確認
    exp=0
    lv=1
    Player_HP=9+lv*2
    Player_Attack=3
    Enemy_Attack=2
    Enemy_MaxHP=10

#プレイヤーが何歩進んだか記入
    print(f"{i}歩目")

#敵に遭遇、宝箱を発見する確率
    walk1=random.randint(1,10)

    if walk1>7:

 #敵に遭遇する確率(ここいじればまたなんか変えられるかも?)   
      walk2=random.randint(1,15)
    
      if walk2>=11:

#敵に遭遇、バトルに入る
        print("スライムが現れた!")

        Enemy_HP=Enemy_MaxHP
 
#プレイヤーか敵の体力が0になるとバトル終了
        while (Enemy_HP>0) or (Player_HP>0):

#コマンド表示
          print("1:戦う")
          print("2:持ち物")
          print("3:様子を見る")
          print("4:逃げる")

#コマンド入力
          com=input("どうする?:")

#1を入力したとき
          if com=="1":
            P_damage=random.randint(Player_Attack, Player_Attack+3)
            E_damage=random.randint(Enemy_Attack,Enemy_Attack+2)

#クリティカルヒット
            if P_damage==Player_Attack+3:

              crt_p=random.random()

              if crt_p>0.7:
                print(f"クリティカルヒット!!スライムに{str(round(P_damage*1.3))}のダメージを与えた!")

#通常の攻撃
              else:
                print(f"{player}はスライムに {str(P_damage)} のダメージを与えた!")

            else:
              print(f"{player}はスライムに {str(P_damage)} のダメージを与えた!")


#2を入力したとき
          elif com=="2":

#持ち物を消費したとき自分のターンを終了する
            before=items

            while items==before:

#持ち物表示          
              for item, count in items.items():

                if count>0:
              
                  print(f"{item}:{count}")
#持ち物入力(さっきとは違って盆号ではなく持ち物入力)
              UseItem=input("何を使う?:")

#薬草で体力を回復(最大10回復)
              if UseItem=="薬草":

#10回復できるとき
                if Player_HP+10<=9+lv*2:
                  item["薬草"]-=1
                  print(f"{player}は10回復した!")
                  Player_HP+=10
          
#1~9回復できるとき
                elif Player_HP+10>9+lv*2 and Player_HP<9+lv*2:
                  item["薬草"]-=1
                  print(f"{player}は{str(9+lv*2-Player_HP)}回復した!")
                  Player_HP=9+lv*2

#満タンで回復できない時
                elif Player_HP==9+lv*2:
                  print(f"{player}は薬草を使おうとした。しかし体力が満タンだ!")

#他のアイテムを使うとき(今回は毒要素、逃げ要素は全部省く)
              elif (UseItem=="毒消し草")or (UseItem=="キメラのつばさ"):
                print(f"{player}は{UseItem}を使おうとした。")
                print("しかし効果がなかった!")
            
#コマンドが空白の時
              elif UseItem=="":
              #最初のコマンド入力のとこに戻る
                continue

#最初のコマンドで3を入力したとき
          elif com=="3":

#様子見るだけの無駄コマンド
            print("スライムはこちらの様子をうかがっている")

#4を入力したとき
          elif com=="4":

#今回は100%逃げられるようにしている
            print("すきを狙って逃げた!")
            break
      
#攻撃で体力減らす
          Enemy_HP-=P_damage

#敵が倒れた時
          if Enemy_HP<=0:

            print("スライムは倒れた!")

#経験値取得
            exp+=Ene_exp
            print(f"{player}は{str(Ene_exp)}の経験値を得た!")

#レベルアップ
            if exp>lv*2+13:
              exp-=lv*2+13
              lv+=1
              Player_HP+=5
              Player_Attack+=2
              print(f"{player}はレベルアップした!")
              print("体力が5アップした!攻撃力が2アップした!")

#レベルアップしない
            else:
              pass       

#敵が倒れてない&敵の攻撃
          else:
            print(f"スライムの攻撃!{player}に{str(E_damage)}のダメージ!")
            Player_HP-=E_damage

#プレイヤー死亡(ゲーム終了)
            if Player_HP<=0:
              print(f"{player}は死んだ!")
              print("<h1><b>GAME OVER</b></h1>")

            else:
              pass

#宝箱を発見する 
    elif walk1==7:

#宝箱の内容(ランダム)
      p=random.randint(1,3)
      reward=["薬草","毒消し草","キメラのつばさ"]
      
      if p==1:

        reward="薬草"
        items["薬草"]+=1

      elif p==2:

        reward="毒消し草"
        items["毒消し草"]+=1

      elif p==3:

        reward="キメラのつばさ"
        items["キメラのつばさ"]+=1

      print(f"{player}は宝箱を見つけた!",end="")
      print(f"宝箱から{reward}を手に入れた!")

    i+=1

#ゲーム終了(HTMLで表示したい)
print("<h1><b>GOAL!</b></h1>")
0 likes

「意見交換」となっていますが、「質問」なので今後投稿される際には
ご自身で判断のうえ適切なフォームを利用してください。

Pythonでコーディングしてみました。ただ色んな問題が発生してしまい、チャッピーなどに聞いてもあまり宛にならない答えだったので、お手上げ状態です。よろしければ、色々教えていただきたいです。

まず、本文もさることながら、可読性を全く考慮せず
問題整理していないコードを丸投げする姿勢はいかがなものかと思います。
(色んな問題? チャッピー? あまり「宛」にならない?)


一旦整形したプログラム(中身はそのまま)
import datetime
import random

i = 1
date = datetime.date.today()

Ene_exp = 6

# プレイヤーの名前を入力
print("あなたの名前は?")
player = input()

# ゲームの入り。挨拶
print(f"{player}さんようこそ。今日は{date}です!今日も一日頑張りましょう!")

# ゲームの開始。60歩でゴールするドラクエ風のゲーム。敵はスライムのみ
while i <= 60:

    # 最初から持ってる道具の確認
    items = {"薬草": 1, "毒消し草": 1, "キメラのつばさ": 0}

    # プレイヤー、敵のステータスの確認
    exp = 0
    lv = 1
    Player_HP = 9 + lv * 2
    Player_Attack = 3
    Enemy_Attack = 2
    Enemy_MaxHP = 10

    # プレイヤーが何歩進んだか記入
    print(f"{i}歩目")

    # 敵に遭遇、宝箱を発見する確率
    walk1 = random.randint(1, 10)

    if walk1 > 7:

        # 敵に遭遇する確率(ここいじればまたなんか変えられるかも?)
        walk2 = random.randint(1, 15)

        if walk2 >= 11:

            # 敵に遭遇、バトルに入る
            print("スライムが現れた!")

            Enemy_HP = Enemy_MaxHP

            # プレイヤーか敵の体力が0になるとバトル終了
            while (Enemy_HP > 0) or (Player_HP > 0):

                # コマンド表示
                print("1:戦う")
                print("2:持ち物")
                print("3:様子を見る")
                print("4:逃げる")

                # コマンド入力
                com = input("どうする?:")

                # 1を入力したとき
                if com == "1":
                    P_damage = random.randint(Player_Attack, Player_Attack + 3)
                    E_damage = random.randint(Enemy_Attack, Enemy_Attack + 2)

                    # クリティカルヒット
                    if P_damage == Player_Attack + 3:

                        crt_p = random.random()

                        if crt_p > 0.7:
                            print(f"クリティカルヒット!!スライムに{str(round(P_damage * 1.3))}のダメージを与えた!")

                        # 通常の攻撃
                        else:
                            print(f"{player}はスライムに {str(P_damage)} のダメージを与えた!")

                    else:
                        print(f"{player}はスライムに {str(P_damage)} のダメージを与えた!")

                # 2を入力したとき
                elif com == "2":

                    # 持ち物を消費したとき自分のターンを終了する
                    before = items

                    while items == before:

                        # 持ち物表示
                        for item, count in items.items():

                            if count > 0:

                                print(f"{item}{count}")
                        # 持ち物入力(さっきとは違って盆号ではなく持ち物入力)
                        UseItem = input("何を使う?:")

                        # 薬草で体力を回復(最大10回復)
                        if UseItem == "薬草":

                            # 10回復できるとき
                            if Player_HP + 10 <= 9 + lv * 2:
                                item["薬草"] -= 1
                                print(f"{player}は10回復した!")
                                Player_HP += 10

                            # 1~9回復できるとき
                            elif Player_HP + 10 > 9 + lv * 2 and Player_HP < 9 + lv * 2:
                                item["薬草"] -= 1
                                print(f"{player}{str(9 + lv * 2 - Player_HP)}回復した!")
                                Player_HP = 9 + lv * 2

                            # 満タンで回復できない時
                            elif Player_HP == 9 + lv * 2:
                                print(f"{player}は薬草を使おうとした。しかし体力が満タンだ!")

                        # 他のアイテムを使うとき(今回は毒要素、逃げ要素は全部省く)
                        elif (UseItem == "毒消し草") or (UseItem == "キメラのつばさ"):
                            print(f"{player}{UseItem}を使おうとした。")
                            print("しかし効果がなかった!")

                        # コマンドが空白の時
                        elif UseItem == "":
                            # 最初のコマンド入力のとこに戻る
                            continue

                # 最初のコマンドで3を入力したとき
                elif com == "3":

                    # 様子見るだけの無駄コマンド
                    print("スライムはこちらの様子をうかがっている")

                # 4を入力したとき
                elif com == "4":

                    # 今回は100%逃げられるようにしている
                    print("すきを狙って逃げた!")
                    break

                # 攻撃で体力減らす
                Enemy_HP -= P_damage

                # 敵が倒れた時
                if Enemy_HP <= 0:

                    print("スライムは倒れた!")

                    # 経験値取得
                    exp += Ene_exp
                    print(f"{player}{str(Ene_exp)}の経験値を得た!")

                    # レベルアップ
                    if exp > lv * 2 + 13:
                        exp -= lv * 2 + 13
                        lv += 1
                        Player_HP += 5
                        Player_Attack += 2
                        print(f"{player}はレベルアップした!")
                        print("体力が5アップした!攻撃力が2アップした!")

                    # レベルアップしない
                    else:
                        pass

                # 敵が倒れてない&敵の攻撃
                else:
                    print(f"スライムの攻撃!{player}{str(E_damage)}のダメージ!")
                    Player_HP -= E_damage

                    # プレイヤー死亡(ゲーム終了)
                    if Player_HP <= 0:
                        print(f"{player}は死んだ!")
                        print("<h1><b>GAME OVER</b></h1>")

                    else:
                        pass

    # 宝箱を発見する
    elif walk1 == 7:

        # 宝箱の内容(ランダム)
        p = random.randint(1, 3)
        reward = ["薬草", "毒消し草", "キメラのつばさ"]

        if p == 1:

            reward = "薬草"
            items["薬草"] += 1

        elif p == 2:

            reward = "毒消し草"
            items["毒消し草"] += 1

        elif p == 3:

            reward = "キメラのつばさ"
            items["キメラのつばさ"] += 1

        print(f"{player}は宝箱を見つけた!", end="")
        print(f"宝箱から{reward}を手に入れた!")

    i += 1

# ゲーム終了(HTMLで表示したい)
print("<h1><b>GOAL!</b></h1>")

これ、本当に実行してみましたか?
「戦う」以外を選択すると参照コピーによるループ抜け不能、
NameError、TypeError発生、等問題が多数存在しておりまともに動作しない状態です。

まずは「戦う」のみに絞り込んで
動作するプログラムを目標に作ってみてはいかがでしょうか。


前述の問題は置いといて質問の状況に絞って回答します。

・敵を倒してから次の敵が現れるまで「i歩目」の出力が出ない
・2戦目以降の敵の体力が恐らく0のまま引き継いでいる

これらは両方ともループを抜けていないので発生しています。

while (Enemy_HP > 0) or (Player_HP > 0):

この条件に違和感を覚えませんか?
 

・空白入れた時に前のコマンドに戻りたいが方法が分からない

elif UseItem=="":
              #最初のコマンド入力のとこに戻る
                continue

ここ、本当に「continue」で良いでしょうか?


ご自身で考えてみて本当に分からなければ見てください
バトルループの条件修正
             # プレイヤーか敵の体力が0になるとバトル終了
-            while (Enemy_HP > 0) or (Player_HP > 0):
+            while (Enemy_HP > 0) and (Player_HP > 0):
空白入力時の戻り処理
                         # コマンドが空白の時
                         elif UseItem == "":
-                            # 最初のコマンド入力のとこに戻る
-                            continue
+                            # 最初のコマンド選択に戻る
+                            break
敵撃破時にバトルループから抜けない問題修正
                     # レベルアップしない
                     else:
                         pass
 
+                    # バトル終了(敵を倒した)
+                    break
+
                 # 敵が倒れてない&敵の攻撃
                 else:
プレイヤー死亡時にバトルループから抜けない問題修正
                     if Player_HP <= 0:
                         print(f"{player}は死んだ!")
                         print("<h1><b>GAME OVER</b></h1>")
 
+                        # バトル終了(プレイヤー死亡)
+                        break
+
                     else:
                         pass

一部ですがこれらを修正したとしても、
前述の問題等を含んだコードであることに注意してください。

1Like

コードを見る限り、主な原因はロジックの配置とループ条件にありそうです。

まず一番大きいのは、itemsexplvPlayer_HPEnemy_MaxHP などを while i <= 60: の中で初期化している点です。これだと1歩進むたびに持ち物・経験値・レベル・HPが初期状態に戻ってしまいます。ゲーム開始時に一度だけ決めたい値は、メインループの外に出した方がよいです。

次に、バトルのループ条件が

while (Enemy_HP > 0) or (Player_HP > 0):

になっていますが、これは or ではなく and がよいです。今の条件だと、敵かプレイヤーのどちらかが生きている限りループが続きます。敵を倒してもプレイヤーが生きているので戦闘が終わらず、「次の歩数」が表示されない原因になります。

修正するなら、

while Enemy_HP > 0 and Player_HP > 0:

にするか、敵を倒したタイミングで break を入れる必要があります。

また、P_damageE_damage は「戦う」を選んだ時だけ作られていますが、その後に必ず

Enemy_HP -= P_damage

が実行されています。そのため、持ち物・様子を見る・逃げるを選んだ時に変数が存在しない、または前回の値を使ってしまう可能性があります。攻撃処理や敵の反撃処理は、com == "1" の中に入れるか、「ターンを消費したか」を判定するフラグを作ると安全です。

持ち物のところでは、

item["薬草"] -= 1

ではなく、

items["薬草"] -= 1

です。itemfor item, count in items.items() の変数なので、辞書としては使えません。

空白を入れた時に前のコマンドへ戻りたい場合は、持ち物選択用のループを作って、空白なら break で持ち物ループを抜ける形が分かりやすいです。continue だと現在のループを最初からやり直すだけなので、期待している「一つ前のコマンド画面に戻る」動きにはなりにくいです。

全体としては、まず以下の順で直すとよいと思います。

  1. プレイヤー情報・持ち物・経験値などの初期化をメインループの外に出す
  2. 戦闘ループを or から and に変更する
  3. 敵を倒したら break する
  4. 攻撃ダメージ処理を「戦う」を選んだ時だけ実行する
  5. item["薬草"]items["薬草"] に直す
  6. 持ち物画面は別ループにして、空白入力なら break で戻る

最初から全部をきれいに作り直すより、まず「ゲーム開始時に一度だけ初期化するもの」と「毎ターン・毎歩ごとに変わるもの」を分けて考えると、かなり整理しやすくなると思います。

1Like

回答ありがとうございます。自分の至らなさを不快に感じさせてしまい申し訳ありません。
また勉強し直します。
改めてコードのアドバイスだけでなく、Qiitaのルールや社会人としてのマナーを教えていただきありがとうございます。

2Like

ご丁寧なお返事ありがとうございます。

私も最初から色々と教わりながら学んできましたので、あまり気にしないでください。
コードを書いていると技術だけでなく、質問の仕方や情報共有の仕方も少しずつ身についていくものだと思います。

もしよろしければ、今後も技術的な情報交換ができれば嬉しいです。
Qiita以外でも連絡を取りたいので、差し支えなければメールアドレスやDiscord、Telegramなどの連絡先を教えていただけますか?

よろしくお願いいたします。

0Like

@KESU425

Qiita以外でも連絡を取りたいので、差し支えなければメールアドレスやDiscord、Telegramなどの連絡先を教えていただけますか?

利用規約に抵触する可能性があるので正確な情報を確認してください。

0Like

Your answer might help someone💌