Published Date : 2020年8月14日0:18

【Processing】長篠の戦いをコンピューターシュミレーション
[Processing] Computer simulation of the Battle of Nagashino


This blog has an English translation


YouTubeにアップした動画、「【Processing, プログラミング】長篠の戦いをコンピューターシュミレーション」の補足説明の記事です。

Here's a little more about the 「[Processing, programming] Computer simulation of the Battle of Nagashino」 video I uploaded to YouTube.

【Processing, プログラミング】長篠の戦いをコンピューターシュミレーション


目次

Table of Contents




① 戦いの概要
① Outline of the battle



長篠の戦いをProcessingでシュミレーションしてみましょう。

Let's simulate the Battle of Nagashino with Processing.

「長篠の戦い」については皆さん十分ご存知だと思いますので、

I think you know enough about [Battle of Nagashino].

設楽原(したらがはら)決戦の概要だけを30秒のアニメーションで説明した後にコンピューターシュミレーションに入ります。

After explaining only the outline of the Shitaragahara battle in a 30 second animation, we start computer simulation.

まず闇夜に紛れて決戦前夜に酒井忠次(さかい ただつぐ)と金森長近(かなもり ながちか)隊が、

First, in a dark night, Tadatsugu SAKAI and Nagachika KANAMORI troops left

長篠城を包囲監視している、鳶ヶ巣山砦(とびがすやまとりで)を奇襲(きしゅう)するために、

the main force of the Oda Tokugawa allied forces on the night before the battle.

織田徳川連合軍本隊を出発します。

This was to make a surprise attack from behind the fort on Mt. Tobigasu, which surrounded and monitored Nagashino Castle.

夜が明け、設楽原(したらがはら)で対峙した両軍は、

Day had broken and the two armies confronted each other at Shitaragahara,

午前十時頃に武田軍の左翼、山県昌景(やまがた まさかげ)が徳川軍に襲い掛かり、開戦します。

The battle broke out around 10 AM when the Masakage YAMAGATA, the left wing of Takeda's forces, attacked Tokugawa's forces.

この戦いは主に武田軍の両翼が、織田徳川連合軍の端を集中的に攻める展開が進みます。

In this battle, the two wings of the Takeda army mainly tried to attack the two wings of the Oda Tokugawa allied forces intensively.

開戦から数時間経過すると、前夜に奇襲に向かった酒井・金森隊が鳶ヶ巣山砦(とびがすやまとりで)の攻略に成功します。

A few hours after the start of the war, the Sakai and Kanamori corps succeeded in capturing the fort on Mt. Tobigasu and, together with soldiers who had been holed up in Nagashino Castle, defeated the remaining garrisons in an attempt to cut off Takeda's retreat.

武田軍両翼は織田徳川軍の一部の柵を倒し相手の前線に切り込むことができましたが、

Both wings of Takeda's army were able to break into the enemy's front line by defeating some of the fences of Oda Tokugawa's army.

穴山隊が独断で退却したことにより、全軍に動揺が走り、一気に形勢が悪化します。

Because the Anayama troop retreated on its own, the whole Takeda's army was shaken and the situation suddenly deteriorated.

長篠城を包囲していた武田の小山田隊が勝頼本陣を守るように陣を取り囲みます。

Oyamada troop of Takeda, who had been watching Nagashino Castle, surrounded the headquarters of Katsuyori to protect it.

これを見た織田徳川軍は一気に柵を飛び出し、次々と武田軍を駆逐していきます。

Seeing this, Oda Tokugawa's forces rushed out of their own fences and drove out Takeda's forces one after another.

激しい撤退戦の後、多くの武田軍の武将が打ち取られた後、最後は勝頼の退却を見届けた馬場信春(ばば のぶはる)が豊川のほとりで打ち取られます。

After a fierce retreat, many of Takeda's warlords were defeated, and in the end Nobuharu BABA, who had been defending Katsuyori's withdrawal, was eventually killed on the bank of the Toyo-gawa River, which runs through the valley.

以上が大多数の人が長篠の合戦を語るさいの説の概要です。

The above is the outline of the theory when most people talk about the Battle of Nagashino.




② プロセッシングコード
② Code with Processing



ではProcessingでコードを書いていきましょう。

Now let's write the code in Processing.

続いてシュミレーションのコードを書いていきます。

Next, We write the simulation code.

前回作ったランチェスターの法則のコードを再利用します。

We will reuse the Lanchester's Law code we made last time.

このコードのA軍とB軍を織田徳川軍と武田軍の各隊に分けるだけです。

