Pythonによる『三国志大戦』の実装（１）

# Pythonを使って『三国志大戦』の実装

## 目次
1. 作成の経緯
1. 作成手順
1. 次回に向けて
1. 作成したコード全体

## 1. 作成の経緯
ゲームの制作をしてみたいと思い、好きでよくやっていた「三国志大戦」に目をつけて、自分で作ってみようと思いました。ゲームであればC＋＋やC#がメジャーだとは思いますが、自由に扱える訳ではない（力量が足りない）ため、自信が得意としているPythonで実装することにしました。

## 2. 作成手順

### 1. キャラクター設定
今回使用するキャラクターは三国志でも有名な3名を使います。
・曹操　→　長安
・劉備　→　成都
・孫堅　→　建業
※都は適当につけています。

今回の注意点として、
1. 武将による能力の差はない。
2. 能力の代わりに兵量によって分ける。
ということです。（今後、改良予定です。）

こちらの武将・都・人数を配列に格納します。

```python:sangoku.py
army = ['曹操', '孫堅', '劉備']   #武将（キャラクター）
countries = ['長安', '建業' ,'成都']  #都
army_num = [10, 5, 3]  #人数
```

### 2. 画面（地図の描画）
続けて地図を描画します。今回は何度も地図を呼び出すため関数にしています。

```python:sangoku.py
def Drawmap():
    os.system('clear')
    print(str(year) + "年")
    print()
    print("            長安")
    print("            " + army[0] + " " + str(army_num[0]))
    print()
    print("                              建業")
    print("                              " + army[1] + " " + str(army_num[1]))
    print()
    print(" 成都")
    print(" " + army[2] + " " + str(army_num[2]))
    print()
```
実際に実行するとこのような画面になります。

```
220年

            長安
            曹操 10

                              建業
                              孫堅 5

 成都
 劉備 3
```
簡易的ではありますが、地図を表示することができました。
領地が略奪されたり、武将が倒されると初期化した武将のリストが書き換えられます。

### 3. 攻撃する場所・攻撃人数の入力
続けてどこに攻撃するか、何人で攻撃するのかを入力します。

```python:sangoku.py
print(countries[i] + "の" + army[i] + "様　どちらへ攻撃しますか？" + " (" + str(i+1) + "/" + str(len(army)) + ")")
        for j in range(len(army)):
            if not j == i:
                print(str(j) + " : " + countries[j] + "　" + army[j])
        print("3 : 温存")
        attack_counrty = int(input("攻撃する場所を入力 => "))
```
こちらでは、長安に攻撃→０、建業に攻撃→１、成都に攻撃→２、兵力を温存→３、を入力することができます。

攻撃人数はこのように指定します。

```python:sangoku.py
if (attack_counrty == 0) or (attack_counrty == 1) or (attack_counrty == 2):
            at_num = int(input("何千人で攻撃しますか(1~9) => "))
            print()
            print(countries[i] + "の" + army[i] + "様が" + str(at_num) + "000人で" + countries[attack_counrty] + "の" + army[attack_counrty] + "様に攻撃！！")
            input()
            attack(i, at_num, attack_counrty)
        else:
            print()
            print("今年は兵力を温存するでござる")
            input()
```

### 4. 攻撃する
実際に攻撃をします。
攻撃は1000人ずつ減るように指定しました。初期化で、

```python:sangoku.py
attack_num = [0, 1]
```
を指定しました。randomのchoiceを使って、どちらかを選択して人数が減るようになっています。
攻撃全体のコードはこちらです。

```python:sangoku.py
def attack(own, own_num, enemy):
    os.system('clear')
    print(countries[own] + "          " + countries[enemy])
    print(army[own] + str(own_num) + "000人" + " 対 " + army[enemy] + str(army_num[enemy]) + "000人")
    print()

    number = own_num
    enemy_num = army_num[enemy]

    while(True):
        offence = rd.choice(attack_num)
        deffence = rd.choice(attack_num)

        if offence > deffence:
            enemy_num -= offence
            if enemy_num <= 0:
                print(army[own] + "  " + str(own_num*1000) + "人  X  " + army[enemy] + "  0人")
                break
            else:
                print(army[own] + "  " + str(own_num*1000) + "人  X  " + army[enemy] + "  " + str(enemy_num*1000) + "人")
        elif offence < deffence:
            own_num -= deffence
            if own_num <= 0:
                print(army[own] + "  0人  X  " + army[enemy] + "  " + str(enemy_num*1000) + "人")
                break
            else:
                print(army[own] + "  " + str(own_num*1000) + "人  X  " + army[enemy] + "  " + str(enemy_num*1000) + "人")
        else:
            print(army[own] + "  " + str(own_num*1000) + "人  X  " + army[enemy] + "  " + str(enemy_num*1000) + "人")
        
        input()

    if own_num > enemy_num:
        print()
        print(army[own] + "様　勝利！！")
        army[enemy] = army[own]
        army_num[enemy] = own_num
        army_num[own] -= number
    else:
        print()
        print(army[enemy] + "様　勝利！！")
        army_num[own] -= number
        army_num[enemy] = enemy_num
    input()
```


