Pythonによる『三国志大戦』の実装(1)


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

目次

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

1. 作成の経緯

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

2. 作成手順

1. キャラクター設定

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

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

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

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

2. 画面(地図の描画)

続けて地図を描画します。今回は何度も地図を呼び出すため関数にしています。

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. 攻撃する場所・攻撃人数の入力

続けてどこに攻撃するか、何人で攻撃するのかを入力します。

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("攻撃する場所を入力 => "))

こちらでは、長安に攻撃→0、建業に攻撃→1、成都に攻撃→2、兵力を温存→3、を入力することができます。

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

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人ずつ減るように指定しました。初期化で、

sangoku.py
attack_num = [0, 1]

を指定しました。randomのchoiceを使って、どちらかを選択して人数が減るようになっています。
攻撃全体のコードはこちらです。

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. 作成したコード

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()