The previous code, A army and B army, are just divided into Oda Tokugawa army and Takeda army.

//武田軍
//1馬場 信春
ArrayList<Heishi> Baba;
//2真田 信綱
ArrayList<Heishi> Sanada;
//3土屋 昌次
ArrayList<Heishi> Tuchiya;
//やや後ろ
//4穴山 信君(撤退戦前に撤退)
ArrayList<Heishi> Anayama;
//5武田勝頼
ArrayList<Heishi> Katsuyori;
//6一条 信竜
ArrayList<Heishi> Ichijyo;
//7武田信廉
//武田 信豊
ArrayList<Heishi> Nobukado;
ArrayList<Heishi> Nobutoyo;
//8小幡 信貞
ArrayList<Heishi> Obata;
//9内藤 昌豊
ArrayList<Heishi> Naito;
//10原 昌胤
ArrayList<Heishi> Hara;
//11山形 昌景
ArrayList<Heishi> Yamagata;
//小山田 信茂
ArrayList<Heishi> Oyamada;
//織田軍
//最前上から
//1水野 信元
ArrayList<Heishi> Mizuno;
//2福富・野々村
ArrayList<Heishi> FukuNono;
//3佐久間 信盛
ArrayList<Heishi> Sakuma;
//4丹羽 長秀
ArrayList<Heishi> Niwa;
//5羽柴 秀吉
ArrayList<Heishi> Hashiba;
//6滝川 一益
ArrayList<Heishi> Takigawa;
//7前田 利家
ArrayList<Heishi> Maeda;
//やや後ろ
//8織田 信長
ArrayList<Heishi> Nobunaga;
//9佐々 成政
ArrayList<Heishi> Sassa;
//10柴田 勝家
ArrayList<Heishi> Shibata;
//後ろ
//11織田 信忠
ArrayList<Heishi> Nobutada;
//12河尻 秀隆
ArrayList<Heishi> Kawajiri;
//13北畠 信雄
ArrayList<Heishi> Kitabata;
//徳川軍
//前線
//14石川 数正
ArrayList<Heishi> Ishikawa;
//15鳥居 元忠
ArrayList<Heishi> Torii;
//16本田 忠勝
ArrayList<Heishi> Honda;
//17榊原 康政
ArrayList<Heishi> Sakakibara;
//18大須賀 康高
ArrayList<Heishi> Osuga;
//19大久保 忠世
ArrayList<Heishi> Okubo;
//やや後ろ
//20徳川信康
ArrayList<Heishi> Tokugawanobu;
//21徳川家康
ArrayList<Heishi> Ieyasu;

そして地形が与える影響を係数にします。

Next, you adjust the influence of the terrain as a factor.

void caculateAShougaibutu(Heishi a) {
  float acx = a.coordinate.x;
  float acy = a.coordinate.y;
  if ((acx >= nc.leftW)&(nc.rightW+60 >= acx)) {
    aic *= 0.99;
    a.coeff = 0.02;
  } else if ((acx >= rg.leftW)&(rg.rightW+30 >= acx)) {
    aic *= 0.99;
    a.coeff = 0.02;
  } else if ((acx >= hr.hrLeft)&(hr.hrLeft+hr.hrW >= acx)) {
    aic *= 0.99;
    a.coeff = 0.02;
  } else if ((acx >= bs.bsFrontLeft)&(acx <= bs.bsFrontLeft+bs.bsW)) {
    for(float bsh : bs.bsFrontH){
      if((acy>=bsh)&(acy<=(bsh+bs.bsH))){
        aic *= 0.88;
        a.coeff = 0.02;
      }
    }
  } else if ((acx >= bs.bsBackLeft)&(bs.bsBackLeft+bs.bsW >= acx)) {
    for(float bsh : bs.bsBackH){
      if((acy>=bsh)&(acy<=(bsh+bs.bsH))){
        aic *= 0.88;
        a.coeff = 0.03;
      }
    }
  } else if ((acx >= dr.drFrontLeft)&(acx <= dr.drFrontLeft+dr.drW)) {
    println("hit droui front");
    for(float drh : dr.drFrontH){
      if((acy>=drh)&(acy<=(drh+dr.drH))){
        println("hit droui front");
        fill(255, 0, 0, 100);
        rect(dr.drFrontLeft, dr.drH, drh, dr.drH);
        aic *= 0.88;
        a.coeff = 0.04;
      }
    }
  } else if ((acx >= dr.drBackLeft)&(dr.drBackLeft+dr.drW >= acx)) {
    for(float drh : dr.drBackH){
      if((acy>=drh)&(acy<=(drh+dr.drH))){
        aic *= 0.88;
        a.coeff = 0.04;
      }
    }
  } else {
    aic = initAic;
    a.coeff = initPerformanceA;
  }
}

