mirror of
https://github.com/neon443/MineSwift.git
synced 2026-03-11 15:16:18 +00:00
v1.0, it works andd so does difficluty settnigs sorryy for the typos im really sleep derpived right noew...
This commit is contained in:
@@ -406,18 +406,19 @@
|
|||||||
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
|
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 18.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 16;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
||||||
MACOSX_DEPLOYMENT_TARGET = 15.1;
|
MACOSX_DEPLOYMENT_TARGET = 13;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.neon443.MineSwift;
|
PRODUCT_BUNDLE_IDENTIFIER = com.neon443.MineSwift;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||||
|
SUPPORTS_MACCATALYST = NO;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2,7";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
XROS_DEPLOYMENT_TARGET = 2.1;
|
XROS_DEPLOYMENT_TARGET = 2.1;
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
@@ -445,18 +446,19 @@
|
|||||||
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
|
"INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 18.1;
|
IPHONEOS_DEPLOYMENT_TARGET = 16;
|
||||||
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
|
||||||
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
|
||||||
MACOSX_DEPLOYMENT_TARGET = 15.1;
|
MACOSX_DEPLOYMENT_TARGET = 13;
|
||||||
MARKETING_VERSION = 1.0;
|
MARKETING_VERSION = 1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.neon443.MineSwift;
|
PRODUCT_BUNDLE_IDENTIFIER = com.neon443.MineSwift;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SDKROOT = auto;
|
SDKROOT = auto;
|
||||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
|
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
|
||||||
|
SUPPORTS_MACCATALYST = NO;
|
||||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_VERSION = 5.0;
|
SWIFT_VERSION = 5.0;
|
||||||
TARGETED_DEVICE_FAMILY = "1,2,7";
|
TARGETED_DEVICE_FAMILY = "1,2";
|
||||||
XROS_DEPLOYMENT_TARGET = 2.1;
|
XROS_DEPLOYMENT_TARGET = 2.1;
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
100
MineSwift/ContentView.swift
Normal file
100
MineSwift/ContentView.swift
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
//
|
||||||
|
// ContentView.swift
|
||||||
|
// MineSwift
|
||||||
|
//
|
||||||
|
// Created by Nihaal Sharma on 08/12/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ContentView: View {
|
||||||
|
@State private var cRows: Int = 10
|
||||||
|
@State private var cCols: Int = 10
|
||||||
|
@State private var cBombs: Int = 10
|
||||||
|
@State private var selectedMode: MinesweeperMode = .beginner
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
let selectedGrid = MinesweeperGrid(mode: selectedMode, cRows: cRows, cCols: cCols, cBombs: cBombs)
|
||||||
|
|
||||||
|
NavigationStack {
|
||||||
|
VStack {
|
||||||
|
List {
|
||||||
|
Section("Game Settings") {
|
||||||
|
Text(selectedMode == .custom ? "Custom Game" : "Preset Difficulty")
|
||||||
|
.font(.system(.title2, design: .rounded, weight: .heavy))
|
||||||
|
ModePicker(selectedMode: $selectedMode)
|
||||||
|
Text(selectedGrid.describe())
|
||||||
|
|
||||||
|
if selectedMode == .custom {
|
||||||
|
CustomSettingsView(cRows: $cRows, cCols: $cCols, cBombs: $cBombs, maxBombs: cRows * cCols)
|
||||||
|
.animation(.spring, value: selectedMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Section("How to play") {
|
||||||
|
Text("1. Select difficulty or choose a custom grid")
|
||||||
|
Text("2. Tap Start Game")
|
||||||
|
Text("3. Tap a square to reveal if it is a mine")
|
||||||
|
Text("4. If it isnt a mine, it will display the number of mines in a 1 square radius, including diagonally")
|
||||||
|
Text("5. Use the flag switch to place flags on squares")
|
||||||
|
Text("Try to find all the squares that are not bombs.")
|
||||||
|
Text("Good Luck!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer()
|
||||||
|
|
||||||
|
if cBombs > cRows * cCols {
|
||||||
|
List {
|
||||||
|
Text("More bombs than squares!")
|
||||||
|
Text("You can have a max of \(cRows*cCols) bombs.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NavigationLink(destination: MinesweeperView(rows: selectedGrid.rows, cols: selectedGrid.cols, bombs: selectedGrid.bombs)) {
|
||||||
|
Text("Start Game")
|
||||||
|
.font(.system(.title, weight: .bold))
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
.padding(10)
|
||||||
|
.background(cBombs > cRows * cCols ? .red : .blue)
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
|
.padding(.bottom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationTitle("MineSwift")
|
||||||
|
#if os(iOS)
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModePicker: View {
|
||||||
|
@Binding var selectedMode: MinesweeperMode
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Picker("Mode", selection: $selectedMode) {
|
||||||
|
ForEach(MinesweeperMode.allCases, id: \.self) { mode in
|
||||||
|
Text(mode.rawValue).tag(mode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pickerStyle(.segmented)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CustomSettingsView: View {
|
||||||
|
@Binding var cRows: Int
|
||||||
|
@Binding var cCols: Int
|
||||||
|
@Binding var cBombs: Int
|
||||||
|
let maxBombs: Int
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Stepper("Rows: \(cRows)", value: $cRows, in: 1...30)
|
||||||
|
Stepper("Columns: \(cCols)", value: $cCols, in: 1...30)
|
||||||
|
Stepper("Bombs: \(cBombs)", value: $cBombs, in: 1...maxBombs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
ContentView()
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
//
|
|
||||||
// ContentView.swift
|
|
||||||
// MineSwift
|
|
||||||
//
|
|
||||||
// Created by Nihaal Sharma on 08/12/2024.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ContentView: View {
|
|
||||||
var body: some View {
|
|
||||||
VStack {
|
|
||||||
Image(systemName: "globe")
|
|
||||||
.imageScale(.large)
|
|
||||||
.foregroundStyle(.tint)
|
|
||||||
Text("Hello, world!")
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#Preview {
|
|
||||||
ContentView()
|
|
||||||
}
|
|
||||||
172
MineSwift/MinesweeperGame.swift
Normal file
172
MineSwift/MinesweeperGame.swift
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
//
|
||||||
|
// MinesweeperGame.swift
|
||||||
|
// MineSwift
|
||||||
|
//
|
||||||
|
// Created by Nihaal Sharma on 08/12/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum MinesweeperMode: String, CaseIterable {
|
||||||
|
case beginner, intermediate, expert, custom
|
||||||
|
|
||||||
|
var details: (rows: Int, cols: Int, bombs: Int) {
|
||||||
|
switch self {
|
||||||
|
case .beginner: return (10, 10, 10)
|
||||||
|
case .intermediate: return (16, 16, 40)
|
||||||
|
case .expert: return (30, 16, 99)
|
||||||
|
case .custom: return (20, 20, 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MinesweeperGrid {
|
||||||
|
let rows: Int
|
||||||
|
let cols: Int
|
||||||
|
let bombs: Int
|
||||||
|
|
||||||
|
init(mode: MinesweeperMode, cRows: Int = 20, cCols: Int = 20, cBombs: Int = 10) {
|
||||||
|
switch mode {
|
||||||
|
case .beginner, .intermediate, .expert:
|
||||||
|
let details = mode.details
|
||||||
|
self.rows = details.rows
|
||||||
|
self.cols = details.cols
|
||||||
|
self.bombs = details.bombs
|
||||||
|
case .custom:
|
||||||
|
self.rows = cRows
|
||||||
|
self.cols = cCols
|
||||||
|
self.bombs = cBombs
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func describe() -> String {
|
||||||
|
return "\(rows)x\(cols) minefield with \(bombs) mines."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MinesweeperGame: ObservableObject {
|
||||||
|
enum CellState {
|
||||||
|
case hidden, revealed, flagged
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Cell {
|
||||||
|
var isMine: Bool = false
|
||||||
|
var adjacentMines: Int = 0
|
||||||
|
var state: CellState = .hidden
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Position: Hashable {
|
||||||
|
var row: Int
|
||||||
|
var col: Int
|
||||||
|
}
|
||||||
|
|
||||||
|
private var rows: Int
|
||||||
|
private var columns: Int
|
||||||
|
@Published var board: [[Cell]]
|
||||||
|
@Published var gameOver: Bool = false
|
||||||
|
@Published var gameWon: Bool = false
|
||||||
|
@Published var revealedCells = Set<Position>()
|
||||||
|
|
||||||
|
init(rows: Int = 10, columns: Int = 10, mineCount: Int = 10) {
|
||||||
|
self.rows = rows
|
||||||
|
self.columns = columns
|
||||||
|
self.board = Array(repeating: Array(repeating: Cell(), count: columns), count: rows)
|
||||||
|
placeMines(mineCount)
|
||||||
|
calculateAdjacentMines()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func placeMines(_ mineCount: Int) {
|
||||||
|
var minesPlaced = 0
|
||||||
|
while minesPlaced < mineCount {
|
||||||
|
let row = Int.random(in: 0..<rows)
|
||||||
|
let col = Int.random(in: 0..<columns)
|
||||||
|
if !board[row][col].isMine {
|
||||||
|
board[row][col].isMine = true
|
||||||
|
minesPlaced += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func calculateAdjacentMines() {
|
||||||
|
for row in 0..<rows {
|
||||||
|
for col in 0..<columns {
|
||||||
|
if board[row][col].isMine {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
var adjacentMines = 0
|
||||||
|
for r in -1...1 {
|
||||||
|
for c in -1...1 {
|
||||||
|
if r == 0 && c == 0 { continue }
|
||||||
|
let newRow = row + r
|
||||||
|
let newCol = col + c
|
||||||
|
if newRow >= 0 && newRow < rows && newCol >= 0 && newCol < columns {
|
||||||
|
if board[newRow][newCol].isMine {
|
||||||
|
adjacentMines += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
board[row][col].adjacentMines = adjacentMines
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func revealCell(row: Int, col: Int) {
|
||||||
|
guard !gameOver else { return }
|
||||||
|
|
||||||
|
var stack: [(Int, Int)] = [(row, col)]
|
||||||
|
var revealedCellsLocal = Set<Position>()
|
||||||
|
|
||||||
|
while !stack.isEmpty {
|
||||||
|
let (r, c) = stack.removeLast()
|
||||||
|
let pos = Position(row: r, col: c)
|
||||||
|
if revealedCellsLocal.contains(pos) { continue }
|
||||||
|
revealedCellsLocal.insert(pos)
|
||||||
|
|
||||||
|
if board[r][c].isMine {
|
||||||
|
gameOver = true
|
||||||
|
revealAllBombs()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
board[r][c].state = .revealed
|
||||||
|
revealedCells.insert(pos)
|
||||||
|
|
||||||
|
if board[r][c].adjacentMines == 0 {
|
||||||
|
for dr in -1...1 {
|
||||||
|
for dc in -1...1 {
|
||||||
|
if dr == 0 && dc == 0 { continue }
|
||||||
|
let newRow = r + dr
|
||||||
|
let newCol = c + dc
|
||||||
|
if newRow >= 0 && newRow < rows && newCol >= 0 && newCol < columns {
|
||||||
|
if !revealedCellsLocal.contains(Position(row: newRow, col: newCol)) {
|
||||||
|
stack.append((newRow, newCol))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func revealAllBombs() {
|
||||||
|
for row in 0..<rows {
|
||||||
|
for col in 0..<columns {
|
||||||
|
if board[row][col].isMine {
|
||||||
|
board[row][col].state = .revealed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gameWon = !board.flatMap { $0 }.contains { $0.state == .hidden && !$0.isMine }
|
||||||
|
}
|
||||||
|
|
||||||
|
func flagCell(row: Int, col: Int) {
|
||||||
|
guard !gameOver else { return }
|
||||||
|
if board[row][col].state == .hidden {
|
||||||
|
board[row][col].state = .flagged
|
||||||
|
} else if board[row][col].state == .flagged {
|
||||||
|
board[row][col].state = .hidden
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
114
MineSwift/MinesweeperView.swift
Normal file
114
MineSwift/MinesweeperView.swift
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
//
|
||||||
|
// MinesweeperView.swift
|
||||||
|
// MineSwift
|
||||||
|
//
|
||||||
|
// Created by Nihaal Sharma on 08/12/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct MinesweeperView: View {
|
||||||
|
@StateObject private var game: MinesweeperGame
|
||||||
|
|
||||||
|
init(rows: Int, cols: Int, bombs: Int) {
|
||||||
|
self.rows = rows
|
||||||
|
self.cols = cols
|
||||||
|
self.bombs = bombs
|
||||||
|
_game = StateObject(wrappedValue: MinesweeperGame(rows: rows, columns: cols, mineCount: bombs))
|
||||||
|
}
|
||||||
|
|
||||||
|
let rows: Int
|
||||||
|
let cols: Int
|
||||||
|
let bombs: Int
|
||||||
|
|
||||||
|
@State var flag: Bool = false
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
ForEach(0..<rows, id: \.self) { row in
|
||||||
|
HStack(spacing: 0) {
|
||||||
|
ForEach(0..<cols, id: \.self) { col in
|
||||||
|
Button(action: {
|
||||||
|
if flag {
|
||||||
|
game.flagCell(row: row, col: col)
|
||||||
|
} else if !flag {
|
||||||
|
game.revealCell(row: row, col: col)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
CellView(cell: game.board[row][col], game: game)
|
||||||
|
.frame(width: 30, height: 30)
|
||||||
|
.border(Color.gray.opacity(0.2))
|
||||||
|
}
|
||||||
|
.buttonStyle(PlainButtonStyle())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||||
|
|
||||||
|
List {
|
||||||
|
Toggle(isOn: $flag, label: {
|
||||||
|
Text("flag")
|
||||||
|
})
|
||||||
|
.padding(.bottom)
|
||||||
|
Text("Total Bombs: \(bombs)")
|
||||||
|
.padding()
|
||||||
|
.frame(alignment: .center)
|
||||||
|
}
|
||||||
|
|
||||||
|
if game.gameOver {
|
||||||
|
Text("Game Over")
|
||||||
|
.font(.largeTitle)
|
||||||
|
.foregroundColor(.red)
|
||||||
|
} else if game.gameWon {
|
||||||
|
Text("You Win!")
|
||||||
|
.font(.largeTitle)
|
||||||
|
.foregroundColor(.green)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct CellView: View {
|
||||||
|
var cell: MinesweeperGame.Cell
|
||||||
|
var game: MinesweeperGame
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
ZStack {
|
||||||
|
if cell.state == .revealed {
|
||||||
|
Color.black
|
||||||
|
} else {
|
||||||
|
Color.blue
|
||||||
|
}
|
||||||
|
if cell.state == .revealed {
|
||||||
|
if cell.isMine {
|
||||||
|
Image(systemName: "multiply")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 20)
|
||||||
|
.foregroundStyle(.red)
|
||||||
|
|
||||||
|
} else if cell.adjacentMines > 0 {
|
||||||
|
Text("\(cell.adjacentMines)")
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
.bold()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cell.state == .flagged {
|
||||||
|
Image(systemName: "flag.fill")
|
||||||
|
.resizable()
|
||||||
|
.scaledToFit()
|
||||||
|
.frame(width: 20)
|
||||||
|
.foregroundStyle(.yellow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#Preview {
|
||||||
|
MinesweeperView(rows: 10, cols: 10, bombs: 5)
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user