時々、
ネットの麻雀ゲームとかしたりしますが、
手牌の向聴(シャンテン)数とか表示されたりするのを、
ただ眺めてたりしていました。
ちなみに、
向聴数とは聴牌(テンパイ)するまでに必要な最小のツモの回数
ということで良いかと思います。
まぁ、そう運良く有効牌を引けたりするわけではないので、
5向聴とか表示されたりすると、
「やれやれ」な感じになります(^_^;)
さて、
ある時ふと、向聴数を計算するために
プログラム的にはどうやれば良いのかな?
と思案してみたら、
思いの外、難しいことに気が付きました。
いわゆる4面子1雀頭な形の場合、
どれを雀頭にし、どれを面子とするかは、
様々な組み合わせが考えられる場合があり、
プログラムでやろうとすると
なかなか一筋縄では行かない感じです。
どうにも、
自分の頭では良い手を思いつかなかったので、
ネットで調べてみました(^_^;)
そしたら、
「麻雀C言語プログラム集」という、お誂え向きのサイトを発見!
アルゴリズムの概要とコードが書いてあって、
大いに参考になります。
なるほど、再帰呼び出しを駆使し、
条件や優先順番に注意しつつ
あらゆる組み合わせを試すのですね!
よく思いついたなぁ、こういうの。
凄いわ。
ただ、コードの最後に
問題点についてのメモ書きがあります。
以下にそのまま引用します。
【問題点】 * 例えば「東東東東南南南南西西西北北北」のシャンテン数は1ですが * このソースでは0(テンパイ)になってしまいます。 * これは4枚目の字牌はターツになる事ができない「死に孤立字牌」なのが理由です。これを回避するには * 「どれか一つでも「4枚目の字牌」を持っていたらシャンテン数+1」とすれば良いかもしれませんが未検証です。
これを改善するにはどうしたら良いのか、
私も考えてみました。
私の結論としては、
1)頭として2枚抜いた後に、残り2枚を面子候補の対子としてしまう。
2)刻子として字牌を3枚抜いた後に、残り1枚を単騎待ち聴牌としてしまう。
の2パターンが問題のようです。
なので、
1)については、
頭として抜いた牌を覚えておき、同じ牌を面子候補の対子とはしない。
2)については、
いったん聴牌と判定された場合に、面子や候補を抜いた後に残った牌が4枚目の字牌だったら向聴数を1つ上げる。
で、うまくいくような気がします。
ということで、
上記の改善も取り入れて、
C言語のコードを参考にしてJavaScriptでやってみました。
結果としてはうまく行ったと思います。
ただ気になったのが実行速度。
最近のCPUは十分早いので実際にはたいしたことないのですが、
調べてみると再帰呼び出しが数百回以上も起こっていました。
多いときは千回を超えていたかも。
うーん、ちょっとこれはどうにかしたい気も。
もっとうまい手法とかないかなと
またネットで調べてみたら、
こちらを発見!
さらに、同時に有効牌・不要牌も求める手法も!
だがしかし・・・。
まるで異次元世界の呪文のような
数学理論が展開されており、
一般人には理解不能な感じ・・・(^_^;)
というか、こういう理論計算を展開できるのがスゴい。
スゴすぎる。
幸いにも
C++なコードが公開されているので、
これを参考にJavaScriptでやってみることにしました。
ということで、
次回に続きます。