日本麻将杠有什么用能不能杠?怎么杠?


该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
master`
});
$branchesDropdown.append(html);
$('.protected-branch-popup').popup()
},
complete: function () {
concurrentRequestLock = false;
}
});
}
贡献代码同步代码Loading...README.md
在日本麻将中,构建双层 LSTM 网络,以预测他人的听牌情况
日本麻将是一种强调防守的麻将。当选择弃胡时,我想知道应该打出什么样的牌才不会点炮。这就是在这个项目中研究的问题:当他家率先立直时,他家可能的听牌有哪些。这个问题可以看成是一个文本分类问题来考虑,将前面已经打过的牌当作文本,听牌考虑成文本最终的分类。在此思考下,我选择了LSTM作为本项目的基础模型。
不过这种讨论与普通文本分类问题又不太一样,因为对于某一个文本一般是固定一个分类(比如情感分类中的积极或者消极);而对于麻将而言首先一次听牌可以听好几种牌,其次同样的舍牌可能听的牌完全不同。
向听数统计、仿真准备
起始牌的平均向听数
巡目
聴牌
1向聴
2向聴
3向聴
4向聴
5向聴
6向聴
平均
0
0.0%
0.6%
9.4%
36.2%
39.9%
13.1%
0.8%
3.58
1
0.1%
2.3%
19.4%
43.7%
28.5%
5.8%
0.2%
3.17
2
0.3%
6.0%
30.6%
43.1%
17.6%
2.3%
0.0%
2.79
3
1.0%
11.9%
39.6%
36.7%
9.9%
0.9%
0.0%
2.45
4
2.5%
19.5%
44.0%
28.2%
5.4%
0.4%
0.0%
2.16
5
5.0%
27.2%
43.9%
20.6%
3.1%
0.2%
0.0%
1.90
6
8.6%
33.8%
40.6%
14.9%
2.0%
0.2%
0.0%
1.68
7
13.1%
38.3%
35.8%
11.1%
1.5%
0.1%
0.0%
1.50
8
18.1%
40.7%
31.0%
8.8%
1.3%
0.1%
0.0%
1.35
9
23.1%
41.1%
26.8%
7.6%
1.2%
0.1%
0.0%
1.23
10
27.8%
40.1%
23.6%
7.1%
1.2%
0.1%
0.0%
1.14
11
32.0%
38.2%
21.5%
6.9%
1.3%
0.1%
0.0%
1.08
12
35.5%
35.9%
20.1%
7.0%
1.3%
0.1%
0.0%
1.03
13
38.4%
33.5%
19.3%
7.3%
1.4%
0.1%
0.0%
1.00
14
40.6%
31.2%
19.0%
7.7%
1.4%
0.1%
0.0%
0.98
15
42.4%
28.9%
18.9%
8.1%
1.5%
0.1%
0.0%
0.98
16
43.8%
26.7%
19.1%
8.6%
1.6%
0.1%
0.0%
0.98
17
45.0%
24.0%
19.9%
9.3%
1.6%
0.1%
0.0%
0.99
18
48.3%
21.1%
20.6%
8.6%
1.3%
0.1%
0.0%
0.94
配牌时平均向听数为3.58,最常见的是4向听。
计算
用简单的公式无法计算。需要分类讨论。
每个字牌和数牌、所有数牌0枚-14枚的情况、按照数牌进行分类等等参数都虚讨论。
情况一般来说分为,[雀头]+N张面子、七对子的对数、国士无双的幺九牌的数量和种类。
找到上述每个类别的模式数量和组合总数。
对于四种类型的牌型的总数为13或14的所有组合,计算组合数和向听数,并为每个向听数计算总数
计算实在过于复杂,在此只给出配牌时的计算式。
n: 配牌の枚数 (親=14、子=13)
k: 槓子の数
a: 刻子の数
t: 対子の数
结果
親 14枚 326520504500种
子 13枚 98521596000种
考虑国士无双、七对子
亲 配牌 平均向听数=13413711220546219200÷4250292170090008326≈3.156
子 配牌 平均向听数=1731757846767061316÷483774556165488000≈3.580
不考虑国士无双
亲 配牌 平均向听数=14092221711682799808÷4250293676040074502≈3.316
子 配牌 平均向听数=11831476779756155204÷483774556165488000≈3.786
**某一巡的平均向听数 **
计算 SSE,RMSE,R-square
天凤1k桌数据
https://ch.nicovideo.jp/curry-powder/blomaga/ar483872
天凤数据
http://tenhou.net/ranking.html
牌效模拟
天凤牌谱解析
https://tomohxx.hatenablog.com/entry/2019/01/16/230436
自摸巡目的期望值
使用随机化算法
对某一巡是否自摸,计算 Brier 分数表示拟合优度
牌山生成:
MT : http://www.google.co.jp/search?q=mt19937ar.c
SHA : http://www.google.co.jp/search?q=sha512.c
天凤api
https://t2t2.cc/?p=157
数据准备
数据主要是来自14年-18年的天凤牌谱。
天凤数据
http://tenhou.net/ranking.html
天凤1k桌数据
https://ch.nicovideo.jp/curry-powder/blomaga/ar483872
《科学する麻雀》作者とつげき東北的个人主页
一共收集有10782份的牌谱。
记录了对局信息,胡牌的番型和各家起手牌、宝牌、每家每一轮的摸牌、切牌和鸣牌。
数据增强
只用这些牌谱数据看起来还有些不够,训练出的结果不是很理想。考虑可以这样生成一些假的牌谱。
将中、发、白以某种顺序置换;将饼、万、索以某种顺序置换;
将123456789变成987654321。这样的变换不能保证是完全合理的。
一个原因是绿一色导致索和饼、万并不是完全等价的,但考虑到绿一色出现的概率如此的低就不管了。
另一个原因是宝牌的问题,比如原来的宝牌指示牌是1m,宝牌是2m。如果进行了123456789变成987654321,宝牌就会变成8m;
这时宝牌指示牌并不能变成9m,而变成了7m。
这两个问题不能很好解决,但为了获得更多的牌谱,还是进行了这几种置换。
中发白的置换共6种,饼万索的置换共6种,数字颠倒共2种(颠倒或者不颠倒),一共662=72种变换方式。对每一份牌谱,我们随机的选择k=7种变换作为增强的数据。(考虑到内存大小,k不要太大)
牌谱编码
将每一次摸牌,鸣牌或者打牌都定义为一个action,然后将这个action嵌入到一个52维向量中。这个向量描述了这个动作是谁执行的(东西南北家),是进行了什么动作(摸牌、切牌、吃碰杠、立直),是和哪一张牌进行了交互,交互牌是否是自风、场风、宝牌这些信息。具体的编码方式可以看**/src/haifu_parser.py中的action_to_vector(action,
player, chanfon, jikaze, dora_list)**函数。
模型训练
模型使用了双层LSTM网络连接34维的Softmax层进行预测(麻将一共34张不同的牌)。损失函数为交叉熵。在两块1080Ti的显卡下训练70个epoch得到了预训练的模型,大约需要训练2个小时。具体的模型可以参照**/src/neural_network.py**中的结构。
预训练好的模型保存在model/tenpai.model。我们需要将牌谱设置为data/test.txt中的格式,并保存到data/test.txt中:
東2局 0本場(リーチ0)
123
[1西]
[2北]1m5m6m7m4p6p1s5s7s東白白中
[3東]
[4南]
[表ドラ]西 [裏ドラ]北
* 3D9s 4d9m 1d北 2G4m 2d1s 3D6p 4d1m
* 1d南 2G2s 2d1m 3D6s 4D2s 1C3s4s 1d8m 2C6m7m 2d2s
* 3D3s 4d9p 4R 1G3s 1d9p
第一行填写东x局(或者南x局),后面的本场、立直棒、点棒信息都不是必要的。
第二行填写符数、翻数、番形,可以留空行,但不能把这行都删了。
第三-六行填写四家起手牌,可以只填自家牌,其他留空。其中m代表万,p代表饼,s代表索;“東南西北中発白”请使用日语汉字。比如:
[1西]
[2北]1m5m6m7m4p6p1s5s7s東白白中
[3東]
[4南]
第七行填写宝牌和里宝牌,里宝牌可以不填。注意是宝牌,不是宝牌指示牌!
第八行起填写这局牌的行进过程。每一行以*开始,每一个行动和行动之间有一个空格。比如第一行的动作3D9s可以翻译为东家摸切9s,4d9m可以翻译为3家切掉9m。只需要记录自家的摸牌动作(在这里就是2G,因为其他家摸到的牌你是看不见的,就算输入了模型也会忽略其他家的摸牌数据)
G
自摸(不是自摸和)
1G1m
d
切牌
1d2s
D
摸切
1D1m
N

1N
C

1C1s3s(1s3s是玩家1自己的牌)
K

1K1s
R
立直
1R
A
胡牌
1A
data/test.txt中可以保存多个牌谱,请在牌谱和牌谱之间用空行分隔。
开始预测
在src文件夹下,使用如下的命令进行预测
python predict.py
就可以看到类似如下的预测结果
Richi player tenpai: ['3m', '6m', '9m']
Player 1:
{'3m': 0.33759603, '6m': 0.33912653, '9m': 0.32323775}
Richi player tenpai: ['3m', '6m', '9m']
Player 2:
{'3m': 0.337948, '6m': 0.33527905, '9m': 0.31589714}
Richi player tenpai: ['3m', '6m', '9m']
Player 3:
{'3m': 0.33415237, '6m': 0.33977884, '9m': 0.32597464}
Richi player tenpai: ['6m']捐赠0 人次";
}
$complainCommentType.find('.menu').html(result);
}
});
$complainCommentType.dropdown({showOnFocus: false});
initedCommentsType = true;
}
}
$complainCommentType.on('click', function() {
$complaintCommentsModal.modal({
autofocus: false,
onApprove: function() {
return false;
},
onHidden: function() {
restoreCommonentDefault();
}
}).modal('show');
});
$complaintCommentsContent.on('change keyup', function(e) {
var content = $(this).val();
if ($.trim(content).length > 0 && $complainCommentType.dropdown('get value').length > 0 ) {
$complaintCommentBtn.removeClass('disabled');
return;
}
$complaintCommentBtn.addClass('disabled');
});
$complainCommentType.dropdown({
showOnFocus: false,
onChange: function(value, text, $selectedItem) {
if (value.length > 0 && $.trim($complaintCommentsContent.val()).length > 0) {
$complaintCommentBtn.removeClass('disabled');
return
}
$complaintCommentBtn.addClass('disabled');
}
});
function restoreCommonentDefault() {
$complainCommentType.dropdown('restore defaults');
$complaintCommentsContent.val('');
$('.exceeded-size-tip').text('').hide();
$complaintModalTip.text('').hide();
setTimeout(function() {
setCommentSendTip(false);
}, 1500);
}
$complaintCommentBtn.on('click',function(e){
var reason = $complaintCommentsContent.val();
var appealableId = $('#landing-comments-complaint-modal').attr('data-id');
if (complaintSending) {
return;
}
var appealType = $complainCommentType.dropdown('get value');
var formData = new FormData();
formData.append('appeal_type_id', appealType);
formData.append('reason', reason);
formData.append('appeal_type','Note');
formData.append('target_id',appealableId);
$.ajax({
type: 'POST',
url: "/appeals",
cache: false,
contentType: false,
processData: false,
data: formData,
beforeSend: function() {
setCommentSendStatus(true);
},
success: function(res) {
if (res.status == 200) {
setCommentSendTip(true);
setTimeout(function() {
$complaintCommentsModal.modal('hide');
restoreCommonentDefault();
}, 3000);
}
setCommentSendStatus(false);
},
error: function(err) {
showCommonTips(err.responseJSON.message, 'error');
setCommentSendStatus(false);
}
})
});
function showCommonTips(text, type) {
$complaintModalTip.text(text).show();
if (type == 'error') {
$complaintModalTip.removeClass('success').addClass('error');
} else {
$complaintModalTip.removeClass('error').addClass('success');
}
}
function setCommentSendStatus(value) {
complaintSending = value;
if (complaintSending) {
$complaintCommentBtn.addClass('loading');
$complaintCommentsContent.attr('readonly', true);
$complainCommentType.attr('readonly', true);
} else {
$complaintCommentBtn.removeClass('loading');
$complaintCommentsContent.attr('readonly', false);
$complainCommentType.attr('readonly', false);
}
}
function setCommentSendTip(value) {
if (value) {
$('.appeal-success-tip').removeClass('hide');
$('.appeal-tip').addClass('hide');
$('.appeal-form').addClass('hide');
$('#landing-comments-complaint-modal .actions').addClass('hide');
} else {
$('.appeal-success-tip').addClass('hide');
$('.appeal-tip').removeClass('hide');
$('.appeal-form').removeClass('hide');
$('#landing-comments-complaint-modal .actions').removeClass('hide');
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。

我要回帖

更多关于 日本麻将杠有什么用 的文章

 

随机推荐