import 'dart:math'; // 乱数用
// MineCellの2次元配列のエイリアス
typedef MineCellContainer = List<List<MineCell>>;
// MineTableクラス
class MineTable {
final int cols, rows, numOfMines; // 列数, 行数, 地雷の数
MineCellContainer table = [];
// コンストラクタ(引数:列数, 行数, 地雷の数)
MineTable(this.cols, this.rows, this.numOfMines) {
// MineCellの2次元配列を生成
table = List.generate(rows, (y) => List.generate(cols, (x) => MineCell(x, y)));
// ここから地雷をランダムに置く処理
Random rnd = Random(); // dart:mathライブラリにあるRandomクラス
for (int i = 0; i < numOfMines; i++) {
int x = rnd.nextInt(cols), y = rnd.nextInt(rows);
MineCell target = table[y][x];
if (target.isMine()) {
i--; // すでにtargetが地雷の場合は地雷を置けないのでループを繰り返す
} else {
target.val = 9; // val=9が地雷(MineCellクラス参照)
}
}
for (var row in table) {
for (var cell in row) {
cell.scanNeighbor(table); // 隣接マスをチェック(MineCellクラス参照)
}
}
}
// openメソッド(x列目y行目のマスを開ける)
void open(x, y) {
table[y][x].open(table);
}
// toStringメソッドを上書き(print用)
String toString() {
String result = '';
for (var row in table) {
result += row.join(' ') + '\n';
}
return result;
}
}
// MineCellクラス
class MineCell {
// 表示用リスト val=0: 空白, val=9: X(地雷)
static List<String> label = [' ', '1', '2', '3', '4', '5', '6', '7', '8', 'X'];
final int x, y; // x列目, y行目
List<int> cols = [], rows = []; // 隣接列・隣接行格納用
int val = 0; // val=0~8: 周囲にある地雷の数, val=9: 地雷
bool opened = false; // すでに開けられているか
String display = '@'; // 開けられていないときの表示
// コンストラクタ(引数:x列目, y行目)
MineCell(this.x, this.y);
// isEmptyメソッド(空白マスか)
bool isEmpty() {
return val == 0;
}
// isMineメソッド(地雷マスか)
bool isMine() {
return val == 9;
}
// scanNeighborメソッド(隣接マスに地雷があるかチェック):地雷を置いたあとに実行する
void scanNeighbor(MineCellContainer table) {
// 0列(行)目, 最終列(行)は隣接マスが違う
// 隣接列を定義
cols = x == 0 ? [x, x+1] : x < table[0].length - 1 ? [x-1, x, x+1] : [x-1, x];
// 隣接行を定義
rows = y == 0 ? [y, y+1] : y < table.length - 1 ? [y-1, y, y+1] : [y-1, y];
if (isEmpty()) { // 空白マスのみチェックする
for (int c in cols) {
for (int r in rows) {
// 隣接マスが地雷ならvalを+1する
if (c != x || r != y) val += table[r][c].isMine() ? 1 : 0;
}
}
}
}
// openメソッド(マスを開ける)
void open(MineCellContainer table) {
if (!opened) { // まだ開けられていない場合のみ処理
opened = true;
display = label[val]; // 表示を@から変更
// 空白のとき隣接マスを開ける
if (isEmpty()) {
for (int c in cols) {
for (int r in rows) {
table[r][c].open(table);
}
}
}
}
}
// toStringメソッドを上書き
String toString() {
return display;
}
}
void main() {
MineTable table = MineTable(9, 9, 9); // 9x9、地雷が9個のテーブルを作る
table.open(0, 0); // x=0, y=0を開ける
print(table);
table.open(8, 8); // x=8, y=8を開ける
print(table);
}