Beautifl - Flash Gallery

Thumbnail : Mine
Mine
flashrod 2010-01-02 MIT License

再生するにはFlash Playerが必要です。デスクトップのブラウザでご覧ください。

package {
    import flash.display.*;
    import flash.events.*;
    import flash.text.*;
    import flash.utils.*;

    [SWF(backgroundColor="0xCCCCCC")]
    public class Mine extends Sprite {

        private static const COLS:int = 9;
        private static const LINES:int = 9;
        private static const MINES:int = 10;
        private static const W:int = 18;

        /** COLS×LINESの2次元配列 */
        private var field:Array = [];

        /** 時間表示 */
        private var time:TextField = new TextField();
        /** 状態表示 */
        private var state:TextField = new TextField();
        /** メッセージ表示 */
        private var message:TextField = new TextField();
        /** 開始時刻 */
        private var t0:int;
        /** カウントアップ中は真 */
        private var countup:Boolean;

        public function Mine() {
            for (var j:int = 0; j < LINES; ++j) {
                field[j] = [];
                for (var i:int = 0; i < COLS; ++i) {
                    var tf:TextField = new TextField();
                    tf.selectable = false;
                    tf.x = i*W;
                    tf.y = j*W + W;
                    field[j][i] = {t:tf};
                    addChild(tf);
                }
            }

            restart();

            stage.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void {
                var i:int = e.stageX / W;
                var j:int = Math.floor((e.stageY - W) / W);
                if (countup && 0 <= i && i < COLS && 0 <= j && j < LINES) {
                    if (e.ctrlKey) {
                        var o:* = field[j][i];
                        if (!o.opened) {
                            if (o.flag) {
                                o.flag = false;
                                o.t.text = "";
                            } else {
                                o.flag = true;
                                o.t.text = "?";
                            }
                        }
                    } else if (e.shiftKey) {
                        sweep(i, j);
                    } else {
                        click(i, j);
                    }
                    repaint();
                    if (finished()) {
                        countup = false;
                        state.text = "complete";
                    }
                }
            });
            addEventListener(Event.ENTER_FRAME, function(e:Event):void {
                if (countup) {
                    var t:int = (getTimer() - t0) / 1000;
                    var m:int = t / 60;
                    var s:int = t % 60;
                    time.text = int(m/10)+""+(m%10)+":"+int(s/10)+""+(s%10);
                }
            });
            // 時刻表示
            time.autoSize = 'left';
            time.text = "00:00";
            time.selectable = false;
            time.x = COLS * W - time.width;
            addChild(time);
            // 状態表示をボタンにしています。
            state.autoSize = 'left';
            var b:SimpleButton = new SimpleButton();
            b.addEventListener(MouseEvent.CLICK, function(e:MouseEvent):void { restart(); });
            b.downState = b.overState = b.upState = b.hitTestState = state;
            b.x = W * COLS / 2 - b.width/2;
            addChild(b);
            // メッセージ表示領域
            message.text = "click:open, ctrl+click:flag, shift+click:sweep";
            message.autoSize = 'left';
            message.selectable = false;
            message.y = LINES * W + W;
            addChild(message);
        }

        /** 再スタート
         */
        private function restart():void {
            state.text = 'start';
            lay();
            repaint();
            countup = true;
            t0 = getTimer();
        }

        /** 指定した点と周りの旗を立てたところ以外を開きます。
         * @param (x,y) 指定位置
         */
        private function sweep(x:int, y:int):void {
            for (var j:int = -1; j < 2; ++j) {
                var v:int = y + j;
                if (0 <= v && v < LINES) {
                    for (var i:int = -1; i < 2; ++i) {
                        var u:int = x + i;
                        if (0 <= u && u < COLS) {
                            if (!field[v][u].flag) {
                                click(u, v);
                            }
                        }
                    }
                }
            }
        }

        /** (x,y)を開きます。
         * @param (x,y) 指定位置
         */
        private function click(x:int, y:int):void {
            var cell:* = field[y][x];
            cell.opened = true;
            if (cell.mine) { // 地雷を踏んだ時地雷を全部可視にします。
                for (var j:int = 0; j < LINES; ++j) {
                    for (var i:int = 0; i < COLS; ++i) {
                        var o:* = field[j][i];
                        if (o.mine) {
                            o.t.text = "X";
                        }
                    }
                }
                state.text = "game over";
                countup = false;
            } else {    // 地雷じゃないとき
                var n:int = around(x, y); // 周りの地雷数を数えて
                if (n) { // 0じゃないなら数字を表示
                    cell.t.text = n+"";
                } else {
                    open(x, y);
                }
            }
        }

        /** (x,y)の周りを全部開きます。
         */
        private function open(x:int, y:int):void {
            for (var j:int = -1; j < 2; ++j) {
                var v:int = y + j;
                if (0 <= v && v < LINES) {
                    for (var i:int = -1; i < 2; ++i) {
                        var u:int = x + i;
                        if (0 <= u && u < COLS) {
                            if (!field[v][u].opened) {
                                click(u, v);
                            }
                        }
                    }
                }
            }
        }

        /** 地雷を敷設します。
         */
        private function lay():void {
            // 全て空にする
            for (var j:int = 0; j < LINES; ++j) {
                for (var i:int = 0; i < COLS; ++i) {
                    var o:* = field[j][i];
                    o.t.text = "";
                    o.mine = o.flag = o.opened = false;
                }
            }
            // 地雷をMINES個置く
            for (var k:int = 0; k < MINES;) {
                i = Math.random() * COLS;
                j = Math.random() * LINES;
                if (!field[j][i].mine) {
                    field[j][i].mine = true;
                    ++k;
                }
            }
        }

        /** (x,y)の周りにある地雷の数を数えます
         * @param (x,y) 指定位置(地雷が無いこと)
         * @return (x,y)の周りにある地雷の数(0~8)
         */
        private function around(x:int, y:int):int {
            var n:int = 0;
            for (var j:int = -1; j < 2; ++j) {
                var v:int = y + j;
                if (0 <= v && v < LINES) {
                    for (var i:int = -1; i < 2; ++i) {
                        var u:int = x + i;
                        if (0 <= u && u < COLS) {
                            if (field[v][u].mine) {
                                ++n;
                            }
                        }
                    }
                }
            }
            return n;
        }

        /** 描画
         */
        private function repaint():void {
            graphics.clear();
            for (var j:int = 0; j < LINES; ++j) {
                var y:int = j * W + W;
                for (var i:int = 0; i < COLS; ++i) {
                    var color:uint = field[j][i].opened ? 0 : -1;
                    var x:int = i * W;
                    with (graphics) {
                        lineStyle(1, color);
                        moveTo(x, y + W-1);
                        lineTo(x, y);
                        lineTo(x + W-1, y);
                        lineStyle(1, color ^ -1);
                        lineTo(x + W-1, y + W-1);
                        lineTo(x, y + W-1);
                    }
                }
            }
        }

        /** 完了したかどうか検査します。
         * @return 完了しているときは真
         */
        private function finished():Boolean {
            var c:int = 0; // 地雷の上に立てた旗の数を数える
            for (var j:int = 0; j < LINES; ++j) {
                for (var i:int = 0; i < COLS; ++i) {
                    var o:* = field[j][i];
                    if (o.mine && o.flag) { // 地雷の上に旗があるとき
                        c++;
                    }
                }
            }
            return c == MINES;  // 地雷の数と一致してたら完成
        }
    }
}