【Ruby】和了判定プログラムを作成する。(6)-完成【麻雀】

前回記事は、こちらです。↓

和了判定プログラムを完成させる。

こちらが、完成したプログラムになります。

def agari_check(t)
	tehai=t
	tehai_check = Array.new(46,0)
	tehai.map {|v|tehai_check[v]+=1}

	#雀頭候補抜き取り
	jt=[]	#雀頭候補格納配列
	tehai_check.each_with_index do |v,i|
		if v>=2 then
			jt << i
		end
	end

	agari_mentsu=[]

	#七対子Check
	if jt.size==7 then
		c=[]
		jt.each do |v|
			c << [v,v]
		end
		agari_mentsu << c
	end

	#国士無双Check
	if jt.size==1 then
		kokushi_check_bit = [
			0,1,0,0,0,0,0,0,0,1,
			0,1,0,0,0,0,0,0,0,1,
			0,1,0,0,0,0,0,0,0,1,
			0,1,0,1,0,1,0,1,0,0,
			0,1,0,1,0,1
		]
		tmp_kokushi=tehai_check.dup
		amtmp_kokushi=[]

		#雀頭を抜く
		amtmp_kokushi << [jt[0],jt[0]]
		tmp_kokushi[jt[0]]-=2
		kokushi_check_bit[jt[0]]-=1
		kokushi_check=true
		kokushi_check_bit.each_with_index do |kv,ki|
			kokushi_check = false if kv!=tmp_kokushi[ki]
		end
		if kokushi_check == true then
			k_tmp=[]
			tmp_kokushi.each_with_index{|kv,ki| k_tmp << ki if kv==1}
			amtmp_kokushi << k_tmp
			agari_mentsu << amtmp_kokushi
		end
	end

	#面子手Check
	#雀頭候補毎にcheck
	jt.each_with_index do |v,i|
		tmp=tehai_check.dup
		amtmp=[]

		#雀頭を抜く
		amtmp << [v,v]
		tmp[v]-=2
		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)

			(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
			agari_mentsu << amtmp2 if tmp2.count{|x|x>0}==0

			#順子を抜く
			(1..27).each do |iii|
				tmp2[iii].times do
					if tmp2[iii]>0&&tmp2[iii+1]>0&&tmp2[iii+2]>0 then
						amtmp2 << [iii,iii+1,iii+2]
						tmp2[iii  ]-=1
						tmp2[iii+1]-=1
						tmp2[iii+2]-=1
					end
				end
			end
			agari_mentsu << amtmp2 if tmp2.count{|x|x>0}==0
		end
		#順子を抜く(刻子なし)
		(1..27).each do |iii|
			tmp[iii].times do
				if tmp[iii]>0&&tmp[iii+1]>0&&tmp[iii+2]>0 then
					amtmp << [iii,iii+1,iii+2]
					tmp[iii  ]-=1
					tmp[iii+1]-=1
					tmp[iii+2]-=1
				end
			end
		end
		agari_mentsu << amtmp if tmp.count{|x|x>0}==0
	end
	if agari_mentsu.count==0 then
		return false
	else
		result=agari_mentsu.uniq
		return result
	end
end

それでは、要点を解説します。

和了り形を格納する。

和了りが確定する可能性がある以下の個所で、和了り形を格納する変数配列”agari_mentsu”に和了り形を格納します。

  • 七対子判定(22行目)
  • 国士無双判定(49行目)
  • 刻子判定(93行目)
  • 順子判定(106行目、119行目)

メソッド化させる。

以上のプログラムを、agari_checkと言う名前のメソッドにしました。

メソッドの引数は手牌を表す配列で、返り値が和了り形です(125行目)。

和了り形ができていなかったら”false”を返すようにしました。

124行目に使用しているメソッド”uniq”は、重複している値(和了り形)を削除するメソッドです。

このプログラムを”agari_check.rb”と言うファイル名で保存したら、完成です。

使用例

それでは、使用例を紹介します。

require_relative './agari_check.rb'

tehai=[1,1,2,2,3,3,3,4,5,11,12,13,19,19]

t = agari_check(tehai)
p t
# => [[[19, 19], [1, 2, 3], [1, 2, 3], [3, 4, 5], [11, 12, 13]]]

3枚ある三萬:麻雀王国(3)を、刻子と判定せずに、和了りであることを判定してくれています。

次に、二盃口形を見てみます。

require_relative './agari_check.rb'

tehai=[1,1,2,2,3,3,11,11,12,12,13,13,19,19]

t = agari_check(tehai)
p t
# => [[[1, 1], [2, 2], [3, 3], [11, 11], [12, 12], [13, 13], [19, 19]],
#     [[19, 19], [1, 2, 3], [1, 2, 3], [11, 12, 13], [11, 12, 13]]]

二盃口だけでなく、七対子形も判定しています。点数計算する際はすべての和了り形を考慮して、一番高い点数を申告するため、このような戻り値になる必要があります。

完成!!

これで、完成しました。

麻雀ゲームを作成している方の参考になれば幸いです。

私は、作成している入れ替えパズルに組み込みたいと思います。

コメント

タイトルとURLをコピーしました