麻雀 シャンテン数
forked from flash on 2010-11-30 (diff: 222)
メモ この方式は手牌を2回走査するのでちょっとあれかもしれない でも対人間用なら十分実用に耐える気がする、どうなんだろう チートイ国士は省略(*´ω`*)
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/mxIZ
*/
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);
}
}
