forked from: 麻雀 シャンテン数

by enecre forked from 麻雀 シャンテン数 (diff: 3)
TODO: mentsu_cut & taatsu_cut get together -> n_loop declining expected
TODO: save tehai division when syanten is min(...or tehai is good)
♥0 | Line 220 | Modified 2010-12-03 14:19:14 | MIT License
play

ActionScript3 source code

/**
 * Copyright enecre ( http://wonderfl.net/user/enecre )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/7X0t
 */

// forked from enecre's 麻雀 シャンテン数
// TODO: mentsu_cut & taatsu_cut get together -> n_loop declining expected
// TODO: save tehai division when syanten is min(...or tehai is good)
package {
    import flash.text.TextFormat;
    import flash.events.Event;
    import flash.text.TextField;
    import flash.display.Sprite;
    import com.bit101.components.*;    
    
    public class FlashTest extends Sprite {
        
        private var tf:TextField = new TextField();
        private var it:InputText;
        
        private var tehai:Tehai;
        
        public function FlashTest() {
            // write as3 code here..
            var defaultInput:String = "123m456p789s2244z";
            
            tf.width = 465;
            tf.height = 465 - 70;
            tf.x = stage.stageWidth / 2 - tf.width / 2;
            tf.y = 70;
            tf.defaultTextFormat = new TextFormat("Meiryo", 12);
            addChild(tf);
            it = new InputText(this, 0, 0, defaultInput, onInput);
            it.width = 150;
            it.x = stage.stageWidth / 2 - it.width / 2;
            it.y = 50;
            addChild(new PushButton(this, 20, 48, "Clear", clearText));
            addChild(new PushButton(this, 340, 48, "Execute", onButton));
            
            Tehai.tr = this.tr;
            Syanten.tr = this.tr;
        }
        
        private function start():void{
            tr("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
            tr(tehai);
            tr("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *");
            tr("シャンテン数: " + tehai.calcSyanten());
            tr("ループ数:" + tehai.n_loop);
            tr("かかった時間:" + tehai.time + "ms");
        }
        
        private function mpsToArray(mps:String):Array{
            var reg:Array = /((\d+?)m)?((\d+?)p)?((\d+?)s)?((\d+?)z)?/.exec(mps);
            if(!reg)return [];
            var arr:Array = [];
            var l:int = mps.length;
            var mode:int = 3;
            var map:Array = [ 4, 0, 1, 2, 3, 4, 5, 6, 7, 8,
                             13, 9,10,11,12,13,14,15,16,17,
                             22,18,19,20,21,22,23,24,25,26,
                             -1,27,28,29,30,31,32,33
                            ];
            loop: while(l--){
                var ch:String = mps.charAt(l);
                switch(ch){
                    case "z": {mode = 3; continue loop;}
                    case "s": {mode = 2; continue loop;}
                    case "p": {mode = 1; continue loop;}
                    case "m": {mode = 0; continue loop;}
                    default: break;
                }
                arr.push(map[mode * 10 + int(ch)]);
            }
            return arr.reverse();
        }
        
        private function onButton(e:Event):void{
            tehai = new Tehai(mpsToArray(it.text));
            start();
        }

        
        private function onInput(e:Event):void{
            var text:String = (e.currentTarget as InputText).text;
            var result:Object = /(.+?)\@/.exec(text);
            if(!result)return;
            tehai = new Tehai(mpsToArray(result[1]));
            start();
        }
        
        private function clearText(e:Event = null):void{
            tf.text = "";
        }

        private function tr(...o:Array):void{
            tf.appendText(o + "\n");
            tf.scrollV = tf.maxScrollV;
        }

    }
}

import flash.utils.*;

class Tehai {
    public static var tr:Function;
    
    private var _tehai:Array;
    
    private var _devisions:Array;
    public var minSyanten:int;
    public var n_loop:int;
    public var time:int;
        
    public function Tehai(tehai:Array){
        minSyanten = 8;
        _tehai = tehai;
        _devisions = [];
    }
    
    public function calcSyanten():int{
        var syanten:Syanten = new Syanten(to34());
        var start:int = getTimer();
        syanten.scanNormal();
        time = getTimer() - start;
        minSyanten = syanten.minSyanten;
        n_loop = syanten.n_loop;
        return minSyanten;
    }
    
    private function to34():Array {
        var retArr:Array = [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];
        var l:int = _tehai.length;
        for (var i:int = 0; i < l; i++) {
            retArr[_tehai[i]] += 1;
        }
        return retArr;
    }
    
    public function toString():String{
        return _tehai.toString();
    }
}

class Syanten {
    
    public static var tr:Function;

    private var c:Array/*int*/ = [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]; 
    private var mentsu:int = 0;
    private var taatsu:int = 0; // ターツ全般
    private var toitsu:int = 0; // 頭のこと 0 or 1
    private var jihai :int = 0;
    
    private var n4:int = 0; // bit, 4mai motteru hai = toitsutukurenai
    private var koritsu:int = 0; //bit
    
    public var minSyanten:int = 8;
    public var n_loop:int = 0;
    
    function Syanten(a:Array/*int*/, n:int = 34){ //a=tehai, n= 136mode or 34mode
        c = a.concat();
    }
    
    public function scanChiitoiKokushi():void { };
    
    public function scanNormal():void{
        mentsu = 0;
        taatsu = 0;
        toitsu = 0;
        minSyanten = 8;
        
        n_loop = 0;
        
        for(var i:int = 0; i < 34; i++){
            if(c[i] == 2 || c[i] == 3 || c[i] == 4){
                c[i] -= 2;
                toitsu += 1;
                mentsu_cut(0);
                toitsu -= 1;
                c[i] -= 2;
            }
        }
        mentsu_cut(0);
    }
    
    private function mentsu_cut(i:int):void{
        while(c[i] == 0)i++;
        if(i == 34){
            taatsu_cut(0);
            return;
        }
        //刻子
        if(c[i] == 3 || c[i] == 4){
            c[i] -= 3;
            mentsu += 1;
            mentsu_cut(i);
            mentsu -= 1;
            c[i] += 3;
        }
        //順子(sampleそのままでは駄目。手牌の表現の実装が違うため)
        if(i <= 26){
            var k:int = i % 9;
            if(k != 8 && k != 7 && c[i + 1] != 0 && c[i + 2] != 0){
                c[i] -= 1;
                c[i + 1] -= 1;
                c[i + 2] -= 1;
                mentsu += 1;
                mentsu_cut(i);
                mentsu -= 1;
                c[i] += 1;
                c[i + 1] += 1;
                c[i + 2] += 1;
            }
        }
        mentsu_cut(i + 1);
    }
    private function taatsu_cut(i:int):void{
        while(c[i] == 0)i++;
        if(i == 34){ //updateResult
            var syanten:int = 8 - mentsu * 2 - taatsu - toitsu;
            if(syanten < minSyanten) { minSyanten = syanten; }
            n_loop += 1;
            return;
        }
        if(mentsu + taatsu < 4){
            //対子
            if(c[i] == 2){
                c[i] -= 2;
                taatsu += 1;
                taatsu_cut(i);
                taatsu -= 1;
                c[i] += 2;
            }
            if(i <= 26){
                var k:int = i % 9;
                //辺張リャンメン
                if(c[i + 1] != 0 && k != 8){
                    c[i] -= 1;
                    c[i + 1] -= 1;
                    taatsu += 1;
                    taatsu_cut(i);
                    taatsu -= 1;
                    c[i] += 1;
                    c[i + 1] += 1;
                }
                //カンチャン
                if(c[i + 2] != 0 && k != 8 && k != 7){
                    c[i] -= 1;
                    c[i + 1] -= 1;
                    taatsu += 1;
                    taatsu_cut(i);
                    taatsu -= 1;
                    c[i] += 1;
                    c[i + 1] += 1;
                }
            }
        }
        taatsu_cut(i + 1);
    }
}