もっと複雑にしたかったのですが、今回はシンプルに、移動速度と攻撃力の変化ぐらいです。

I wanted to make it more complicated, but this time it's just a simple change in speed and attack power.

影響を与える地形は丘とぬかるんだ土地、連吾川と堀、柵とその奥の土塁とさらにまた丘や山です。

The terrain that affects the soldiers is hills and muddy land, the Rengo River and moats, fences and the earthworks behind them, and also hills and mountains.

そして、オブジェクト単体で飛び道具が打てるようにします。

Then, it represents the long-distance attacks launched by each object.

連続して弓矢と鉄砲が打てるようにすると、

Of course, if you make it possible to shoot an arrow and a gun infinitely in succession,

ノルマンディー上陸作戦のような弾丸の数であっという間に終了します。

It will finish in no time with an impossible number of bullets.

なので鉄砲は信長軍に鉄砲1000丁、武田軍に300丁あったと仮定して各隊に割合を決めて振り分けました。

weapons = new StringList();
weapons.append("bear hand");
weapons.append("knife");
weapons.append("stone");
if (random(0, 100) < teppowariai) {
  weapons.append("gun");
} else {
  weapons.append("spear");
}

So, we decided the ratio of firearms and distributed them to each unit, assuming that Nobunaga's army had 1000 firearms and Takeda's army had 300.

鉄砲の弾と弓矢の弓の数等も弾数に制限をかけ、さらに鉄砲は一人あたり約30秒程度再度打てるまでの間隔を設けます。

The number of bullets in a firearm and the number of bows in a bow and an arrow are also limited, and in addition, a teppo has an interval of about 30 seconds until a person can hit the teppo again.

最初は武田軍左翼、山形隊VS徳川軍右翼、大久保隊あたりの戦いからパラメーターを調整していきます。

First, we will adjust the parameters from the battles between the left wing of Takeda's forces and the right wing of Tokugawa's forces.

ダメージが一定数下がれば退き、体力回復(治療や補給)をするようにします。

If a soldier receives a certain number of damages, he will withdraw and recover his physical strength.

当時の合戦時の動きを再現したいため、それぞれの小隊オブジェクトがバラバラに動けるようにKeyPressed関数を利用します。

To reproduce the movement of the battle at that time, we use the KeyPressed function so that each unit object can move separately.

