【Ruby初心者向け】打順の組み方を変えて得点の入り方をシミュレーションして比較してみた

##概要
野球が好きなので、打順の最適な組み方をついつい考えてしまいます。

ある検証で**「強打者と弱い打者を交互に並べる」よりも「強打者を下位打線に固める」方が得点が入りやすい**という結果が出たというのを知り、単純化したモデルで検証してみようと思い試してみました。

**本格的な検証ではない**ので、Rubyを使って何か簡単な検証や計算を行ってみたいという人に大雑把な流れだけわかってもらえれば嬉しいです。

##前提条件

- 3割打者5人と２割打者4人の2タイプを用意
- 打者は凡打か単打のみを打つ
- 凡打においてランナーは進塁せず、３連打で１点が入る
- ３連打以上では安打のたびに１得点を追加
- エラーや四死球は簡略化のため考慮しない
- 盗塁や送りバントはセイバーメトリクスで推奨されないので行わない
- 1万試合回して合計得点を競う

この超簡略化した野球で2タイプの打者の打順を入れ替えて、どれだけ得点が入るかを検証します。ただ四死球と長打を全て排除するのはあまりにも酷なので、あとでそれらを考慮したコードも紹介していきます。

打順の組み方は

- 上位5人に３割打者を固める
- ３割打者と２割打者を交互におく
- ３割打者を5-9番の下位に固める

の３種類とします。
##変数を宣言
```baseball.rb
#1-9番の打者の打順を記録した配列
average=[0.3,0.3,0.3,0.3,0.3,0.2,0.2,0.2,0.2]

#合計得点
sumScore=0
#打席に立っている打者の打順
batter=1
#アウトカウント
outCount=0
#塁上のランナーの数
runner=0
#アウトカウント
iningCount=0
```
##1イニングを終わらせてみる
```baseball.rb
loop {
    hit = rand(1..100)
    hit = hit/100.0
    #乱数を使って単打か凡打を記録

    if hit <= average[batter-1]
      #走者を一人増やす
      runner+=1
      if runner>=3
        #走者が2人以上たまっていたらランナーを本塁に返す
        runner=2
        sumScore+=1
      end
    else
        #凡打なのでアウトカウントを増やすだけ
        outCount+=1
        if outCount == 3
            #３アウトチェンジしてループを抜ける
            runner=0
            outCount=0
            break
        end
     end
 #次のバッターに交代
 batter+=1
 #9番打者を打ち終わったら一番に戻る
 batter = (batter-1)%9 + 1
}

```

##1万試合を回してみる
1万試合なので90000イニング繰り返して、何点入るかを検証します。ただ９万回回すのではなく、９回が終わったら打順を1番に戻す処理を忘れないようにします。

```baseball.rb
90000.times {
  iningCount+=1
  loop {
    hit = rand(1..100)
    hit = hit/100.0
    #乱数を使って単打か凡打を記録

    if hit <= average[batter-1]
      #走者を一人増やす
      runner+=1
       if runner>=3
         #走者が2人以上たまっていたらランナーを本塁に返す
         runner=2
         sumScore+=1
       end
    else
        #凡打なのでアウトカウントを増やすだけ
        outCount+=1
        if outCount == 3
            #３アウトチェンジしてループを抜ける
            runner=0
            outCount=0
            break
        end
     end
    #次のバッターに交代
    batter+=1
    #9番打者を打ち終わったら一番に戻る
    batter = (batter-1)%9 + 1
   }

 if iningCount == 9 
    #９回が終了したらイニングと打順をリセットする
    iningCount=0
    batter=1
 end
}

##最後に合計得点を出力
puts sumScore
```

##結果
|打線の組み方|上位打線に強打者|下位打線に強打者|交互に並べる|
|:--:|:--:|:--:|:--:|
|1試合平均得点|1.57|1.52|1.50|

という結果になりました。ものすごく簡単な検証でしたが、**強打者は分散して配置するよりも、下位打線でも良いから連続させて打順を組む方が効果的**ということがわかります。

今回のルールでは連打が出ないと点が入らないので、チャンスでいかに打てるかが大事です。強打者が作ったチャンスを平凡な打者が潰してしまうのを減らすためには、強打者は集中させるのがいいという直感と合致しますね。

##おまけ　得点が少なすぎるので調整

上のルールにおける検証結果では強打者を上位に並べても1試合あたり1,2点しか入らないということになり、あまりにも少なすぎるので、もう少し実際の野球に近づけてみました。

近年の野球において特に重視されるのは、**出塁率と長打率**です。野球は27個のアウトを取られるまでは永遠に攻撃を続けられるスゴロクゲームと捉えることができます。

スゴロクに置いて重要なのは

- いかにアウトにならず塁に出られるか
- 長打によって一度にたくさん駒を進められるか

の２点です。実際の野球ではヒットでなくても四球で塁に出ることができますし、本塁打が出ればその時点で得点が入ります。

プロ野球で打率３割を残せるのはごく一部ですが、出塁率３割はレギュラークラスなら超えておかなければならない数字です。

##コードで本塁打と四球を反映させてみた

ここからは打線の組み方というよりも本物の野球の点の入り方に近づけることを目標とします。四球は単打と同じ扱いとし、全員の出塁率を一律に３割2分とします。３回に１回塁に出る計算になります。

また、出塁のうちの10本の1本はホームランが出て、ランナーを全員返すと仮定しましょう。（この辺りの仮定は実際のプロ野球のパリーグのデータを用いています）

```baseball.rb
#チーム全員の出塁率を宣言する
average=[0.32,0.32,0.32,0.32,0.32,0.32,0.32,0.32,0.32]

sumScore=0
batter=1
outCount=0
runner=0
iningCount=0

90000.times {
    iningCount+=1
     loop {
        hit = rand(1..100)
        hit = hit/100.0

        if hit <= average[batter-1]
            runner+=1
            if rand(1..10) == 1
                #１０回に一回はホームランが出て全員が帰りランナーを0に戻す
                sumScore+=runner
                runner=0
            elsif runner>=3
                runner=2
                sumScore+=1
            end
        else
            outCount+=1
            if outCount == 3
                runner=0
                outCount=0
                break
            end
        end
        
        batter+=1
        batter = (batter-1)%9 + 1
    }
    
    if iningCount == 9 
        iningCount=0
        batter=1
    end
    
}

puts sumScore
```

四球とホームランを考慮した結果、**１試合あたりの平均得点は4.4点**となりました。DH制を利用しているパリーグの昨年の平均得点が4.31点だったので、大雑把なモデルの割にはかなり近い感じになりました。

##まとめと展望
出塁率と長打率さえ調整すれば、実際の野球と近い平均得点を出せることがわかりました。ここからさらに実際の野球に近づけるには、以下のことをする必要があるでしょう。

- ホームランバッターを上位におく
- ３連続出塁で１点も入らない場合も想定する
- 打者の出塁率の差を考慮する
- 2塁打を考慮する（3塁打は少なすぎて誤差の範囲）

バント、盗塁はセイバーメトリクスでは推奨されていませんし、エラーも出塁と同値と考えて良いのかもしれません。コードが簡潔に保てる範囲内で色々試してみたいと思います。