前回記事はこちらです。↓
和了判定を組み込んで、遊べる形にする。
和了判定プログラムを組み込んで、ゲームとして遊べる形にしたいと思います。
使用する和了判定プログラムはこちらです。↓
まずは、和了判定プログラムを組み込みます。コードのはじめを次のようにします。
require 'dxruby'
require_relative './agari_check.rb' #←これを追加
これで、和了判定プログラムを使用する準備ができました。
牌交換待機状態で、牌入れ替え後に和了チェック
和了判定が必要になるのは、
- 牌交換待機状態で縦に牌交換をした時
- 交換した手牌の中にダミー牌(99)がない場合
です。
なので、牌交換待機状態を以下のように変更します。
when "change_steel" #牌交換待機状態
#牌交換待機状態の処理を書く
if Input.mouse_release?(0) then
if (Input.mouse_x > 0) && (Input.mouse_x < tile_w * 14) && (Input.mouse_y > 0) && (Input.mouse_y < tile_h * 10) then
y = Input.mouse_y/tile_h
x = Input.mouse_x/tile_w
if base_y==y then #横方向の交換
if base_x!=x then
tiles[base_y][base_x], tiles[y][x] = tiles[y][x], tiles[base_y][base_x]
rest-=1 #牌を交換したら、入れ替え回数を1減らす。
end
base_x=-1
base_y=-1
state= "steel"
else #縦方向の交換
if base_x==x then
tiles[base_y][base_x], tiles[y][x] = tiles[y][x], tiles[base_y][base_x]
#和了判定
#tiles[base_y]に"99"があればresult0=falseとする。
if tiles[base_y].include?(99) then
result0=false
else
result0=agari_check(tiles[base_y]) #←和了判定
end
#tiles[y]に"99"があればresult1=falseとする。
if tiles[y].include?(99) then
result1=false
else
result1=agari_check(tiles[y]) #←和了判定
end
if result0==false&&result1==false then
rest-=1 #入れ替えた手牌が和了りになっていなかったら、入れ替え回数を1減らす。
else
if result0!=false then
tiles[base_y].sort!
rest+=8
end
if result1!=false then
tiles[y].sort!
rest+=8
end
end
#ここまでが和了判定
end
base_x=-1
base_y=-1
state= "steel"
end
end
end
これを実行すると、以下のように動作します。
これで、和了形ができると入れ替え残り回数が増えるようになりましたが、和了った手牌(横軸)の牌を動かす事ができてしまうため、同じ横軸で何回も和了ることができてしまって、ゲームが崩壊してしまいます。よって、和了形の手牌を触れないよう固定します。
和了形の手牌を固定
横軸が和了形になったら、その牌を触れないよう固定します。
そのためには和了り形になっている横軸を記憶させる必要があります。
その横軸を格納する変数”agari_y_list”を”Window.loop”の前に設定したうえで、和了形完成時に”agari_y_list”に完成した横軸の値を格納します。
#和了手牌格納
agari_y_list =[]
また、Windows.loopブロック内の一番上に、今クリックした横軸の和了形であれば”true”格納する和了判定変数”agari_y”を用意します。
Window.loop do
# ここにゲームの処理を書く
agari_y=false #和了判定変数
# update
#略
次に、和了ったタイミングでこの変数に、和了り手牌の横軸が上から何番目なのかを格納します。
when "change_steel" #牌交換待機状態
#略
if result0!=false then
agari_y_list << base_y #追加
tiles[base_y].sort!
rest+=8
end
if result1!=false then
agari_y_list << y #追加
tiles[y].sort!
rest+=8
end
#略
end
最後に、各状態(選択待機状態、交換牌選択可能状態、牌交換待機状態)でこの横軸の牌をクリックしても、何も動作しないように、各状態の処理ブロック内に以下のコードを追加します。
#すでに和了っている横軸をクリックしても何もない。
agari_y_list.each do |v|
agari_y=true if v==y #クリックした横軸が和了形であれば、"true"に変更
end
if agari_y==false then #クリックした牌が和了形でなければ、その状態での処理を実施
#略
end
以上を踏まえて、各状態の処理を以下のように変更します。
#略
Window.loop do
# ここにゲームの処理を書く
agari_y=false #和了判定変数
# update
case state #case文で条件分岐
when "steel" #選択待機状態
#選択待機状態の処理を書く
base_y =-1 #選択された縦方向の牌の位置
if Input.mouse_release?(0) then
#牌が表示されている範囲をクリックしたら以下を処理
if (Input.mouse_x > 0) && (Input.mouse_x < tile_w * 14) && (Input.mouse_y > 0 ) && (Input.mouse_y < tile_h * 10) then
#クリックされた箇所が上から何段目かを取得
y = Input.mouse_y/tile_h
#すでに和了っている横軸をクリックしても何もない。
agari_y_list.each do |v|
agari_y=true if v==y
end
if agari_y==false then #クリックした牌が和了形でなければ、その状態での処理を実施
#選択された縦方向の位置を取得し、交換牌選択可能状態に進む
if y>-1 then
base_y=y
sorted =tiles[base_y].sort #理牌用
state="base_click"
end
end
end
end
when "base_click" #交換牌選択可能状態
#交換牌選択可能状態の処理を書く
base_x =-1 #選択された横方向の牌の位置
if Input.mouse_release?(0) then
#牌が表示されている範囲をクリックしたら以下を処理する
if (Input.mouse_x > 0) && (Input.mouse_x < tile_w * 14) && (Input.mouse_y > 0) && (Input.mouse_y < tile_h * 10) then
#クリックされた箇所が上から何段目かを取得
y =Input.mouse_y/tile_h
#クリックされた箇所が左から何番目かを取得
x = Input.mouse_x/tile_w
#すでに和了っている横軸をクリックしても何もない。
agari_y_list.each do|v|
agari_y=true if v==y
end
if agari_y==false then
#クリックされた手牌が、選択待機状態時に選択された手牌と同じであれば、
#選択された横方向の位置を取得し、牌交換待機状態に進む
if base_y==y then
base_x=x
state="change_steel"
else
#違う手牌を再選択
base_y = y
sorted =tiles[base_y].sort #理牌用
state="base_click"
end
end
end
end
when "change_steel" #牌交換待機状態
#牌交換待機状態の処理を書く
if Input.mouse_release?(0) then
if (Input.mouse_x > 0) && (Input.mouse_x < tile_w * 14) && (Input.mouse_y > 0) && (Input.mouse_y < tile_h * 10) then
y = Input.mouse_y/tile_h
x = Input.mouse_x/tile_w
#すでに和了っている横軸をクリックしても何もない。
agari_y_list.each do |v|
agari_y=true if v==y
end
if agari_y==false then
if base_y==y then #横方向の交換
if base_x!=x then
tiles[base_y][base_x], tiles[y][x] = tiles[y][x], tiles[base_y][base_x]
rest-=1 #牌を交換したら、入れ替え回数を1減らす。
end
base_x=-1
base_y=-1
state= "steel"
else #縦方向の交換
if base_x==x then
tiles[base_y][base_x], tiles[y][x] = tiles[y][x], tiles[base_y][base_x]
#和了判定
#tiles[base_y]に"99"があればresult0=falseとする。
if tiles[base_y].include?(99) then
result0=false
else
result0=agari_check(tiles[base_y])
end
#tiles[y]に"99"があればresult1=falseとする。
if tiles[y].include?(99) then
result1=false
else
result1=agari_check(tiles[y])
end
p "0=#{result0}"
p "1=#{result1}"
if result0==false&&result1==false then
rest-=1 #入れ替えた手牌が和了りになっていなかったら、入れ替え回数を1減らす。
else
if result0!=false then
agari_y_list << base_y
tiles[base_y].sort!
rest+=8
end
if result1!=false then
agari_y_list << y
tiles[y].sort!
rest+=8
end
end
#ここまでが和了判定
else
state="change_steel"
end
base_x=-1
base_y=-1
state= "steel"
end
end
end
end
end #ここまでがcase文
break if rest <= 0 #入替回数0以下になったら終了。
# draw
tiles.each_with_index do |rows,y|
rows.each_with_index do |v,x|
Window.draw(tile_w * x, tile_h * y, hai_images[v])
end
end
#理牌表示
if base_y>-1 then
sorted.each_with_index do |v,i|
Window.draw(tile_w*i,tile_h * 11,hai_images[v])
end
end
#入替回数表示
Window.draw_font(0, tile_h * 10, "回数残 = #{rest}", font, {:color => C_WHITE})
#選択した手牌を枠線で囲む
Window.draw(0,tile_h*base_y,y_guide)
#選択した牌の縦軸を枠線で囲む
Window.draw(tile_w*base_x,0,x_guide)
end
配牌後に、和了チェック
ゲーム開始直後に和了ってる場合があります(いわゆる天和や地和)。これをチェックするため。配牌直後の状態”start”を追加して、この中で和了りのチェックを行います。
case state #case文で条件分岐
when "start" #配牌直後状態
#配牌直後に和了りが成立していないか(地和)チェック
tiles.each_with_index do |t,i|
r = false
if t.include?(99) then
r = false
else
r = agari_check(t)
end
if r!=false then
agari_y_list << i
t.sort!
rest+=8
end
end
state="steel"
#略
end
和了判定処理完成
画面をわかりやすくするため、和了形の手牌を赤い枠線で囲むようにして(作成:86~93行目 表示:248~251行目)、和了判定処理を完成させたプログラムが、以下のコードになります。
require 'dxruby'
require_relative './agari_check.rb'
#ウィンドウサイズ
Window.resize 672,900
#キャプション
Window.caption = "mjpzl"
#バックグラウンド色(濃い緑色)
Window.bgcolor=[63, 0, 63, 0]
font = Font.new(32) #サイズ32の文字(フォント)を使用する。
#牌生成
hai_type=[
1, 2, 3, 4, 5, 6, 7, 8, 9, #萬子
11,12,13,14,15,16,17,18,19, #索子
21,22,23,24,25,26,27,28,29, #筒子
31,33,35,37, #風牌
41,43,45, #三元牌
99 #裏牌
]
#牌の数は各牌4枚
hais = hai_type*4
#牌をランダムにシャッフル
hais.shuffle!
#牌を14*10に並べる
tiles =Array.new
(0..9).each do |y|
tiles[y]=Array.new
(0..13).each do |x|
#haisの先頭からtilesにひとつずつ代入していく。
tiles[y][x]=hais.shift
end
end
#牌画像
hai_images=Array.new
(1..9).each do |i|
hai_images[ i] = Image.load("./image/p_ms#{i}_1.png")
hai_images[ 10 +i] = Image.load("./image/p_ps#{i}_1.png")
hai_images[ 20 +i] = Image.load("./image/p_ss#{i}_1.png")
end
hai_images[31] = Image.load("./image/p_ji_e_1.png")
hai_images[33] = Image.load("./image/p_ji_s_1.png")
hai_images[35] = Image.load("./image/p_ji_w_1.png")
hai_images[37] = Image.load("./image/p_ji_n_1.png")
hai_images[41] = Image.load("./image/p_no_1.png")
hai_images[43] = Image.load("./image/p_ji_h_1.png")
hai_images[45] = Image.load("./image/p_ji_c_1.png")
hai_images[99] = Image.load("./image/p_bk_1.png")
tile_w = 48 #牌画像の幅
tile_h = 64 #牌画像の高さ
base_x =-1 #選択された横方向の位置
base_y =-1 #選択された縦方向の位置
sorted =Array.new #理牌用変数
#状態変数
state = "start" #初期値:配牌直後状態
#入替回数
rest=8
#和了手牌格納
agari_y_list =[]
#ガイド枠線(横)
y_guide=Image.new(tile_w*14,tile_h ).box(0,0,tile_w*14,tile_h ,C_CYAN)
.box(1,1,tile_w*14-1,tile_h-1,C_CYAN)
.box(2,2,tile_w*14-2,tile_h-2,C_CYAN)
.box(3,3,tile_w*14-3,tile_h-3,C_CYAN)
#ガイド枠線(縦)
x_guide=Image.new(tile_w ,tile_h*10).box(0,0,tile_w ,tile_h*10 ,C_CYAN)
.box(1,1,tile_w-1,tile_h*10-1,C_CYAN)
.box(2,2,tile_w-2,tile_h*10-2,C_CYAN)
.box(3,3,tile_w-3,tile_h*10-3,C_CYAN)
#和了り枠線
agai_guide_list=[]
(0..9).each do |i|
agai_guide_list[i]=Image.new(tile_w*14,tile_h).box(0,0,tile_w*14,tile_h,C_RED)
.box(1,1,tile_w*14-1,tile_h-1,C_RED)
.box(2,2,tile_w*14-2,tile_h-2,C_RED)
.box(3,3,tile_w*14-3,tile_h-3,C_RED)
end
Window.loop do
# ここにゲームの処理を書く
agari_y=false #和了判定変数
# update
case state #case文で条件分岐
when "start" #配牌直後状態
#配牌直後に和了りが成立していないか(地和)チェック
tiles.each_with_index do |t,i|
r = false
if t.include?(99) then
r = false
else
r = agari_check(t)
end
if r!=false then
agari_y_list << i
t.sort!
rest+=8
end
end
state="steel"
when "steel" #選択待機状態
#選択待機状態の処理を書く
base_y =-1 #選択された縦方向の牌の位置
if Input.mouse_release?(0) then
#牌が表示されている範囲をクリックしたら以下を処理
if (Input.mouse_x > 0) && (Input.mouse_x < tile_w * 14) && (Input.mouse_y > 0 ) && (Input.mouse_y < tile_h * 10) then
#クリックされた箇所が上から何段目かを取得
y = Input.mouse_y/tile_h
#すでに和了っている横軸をクリックしても何もない。
agari_y_list.each do |v|
agari_y=true if v==y
end
if agari_y==false then #クリックした牌が和了形でなければ、その状態での処理を実施
#選択された縦方向の位置を取得し、交換牌選択可能状態に進む
if y>-1 then
base_y=y
sorted =tiles[base_y].sort #理牌用
state="base_click"
end
end
end
end
when "base_click" #交換牌選択可能状態
#交換牌選択可能状態の処理を書く
base_x =-1 #選択された横方向の牌の位置
if Input.mouse_release?(0) then
#牌が表示されている範囲をクリックしたら以下を処理する
if (Input.mouse_x > 0) && (Input.mouse_x < tile_w * 14) && (Input.mouse_y > 0) && (Input.mouse_y < tile_h * 10) then
#クリックされた箇所が上から何段目かを取得
y =Input.mouse_y/tile_h
#クリックされた箇所が左から何番目かを取得
x = Input.mouse_x/tile_w
#すでに和了っている横軸をクリックしても何もない。
agari_y_list.each do|v|
agari_y=true if v==y
end
if agari_y==false then
#クリックされた手牌が、選択待機状態時に選択された手牌と同じであれば、
#選択された横方向の位置を取得し、牌交換待機状態に進む
if base_y==y then
base_x=x
state="change_steel"
else
#違う手牌を再選択
base_y = y
sorted =tiles[base_y].sort #理牌用
state="base_click"
end
end
end
end
when "change_steel" #牌交換待機状態
#牌交換待機状態の処理を書く
if Input.mouse_release?(0) then
if (Input.mouse_x > 0) && (Input.mouse_x < tile_w * 14) && (Input.mouse_y > 0) && (Input.mouse_y < tile_h * 10) then
y = Input.mouse_y/tile_h
x = Input.mouse_x/tile_w
#すでに和了っている横軸をクリックしても何もない。
agari_y_list.each do |v|
agari_y=true if v==y
end
if agari_y==false then
if base_y==y then #横方向の交換
if base_x!=x then
tiles[base_y][base_x], tiles[y][x] = tiles[y][x], tiles[base_y][base_x]
rest-=1 #牌を交換したら、入れ替え回数を1減らす。
end
base_x=-1
base_y=-1
state= "steel"
else #縦方向の交換
if base_x==x then
tiles[base_y][base_x], tiles[y][x] = tiles[y][x], tiles[base_y][base_x]
#和了判定
#tiles[base_y]に"99"があればresult0=falseとする。
if tiles[base_y].include?(99) then
result0=false
else
result0=agari_check(tiles[base_y])
end
#tiles[y]に"99"があればresult1=falseとする。
if tiles[y].include?(99) then
result1=false
else
result1=agari_check(tiles[y])
end
if result0==false&&result1==false then
rest-=1 #入れ替えた手牌が和了りになっていなかったら、入れ替え回数を1減らす。
else
if result0!=false then
agari_y_list << base_y
tiles[base_y].sort!
rest+=8
end
if result1!=false then
agari_y_list << y
tiles[y].sort!
rest+=8
end
end
#ここまでが和了判定
else
state="change_steel"
end
base_x=-1
base_y=-1
state= "steel"
end
end
end
end
end #ここまでがcase文
break if rest <= 0 #入替回数0以下になったら終了。
# draw
tiles.each_with_index do |rows,y|
rows.each_with_index do |v,x|
Window.draw(tile_w * x, tile_h * y, hai_images[v])
end
end
#理牌表示
if base_y>-1 then
sorted.each_with_index do |v,i|
Window.draw(tile_w*i,tile_h * 11,hai_images[v])
end
end
#入替回数表示
Window.draw_font(0, tile_h * 10, "回数残 = #{rest}", font, {:color => C_WHITE})
#和了り枠線表示
agari_y_list.each do |v|
Window.draw(0,tile_h * v,agai_guide_list[v])
end
#選択した手牌を枠線で囲む
Window.draw(0,tile_h*base_y,y_guide)
#選択した牌の縦軸を枠線で囲む
Window.draw(tile_w*base_x,0,x_guide)
end
このプログラムを実行させると、以下のようになります。
これで、当初の目的である、
- 入れ替え残り回数内で、手牌を完成させて、
- 完成させたら、入れ替え残り回数が増えて、ゲーム続行。
- 入れ替え残り回数が無くなったら、ゲームオーバー
という流れが完成しました。
次回からは、実際の麻雀のようにできあがった手牌で、点数計算をするようにしたいと思います。
次回記事は、こちらです。↓
コメント