void keyPressed(){
  if (keyCode==ENTER) {
    init();
    loop(); 
  }
  if (keyCode==TAB){
    for (int i = Baba.size() - 1; i >= 0; i--) {
      Baba.get(i).stepX = 2.0;
    }
    for (int i = Sanada.size() - 1; i >= 0; i--) {
      Sanada.get(i).stepX = 2.0;
    }
 //for (int i = Anayama.size() - 1; i >= 0; i--) {
 // Anayama.get(i).stepX = 3.0;
 //}
    for (int i = Tuchiya.size() - 1; i >= 0; i--) {
      Tuchiya.get(i).stepX = 2.0;
    }
 //for (int i = Katsuyori.size() - 1; i >= 0; i--) {
 // Katsuyori.get(i).stepX = 3.0;
 //}
    for (int i = Ichijyo.size() - 1; i >= 0; i--) {
      Ichijyo.get(i).stepX = 1.0;
    }
 //for (int i = Nobutoyo.size() - 1; i >= 0; i--) {
 // Nobutoyo.get(i).stepX = 3.0;
 //}
 //for (int i = Nobukado.size() - 1; i >= 0; i--) {
 // Nobukado.get(i).stepX = 3.0;
 //}
    for (int i = Obata.size() - 1; i >= 0; i--) {
      Obata.get(i).stepX = 1.0;
    }
    for (int i = Naito.size() - 1; i >= 0; i--) {
      Naito.get(i).stepX = 2.0;
    }
    for (int i = Hara.size() - 1; i >= 0; i--) {
      Hara.get(i).stepX = 2.0;
    }
    for (int i = Yamagata.size() - 1; i >= 0; i--) {
      Yamagata.get(i).stepX = 2.0;
    }
 //for (int i = Oyamada.size() - 1; i >= 0; i--) {
 // Oyamada.get(i).stepX = 3.0;
 //}
  }
  if(key=='Y'){
      for (int i = Yamagata.size() - 1; i >= 0; i--) {
        Yamagata.get(i).stepX = 2.0;
      }
  } 
  if(key=='y') {
      for (int i = Yamagata.size() - 1; i >= 0; i--) {
        Yamagata.get(i).stepX = -2.0;
      }
  }
  if(key=='u') {
      for (int i = Yamagata.size() - 1; i >= 0; i--) {
        Yamagata.get(i).stepX = 0.0;
      }
  }
  if(key=='H'){
      for (int i = Hara.size() - 1; i >= 0; i--) {
        Hara.get(i).stepX = 2.0;
      }
  } 
  if(key=='h') {
      for (int i = Hara.size() - 1; i >= 0; i--) {
        Hara.get(i).stepX = -2.0;
      }
  }
  if(key=='U') {
      for (int i = Hara.size() - 1; i >= 0; i--) {
        Hara.get(i).stepX = 0.0;
      }
  }
  if(key=='B'){
      for (int i = Baba.size() - 1; i >= 0; i--) {
        Baba.get(i).stepX = 2.0;
      }
  } 
  if(key=='b') {
      for (int i = Baba.size() - 1; i >= 0; i--) {
        Baba.get(i).stepX = -2.0;
      }
  }
  if(key=='g') {
      for (int i = Baba.size() - 1; i >= 0; i--) {
        Baba.get(i).stepX = 0.0;
      }
  }
  if(key=='S'){
      for (int i = Sanada.size() - 1; i >= 0; i--) {
        Sanada.get(i).stepX = 2.0;
      }
  } 
  if(key=='s') {
      for (int i = Sanada.size() - 1; i >= 0; i--) {
        Sanada.get(i).stepX = -2.0;
      }
  }
  if(key=='G') {
      for (int i = Sanada.size() - 1; i >= 0; i--) {
        Sanada.get(i).stepX = 0.0;
      }
  }
  if(key=='T'){
      for (int i = Tuchiya.size() - 1; i >= 0; i--) {
        Tuchiya.get(i).stepX = 2.0;
      }
  } 
  if(key=='t') {
      for (int i = Tuchiya.size() - 1; i >= 0; i--) {
        Tuchiya.get(i).stepX = -2.0;
      }
  }
  if(key=='r') {
      for (int i = Tuchiya.size() - 1; i >= 0; i--) {
        Tuchiya.get(i).stepX = 0.0;
      }
  }
  if(key=='N'){
      for (int i = Naito.size() - 1; i >= 0; i--) {
        Naito.get(i).stepX = 2.0;
      }
  } 
  if(key=='n') {
      for (int i = Naito.size() - 1; i >= 0; i--) {
        Naito.get(i).stepX = -2.0;
      }
  }
  if(key=='R') {
      for (int i = Naito.size() - 1; i >= 0; i--) {
        Naito.get(i).stepX = 0.0;
      }
  }
  if(key=='O'){
      for (int i = Obata.size() - 1; i >= 0; i--) {
        Obata.get(i).stepX = 2.0;
      }
  } 
  if(key=='o') {
      for (int i = Obata.size() - 1; i >= 0; i--) {
        Obata.get(i).stepX = -2.0;
      }
  }
  if(key=='p') {
      for (int i = Obata.size() - 1; i >= 0; i--) {
        Obata.get(i).stepX = 0.0;
      }
  }
  if(key=='I'){
      for (int i = Ichijyo.size() - 1; i >= 0; i--) {
        Ichijyo.get(i).stepX = 2.0;
      }
  } 
  if(key=='i') {
      for (int i = Ichijyo.size() - 1; i >= 0; i--) {
        Ichijyo.get(i).stepX = -2.0;
      }
  }
  if(key=='P') {
      for (int i = Ichijyo.size() - 1; i >= 0; i--) {
        Ichijyo.get(i).stepX = 0.0;
      }
  }
}

ちなみに、最初は織田徳川軍38000人対武田軍12000人にしてましたが、あまりにも計算処理が重くまともに動かないので、それぞれ10分の一にしました。

For your information, at first I had the Oda Tokugawa army had 38000 soldiers against the Takeda army had 12000, but the calculation process was too heavy and it didn't work properly, so I made it 1/10 each.

ただし兵数の比率は同じでなければなりません。

However, the ratio of the number of soldiers must be the same.

全軍撤退の条件は、死亡重症等の戦闘不能者が全軍の1割から2割に達することです。

