3,424
社区成员
发帖
与我相关
我的任务
分享
//牌号定义
//红:11-19
//绿:21-29
//黄:31-39
//紫:41-49
//东:1 南:3 西:5 北:7
//未定义:0,2,4,6,8,9,10,20,30,40,50及以上
function test(f:Function, n:Number) {
//检验目标函数运算时间
var t = getTimer();
for (var i = 0; i<=n; i++) {
f();
}
trace(((getTimer()-t))/n+"ms");
}
function copy(deck:Array):Array {
//复制牌组
var copied = [];
for (var i = 0; i<deck.length; i++) {
copied[i] = deck[i];
}
return copied;
}
function copyUnique(deck:Array):Array {
//复制牌组,并且删除冗余牌
var copied = [];
var j = 0;
for (var i = 0; i<deck.length; i++) {
if (deck[i] != copied[j-1]) {
copied[j] = deck[i];
j++;
}
}
return copied;
}
function copyExtend(deck:Array):Array {
//复制牌组,删除冗余牌并向周围扩散1个数字
var copied = [];
for (var i = 0; i<deck.length; i++) {
copied.push(deck[i]);
if (deck[i]+1>10 && (deck[i]+1)%10 != 0) {
copied.push(deck[i]+1);
}
if (deck[i]-1>10 && (deck[i]-1)%10 != 0) {
copied.push(deck[i]-1);
}
}
copied.sort();
return copyUnique(copied);
}
function haveTile(deck:Array, tile:Number):Boolean {
//判断牌组里是否有目标牌
for (var i = 0; i<deck.length; i++) {
if (tile == deck[i]) {
return true;
}
}
return false;
}
function countTile(deck:Array, tile:Number):Number {
//计算牌组里目标牌的数目
var count = 0;
for (var i = 0; i<deck.length; i++) {
if (tile == deck[i]) {
count++;
}
}
return count;
}
function isShun(deck:Array):Boolean {
//判断长度为3的牌组是否成顺
if (deck.length != 3) {
return false;
}
deck.sort();
return (deck[2] == deck[1]+1) && (deck[1] == deck[0]+1);
}
function isKe(deck:Array):Boolean {
//判断长度为3的牌组是否成刻
if (deck.length != 3) {
return false;
}
return (deck[2] == deck[1]) && (deck[1] == deck[0]);
}
function isDui(deck:Array):Boolean {
//判断长度为2的牌组是否成对
if (deck.length != 2) {
return false;
}
return deck[1] == deck[0];
}
function isKang(deck:Array):Boolean {
//判断长度为4的牌组是否成杠
if (deck.length != 4) {
return false;
}
return (deck[3] == deck[2]) && (deck[2] == deck[1]) && (deck[1] == deck[0]);
}
function isKan(deck:Array):Boolean {
//判断长度为2的牌组是否为砍张待和
if (deck.length != 2) {
return false;
}
deck.sort();
return (deck[1] == deck[0]+2) && (deck[0]%10 != 9) && (deck[0]>10);
}
function isLiangMian(deck:Array):Boolean {
//判断长度为2的牌组是否为两面待和
if (deck.length != 2) {
return false;
}
deck.sort();
return (deck[1] == deck[0]+1) && (deck[0]%10 != 1) && (deck[1]%10 != 9);
}
function isShangBian(deck:Array):Boolean {
//判断长度为2的牌组是否为上边张待和(8、9,和7)
if (deck.length != 2) {
return false;
}
deck.sort();
return (deck[1] == deck[0]+1) && (deck[1]%10 == 9);
}
function isXiaBian(deck:Array):Boolean {
//判断长度为2的牌组是否为下边张待和(2、1,和3)
if (deck.length != 2) {
return false;
}
deck.sort();
return (deck[1] == deck[0]+1) && (deck[0]%10 == 1);
}
function isHu(deck:Array):Boolean {
//判断牌组(长度除以3余2)是否组成和牌
//已知最长耗时2.7459ms
if (deck.length%3 != 2) {
return false;
}
if (deck.length == 2) {
if (isDui(deck)) {
return true;
} else {
return false;
}
}
var extract_ke = cutKeEnum(deck);
for (var i = 0; i<extract_ke.count; i++) {
if (isHu(extract_ke.remain[i])) {
return true;
}
}
var extract_shun = cutShunEnum(deck);
for (var i = 0; i<extract_shun.count; i++) {
if (isHu(extract_shun.remain[i])) {
return true;
}
}
return false;
}
//听牌算法
function ting(deck:Array):Array {
//判断牌组(长度除以3余1)是否听牌并输出所有待和之牌。
//遍历牌库里每一张牌,加入到牌组来判定是否和牌。
//已知最长耗时1751ms(太长了……)
var tingArray = [];
var tileArray = [11, 12, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 24, 25, 26, 27, 28, 29, 31, 32, 33, 34, 35, 36, 37, 38, 39, 41, 42, 43, 44, 45, 46, 47, 48, 49, 1, 3, 5, 7];
for (var i = 0; i<tileArray.length; i++) {
var m_deck = copy(deck);
m_deck.push(tileArray[i]);
if (isHu(m_deck)) {
tingArray.push(tileArray[i]);
}
}
return tingArray;
}
function ting2(deck:Array):Array {
//判断牌组(长度除以3余1)是否听牌并输出所有待和之牌。
//基于ting1算法,选择牌库中与牌堆相同或者差1的牌来进行判别,其他一律不判别
var tingArray = [];
var tileArray = copyExtend(deck);
for (var i = 0; i<tileArray.length; i++) {
var m_deck = copy(deck);
m_deck.push(tileArray[i]);
if (isHu(m_deck)) {
tingArray.push(tileArray[i]);
}
}
return tingArray;
}
function ting3(deck:Array):Array {
//判断牌组(长度除以3余1或2)是否听牌并输出所有待和之牌。
//不通过判定和牌直接来判定是否听牌。
//单骑、一对、两面待、上边张、下边张、砍张则可以直接判定;
//长度为4的牌组进行对提取、刻提取和顺提取,然后将剩余牌型判定;
//长度大于4的牌组进行刻提取和顺提取,然后剩余牌型判定。
//已知最长耗时89ms(还是很长,不能接受,原因见后)
var tingArray = [];
if (deck.length%3 == 0) {
return [];
}
if (deck.length == 1) {
return [deck[0]];
}
if (deck.length == 2) {
if (isDui(deck)) {
return [deck[0]];
}
if (isKan(deck)) {
return [deck[0]+1];
}
if (isLiangMian(deck)) {
return [deck[0]-1, deck[1]+1];
}
if (isShangBian(deck)) {
return [deck[0]-1];
}
if (isXiaBian(deck)) {
return [deck[1]+1];
}
}
if (deck.length == 4) {
var extract_dui = cutDuiEnum(deck);
for (var i = 0; i<extract_dui.count; i++) {
tingArray=tingArray.concat(ting3(extract_dui.remain[i]));
}
var extract_ke = cutKeEnum(deck);
for (var i = 0; i<extract_ke.count; i++) {
tingArray=tingArray.concat(ting3(extract_ke.remain[i]));
}
var extract_shun = cutShunEnum(deck);
for (var i = 0; i<extract_shun.count; i++) {
tingArray=tingArray.concat(ting3(extract_shun.remain[i]));
}
}
if (deck.length>4) {
var extract_ke = cutKeEnum(deck);
for (var i = 0; i<extract_ke.count; i++) {
tingArray=tingArray.concat(ting3(extract_ke.remain[i]));
}
var extract_shun = cutShunEnum(deck);
for (var i = 0; i<extract_shun.count; i++) {
tingArray=tingArray.concat(ting3(extract_shun.remain[i]));
}
}
tingArray.sort();
return copyUnique(tingArray);
}
//提取操作
function cutTile(deck:Array, tile:Number):Array {
//从牌组中尝试提取目标牌(如果存在多个则只提取1个,如果不存在则不提取,返回剩下的牌组成的牌组)
var cut = copy(deck);
for (var i = 0; i<=cut.length-1; i++) {
if (cut[i] == tile) {
cut.splice(i, 1);
break;
}
}
return cut;
}
function cutDuiEnum(deck:Array):Object {
//对提取操作。
//返回一个对象:
//count为成功进行对提取操作的次数;
//extract[n]为一次对提取操作中提取的牌构成的牌组;
//remain[n]为一次对提取操作中剩余的牌构成的牌组;
//n的取值范围为0到count-1。
deck.sort();
var enum = new Object();
var uniqueDeck = copyUnique(deck);
enum.count = 0;
enum.extract = [];
enum.remain = [];
for (var i = 0; i<uniqueDeck.length; i++) {
var tile = uniqueDeck[i];
var cut = copy(deck);
if (countTile(cut, tile)>=2) {
cut = cutTile(cut, tile);
cut = cutTile(cut, tile);
enum.extract[enum.count] = [tile, tile];
enum.remain[enum.count] = copy(cut);
enum.count++;
}
}
return enum;
}
function cutShunEnum(deck:Array):Object {
//顺提取操作。
//返回一个对象:
//count为成功进行顺提取操作的次数;
//extract[n]为一次顺提取操作中提取的牌构成的牌组;
//remain[n]为一次顺提取操作中剩余的牌构成的牌组;
//n的取值范围为0到count-1。
//最长耗时950微秒。
deck.sort();
var enum = new Object();
var uniqueDeck = copyUnique(deck);
enum.count = 0;
enum.extract = [];
enum.remain = [];
for (var i = 0; i<uniqueDeck.length-2; i++) {
var tile = uniqueDeck[i];
var cut = copy(deck);
if (haveTile(cut, tile+1) && haveTile(cut, tile+2)) {
cut = cutTile(cut, tile);
cut = cutTile(cut, tile+1);
cut = cutTile(cut, tile+2);
enum.extract[enum.count] = [tile, tile+1, tile+2];
enum.remain[enum.count] = copy(cut);
enum.count++;
}
}
return enum;
}
function cutKeEnum(deck:Array):Object {
//刻提取操作。
//返回一个对象:
//count为成功进行刻提取操作的次数;
//extract[n]为一次刻提取操作中提取的牌构成的牌组;
//remain[n]为一次刻提取操作中剩余的牌构成的牌组;
//n的取值范围为0到count-1。
//最长耗时581微秒。
deck.sort();
var enum = new Object();
var uniqueDeck = copyUnique(deck);
enum.count = 0;
enum.extract = [];
enum.remain = [];
for (var i = 0; i<uniqueDeck.length; i++) {
var tile = uniqueDeck[i];
var cut = copy(deck);
if (countTile(cut, tile)>=3) {
cut = cutTile(cut, tile);
cut = cutTile(cut, tile);
cut = cutTile(cut, tile);
enum.extract[enum.count] = [tile, tile, tile];
enum.remain[enum.count] = copy(cut);
enum.count++;
}
}
return enum;
}
/////////////////////
function canLi(deck:Array, tile:Number):Array {
//判断抓到目标牌时,牌组能否打出一张牌进行立直,输出所有可以打出的牌。
//目前最短耗时798ms,使用ting3算法。
var li_array = [];
var m_deck = copy(deck);
m_deck.push(tile);
for (var i = 0; i<m_deck.length; i++) {
var m_deck2 = copy(m_deck);
m_deck2.splice(i, 1);
var m_ting = ting3(m_deck2);
trace("cut "+m_deck[i]+": "+m_ting);
if (m_ting.length != 0) {
li_array.push(m_deck[i]);
}
}
return li_array;
}
//Debug
function dispCut(n:Object) {
//Debug用:输出提取对象的内容。
trace("Enum count:"+n.count+"\n");
for (var i = 0; i<n.count; i++) {
trace(i+" Extract: "+n.extract[i].toString()+"\n");
trace(i+" Remain: "+n.remain[i].toString()+"\n");
}
}