前回記事は、こちらです。↓
刻子を判定する。
今回は、同じ牌が3枚あるときの判定処理を作成します。
3枚同じ牌だからと言って、必ずしも「刻子」とは限らない。
同じ牌が3枚集まると、「刻子」となり、ひとつの面子になるのですが、3枚組が必ずしも刻子となるわけではありません。
下の手牌を見てください。
この手牌はが3枚ありますが、を刻子とすると、和了りになりません。
この様に、3枚組に対しては、それが刻子の場合と、そうではない場合で分けて判定する必要があります。
3枚組の数が増えると、それぞれの3枚組に対してこの判定を行う必要があります。
力技による刻子判定
ただ、この3枚組も最大で4つしかないと考えると、下のプログラムになります。
#雀頭候補毎にcheck
jt=[] #雀頭候補格納配列
tehai_check.each_with_index do |v,i|
if v>=2 then
jt << i
end
end
jt.each_with_index do |v,i|
tmp=tehai_check.dup #tehai_checkを複製
amtmp=[] #和了りの手牌を格納する配列
#刻子判定
kohtsu_list = [] #刻子候補リスト
#刻子をチェック
tmp.each_with_index do |vv,ii|
kohtsu_list << ii if vv>=3
end
#刻子候補洗い出し
kohtsu_ptn = []
kohtsu_ptn_bit=[]
case kohtsu_list.size
when 4 then
kohtsu_ptn_bit=[
[1,1,1,1],
[1,1,1,0],
[1,1,0,1],
[1,1,0,0],
[1,0,1,1],
[1,0,1,0],
[1,0,0,1],
[1,0,0,0],
[0,1,1,1],
[0,1,1,0],
[0,1,0,1],
[0,1,0,0],
[0,0,1,1],
[0,0,1,0],
[0,0,0,1],
[0,0,0,0]
]
kohtsu_ptn_bit.each do |vv|
kpb_tmp=[]
kpb_tmp=[
vv[0]*kohtsu_list[0],
vv[1]*kohtsu_list[1],
vv[2]*kohtsu_list[2],
vv[3]*kohtsu_list[3]
]
kpb_tmp.delete(0)
kohtsu_ptn << kpb_tmp
end
when 3 then
kohtsu_ptn_bit=[
[1,1,1],
[1,1,0],
[1,0,1],
[1,0,0],
[0,1,1],
[0,1,0],
[0,0,1],
[0,0,0]
]
kohtsu_ptn_bit.each do |vv|
kpb_tmp=[]
kpb_tmp=[
vv[0]*kohtsu_list[0],
vv[1]*kohtsu_list[1],
vv[2]*kohtsu_list[2]
]
kpb_tmp.delete(0)
kohtsu_ptn << kpb_tmp
end
when 2 then
kohtsu_ptn_bit=[
[1,1],
[1,0],
[0,1],
[0,0]
]
kohtsu_ptn_bit.each do |vv|
kpb_tmp=[]
kpb_tmp=[
vv[0]*kohtsu_list[0],
vv[1]*kohtsu_list[1]
]
kpb_tmp.delete(0)
kohtsu_ptn << kpb_tmp
end
when 1 then
kohtsu_ptn_bit=[
[1],
[0]
]
kohtsu_ptn_bit.each do |vv|
kpb_tmp=[]
kpb_tmp=[
vv[0]*kohtsu_list[0]
]
kpb_tmp.delete(0)
kohtsu_ptn << kpb_tmp
end
end
#刻子パターンごとに刻子を抜く
kohtsu_ptn.each_with_index do |vv,ii|
tmp2=tmp.dup
amtmp2=amtmp.dup
vv.each do |vvv|
amtmp2 << [vvv,vvv,vvv]
tmp2[vvv]-=3
end
#順子を抜く(未実装)
end
#順子を抜く(刻子候補なし)(未実装)
end
これは、何をしているプログラムなのかと言うと、
- 3枚組の数毎に条件分岐をした後に、(22行目のcase以降)
- 3枚組の数分に刻子であれば1、そうでなければ0として、(kohtsu_ptn_bit)
- 刻子候補の牌を表す数値を掛けることで、刻子候補リストを作成し、(kpb_tmp)
- それを基に刻子を抜く。(105行目以降)
と言う形になっています。
この後で、順子を抜いて牌が残らなければ、「和了り」。残ったら「ノーテン(和了っていない)」と言うわけです。
これでも、動くことは動くのですが、あまりに冗長です。
このプログラムを「ビット(2進数)」を使用したプログラムに書き換えます。
ビットを使用した刻子判定
ビットを使用すると、以下のプログラムになります。
#雀頭候補毎にcheck
jt=[] #雀頭候補格納配列
tehai_check.each_with_index do |v,i|
if v>=2 then
jt << i
end
end
jt.each_with_index do |v,i|
tmp=tehai_check.dup #tehai_checkを複製
amtmp=[] #和了りの手牌を格納する配列
#刻子判定
kohtsu_list = [] #刻子候補リスト
#刻子をチェック
tmp.each_with_index do |vv,ii|
kohtsu_list << ii if vv>=3
end
#刻子候補洗い出し
kohtsu_ptn = []
num = 2**kohtsu_list.size
bit = kohtsu_list.size
if kohtsu_list.size != 0 then
kohtsu_ptn_bit=Array.new(num)
#ここからビット(2進数)を使用
(num-1).downto(0) do |i|
kpb_tmp=Array.new(bit - 1)
(bit-1).downto(0) do |ii|
kpb_tmp[ii]= i[ii]!=0 ? kohtsu_list[ii] : 0 #ビットを活用した判定
end
kpb_tmp.delete(0)
kohtsu_ptn << kpb_tmp
end
#ここまで
end
#刻子パターンごとに刻子を抜く
kohtsu_ptn.each_with_index do |vv,ii|
tmp2=tmp.dup
amtmp2=amtmp.dup
vv.each do |vvv|
amtmp2 << [vvv,vvv,vvv]
tmp2[vvv]-=3
end
#順子を抜く(未実装)
end
#順子を抜く(刻子なし)(未実装)
end
このプログラムは31行目でRubyの以下の機能を活用しています。
i = 15
ii=0
puts i[ii] #iをビット(2進数)にした時の、1の位の数値(0あるいは1)
#=> 1
このように、整数に配列の添え字である「[]」をつけると、その整数をビット(2進数)であらわした時の、添え字の位の値を表示します(上のコードでは、1の位)。上のプログラムの27行目から36行目で使用することで、整理されたプログラムになりました。
これで、刻子判定のプログラムが完成しましたので、次回は順子判定のプログラムを作成します。
次回記事は、こちらです。↓
コメント