EmEditorみんなでまとめサイト

マインスイーパマクロ

最終更新:

匿名ユーザー

- view
だれでも歓迎! 編集

マクロ

2004/02/18 by swat: 説明は不用だと思うので割愛。 実際にプレイするととにかくめんどくさいです。

var BOARD_WIDTH  = 5; //横マス数
var BOARD_HEIGHT = 5; //縦マス数
var NUMBER_MINES = 5; //爆弾の数

//マスの状態フラグ設定
var STATUS_COVERED  = 0x10; //マスが閉じている
var STATUS_MINED    = 0x20; //爆弾がある
var STATUS_FLAGGED  = 0x40; //旗が立っている
var STATUS_EXPLODED = 0x80; //爆弾が爆発している
var STATUS_NEIGHBORMINES_MASK = 0x0f; //周囲の爆弾の数を得るときのマスク

//状態取得用関数
function isCovered(x, y) {return ((board[y][x] & STATUS_COVERED) == STATUS_COVERED);}
function isMined(x, y) {return ((board[y][x] & STATUS_MINED) == STATUS_MINED);}
function isFlagged(x, y) {return ((board[y][x] & STATUS_FLAGGED) == STATUS_FLAGGED);}
function isExploded(x, y) {return ((board[y][x] & STATUS_EXPLODED) == STATUS_EXPLODED);}
function countNeighborMines(x, y) {return board[y][x] & STATUS_NEIGHBORMINES_MASK;}

//盤の初期化
var board = new Array(BOARD_HEIGHT);
for(var y = 0; y < BOARD_HEIGHT; y++) {
	board[y] = new Array(BOARD_WIDTH);
	for(var x = 0; x < BOARD_WIDTH; x++) board[y][x] = STATUS_COVERED;
}
var panelsLeft = BOARD_WIDTH * BOARD_HEIGHT; //開いていないマスの数

//爆弾を配置--指定座標(最初に開けたマス)には配置しない
function generateMines(avoidX, avoidY) {
	if(NUMBER_MINES >= (BOARD_WIDTH * BOARD_HEIGHT - 1)) throw new Error("盤に対して爆弾が多すぎます");
	var mine = 0;
	while(mine < NUMBER_MINES) {
		var x = Math.floor(Math.random() * BOARD_WIDTH);
		var y = Math.floor(Math.random() * BOARD_HEIGHT);
		if(!(x == avoidX && y == avoidY) && !isMined(x, y)) {
			board[y][x] |= STATUS_MINED;
			incrementNeighbors(x, y);
			mine++;
		}
	}
}

//有効な座標かどうかチェック
function isValidCoord(x, y) {return ((x >= 0) && (x < BOARD_WIDTH) && (y >= 0) && (y < BOARD_HEIGHT));}

var NEIGHBORS = [[-1, -1], [0, -1], [1, -1],
				 [-1,  0],          [1,  0],
				 [-1,  1], [0,  1], [1,  1]];

//周囲のマスの爆弾の数を+1する
function incrementNeighbors(checkX, checkY) {
	for(var i = 0; i < NEIGHBORS.length; i++) {
		var x = checkX + NEIGHBORS[i][0];
		var y = checkY + NEIGHBORS[i][1];
		if(isValidCoord(x, y)) board[y][x]++;
	}
}
//周囲の旗の数を数える
function countNeighborFlags(checkX, checkY) {
	var count = 0;
	for(var i = 0; i < NEIGHBORS.length; i++) {
		var x = checkX + NEIGHBORS[i][0];
		var y = checkY + NEIGHBORS[i][1];
		if(isValidCoord(x, y)) {if(isFlagged(x, y)) count++;}
	}
	return count;
}

