[Python] OpenWeatherMap APIを利用してバトルゲームを作る

こんにちは！

前回、以下の記事でmathの関数を使った対話型バトルゲームを作りました。
[[Python] mathの関数を使ったバトルゲームを作ってみる](https://qiita.com/yam_dev/items/93e6249ecfeb6697c759)

もう少し本格的にしたかったので、今回は、気象情報を使ってバトルしてみます。

# 要件
- 緯度、経度をランダムに取得する
- WeatherMapのAPIと緯度経度を使って、気象情報を取得する
- 気象情報を使って攻撃する
- 先にHPが0になった方が負け

# コード

```python:main.py
import random
import requests
import time

# OpenWeatherMap APIキー
API_KEY = "xxxxxxxx"

def get_weather(latitude, longitude):
    """指定された緯度経度の気象情報を取得"""
    url = f"http://api.openweathermap.org/data/2.5/weather?lat={latitude}&lon={longitude}&appid={API_KEY}&units=metric"
    response = requests.get(url)
    if response.status_code == 200:
        return response.json()
    else:
        print("気象情報の取得に失敗しました。")
        return None

def weather_attack(weather_data):
    """気象情報に基づいて攻撃を生成"""
    if weather_data is None:
        return 0, "不明な攻撃", "不明な天気"

    main_weather = weather_data["weather"][0]["main"]
    temp = weather_data["main"]["temp"]
    wind_speed = weather_data["wind"]["speed"]

    if main_weather == "Thunderstorm":
        damage = int(20 + temp * 0.5 + wind_speed * 2)
        attack_name = "雷撃"
    elif main_weather == "Rain":
        damage = int(10 + temp * 0.2 + wind_speed)
        attack_name = "豪雨"
    elif main_weather == "Snow":
        damage = int(15 + (0 - temp) * 0.3)  # 温度が低いほどダメージ大
        attack_name = "吹雪"
    elif main_weather == "Clouds":
        damage = int(5 + wind_speed * 0.5)
        attack_name = "突風"
    elif main_weather == "Clear":
        damage = int(8 + temp * 0.1)  # 温度が高いほどダメージ大
        attack_name = "灼熱"
    else:
        damage = 5
        attack_name = "通常攻撃"
    description = f"{main_weather}({temp}℃, 風速{wind_speed}m/s)"
    return damage, attack_name, description

def math_battle():
    """対話型気象バトルゲーム"""
    player_hp = 100
    monster_hp = 100

    print("\n気象バトル開始！")

    while player_hp > 0 and monster_hp > 0:
        # プレイヤーのターン
        print(f"\n--- プレイヤーのターン ---")
        print(f"プレイヤーHP: {player_hp}")
        print(f"モンスターHP: {monster_hp}")

        input("\n攻撃場所を決定するため、Enterキーを押してください...") # ウェイト
        player_lat = random.uniform(-90, 90)
        player_lon = random.uniform(-180, 180)
        player_weather = get_weather(player_lat, player_lon)
        player_damage, player_attack_name, player_weather_description = weather_attack(player_weather)


        print(f"緯度:{player_lat:.2f} 経度:{player_lon:.2f} の{player_weather_description}")
        print(f"{player_attack_name}！{player_damage}のダメージ！")
        monster_hp -= player_damage
        time.sleep(1)


        # モンスターのターン (モンスターも気象攻撃)
        if monster_hp > 0:
            print(f"\n--- モンスターのターン ---")
            monster_lat = random.uniform(-90, 90)
            monster_lon = random.uniform(-180, 180)
            monster_weather = get_weather(monster_lat, monster_lon)
            monster_damage, monster_attack_name, monster_weather_description = weather_attack(monster_weather)
            print(f"緯度:{monster_lat:.2f} 経度:{monster_lon:.2f} の{monster_weather_description}")
            print(f"{monster_attack_name}！{monster_damage}のダメージ！")
            player_hp -= monster_damage
            time.sleep(1)


    if player_hp <= 0:
        print("\n敗北…")
    else:
        print("\n勝利！")

if __name__ == "__main__":
    math_battle()
```

# 実行結果
```bash
% python main.py

気象バトル開始！

--- プレイヤーのターン ---
プレイヤーHP: 100
モンスターHP: 100

攻撃場所を決定するため、Enterキーを押してください...
緯度:-10.46 経度:17.24 のRain(20.12℃, 風速2.22m/s)
豪雨！16のダメージ！

--- モンスターのターン ---
緯度:55.15 経度:-62.38 のClouds(-23.72℃, 風速4.18m/s)
突風！7のダメージ！
```

```bash
--- プレイヤーのターン ---
プレイヤーHP: 93
モンスターHP: 84

攻撃場所を決定するため、Enterキーを押してください...
緯度:-63.89 経度:68.28 のSnow(-1.54℃, 風速13.29m/s)
吹雪！15のダメージ！

--- モンスターのターン ---
緯度:-4.23 経度:35.09 のRain(23.46℃, 風速2.06m/s)
豪雨！16のダメージ！
```

```bash
--- プレイヤーのターン ---
プレイヤーHP: 77
モンスターHP: 69

攻撃場所を決定するため、Enterキーを押してください...
緯度:-53.79 経度:-140.87 のClouds(4.91℃, 風速8.75m/s)
突風！9のダメージ！

--- モンスターのターン ---
緯度:-80.30 経度:176.96 のClear(-11.07℃, 風速1.54m/s)
灼熱！6のダメージ！
```

```bash
--- プレイヤーのターン ---
プレイヤーHP: 71
モンスターHP: 60

攻撃場所を決定するため、Enterキーを押してください...
緯度:47.39 経度:102.32 のClouds(-14.64℃, 風速5.23m/s)
突風！7のダメージ！

--- モンスターのターン ---
緯度:-68.90 経度:133.24 のClouds(-13.21℃, 風速8.66m/s)
突風！9のダメージ！
```

```bash
--- プレイヤーのターン ---
プレイヤーHP: 62
モンスターHP: 53

攻撃場所を決定するため、Enterキーを押してください...
緯度:16.74 経度:-68.10 のClouds(27.48℃, 風速8.5m/s)
突風！9のダメージ！

--- モンスターのターン ---
緯度:18.07 経度:78.01 のClear(29.38℃, 風速5.19m/s)
灼熱！10のダメージ！
```

```bash
--- プレイヤーのターン ---
プレイヤーHP: 52
モンスターHP: 44

攻撃場所を決定するため、Enterキーを押してください...
緯度:-83.05 経度:-103.56 のClouds(-14.4℃, 風速4.96m/s)
突風！7のダメージ！

--- モンスターのターン ---
緯度:-77.30 経度:-179.51 のClouds(-4.22℃, 風速4.66m/s)
突風！7のダメージ！
```

```bash
--- プレイヤーのターン ---
プレイヤーHP: 45
モンスターHP: 37

攻撃場所を決定するため、Enterキーを押してください...
緯度:-30.32 経度:-125.79 のClouds(21.8℃, 風速5.29m/s)
突風！7のダメージ！

--- モンスターのターン ---
緯度:-32.90 経度:11.83 のClear(18℃, 風速8.33m/s)
灼熱！9のダメージ！
```

```bash
--- プレイヤーのターン ---
プレイヤーHP: 36
モンスターHP: 30

攻撃場所を決定するため、Enterキーを押してください...
緯度:-82.54 経度:85.35 のClouds(-28.25℃, 風速5.28m/s)
突風！7のダメージ！

--- モンスターのターン ---
緯度:-64.45 経度:175.85 のClouds(-1.17℃, 風速6.7m/s)
突風！8のダメージ！
```

```bash
--- プレイヤーのターン ---
プレイヤーHP: 28
モンスターHP: 23

攻撃場所を決定するため、Enterキーを押してください...
緯度:65.30 経度:-79.67 のSnow(-11.47℃, 風速4.28m/s)
吹雪！18のダメージ！

--- モンスターのターン ---
緯度:25.77 経度:-65.78 のClouds(21.88℃, 風速7.88m/s)
突風！8のダメージ！
```

```bash
--- プレイヤーのターン ---
プレイヤーHP: 20
モンスターHP: 5

攻撃場所を決定するため、Enterキーを押してください...
緯度:38.24 経度:13.57 のClouds(9.92℃, 風速10.67m/s)
突風！10のダメージ！

勝利！
```

いいですね！
緯度軽度とOpenWeatherMap APIで、気象データに応じた攻撃をすることができました。
これを応用すると、位置情報を使ったバトルができそうです。

# まとめ
今回はOpenWeatherMap APIを利用してバトルゲームを作ってみました。
もっと工夫すると面白くなりそうなので、またチャレンジしてみます！