Mine
/**
* Copyright flashrod ( http://wonderfl.net/user/flashrod )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/fqtR
*/
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; // 地雷の数と一致してたら完成
}
}
}