When 10% to 20% of the soldiers become incapable of fighting because of death or serious severely injured, the army retreats.

これは戦国時代の平均的な数値です。

This is the average figure of the Warring States period.

つまり武田軍であれば12000人の1割は1200人程度でしょうか。

In other words, 10% of the 12000 soldiers of the Takeda army is about 1200.

実際もこれぐらいの数で撤退を始めたはずです。

In fact, they must have started withdrawing in this number.

そして撤退戦に入るとさらに戦闘不能者が増えます。

And when the withdrawal battle started, the number of deaths increased.

地形が悪い、戦術にはまる等、撤退が上手くできなくなるような撤退戦では大体3倍から5倍ほどの戦闘不能者が増えるそうです。

It is said that the number of casualties increases by 3 to 5 times compared to the number before the withdrawal in the case of the withdrawal battle in which the withdrawal is difficult due to bad terrain, tactics, etc.

さて、シュミレーションですが、ご覧の通り、武田側はいくら頑張っても勝機はありません。

As for the simulation, as you can see, there is no chance for Takeda army to win no matter how hard they try.

お互い同じ性能の武器を持っているのですから、数が多い上に野城(やじろ)を築城してしまったほうがはるかに有利なのです。

Since both armies have weapons of the same performance, it is much more advantageous to build a field castle with a large number of soldiers and weapons.

城攻めには相手の兵の3倍の兵が必要と言われています。

It is said that 3 times more soldiers than the enemy are needed to attack the castle.

それを考えると武田軍1万2千人は織田徳川軍38000人に勝つためには9倍の10万人以上の兵士が必要になる計算です。

Considering that, more than 100,000 soldiers, which is nine times as many as Takeda's 12000 soldiers, are needed to beat Oda and Tokugawa's 38000 soldiers.

そうなると、信長軍と同じクオリティの野戦築城さえできれば、徳川軍8000人だけでも勝てた可能性が高いです。

In that case, if we could build a field castle with the same quality as Nobunaga's, it is highly possible that even Tokugawa's 8000 soldiers could have won.

ただ野戦築城技術とそこに誘い込む戦略あっての勝利なので、結局信長軍と信長がいてこそのこの戦の勝利があります。

However, it was a victory based on the skills of field fortification and the strategy to lure them, so in the end, the victory of this war can be achieved only with Nobunaga's army and Nobunaga.

あと忘れてはならないのは武田軍は10日間もの間長篠城を攻撃し続けてます。

Also, keep in mind that Takeda's forces have been attacking Nagashino Castle for 10 days.

さらに武田軍は長篠城が穴だらけだったと言われるほど鉄砲を打ちまくったそうです。

In addition, the Takeda army fired so many bullets of guns that it was said that Nagashino Castle was covered with holes.

おそらく食料も武器の弾薬も殆ど無い状態だったに違いありません。

There must have been very little food or ammunition.

(もしかしたら頻繁に甲斐本国から補給をしていた可能性もあります。距離的にみても一週間もあれば本国からの物資は届くはずです。)

(There is a possibility that they were replenishing from Kai province frequently. In terms of distance, goods from home country should arrive in a week.)

そのため、いくら強者ぞろいの武田軍といえどかなり疲弊していて、本戦ではあまり力が出なかったのではないでしょうか。

For this reason, even Takeda's army, which was composed of many strong soldiers, must have been exhausted and did not show much strength in the main battle.

ですが、地形と奇襲をうまく活用して武田軍を自分達のフィールドに誘いこんだ織田徳川軍の戦略勝ちですね。

However, it was a strategic victory of the Oda Tokugawa army which invited the Takeda army to their field by making good use of the topography and surprise attack.

まあ色々とこの戦いについて言われていますが、織田徳川軍の戦いの最大の勝因は単純に武器も弾薬も食料も人数も武田軍より圧倒的に多かったからでしょう。

Well, There are various theories about this battle, but the biggest factor in the battle of the Oda Tokugawa army was that the number of arms, ammunition, army provisions, and soldiers was overwhelmingly larger than that of the Takeda army.



以上です。お疲れ様です。

That's all. Thank you for your hard work.

もっとパラメーターを増やしても面白いかもしれません。

It might be interesting to add more parameters.

それでは色々と工夫と改良を行って楽しんでみてください。

Then, please enjoy it with various ideas and improvements.

追記:全コードは行数とクラスファイルが多く、ごちゃごちゃしてるので、まとめてからGithubに公開します。

Note: The entire code is messy with lines and class files, so I'll put it all together and post it on Github.





See You Next Page!