こちらはみゅーもり Advent Calendar 2018の21日目の記事になります.
https://adventar.org/calendars/3429
21日目ということで, 21点をとると1セットとれるルールのスポーツ, バドミントンを題材にします.
【ABSTRACT】
バドミントンは瞬間瞬間でリスクコントロールをしていく一面のあるスポーツである. そのリスクコントロールの一面に注目してモデル化を行い, シミュレーションによってショットの選択戦略を評価した. リスキーなショットはリスクに見合う効果が無いのならば打たない方が良いということと, 相応の効果がある場合は攻め時と守り時でリスクコントロールをしていくと良いということが確認できた.
【OBJECTIVE】
モチベーション
この記事を書くモチベーションは二つある.
一つは, バドミントンをあまりよく知らない人に, バドミントンの奥深さを知ってもらうことである. 今年はバドミントンの知名度が大きく上がった1年になったように思える。世界選手権で日本男子初の金メダルを獲得した桃田選手を初め、数多くの日本人選手が活躍した.『はねバド!』というバドミントン部の高校生が主役のアニメも放映された. これらをきっかけにバドミントンに少しでも興味を持った人に, もう少しバドミントンをよく知ってもらいたいという気持ちがある.
以下は男子ダブルスのラリーの動画である.
https://www.youtube.com/watch?v=PCO23zl9vaA
このような素早いラリー(スマッシュの初速のギネス記録は493km/hなんだとか)の中で, プレイヤーが意識的に・無意識に、緩急やコースの打ち分け,ショットの種類について, 戦略を立て予測・判断してプレーしている. このことが分かると観戦するときの楽しみ方が増えるかもしれない.
もう一つは, バドミントンの中級者に上がりたい初級者に, リスクコントロールの大切さを伝えることである. バドミントンを始めて一通りのショットが打てるようになると, スマッシュなど一見,強いショットをたくさん打ちたくなる. 体勢が悪いところからでもそのようなショットを打ってしまいたくなる. 決まると楽しいからである.しかしながら, そのようなショットは得てして成功率が低く, 多用してばかりいると試合でなかなか勝てない. そんな初級者に, 私が先輩に教わったり, 『ベイビーステップ』や, もこう先生の厨ポケ狩り講座, 遊戯王などから学んだリスクコントロールの面白さ, 強さを伝えたい. 良い体勢からは有効打が打ちやすいし, 悪い体勢からは打ちにくい. 悪い体勢で有効打が打てないわけではないが成功する確率は当然低くなる. このへんのショット選択の駆け引きやリスクコントロールが, 勝敗の鍵を握っている. このリスクコントロール術は自分より格下の相手に負けにくくすることであると同時に, 自分より格上の相手に勝つ可能性を高めることでもある. 直感的にやっていって言語化してしにくいことを, 人に分かりやすく示すためにシミュレーションで確認する.
ルールの紹介とモデルのための簡単化
分からない人のためにも, 現行のバドミントンのルールの確認を行う. サービスを打ってラリーが始まると, 自分の打ったシャトルが相手のコートの中に落ちるか, 相手の打ったシャトルが自分のコートの外に落ちたら, 得点が1点入る. 得点をとったプレイヤーが次のサービスを打つ. ラリーを繰り返し, 21点を先にとった方が1ゲームを取ることができる. 20-20となった場合はそれ以降,点差が2点になるか,どちらかが30点をとるまでゲームが続く. 2ゲーム先取でその試合の勝者になる. シミュレーションでは簡単化のため, デュースはルールに入れず21点を先取したら1ゲーム取れることにしている. さらに, 1ゲーム取れば勝ちとする.
【METHODS】
モデルのセッティング
バドミントンのリスクコントロールの要素の側面を抽出したモデルによって, シミュレーションを行う.
一番基本的なモデルのイメージは以下のようなものである. 1ラリーの流れを示している.
まず, player1がサービスを打つ. このときsafety shotかrisky shotを選ぶ. safety shotは成功率が0.9と高いが, 次の相手のshotの成功率に影響を与えない(reffect=0). 一方, risky shotは成功率が0.7と低いが, 次の相手のshotの成功率を0.2低下させる(reffect=0.2). つまりリスクはあるが, 効果のあるshotということだ. shotを選んだら, 判定のフェイズに入る. 成功率 - reffect でshotが成功する(サービス時点では, 相手のshotに依存しないのでreffect=0). 成功したら, player0の手番になり, 同じことを行う. 失敗したら, player0の得点となり, 次は得点したplayer0のサービスでラリーが始まる. (念のために述べておくが, 現実では審判がシャトルのジャッジをするのは地面に落ちたときのみである.) このラリーをどちらかが21点とるまで繰り返すのが1ゲームである. 以下のコードがそれを実行するコードである.
#### strategy functionの定義(戦略関数は別で用意して読み込む) ####
source("strategy.R")
#### playerの戦略関数の決定 ####
list_fstr #戦略関数リストから選択
fstr1 <- fstr_allsafety
fstr0 <- fstr_allrisky
#### game result 変数の初期値 ####
vcrally <- c() #rally count vector
p1point <- 0 #player1のポイント
p0point <- 0 #player0のポイント
player <- 1 #first serverはplayer1
#### rallyの定義とgameの定義 ####
#rallyをjudge==0になるまでのwhileループとする.
#gameをどちらかのplayerのpointが21になるまでのwhileループとする.
while(p1point < 21 & p0point < 21){
#ラリー前に初期化する
judge <- 1 #shotの成功失敗の判定(1=>成功,0=>失敗)
shot <- 0 #ラリー最初のサーブは成功率へのeffectは0なので相手のshotはsafetyとみなす.
crally <- 0 #rally count
while(judge==1){
#手番のplayerの戦略関数をfstrに代入
fstr <- ifelse(player==1,fstr1,fstr0)
#相手のshotからeffectを決定(ここではrisky shotの効果を0.2としている)
effect <- ifelse(shot==0, 0, 0.2)
#自分のshotの決定
shot <- fstr(shot)
prob <- ifelse(shot==0, 0.9-effect, 0.7-effect)
#shotの成功判定
judge <- ifelse(runif(1)<prob, 1, 0)
#手番playerの交代
player <- ifelse(player==1, 0, 1)
#rally count追加
crally <- crally + 1
}
#ラリーカウントベクトルの更新
vcrally <- c(vcrally, crally)
#ポイントの更新
if(player==1){
p1point <- p1point + 1
}else{p0point <- p0point + 1}
}
#試合結果(ラリー数平均,ラリー数分散,最大ラリー数p1point,p0point,gamewinplayer)
vresult<- c(mean(vcrally),var(vcrally),max(vcrally),p1point,p0point,ifelse(p1point>p0point,1,0))
これで, 最も基本的なモデルによる1ゲームが定義された. (strategy.Rは戦略関数を定義している. これについては次に中身を説明し, 別記事でコードを掲載する.) ゲームを10000回繰り返すことで各戦略の勝率(ゲーム取得率)を計算していく. 上のモデルでは, player1もplayer0も同じ能力を持っている. shotの成功率とreffectの大きさが同じである.
準備した戦略
戦略関数は一つ前の相手のshotを入力してsafety shotを打つかrisky shotを打つかを返す関数である(サービス時点では一つ前の相手のshotはsafetyと定義している.). 今回は, 以下の6種類を用意している.
## [1] "fstr_allsafety" "fstr_allrisky" "fstr_tit4tat"
## [4] "fstr_tit4tat_inv" "fstr_trigger" "fstr_random"
- fstr_allsafety: 相手が何を打ってこようとsafety shotを打つ戦略. safety戦略と呼ぶ.
- fstr_allrisky: 相手が何を打ってこようとrisky shotを打つ戦略. risky戦略と呼ぶ.
- fstr_tit4tat: 一つ前の相手の打ってきたshotと同じshotで返す戦略. いわゆる, しっぺ返し戦略.
- fstr_tit4tat_inv: 一つ前の相手の打ってきたshotと違うshotで返す戦略. 逆しっぺ返し戦略または天邪鬼戦略と呼ぶ.
- fstr_trigger: 一度相手がrisky shotを打ってきたら, こちらはずっとrisky shotを打ち続ける戦略. いわゆる, トリガー戦略.
- fstr_random: 相手が何を打ってこようと確率0.5でsafety, 確率0.5でriskyを選択する戦略. ランダム戦略と呼ぶ.
【RESULTS】
基本モデル(reffect=0.2の場合)
・safety vs safety
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.5016 10.0062 90.1300 18.5416 18.5224
## [1] 113
player1の勝率は 0.5016なので, 互角の勝負をしている. 互いにsafetyな戦略で戦っているのでラリー回数の平均は 10.0062 回, 最大ラリー回数は113回と長いラリーを続けている. ちなみに、2013年の世界選手権大会で, ラリー数108打の2分も続いたラリーがあった. 詳しくは以下の記事と動画を見てほしい.
・risky vs risky
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.4996 2.3988 2.2404 18.5287 18.5728
## [1] 19
player1の勝率は0.4996なので, 互角の勝負をしている. 互いにriskyな戦略で戦っているのでラリー回数の平均は2.3988回, 最大ラリー回数は19回と, safety vs safetyより断然短いラリーで終わっていることが分かる.
・safety vs risky
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.7746 3.7063 8.0190 20.1195 16.1272
## [1] 35
player1の勝率は0.7746であり, risky戦略の分の悪さが露骨に出ている. 現実でも, やはり相手が勝手にミスってくれると戦っていて楽である. ただし, この結果はrisky shotの成功率を下げる効果が0.2とあまり強くない(risky shotとsafety shotの成功率の差分と等しい)のが原因である. 後でこの効果をいじって, リベンジマッチを行う.
以降, player1にはランダム戦略のみで戦ってもらい, player0に他の戦略で戦ってもらって, 様子を見てみる.
・ランダム vs safety
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.2888 5.4007 21.6333 16.7775 19.8119
## [1] 62
player1の勝率は0.2888である. このセッティングではsafetyが圧倒的に強く,safetyには勝てない.
・ランダム vs risky
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.6191 2.9211 4.1788 19.2997 17.6817
## [1] 29
player1の勝率は0.6191である. やはり,このセッティングにおけるrisky戦略の弱さがうかがえる.
・ランダム vs しっぺ返し
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.4961 4.2780 10.7494 18.4860 18.5934
## [1] 40
player1の勝率は0.4961である. ほぼ互角の戦いをしている.
・ランダム vs 天邪鬼
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.5062 3.3518 7.2292 18.6457 18.5635
## [1] 35
player1の勝率は0.5062である. ほぼ互角であることが分かる.
・ランダム vs トリガー
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.495 4.278 10.731 18.532 18.526
## [1] 47
player1の勝率は0.495である. これまた,ほぼ互角か.
以上のシミュレーションではsafety shotを打ち続けるのが支配的な戦略となっている. これは, risky shotの効果がそのリスクに見合うものでなかったからだと分かる. したがって, 以下ではrisky shotの効果を上昇させて, safetyとriskyが釣り合うようにして, 戦略の強さを確認していく.
リベンジモデル(reffect=0.284の場合)
・リベンジ safety vs risky
safety vs riskyで, risky戦略は分の悪い結果となったが, risky shotの効果を0.2から0.284まで強化してみる.
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.5057 3.3521 5.8394 18.6062 18.5297
## [1] 30
player1の勝率は0.5057であり, 互角の勝負となっている. これでsafetyとriskyが釣り合った状態になった. これ以上, risky shotの効果を高めるとrisky shotが支配的な戦略となってしまうので, risky shotの効果を0.284にして他の戦略を見ていく.
・リベンジ ランダム vs しっぺ返し
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.5995 3.9948 8.7118 19.1948 17.7721
## [1] 39
player1の勝率は0.5995である. しっぺ返し戦略の方が分が悪いことが分かる. これは相手のrisky shotに対してrisky shotで挑んでしまうため, 相手のrisky shotが成功した場合, ミスしやすいという状況に陥ってしまう一方で, 相手がsafety shotを打っていても, こちらはrisky shotで攻めないため, 相手の安定性を崩せていないという解釈ができる.
・リベンジ ランダム vs 天邪鬼
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.4062 3.0051 5.0159 17.8443 19.1606
## [1] 29
player1の勝率は0.4062である. 天邪鬼戦略の方が強いことが分かる. これは相手のrisky shotが成功したら, safety shotで安全に返し, 相手がsafety shotを打って来たら, risky shotで攻めに行ってるのが功を奏しているのだろう. 攻め時と守り時のリスクコントロールがよくできていると解釈できる.
・リベンジ ランダム vs トリガー
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.6063 3.9975 8.7577 19.2244 17.7147
## [1] 39
player1の勝率は0.6063である. しっぺ返し戦略同様分が悪い. 解釈も同様である.
1ゲーム21点先取でない場合
現行のルールでは1ゲーム21点先取となっているのだが, 11点先取のルールが新ルールとして,今年提案されていたのだが,この案は却下された.11点だった場合,1ゲームを先取する場合,最適なリスクコントロール戦略は変わってくるだろう.おそらく,よりリスキーな戦略の方が有効になるのではないだろうか.
・11点制 リベンジ safety vs risky
risky shotの効果を0.284まで強化した状態で, safety戦略とrisky戦略で戦わせてみる. 予想では, risky戦略の方が勝率が高くなるのではないだろうか.
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.4982 3.3655 5.8964 9.2070 9.2109
## [1] 30
player1の勝率は0.4982であり, 予想と異なり, 21点のときと結果は変わっていない.
・271点制 リベンジ safety vs risky
逆に, 21点制より多い271点制を試してみる.
上段はplayer1の勝率, ラリー回数の平均と分散, player1の平均得点, player2の平均得点であり, 下段はラリー回数の最大値である.
## winp mean var p1point p2point
## 0.5105 3.3345 5.7968 262.5071 261.8643
## [1] 35
player1の勝率は0.5105であり, これまた, 21点のときと結果は変わらない.
以上, 実験してみたように, このセッティングでは, 点数の制度を変更しても勝率(ゲーム取得率)はあまり変わらなかった.
【CONCLUSIONS】
得られた結論
リスキーなショットは, リスクを背負うだけの強さがない限り(今回で言えば,reffectが0.2のケース)は使うべきでないことがよく分かった. 以下の動画のように, 上手く決まれば効果は絶大だが, 成功確率がそれに見合わないなら多用しない方が良いのである.
https://www.youtube.com/watch?v=eX9r9lTEbqw
一方でリスキーなショットにそれなりの効果がある場合(今回で言えば,reffectが0.284のケース)は, 天邪鬼戦略のように, 相手のリスキーなショットには安全なショットで守り, 相手の安全なショットにはリスキーなショットで攻めてリスクをコントロールするのが有効な戦略であることが確認された。
あることを失敗したら相手の得点になるという要素が濃いスポーツでは、このような戦略が最適になるのではないだろうか。逆に、あることを成功したら自分の得点になるという要素が濃いスポーツもある. この2つの要素の濃淡でリスク管理の質が変わってくると予想される.
バドミントンは相手のコートに返球し続ければ理論上負けない競技である. どんなに素晴らしいショットを打とうが芸術点は入らないので, 得点したとしても1点は1点であり, 自分からミスをして失点すると負ける競技なのである. だからといって, リスキーなショットが不要かというとそうではない. 相手にミスらせないと勝てないのである. 相手がミスをしないのならば, リスキーなショットを混ぜ合わせて得点しにいかないといけない. ミスを減らしたうえで そのような駆け引きができるようになるとバドミントンの強さが上がっていく. リスキーなショットは決まると楽しいので, つい使ってしまいがちだが, 強さを求めるのならば, リスキーなショットの使いどころは考えた方が良いだろう. ただし, 全く使わないのではなく, 有効な場面で使うことが重要である. また, 日々練習を繰り返し, 各ショットの成功率を上げることと, ショットの効果を高めることが重要である.
モデルの拡張可能性
戦略関数やモデルの設定を変更すれば容易に拡張可能である. 現在のモデルでは, 一つ前の相手のshotのみ記憶していて, それに対して反応を決めることしかできない. 一つ前相手のショットのみ記憶できるが、ショットの割合の記憶(最初は平坦な事前分布にしてベイズの公式で更新していく)するケースやショットの履歴を完全記憶できるケースに拡張でき, もっと複雑な戦略関数でシミュレーションすることができる. 現実のところは覚えているのはだいたいの割合だろう. 割合から予測を立てている気がする. 逆にそれを考えたうえで, 勝負をかけたいところで今まで打っていなかったshotを打つこともある. 割合を用いた戦略を立てるモデルにすれば, より現実に近いシミュレーションができるかもしれない.
戦略関数や高速化について
別の記事に用意した。
【Acknowledgments】
人生初のAdvent Calendar参加でした. カレンダーの企画者のみゅーもり様, 共に参加している皆様, そしてここまで読んで下さった読者の皆様, ありがとうございました. ドンドンドーナツどーんと行こう!