360°回転砲台のアルゴリズム


1944年 4号戦車J型
第二次世界大戦末期になるとドイツ軍の主力戦車はティーガーやパンター等の強力な戦車へ移行し、それまでの主力だった4号戦車は非力な存在になってしまった。しかし貧しい国力で高価なティーガーを大量生産できるわけもなく、また敵の主力であるT34やシャーマンにはそれなりに対抗できたので、4号戦車は終戦までドイツ軍を支える大事な軍馬であった。
そこで最新型であったH型を元に、コストを抑えた簡易モデルである4号戦車J型が生産されることになった。しかしコスト削減のため砲塔旋回用のエンジンまで設計図から削除されてしまい、砲塔を回転させるため乗員はひたすら手動ハンドルを回し続けなければならないという、乗組員にとっては悪夢の戦車が前線に送られることになったのであった。


戦場において敵は360°どこから攻撃してくるか分からない、1秒でも早く砲塔を回転させ敵を撃破しなければこちらがやられてしまう。
まず、目視で10時の方向にT34がが現れた。あなたは必死にハンドルを回して10時の方向に砲塔を向け敵よりも先に砲撃を喰らわせこれを撃破することに成功した。移動していて視界が悪いT34に対しては簡単に先制攻撃を行うことができたのだ。
しかしその直後クレインハイム師団長より無線連絡がはいる「5時の方角より新手のT34接近中」。あなたはまた必死になってハンドルを回さなければならなくなった。

問題は、あなたが右回り、左回りのどちらの方向にまわしたのかということである。

左回りで回したあなたはぎりぎりで出現した2台目のT34を撃破することに成功する。
右回りで回したあなたは砲塔が回転し終わる前に攻撃を食らってしまい戦死する。


要約すると、車体方向(進行方向)を0時として、10時の方角に砲塔があるとすると、5時の方角に砲塔を回す場合左回り(反時計)で回せば最短である。

ちなみにこれはシューティングゲーム等で敵の砲台が自機の方向を向こうとする時の状況に当てはまる。もしくは旋回する船やホーミングミサイル等々。
しかし、人間だったら感覚で分かってしまうこのこの角度の移動量を、式で表すとなると頭を悩ましてしまう。通常の−+(左回り右回り)以外にも、0時をまたいだ状態での移動が発生するからだ。結局解らなかったのでkench氏と相談の末導き出した式が以下である。

to 目的角度
now 現在角度
add 求める移動角度

add = to - now;
if(add < 0)
    add = add + 12;
if(add > 6)
    add = add - 12;



ラジアンで表記するなら

add = to - now;
if(add < 0)
    add = add + 2π;
if(add > π)
    add = add - 2π

こうなる。
しかしこれだけの式にif文を2個も使わないと駄目なんだろうか?



追記 

grassさんの書き込みより

ところで回転砲台のアルゴリズムですが自分なりに考えてみました。
始めに考えたのは求める移動範囲はー6〜6なので

add = (to - now + 6)%12 - 6;

つまり6を加減算することでmodで限定する範囲をずらしているわけですが・・・
差がー6より小さいと厄介なことになりそうですね・・・。
そこで一工夫して・・・

add = (to - now + 18)%12 - 6;

こうすれば括弧内の値が必ず正になるので問題ないかと思います・・・。


なるほど、12で剰余することを前提に+18にすることで正規化も兼ねているんですね。

ラジアンで書くと
add = (to - now + 3π) % 2π - π

度数法では
add = (to - now + 560) % 360 - 180

Cで書くと
add = fmod((to - now + 3pi), 2pi) - pi;

剰余が入ってるのでifよりスピードは落ちる気がするのですが、1行で書けるのでエレガントです。






4号戦車J型 諸元
Panzerkampfwagen IV
生産台数: 1758両(1944年6月〜1945年3月)
主兵装 48口径7.5cm40式戦車砲
副兵装 7.92mm機関銃MG34×2

参考
ハンスの帰還(泥まみれの虎より)