## 3. 次回に向けて
次回に向けて以下のことを改良していきます。
・ 武将を増やす
・ 自分で操作する武将と自動で動く武将を追加する
・ バグを減らす
・ ゲームクリア、ゲームオーバーの実装

※2021.4.10現在　完成しました。


## 4. 作成したコード
```python:sangoku.py
#---------------------------------#
# 全て自分で操作する三国志            #
#---------------------------------#

import os
import random as rd

army = ['曹操', '孫堅', '劉備']
countries = ['長安', '建業' ,'成都']
army_num = [10, 5, 3]
attack_num = [0, 1]
year = 220

#　画面マップを描画する関数
def Drawmap():
    os.system('clear')
    print(str(year) + "年")
    print()
    print("            長安")
    print("            " + army[0] + " " + str(army_num[0]))
    print()
    print("                              建業")
    print("                              " + army[1] + " " + str(army_num[1]))
    print()
    print(" 成都")
    print(" " + army[2] + " " + str(army_num[2]))
    print()

# 対戦をする関数
def attack(own, own_num, enemy):
    os.system('clear')
    print(countries[own] + "          " + countries[enemy])
    print(army[own] + str(own_num) + "000人" + " 対 " + army[enemy] + str(army_num[enemy]) + "000人")
    print()

    number = own_num
    enemy_num = army_num[enemy]

    while(True):
        offence = rd.choice(attack_num)
        deffence = rd.choice(attack_num)

        if offence > deffence:
            enemy_num -= offence
            if enemy_num <= 0:
                print(army[own] + "  " + str(own_num*1000) + "人  X  " + army[enemy] + "  0人")
                break
            else:
                print(army[own] + "  " + str(own_num*1000) + "人  X  " + army[enemy] + "  " + str(enemy_num*1000) + "人")
        elif offence < deffence:
            own_num -= deffence
            if own_num <= 0:
                print(army[own] + "  0人  X  " + army[enemy] + "  " + str(enemy_num*1000) + "人")
                break
            else:
                print(army[own] + "  " + str(own_num*1000) + "人  X  " + army[enemy] + "  " + str(enemy_num*1000) + "人")
        else:
            print(army[own] + "  " + str(own_num*1000) + "人  X  " + army[enemy] + "  " + str(enemy_num*1000) + "人")
        
        input()

    if own_num > enemy_num:
        print()
        print(army[own] + "様　勝利！！")
        army[enemy] = army[own]
        army_num[enemy] = own_num
        army_num[own] -= number
    else:
        print()
        print(army[enemy] + "様　勝利！！")
        army_num[own] -= number
        army_num[enemy] = enemy_num
    input()


# メイン関数
while(True):
    for i in range(len(army)):
        Drawmap()
        print(countries[i] + "の" + army[i] + "様　どちらへ攻撃しますか？" + " (" + str(i+1) + "/" + str(len(army)) + ")")
        for j in range(len(army)):
            if not j == i:
                print(str(j) + " : " + countries[j] + "　" + army[j])
        print("3 : 温存")
        attack_counrty = int(input("攻撃する場所を入力 => "))

        if (attack_counrty == 0) or (attack_counrty == 1) or (attack_counrty == 2):
            at_num = int(input("何千人で攻撃しますか(1~9) => "))
            print()
            print(countries[i] + "の" + army[i] + "様が" + str(at_num) + "000人で" + countries[attack_counrty] + "の" + army[attack_counrty] + "様に攻撃！！")
            input()
            attack(i, at_num, attack_counrty)
        else:
            print()
            print("今年は兵力を温存するでござる")
            input()

    os.system('clear')
    print("兵力が回復しました。")
    for n in range(len(army)):
        army_num[n] += 1
    year += 1
    input()
```