//マスを開く
function open(x, y) {
	if(isFlagged(x, y) || !isCovered(x, y)) return;
	if(isMined(x, y)) {
		board[y][x] |= STATUS_EXPLODED;
		for(var y = 0; y < BOARD_HEIGHT; y++) {
			for(var x = 0; x < BOARD_WIDTH; x++) {
				if(isMined(x, y)) board[y][x] &= ~STATUS_COVERED;
			}
		}
		var e = new Error("OOPS!");
		e.name = "GameOverError";
		throw e;
	}
	board[y][x] &= ~STATUS_COVERED;
	panelsLeft--;
	if(panelsLeft == NUMBER_MINES) {
		var e = new Error("Congratulations!");
		e.name = "GameOverError";
		throw e
	}
	if(countNeighborMines(x, y) == 0) openNeighbors(x, y);
}
function openNeighbors(checkX, checkY) { //周囲のマスをすべて開く
	for(var i = 0; i < NEIGHBORS.length; i++) {
		var x = checkX + NEIGHBORS[i][0];
		var y = checkY + NEIGHBORS[i][1];
		if(isValidCoord(x, y)) open(x, y);
	}
}
//既に開いたマスを指定し、マス目の数字と周囲の旗の数が等しければ、
//周囲のマスをすべて開く(winmineの左右ボタン同時クリックと同様)
function check(x, y) {
	if(isCovered(x, y)) return;
	if(countNeighborMines(x, y) != countNeighborFlags(x, y)) return;
	openNeighbors(x, y);
}
//旗のON/OFF切り替え
function flag(x, y) {board[y][x] ^= STATUS_FLAGGED}

//盤を文字列として取得
function boardToString() {
	var BOX_NUMBER = [" ", "1", "2", "3", "4", "5", "6", "7", "8"];
	var BOX_PLAIN = "■"
	var BOX_FLAGGED = "□"
	var BOX_MINE = "●"
	var BOX_MINE_EXPLODED = "※"
	
	var str = "\r\n\r\n\r\n\r\n\r\n\r\n   |";
	for(var x = 0; x < BOARD_WIDTH; x++) str += fillSpace(x, 3);
	str += "\r\n---+";
	for(var x = 0; x < BOARD_WIDTH; x++) str += "---";
	str += "\r\n";
	for(var y = 0; y < BOARD_HEIGHT; y++) {
		str += fillSpace(y, 3) + "|";
		for(var x = 0; x < BOARD_WIDTH; x++) {
			var chr;
			if(isCovered(x, y)) {
				chr = (isFlagged(x, y) ? BOX_FLAGGED : BOX_PLAIN);
			} else if(isMined(x, y)) {
				chr = (isExploded(x, y) ? BOX_MINE_EXPLODED : BOX_MINE);
			} else {
				chr = BOX_NUMBER[countNeighborMines(x, y)];
			}
			str += " " + chr;
		}
		str += "\r\n";
	}
	return str;
	
}
function fillSpace(num, digits) { //digitsに足りない桁数をスペースで補完する
	var str = "";
	for(i = 0; i < digits - num.toString().length; i++) str += " ";
	return str + num.toString();
}

function redrawBoard() { //盤の再描画
	document.selection.SelectAll();
	document.selection.Text = boardToString();
}

function main() {
	var isFirstOpen = true;
	while(true) {
		redrawBoard();
		var pr = prompt("マスを開く:o(省略可) x y / 旗を立てる: f x y / 周囲のマスを一度に開く: c x y",
						"コマンドを入力(キャンセルで終了)"); //
		if(pr == "") break;
		var cmds = /^\s*(?:(\w)\s+)?(\d+)\s+(\d+)\s*$/.exec(pr);
		if(cmds == null) continue;
		var cmd = cmds[1]; var x = parseInt(cmds[2]); var y = parseInt(cmds[3]);
		if(!isValidCoord(x, y)) continue;
		switch(cmd) {
		case "":
		case "o":
			try {
				if(isFirstOpen) {
					isFirstOpen = false;
					generateMines(x, y);
				}
				open(x, y);
			} catch(e) {
				if(e.name == "GameOverError") {
					redrawBoard();
					document.selection.Text = e.message;
					return;
				} else {
					alert(e.message);
					return;
				}
			}
			break;
		case "f":
			flag(x, y);
			break;
		case "c":
			check(x, y);
			break;
		}
	}
}

main();

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

目安箱バナー