From 191a5698f6b8fb2fcad39a994e165581318d80db Mon Sep 17 00:00:00 2001 From: yutaro matsui Date: Fri, 3 Jul 2015 18:21:57 +0900 Subject: [PATCH] =?UTF-8?q?=E9=BA=BB=E9=9B=80BOT=E6=A9=9F=E8=83=BD?= =?UTF-8?q?=E3=81=AE=E5=8F=AF=E8=AA=AD=E6=80=A7=E3=81=AE=E5=90=91=E4=B8=8A?= =?UTF-8?q?=E3=81=A8=E3=83=89=E3=83=A9=E3=81=AE=E8=BF=BD=E5=8A=A0=20#33=20?= =?UTF-8?q?#21?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/mahjong.coffee | 485 +++++++++++++++++------------------------ 1 file changed, 206 insertions(+), 279 deletions(-) diff --git a/scripts/mahjong.coffee b/scripts/mahjong.coffee index 41d9e94..1a3d752 100644 --- a/scripts/mahjong.coffee +++ b/scripts/mahjong.coffee @@ -7,301 +7,229 @@ # # Documentation: # 麻雀の役を登録するルールとして雀頭が予め登録してあり面子4つと組み合わせて出力することにします. -# きちんと考えて書かないと字牌が5個とか出てしまうので考えてかいてください. (特に順子を追加するとき) # -jhands1 = [":hai-ton:",":hai-sha:",":hai-nan:",":hai-pei:",":hai-hatsu:",":hai-chun:",":hai-haku:",] - -hands1 = [[":1man:", ":2man:", ":3man:", ":4man:", ":5man:", ":6man:", ":7man:", ":8man:", ":9man:",], -[":1so:",":2so:",":3so:",":4so:",":5so:",":6so:",":7so:",":8so:",":9so:",], -[":1pin:",":2pin:",":3pin:",":4pin:",":5pin:",":6pin:",":7pin:",":8pin:",":9pin:"],] +module.exports = (robot) -> + robot.hear /mahjong|麻雀|マージャン|まーじゃん/, (msg) -> -#赤ドラ -redhands = [":5mana:",":5soa:",":5pina:"] + # 使った牌の個数を記憶しておく + count = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + ] + # 使った赤ドラを記憶しておく(左から萬子,索子,筒子) + useDora = [false, false, false] -# 10の位を切り上げ -carry10 = (num) -> - Math.ceil(num / 100) * 100 # 小数にしてから小数点以下を切り捨てる + # 鳴いたかどうか確かめる.一発,鳴いちゃった罵倒判定に使用 + naita = false -# 1の位を切り上げ -carry1 = (num) -> - Math.ceil(num / 10) * 10 # 小数にしてから小数点以下を切り捨てる + # 槓子の個数 + kantsu = 0 -module.exports = (robot) -> - robot.hear /mahjong|麻雀|マージャン|まーじゃん/, (msg) -> - kaze = (n1,n2) -> - if n1 < 5 - msg.send "場風:北" - else if 5 <= n1 < 20 - msg.send "場風:西" - else if 20 <= n1 < 40 - msg.send "場風:南" - else msg.send "場風:東" - switch n2 - when 1 then msg.send "自風:東" - when 2 then msg.send "自風:南" - when 3 then msg.send "自風:北" - else msg.send "自風:西" - # 牌のカウント - jhcount = [0,0,0,0,0,0,0] - hcount = [[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0]] - #チートイ用カウント - tijhcount = [0,0,0,0,0,0,0] - tihcount = [[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0]] - #赤ドラカウント - acount = [0,0,0] + # 0からiまでの数をランダムに生成する関数randNum + randNum = (i) -> + Math.floor(Math.random() * i) - # ドラ設定 - dorandam = Math.floor(Math.random()*4)+1 - if dorandam == 1 - doj = Math.floor(Math.random()*7)+1 - dojh = doj-1 - jhcount[dojh] = jhcount[dojh]+1 - tijhcount[dojh] = tijhcount[dojh]+1 - msg.send "ドラ表示牌:#{jhands1[dojh]}" - else - dom = Math.floor(Math.random()*3)+1 - domsp = dom-1 - dora = Math.floor(Math.random()*9)+1 - doh = dora-1 - hcount[domsp][doh] = hcount[domsp][doh]+1 - tihcount[domsp][doh] = tihcount[domsp][doh]+1 - msg.send "ドラ表示牌:#{hands1[domsp][doh]}" - # 雀頭生成 - # 雀頭選択用乱数生成1(字牌か数牌か) - headra = Math.floor(Math.random() * 4)+1 - # 雀頭選択用乱数生成2(字牌を選んだ場合) - headrb = Math.floor(Math.random() * 7)+1 - # 雀頭選択用乱数生成3(数牌を選んだ場合) - headrc = Math.floor(Math.random() * 9)+1 - hb = headrb-1 - hc = headrc-1 - count = 1 - #検証用 - headra1 = 2 - if headra1 == 1 - loop - hbodyrb = Math.floor(Math.random() * 7)+1 - heb = hbodyrb-1 - break unless jhcount[heb] >= 3 - head1 = jhands1[heb].concat(jhands1[heb]) - jhcount[heb] = jhcount[heb]+2 - tijhcount[heb] = tijhcount[heb]+3 - else - hms = Math.floor(Math.random()*3)+1 - hmsp = hms-1 - loop - hbodyrc = Math.floor(Math.random() * 9)+1 - hc = hbodyrc-1 - break unless hcount[hmsp][hc] >= 3 - head1 = hands1[hmsp][hc].concat(hands1[hmsp][hc]) - #head1 = hands1[1][8].concat(hands1[1][8]) - hcount[hmsp][hc] = hcount[hmsp][hc]+2 - tihcount[hmsp][hc] = tihcount[hmsp][hc]+3 - #雀頭の確認 - #msg.send "雀頭字牌" - #msg.send "東,西,南,北,發,中,白" - #msg.send "#{jhcount}" - #msg.send "雀頭数牌" - #msg.send "#{hcount[0]}" - #msg.send "#{hcount[1]}" - #msg.send "#{hcount[2]}" - # 場風、自風の設定(関数呼び出し) - bakaze = Math.floor(Math.random() * 100)+1 - mykaze = Math.floor(Math.random() * 4)+1 - kaze.call(null,bakaze,mykaze) + ### + * 0から33までの値を受け取ると対応する牌を返す関数int2hai + * 5の牌に関しては,適当に1つだけ赤ドラを出す + ### + int2hai = (n) -> + switch n + when 0 then return ":1man:" + when 1 then return ":2man:" + when 2 then return ":3man:" + when 3 then return ":4man:" + when 4 then return hai5(0) + when 5 then return ":6man:" + when 6 then return ":7man:" + when 7 then return ":8man:" + when 8 then return ":9man:" + when 9 then return ":1so:" + when 10 then return ":2so:" + when 11 then return ":3so:" + when 12 then return ":4so:" + when 13 then return hai5(1) + when 14 then return ":6so:" + when 15 then return ":7so:" + when 16 then return ":8so:" + when 17 then return ":9so:" + when 18 then return ":1pin:" + when 19 then return ":2pin:" + when 20 then return ":3pin:" + when 21 then return ":4pin:" + when 22 then return hai5(2) + when 23 then return ":6pin:" + when 24 then return ":7pin:" + when 25 then return ":8pin:" + when 26 then return ":9pin:" + when 27 then return ":hai-haku:" + when 28 then return ":hai-hatsu:" + when 29 then return ":hai-chun:" + when 30 then return ":hai-ton:" + when 31 then return ":hai-nan:" + when 32 then return ":hai-sha:" + when 33 then return ":hai-pei:" + else return ":bug:" # bug発見用 - # makebody! - # body! - body = [] - finalbody = [] - # 順子にするのか刻子にするのかの乱数生成 - # 字牌の場合の乱数生成 - # bodyrb = Math.floor(Math.random() * 7)+1 - # 数牌の場合の乱数生成 - bodyrc = Math.floor(Math.random() * 9)+1 - bb = bodyrb-1 - bc = bodyrc-1 - count = [0,0,0,0,0] - nakicount = 0 + # 赤ドラを出したい + hai5 = (i) -> + if !useDora[i] + # 残っている牌のうち,赤ドラを引く確率 + j = randNum(4 - count[4 + i * 9]) + if j == 0 + useDora[i] = true + i += 3 + switch i + when 0 then return ":5man:" + when 1 then return ":5so:" + when 2 then return ":5pin:" + when 3 then return ":5mana:" + when 4 then return ":5soa:" + when 5 then return ":5pina:" - for i in [0..3] - j = 5 - j = j - i - sork = Math.floor(Math.random() * 2)+1 - #検証用:生成するのを刻子に固定 - sork1 = 1 - na = Math.floor(Math.random()*5)+1 - naki = na-1 - # 乱数の生成(字牌にするか数牌にするか) - bodyra = Math.floor(Math.random() * 4)+1 - switch sork - # 刻子の場合 - when 1 - ms = Math.floor(Math.random()*3)+1 - msp = ms-1 - #msp = 1 - if bodyra == 1 - loop - bodyrb = Math.floor(Math.random() * 7)+1 - bb = bodyrb-1 - break unless jhcount[bb] >= 2 - jhcount[bb] = jhcount[bb]+3 - if naki != 4 - hand2 = ((["("].concat(jhands1[bb])).join("")).concat(jhands1[bb].concat(jhands1[bb].concat([")"]))) - nakicount = nakicount + 1 - else - hand2 = jhands1[bb].concat(jhands1[bb].concat(jhands1[bb])) - body = body.concat(hand2) - else - loop - bodyrb = Math.floor(Math.random() * 9)+1 - bb = bodyrb-1 - break unless hcount[msp][bb] >= 2 - akar = Math.floor(Math.random()*4)+1 - hcount[msp][bb] = hcount[msp][bb]+3 - if naki == 1 || naki == 2 - if bb == 4 && akar == 1 && acount[msp] == 0 - hand2 = ((["("].concat(hands1[msp][bb])).join("")).concat(redhands[msp].concat(hands1[msp][bb].concat([")"]))) - acount[msp] = 1 - nakicount = nakicount + 1 - else - hand2 = ((["("].concat(hands1[msp][bb])).join("")).concat(hands1[msp][bb].concat(hands1[msp][bb].concat([")"]))) - nakicount = nakicount + 1 - else - if bb == 4 && akar == 1 && acount[msp] == 0 - hand2 = hands1[msp][bb].concat(redhands[msp].concat(hands1[msp][bb])) - acount[msp] = 1 - else - hand2 = hands1[msp][bb].concat(hands1[msp][bb].concat(hands1[msp][bb])) - body = body.concat(hand2) - # 順子の場合 - else - ms1 = Math.floor(Math.random()*3)+1 - msp1 = ms1-1 - loop - # 選択した牌の番号 - tbodyrb = Math.floor(Math.random() * 7)+1 - # 選択した牌の一つ前の牌の番号 - tbb = tbodyrb-1 - # 選択した牌の一つ後の牌の番号 - tbb1 = tbodyrb+1 - break unless hcount[msp1][tbodyrb] >= 4 || hcount[msp1][tbb] >= 4 || hcount[msp1][tbb1] >= 4 - akar = Math.floor(Math.random()*4)+1 - hcount[msp1][tbodyrb] = hcount[msp1][tbodyrb]+1 - hcount[msp1][tbb] = hcount[msp1][tbb]+1 - hcount[msp1][tbb1] = hcount[msp1][tbb1]+1 - if naki == 1 - if tbb == 4 && akar == 1 && acount[msp1] == 0 - hand2 = ((["("].concat(redhands[msp1])).join("")).concat(hands1[msp1][tbodyrb].concat(hands1[msp1][tbb1].concat([")"]))) - acount[msp1] = 1 - nakicount = nakicount + 1 - else if tbb == 3 && akar == 1 && acount[msp1] == 0 - hand2 = ((["("].concat(hands1[msp1][tbb])).join("")).concat(redhands[msp1].concat(hands1[msp1][tbb1].concat([")"]))) - acount[msp1] = 1 - nakicount = nakicount + 1 - else if tbb == 2 && akar == 1 && acount[msp1] == 0 - acount[msp1] = 1 - nakicount = nakicount + 1 - hand2 = ((["("].concat(hands1[msp1][tbb])).join("")).concat(hands1[msp1][tbodyrb].concat(redhands[msp1].concat([")"]))) - else - nakicount = nakicount + 1 - hand2 = ((["("].concat(hands1[msp1][tbb])).join("")).concat(hands1[msp1][tbodyrb].concat(hands1[msp1][tbb1].concat([")"]))) - else - if tbb == 4 && akar == 1 && acount[msp1] == 0 - acount[msp1] = 1 - hand2 = redhands[msp1].concat(hands1[msp1][tbodyrb].concat(hands1[msp1][tbb1])) - else if tbb == 3 && akar == 1 && acount[msp1] == 0 - acount[msp1] = 1 - hand2 = hands1[msp1][tbb].concat(redhands[msp1].concat(hands1[msp1][tbb1])) - else if tbb == 2 && akar == 1 && acount[msp1] == 0 - acount[msp1] = 1 - hand2 = hands1[msp1][tbb].concat(hands1[msp1][tbodyrb].concat(redhands[msp1])) - else - hand2 = hands1[msp1][tbb].concat(hands1[msp1][tbodyrb].concat(hands1[msp1][tbb1])) - body = body.concat(hand2) - #検証用コメント - #msg.send "字牌" - #msg.send "#{jhcount}" - #msg.send "数牌" - #msg.send "#{hcount[0]}" - #msg.send "#{hcount[1]}" - #msg.send "#{hcount[2]}" + ### + * 七対子の実装 + * 適当に7種類選び,出力するだけ + ### + toitsu7 = -> + str = "" + for i in [0 .. 6] + # 使ってない牌を探す + while true + j = randNum(34) + if count[j] == 0 + break + count[j]++ + str += int2hai(j) + int2hai(j) + " " + return str - b1 = body.shift()# i = 3 - b2 = body.shift()# i = 2 - b3 = body.shift()# i = 1 - b4 = body.shift()# i = 0 - #msg.send "#{head1} #{b1} #{b2} #{b3} #{b4}" - #チートイ錬成 - tibody = [] + ### + * 国士無双の実装 + * tは2枚使う牌を指定 + * ychは使用牌の集合 + ### + kokushi = -> + t = randNum(13) + ych = [0, 8, 9, 17, 18, 26, 27, 28, 29, 30, 31, 32, 33] + str = "" + for i in [0 .. 12] + if i == t + str += int2hai(ych[i]) + int2hai(ych[i]) + else + str += int2hai(ych[i]) + return str - for k in [0..5] - theadra = Math.floor(Math.random() * 4)+1 - if theadra == 1 - loop - hbodyrb = Math.floor(Math.random() * 7)+1 - heb = hbodyrb-1 - break unless tijhcount[heb] >= 2 - tihead1 = jhands1[heb].concat(jhands1[heb]) - tijhcount[heb] = tijhcount[heb]+2 - tibody = tibody.concat(tihead1) + ### + * 4面子1雀頭の生成 + * 雀頭を設定した後,順子か刻子を4個後ろにつける + * 順子:刻子 = 1 : 1 + ### + normal = -> + str = "" + # 雀頭の生成 + head = randNum(34) + count[head] += 2 + str += int2hai(head) + int2hai(head) + " " + # 面子を4つ作る + for i in [0 .. 3] + # 順子にするか,刻子にするか + j = randNum(2) + if j == 0 + mentsu = kotsu() else - hms = Math.floor(Math.random()*3)+1 - hmsp = hms-1 - loop - hbodyrc = Math.floor(Math.random() * 9)+1 - hc = hbodyrc-1 - break unless tihcount[hmsp][hc] >= 2 - tihead1 = hands1[hmsp][hc].concat(hands1[hmsp][hc]) - tihcount[hmsp][hc] = tihcount[hmsp][hc]+2 - tibody = tibody.concat(tihead1) + mentsu = shuntsu() + # 順子の場合,鳴く確率は1/5.刻子の場合,鳴く確率は1/3 + if (randNum(2 * j + 3)) == 0 + naita = true + str += "(" + mentsu + ") " + else + str += mentsu + " " + return str - tirandom = Math.floor(Math.random()*20)+1 - #tirandom = 7 - tb1 = tibody.shift() - tb2 = tibody.shift() - tb3 = tibody.shift() - tb4 = tibody.shift() - tb5 = tibody.shift() - tb6 = tibody.shift() + shuntsu = -> + while true + i = randNum(21) + i += (Math.floor(i / 7)) * 2 + if (count[i] < 4 and count[i + 1] < 4 and count[i + 2] < 4) + break + count[i]++ + count[i + 1]++ + count[i + 2]++ + return int2hai(i) + int2hai(i + 1) + int2hai(i + 2) - #国士実装 - kokusirandom = Math.floor(Math.random()*16)+1 - #kokusirandom = 13 - kokusibody = ":1man::9man::1so::9so::1pin::9pin::hai-ton::hai-nan::hai-sha::hai-pei::hai-haku::hai-hatsu::hai-chun:" - kokushijork = Math.floor(Math.random()*2)+1 - if kokushijork == 1 - kr = Math.floor(Math.random()*3)+1 - kor = kr-1 - khai = Math.floor(Math.random()*2)+1 - if khai == 1 - kokusipin = hands1[kor][0] - else - kokusipin = hands1[kor][8] - else - jkr = Math.floor(Math.random()*7)+1 - jikor = jkr-1 - kokusipin = jhands1[jikor] + kotsu = -> + while true + i = randNum(34) + if count[i] < 2 + break + # 牌が1枚も使われていないとき,20%の確率で槓子になる + if count[i] == 0 and (randNum(5)) == 0 + count[i] += 4 + kantsu++ + return "[" + int2hai(i) + int2hai(i) + int2hai(i) + int2hai(i) + "]" + count[i] += 3 + return int2hai(i) + int2hai(i) + int2hai(i) + + # ドラの生成 + makeDora = -> + while true + i = randNum(34) + if count[i] < 4 + break + count[i]++ + return int2hai(i) + + # 槓ドラ,裏ドラ + addDora = -> + str = "追加ドラ" + if !naita + for i in [0 .. kantsu] + str += makeDora() + for i in [0 ... kantsu] + str += makeDora() + return str + # ドラ,風を表示する + kaze_and_firstDora = -> + return "ドラ表示" + makeDora() + " 場風" + int2hai((randNum(4)) + 30) + " 自風" + int2hai((randNum(4)) + 30) - if tirandom == 7 - if kokusirandom == 13 && kokusirandom == 1 - msg.send "#{kokusibody} #{kokusipin}" - else - msg.send "#{head1} #{tb1} #{tb2} #{tb3} #{tb4} #{tb5} #{tb6}" + ### + * main + * 1%で国士無双,5%で七対子,94%でその他 + * チノちゃん風にコメントを出す + * 鳴いた場合,33%の確率で罵倒される + * 鳴かない場合,10%の確率で一発 + ### + msg.send "#{kaze_and_firstDora()}" + n = randNum(100) + if n < 1 + msg.send "#{kokushi()}" + else if n < 6 + msg.send "#{toitsu7()}" else - msg.send "#{head1} #{b1} #{b2} #{b3} #{b4}" + msg.send "#{normal()}" + if (!naita or kantsu > 0) + msg.send "#{addDora()}" + if naita and (randNum(3)) == 0 + msg.send "何で鳴いちゃったんですか? バカなんですか?" + if !naita and (randNum(10)) == 0 + msg.send "一発ですよ! すごい!" - #一発かどうかの判定 - pon = Math.floor(Math.random()*8)+1 - if pon == 1 && nakicount == 0 - msg.send "一発だよ!!すごい!!" - else if pon == 1 && nakicount != 0 - msg.send "なんで鳴いちゃったの?馬鹿なの?" robot.hear /(\d+)(翻|飜)(\d+)符/, (msg) -> + + # 10の位を切り上げ + carry10 = (num) -> + Math.ceil(num / 100) * 100 # 小数にしてから小数点以下を切り捨てる + + # 1の位を切り上げ + carry1 = (num) -> + Math.ceil(num / 10) * 10 # 小数にしてから小数点以下を切り捨てる + han = parseInt(msg.match[1], 10) hu = parseInt(msg.match[3], 10) if (hu <= 10 and 110 < hu) or (han == 1 and hu <= 20) or han < 1 @@ -341,9 +269,8 @@ module.exports = (robot) -> children_ron = children_ron.toString() children_tumo4parent = children_tumo4parent.toString() children_tumo4children = children_tumo4children.toString() - msg.send """ロン:親は #{parent_ron} 点です - 子は #{children_ron} 点です - ツモ:親は #{parent_tumo} オールです - 子は (#{parent_tumo} ,#{children_tumo4children}) です + msg.send """ロン:親は #{parent_ron}点 です + 子は #{children_ron}点 です + ツモ:親は #{parent_tumo}点 オールです + 子は (#{parent_tumo}点, #{children_tumo4children}点) です """ -