麻雀の待ち問題をやってみた
forked from trace("自分用") (diff: 163)
makeplex salon:あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定 (1/2) - ITmedia エンタープライズ http://www.itmedia.co.jp/enterprise/articles/1004/03/news002.html の問題を解いてみた 問題文を読んでから正しい答えが出せるようになるまで1時間と少し wonderflにアップロードして体裁を整えるのにさらに15分くらい? いろいろ面倒だったので深く考えずに正規表現でガンガン回す方針 最初は面子抽出中の手牌データをクラスを作って持とうかと思ったけど クラスを定義するのが面倒だったので文字列操作でどうにかする方針に。 コーディングしながらJavaっぽくなるかLLっぽくなるか考えられるのが AS3の最大の魅力でしょうか・・・ いちおう正常に動いてはいるみたいだけど結構ボロがあるみたい・・・ 後から気付いた要改善点も敢えてリファクタリングはしないで 日本語のコメントで書いておくにとどめるという方針で
ActionScript3 source code
/**
* Copyright kaikoga ( http://wonderfl.net/user/kaikoga )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/mX6V
*/
// forked from kaikoga's trace("自分用")
package {
/*
* makeplex salon:あなたのスキルで飯は食えるか? 史上最大のコーディングスキル判定 (1/2) - ITmedia エンタープライズ
* http://www.itmedia.co.jp/enterprise/articles/1004/03/news002.html
*
* の問題を解いてみた
* 問題文を読んでから正しい答えが出せるようになるまで1時間と少し
* wonderflにアップロードして体裁を整えるのにさらに15分くらい?
* いろいろ面倒だったので深く考えずに正規表現でガンガン回す方針
*
* 最初は面子抽出中の手牌データをクラスを作って持とうかと思ったけど
* クラスを定義するのが面倒だったので文字列操作でどうにかする方針に。
* コーディングしながらJavaっぽくなるかLLっぽくなるか考えられるのが
* AS3の最大の魅力でしょうか・・・
*
* いちおう正常に動いてはいるみたいだけど結構ボロがあるみたい・・・
* 後から気付いた要改善点も敢えてリファクタリングはしないで
* 日本語のコメントで書いておくにとどめるという方針で
*/
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 + "): ");
// いやせっかく machi() 作ったんだからそっち呼べし
this.trace(this.doMachi(input).join(", "));
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);
}
//Extract sets many times
for each (var koutsu:String in ["111", "222", "333", "444", "555", "666", "777", "888", "999"]) {
this.multiTryAddExtractSet(intermediate, koutsu);
this.multiTryAddExtractSet(intermediateNoAtama, koutsu);
}
for each (var shuntsu:String in ["123", "234", "345", "456", "567", "678", "789"]) {
this.multiTryAddExtractSet(intermediate, shuntsu);
this.multiTryAddExtractSet(intermediateNoAtama, shuntsu);
}
//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(0) - hand.charCodeAt(1)) {
case -2:
case 2:
case -1:
case 1:
case 0:
// たぶん間違い。
// 入力は既にソートされているので、
// case 1とcase 2は考慮に入れなくていい。
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 multiTryAddExtractSet(hands:Array, tiles:String, target:Array = null):void {
//Simple loop without thinking
// tryAddExtractSet()の挙動のせいで
// 実は4回繰り返す必要はなかった
for (var i:int = 0; i < 4; i++) {
if (!this.tryAddExtractSet(hands, tiles, target)) {
break;
}
}
}
private function tryAddExtractSet(hands:Array, tiles:String, target:Array = null):Boolean {
//Add to array if tryExtractSet() succeeds with unique result
// 実は(hands == target)の場合のみ面子の抽出が複数回行われるらしい
// 半ばウラ技じみた挙動だったけどたまたま動いてたらしい
// たぶん新しく生成された手牌データを一旦別の配列に保存しておく
// (再処理しない)のが当初意図していた挙動だと思う
target ||= hands;
var success:Boolean = false;
var regExp:RegExp = new RegExp("(.*)" + tiles.split("").join("(.*)") + "(.*)@(.*)");
//trace("Main.tryAddExtractSet(): RegExp: ", regExp.source);
for each (var hand:String in hands) {
var newHand:String = tryExtractSet(hand, tiles, regExp);
if (newHand && hands.indexOf(newHand) < 0) {
target.push(newHand);
success = true;
}
}
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");
}
}
}
