麻雀の待ち問題を少し真面目に書き直した
makeplex salon:あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定 (1/2) - ITmedia エンタープライズ
http://www.itmedia.co.jp/enterprise/articles/1004/03/news002.html
の問題を解いてみた
いろいろ面倒だったので深く考えずに正規表現でガンガン回す方針
回答を提出した半日後に少し真面目に書き直した
/**
* Copyright kaikoga ( http://wonderfl.net/user/kaikoga )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/Ah4X
*/
// forked from kaikoga's 麻雀の待ち問題をやってみた
// forked from kaikoga's trace("自分用")
package {
/*
* makeplex salon:あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定 (1/2) - ITmedia エンタープライズ
* http://www.itmedia.co.jp/enterprise/articles/1004/03/news002.html
*
* の問題を解いてみた
* いろいろ面倒だったので深く考えずに正規表現でガンガン回す方針
*
* 回答を提出した半日後に少し真面目に書き直した
*/
import flash.display.Sprite;
import flash.text.TextField;
import flash.text.TextFormat;
public class FlashTest extends Sprite {
private var v:Array = [];
public function FlashTest() {
this.machiOut("1112224588899"); //(111)(222)(888)(99)[45]
this.machiOut("1122335556799"); //(123)(123)(555)(99)[67]、(123)(123)(55)(567)[99]、(123)(123)(99)(567)[55]
this.machiOut("1112223335559"); //(123)(123)(123)(555)[9]と(111)(222)(333)(555)[9]
this.machiOut("1223344888999"); //4をアタマにしての[23]待ちと、1単騎、4単騎で3個の答えになります。
this.machiOut("1112345678999"); //九蓮宝燈
}
public function machiOut(input:String):void {
this.trace("machi(" + input + "): ");
this.trace(this.machi(input));
this.trace();
}
public function machi(input:String):String {
return this.doMachi(input).join(", ");
}
private function doMachi(input:String):Array {
//Internal intermediate format: "14588899@(11)(222)"
//Unorganized tiles and "@", followed by organized sets
var intermediate:Array = [input + "@"];
//Extract atama only once
var intermediateNoAtama:Array = [];
for each (var atama:String in ["11", "22", "33", "44", "55", "66", "77", "88", "99"]) {
this.tryAddExtractSet(intermediate, atama, intermediateNoAtama, false);
}
//Extract sets many times
for each (var koutsu:String in ["111", "222", "333", "444", "555", "666", "777", "888", "999"]) {
this.tryAddExtractSet(intermediate, koutsu, null, true);
this.tryAddExtractSet(intermediateNoAtama, koutsu, null, true);
}
for each (var shuntsu:String in ["123", "234", "345", "456", "567", "678", "789"]) {
this.tryAddExtractSet(intermediate, shuntsu, null, true);
this.tryAddExtractSet(intermediateNoAtama, shuntsu, null, true);
}
//intermediate = intermediate.concat(intermediateNoAtama);
intermediate = this.filterTanki(intermediate).concat(this.filterPairMachi(intermediateNoAtama));
var result:Array = [];
for each (var hand:String in intermediate) {
result.push(hand.split("@", 2)[1]);
}
return result.sort();
}
private function filterPairMachi(hands:Array):Array {
//filters machi created with double tiles and extract
var result:Array = [];
for each (var hand:String in hands) {
if (hand.indexOf("@") == 2) {
switch (hand.charCodeAt(1) - hand.charCodeAt(0)) {
case 2:
case 1:
case 0:
result.push(this.extractMachi(hand));
break;
}
}
}
return result;
}
private function filterTanki(hands:Array):Array {
//filters machi created with single tile and extract
var result:Array = [];
for each (var hand:String in hands) {
if (hand.indexOf("@") == 1) {
result.push(this.extractMachi(hand));
}
}
return result;
}
private function extractMachi(hand:String):String {
//The machi must be valid, check is done in filter~ methods
var handArray:Array = hand.split("@", 2);
var sets:String = handArray[1];
var machi:String = handArray[0];
sets = (")" + sets + "(").split(")(").slice(1, -1).sort().join(")(");
sets = "(" + sets + ")";
return "@" + sets + "[" + machi + "]";
}
private function tryAddExtractSet(hands:Array, tiles:String, target:Array = null, multiple:Boolean = false):Boolean {
//Add to array if tryExtractSet() succeeds with unique result
//Does multiple application if (multiple == true)
target ||= hands;
var success:Boolean = false;
var regExp:RegExp = new RegExp("(.*)" + tiles.split("").join("(.*)") + "(.*)@(.*)");
//trace("Main.tryAddExtractSet(): RegExp: ", regExp.source);
var c:int = hands.length;
for (var i:int = 0; i < c; i++) {
var hand:String = hands[i];
var newHand:String = tryExtractSet(hand, tiles, regExp);
if (newHand && hands.indexOf(newHand) < 0) {
target.push(newHand);
success = true;
if (multiple) {
c++;
}
}
}
return success;
}
private function tryExtractSet(hand:String, tiles:String, regExp:RegExp):String {
//Extracts set from unorganized section and append to organized section
var tileCount:int = tiles.length;
if (hand.indexOf("@") < tileCount) {
return null;
}
var exec:Object = regExp.exec(hand);
if (!exec) {
return null;
}
var result:String = "";
for (var i:int = 1; i <= tileCount + 1; i++) {
result += exec[i];
}
result += "@" + exec[i] + "(" + tiles + ")";
//trace("Main.tryExtractSet(): Extraction: ", hand, "->", tiles, "=>", result, "//", exec)
return result;
}
private var _traceField:TextField;
public function trace(...message):void {
if (!this._traceField) {
this._traceField = new TextField();
this._traceField.width = this.stage.stageWidth;
this._traceField.height = this.stage.stageHeight;
this._traceField.defaultTextFormat = new TextFormat("_typewriter", 10);
this._traceField.wordWrap = true;
this.addChild(this._traceField);
}
this._traceField.appendText(message.join(" ") + "\n");
}
}
}