The following built-in MATLAB functions and commands are permitted for this assignment.
Vector/Matrix
Flow Control
Strings and Character Arrays
Other
Points will be deducted from any programs using functions outside this list.
AI for any part of this problem.function_name.m, where each function_name is listed below.minesweeper.m.minesweeper.m and decide to use every helper key.minesweeper. If it returns an error on my end, you will receive a zero. To avoid this situation, run the game in an isolated folder with a cleared workspace. If the game runs without error, then it will run without error on my end.init_settings
settings = init_settings(difficulty)
I:
|
difficulty |
\((1\times 1)\) string
Difficulty level controlling board size, mine density, time limits, and figure layout. Valid choices: โtestโ, โeasyโ, โnormalโ, โhardโ, or anything else (treated as a โbrutalโ mode).
|
O:
|
settings |
\((1\times 1)\) struct
Full configuration for the game, containing board parameters, mine count, figure position, icon strings, text sizes, color matrix, time-limit settings, and explosion timing.
|
switch statement on difficulty to assign:gridSize โ number of tiles per side.pctMines โ mine percentage for the selected difficulty.timeLimit โ countdown duration in seconds (โinfโ means no timer).otherwise) case uses the brutal settings.| Mode | Grid Size | Mine Fraction | Time Limit |
| โtestโ | \(5\times 5\) | \(0.10\) | \(30\) seconds |
| โeasyโ | \(10\times 10\) | \(0.10\) | โพ๏ธ (no timer) |
| โnormalโ | \(15\times 15\) | \(0.13\) | \(160\) seconds |
| โhardโ | \(20\times 20\) | \(0.16\) | \(100\) seconds |
| โbrutalโ (default) | \(20\times 20\) | \(0.18\) | \(80\) seconds |
pctMines and gridSize. Make sure to round this number to the nearest integer.settings struct must contain the following fields:
gridSize |
\((1\times 1)\) integer
Number of tiles on each side of the board.
|
figPosition |
\((1\times 4)\) double
Figure position vector \([x_0, y_0, w, h]\) used by
init_gui to size and place the window. In the provided implementation, the width w scales with gridSize so that tiles remain roughly square.
|
nMines |
\((1\times 1)\) integer
Total number of mines on the board.
|
icons |
\((1\times 1)\) struct
Emoji-based icons used throughout the GUI:
|
sizes |
\((1\times 1)\) struct
Font sizes for different GUI elements:
|
colors |
\((8\times 3)\) double
RGB colors for the numbers \(1\) through \(8\) on revealed tiles. The default palette is designed to resemble classic Minesweeper colors.
|
timeLimit |
\((1\times 1)\) double
Maximum time, in seconds, for the game. Use
inf for no time limit (for example, on โeasyโ).
|
explosionDelay |
\((1\times 1)\) double
Pause between clicking a mine and beginning the explosion animation (Tier 3 feature). The demo uses \(3.5\) seconds.
|
settings output.% Example 1 โ Normal difficulty
settings = init_settings("normal");
settings.gridSize % returns 15
settings.nMines % returns round(0.13 * 225)
settings.timeLimit % returns 160
size(settings.colors) % returns [8 3]
settings.figPosition % 1x4 vector for the figure position
% Example 2 โ Unrecognized difficulty โ Brutal mode
settings = init_settings("banana");
settings.gridSize % returns 20
settings.nMines % returns 72
settings.timeLimit % returns 80
settings.explosionDelay % default: 3.5 seconds
init_state
state = init_state(n)
I:
|
N |
\((1 \times 1)\) integer
Number of tiles on one side of the game grid.
|
O:
|
state |
\((1 \times 1)\) struct
Initial game state structure with all fields set to their default values. See details below.
|
state are described and initialized as follows: isMine |
Indicates if the \((r,c)\)-tile hides a Mine.
|
minesNearBy |
Number of Mines touching the \((r,c)\)-tile (up to 8).
|
flagged |
Indicates if the \((r,c)\)-tile is flagged.
|
revealed |
Indicates if the \((r,c)\)-tile has been revealed.
|
gameStarted
|
Signals that the first tile has been clicked.
|
gameOver |
Signals if the game is over (win, loss, or time-out).
|
playerWon |
Signals if the player has successfully cleared the board.
|
startTime |
Starting time stamp (returned by
tic) after first-click.
|
timesUp |
Signals if the time limit has been reached.
|
settings output.% Example 1: Small grid
state = init_state(2);
% Check a few sample values:
state.isMine % โ 2x2 logical with all false
state.minesNearBy % โ 2x2 with all 0
state.flagged % โ 2x2 logical with all false
state.revealed % โ 2x2 logical with all false
state.gameStarted % โ false
state.startTime % โ 0
state.playerWon % โ false
% Example 2: Large grid
state = init_state(18);
% Check a few sample values:
size(state.isMine) % โ [18 18]
state.minesNearBy % โ 18x18, all 0
state.gameOver % โ false
init_gui
gui structure containing all on-screen components.
[gui, fig] = init_gui(settings)
I:
|
settings |
\((1\times 1)\) struct
Configuration structure returned by
init_settings. In particular, this helper uses settings.gridSize, settings.figPosition, settings.icons, settings.sizes, and settings.timeLimit.
|
O:
|
gui |
\((1\times 1)\) struct
Collection of all graphical components used by the game. See below for its fields.
|
fig |
\((1\times 1)\) figure
|
gui structure that stores handles to all onโscreen components.fig that contains the Minesweeper board.settings:
zoneLbls |
\((N\times N)\) text
Text label displaying the mine counts or mine icons.
|
tiles |
\((N\times N)\) text
Text label displaying the tile icons.
|
flags |
\((N\times N)\) text
Text label displaying flag icons drawn on top of tiles.
|
resetButton |
\((1\times 1)\) text
Text label displaying the reset icon below the grid.
|
resultsLabel |
\((1\times 1)\) text
Status text used to show feedback at the end of the game.
|
timeLabel \(^{๐}\)
|
\((1\times 1)\) text
Text label used to display remaining time.
|
zoneLbls, tiles, and flags matrices as described above. Before you do, preallocate them with gobjects(N, N).fig = figure;
fig.Position = position;
fig.ToolBar = "none";
fig.MenuBar = "none";
title("Mine Sweeper", "FontSize", 18)
xlim([1 N+1]); ylim([1 N+1]);
axis off
axis square
axis ij % orients the positive y-axis downward
init_gui, the board should show an \(N\times N\) array of covered tiles, a reset icon, and empty status/timer labels. Mines and numbers remain hidden until other helpers update them.% Create an "easy" Minesweeper GUI.
settings = init_settings("easy");
[gui, fig] = init_gui(settings);
% The window should show a 10-by-10 grid of covered tiles,
% a reset icon, and a timer label reading either "Time: โพ๏ธ"
% or a numeric time, depending on the difficulty.
get_neighbors
neighbors = get_neighbors(r, c, N)
I:
|
r |
\((1\times 1)\) integer
Row index of the tile being inspected.
|
c |
\((1\times 1)\) integer
Column index of the tile being inspected.
|
|
N |
\((1\times 1)\) integer
Number of tiles along one side of the square grid.
|
|
O:
|
neighbors |
\((K \times 2)\) integer matrix
Each row is a valid neighbor coordinate \((\text{row}, \text{col})\text{,}\) where \(K = 3, 5,\) or \(8\) depending on whether \((r,c)\) is on a corner, edge, or interior tile.
|
get_mineCounts โ to count Mines in adjacent cells,reveal_tiles โ to propagate a flood-fill reveal,% Example 1: Corner tile on a 5ร5 board
neighbors = get_neighbors(1, 1, 5)
% Expected: three neighbors
% 1 2
% 2 1
% 2 2
% Example 2: Center tile on a 10ร10 board
neighbors = get_neighbors(5, 5, 10)
% Expected: eight neighbors
% 4 4
% 4 5
% 4 6
% 5 4
% 5 6
% 6 4
% 6 5
% 6 6
get_mines
g.state.isMine with a random Mine layout that uses exactly g.settings.nMines Mines on an \(N \times N\) grid and avoids the tile at (initRow, initCol).
mines = get_mines(g, initRow, initCol)
I:
|
g |
\((1 \times 1)\) struct
|
initRow |
\((1 \times 1)\) integer
Row index of the tile where the player first clicked.
|
|
initCol |
\((1 \times 1)\) integer
Column index of the tile where the player first clicked.
|
|
O:
|
mines |
\((N \times N)\) logical
|
(initRow, initCol).g.settings:N = g.settings.gridSize โ board dimension.M = g.settings.nMines โ total Mines to place.mines of size \(N \times N\) initialized to false.mines(initRow, initCol) = true.k = 1:M, repeatedly generate random row/column indices using randi(N) until you find a location that does not already contain a Mine.mines(row, col) = true.(initRow, initCol) by setting mines(initRow, initCol) = false.g.state.isMine = mines.% Setup a reproducible testing environment:
rng(7,"twister");
g.settings = init_settings("easy");
g.state = init_state(g.settings.gridSize);
% Example: Player clicked the (row=7, col=5) location
clickedRow = 7;
clickedCol = 5;
mines = get_mines(g, clickedRow, clickedCol);
% Check:
% - mines is a 10x10 logical array.
% - Exactly g.settings.nMines entries are true.
% - mines(7,5) is false.
get_mineCounts
g.state.minesNearBy as an \(N \times N\) array of counts, where each entry records the number of Mines in the 8 surrounding tiles (or fewer on edges and corners).
counts = get_mineCounts(g)
I:
|
g |
\((1 \times 1)\) struct
Game structure containing the following fields:
|
O:
|
counts |
\((N \times N)\) integer
|
g.state.minesNearBy.g.state.isMine has already been generated by get_mines.(r,c)-tile on the grid.(r,c)-tile:get_neighbors
% Example 1: Compute mine counts on a small test board.
% Setup a small test board:
g.settings = init_settings("test");
g.state = init_state(g.settings.gridSize);
% First, hardcode some mine locations:
g.state.isMine = [ ...
true true false false false; ...
true false false false false; ...
false true true false true; ...
false false false false true; ...
false true false false true; ...
];
% View the mines as 1s and 0s:
g.state.isMine
% Returns:
% 5x5 logical array
% 1 1 0 0 0
% 1 0 0 0 0
% 0 1 1 0 1
% 0 0 0 0 1
% 0 1 0 0 1
counts = get_mineCounts(g)
% Returns:
% counts =
% 0 0 1 0 0
% 0 5 3 2 1
% 2 0 0 3 0
% 2 3 3 4 0
% 1 0 1 2 0
update_zoneLabels
g.gui.tiles can reveal them during play.
new_g = update_zoneLabels(g)
I:
|
g |
\((1 \times 1)\) struct
|
O:
|
new_g |
\((1 \times 1)\) struct
Same as
g, except g.gui.zoneLabels is updated to show the correct Mine icons and proximity numbers.
|
g.gui.zoneLabels with either a Mine icon or a Mine-proximity number for each tile.N = g.settings.gridSizeicons = g.settings.icons (especially icons.mine)colors = g.settings.colors โ the 8 colors for numbers 1-8isMine = g.state.isMinevalues = g.state.minesNearByzoneLabel so that it contains a number or a mine.g.settings.colors to set the number colors.g.gui.tiles is hidden by other helpers.% Setup a minimal test environment:
rng(77,"twister");
g.settings = init_settings("easy");
g.state = init_state(g.settings.gridSize);
[g.gui, fig] = init_gui(g.settings);
% Build a Mine layout and proximity numbers:
g.state.isMine = get_mines(g, 4, 5);
g.state.minesNearBy = get_mineCounts(g);
% Example: update labels, then delete tiles to reveal them all at once:
g = update_zoneLabels(g);
delete(g.gui.tiles) % โ ๏ธ This is a quick way to remove all
% tiles, do not do this in your assignment!

reveal_tiles
state.revealed and hides the covering tiles in gui.tiles, but it does not modify mine locations, flags, timers, or game-over status.
new_g = reveal_tiles(g, r, c)
I:
|
g |
\((1 \times 1)\) struct
|
r |
\((1 \times 1)\) integer
Row index of the tile where the player clicked.
|
|
c |
\((1 \times 1)\) integer
Column index of the tile where the player clicked.
|
|
O:
|
new_g |
\((1 \times 1)\) struct
|
revealed matrix to match what the player sees. Below are general hints for implementing this logic.explore_queue.explore_queue is a pair [row col].[r c] in the queue. This is our current location.get_neighbors
% After the first click at (r, c), and assuming the board is built
% and g.state.minesNearBy has been computed:
g = reveal_tiles(g, r, c);
% Now g.state.revealed marks all tiles that should be visible, and
% the corresponding rectangles in g.gui.tiles have been hidden so the
% underlying labels show through.
game_over_screen
new_g = game_over_screen(g, r, c)
I:
|
g |
\((1 \times 1)\) struct
|
r |
\((1 \times 1)\) integer
Row index of the last tile clicked.
|
|
c |
\((1 \times 1)\) integer
Column index of the last tile clicked.
|
|
O:
|
new_g |
\((1 \times 1)\) struct
|
stop(g.clock). This prevents further time-limit checks after the game is over.explosion_animation
% Setup a minimal testing environment:
rng(77,"twister");
g.settings = init_settings("easy");
g.state = init_state(g.settings.gridSize);
[g.gui, fig] = init_gui(g.settings);
g.clock = init_clock(fig);
% Example 1: Player Won
g.state.playerWon = true;
g = game_over_screen(g, 2, 2);
% Example 2: Player Lost - Clicked on a Mine
g.state.playerWon = false;
g.state.timesUp = false;
g = game_over_screen(g, 4, 5);
% Example 3: Time-out Loss & Explosion from center (Tier 3)
g.state.playerWon = false;
g.state.timesUp = true;
g = game_over_screen(g, 1, 1);
reset_game
reset_game(fig)
I:
|
fig |
\((1\times 1)\) figure
|
O:
|
None | No direct output, but it modifies the game data stored in fig and saves the updated game struct via guidata.
|
state and visible gui back to their starting values without constructing a new figure window.state structure can be reset by calling init_state.init_gui. Instead, reset their properties in-place. Use a nested loop for the matrix components.timeLabel to its initial value.\(^{๐}\)
init_state
clicked_on_tile
clicked_on_tile(src, event, fig)
I:
|
src |
\((1 \times 1)\) MATLAB graphics object (struct with many fields)
The GUI component that received the click. In this game, that is either a tile (
g.gui.tiles(r,c)) or a flag (g.gui.flags(r,c)).
|
evt |
\((1 \times 1)\) MATLAB event data (struct with fields listed below)
Mouse-click event data, used to determine which mouse button was pressed (left vs right click).
|
|
fig |
\((1 \times 1)\) figure
|
|
O:
|
None | No direct output, but it modifies the stored game struct and saves it back to fig using guidata.
|
init_gui, you set the ButtonDownFcn property of the tiles and flags to @(src,evt) clicked_on_tile(src,evt,fig). Meaning, this helper is automatically called (by MATLAB) when one of the zoneLbls and flags are clicked. You should never call clicked_on_tile anywhere else in your code.
ButtonDownFcn callback for both tiles and flags so that every left or right click on the board passes through here.src variable contains the gui component that was clicked. This is used in this helper to get the \((x,y)\) location of the clicked space usingc = floor(src.Position(1)); - the column index.r = floor(src.Position(2)); - the row index.evt variable contains the information about the type of click. In particular, the value of its Button property is interpreted as follows:1 means there was a left-click (reveal).3 means there was a right-click (flag).g.state.gameStarted will be important in this helper.clicked_on_tile and verify that:game_over_screen.radially_sorted_grid\(^{๐}\)
gridList = radially_sorted_grid(N, centerRow, centerCol)
I:
|
N |
\((1 \times 1)\) integer
Number of tiles on one side of the game grid.
|
centerRow |
\((1 \times 1)\) integer
Row index of the center point of the explosion.
|
|
centerCol |
\((1 \times 1)\) integer
Column index of the center point of the explosion.
|
|
O:
|
gridList |
\((N^2 \times 2)\) integer
Each row is a lattice point \((i,j)\) with \(i,j = 1,\dots,N\text{,}\) sorted by their distance from \((\text{centerRow},\text{centerCol})\text{.}\)
|
points where each row is the grid point [i, j].dists where dists(k) is the squared distance between points(k,:) and [centerRow, centerCol].sort command to sort the distances and capture the corresponding index order: [~, idx] = sort(dists);.gridList = points(idx,:);.% Example 1: Small Grid
gridList = radially_sorted_grid(3, 1, 3)
%
% Returns gridList =
%
% 1 3
% 1 2
% 2 3
% 2 2
% 1 1
% 3 3
% 2 1
% 3 2
% 3 1
% Example 2: Big Grid
gridList = radially_sorted_grid(30, 27, 19);
%
% Check the output size
size(gridList) % should be: 900 2
% Check a few rows
gridList(11,:) % should be: 27 17
gridList(end,:) % should be: 1 1
explosion_animation\(^{๐}\)
new_g = explosion_animation(g, detRow, detCol)
I:
|
g |
\((1 \times 1)\) struct
|
detRow |
\((1 \times 1)\) integer
Row index of the detonation tile.
|
|
detCol |
\((1 \times 1)\) integer
Column index of the detonation tile.
|
|
O:
|
new_g |
\((1 \times 1)\) struct
|
g.settings:N = g.settings.gridSize โ size of the board.icons = g.settings.icons โ especially icons.explosion.delay = g.settings.explosionDelay โ overall pace of the animation.landmine.mp3):audioread and sound commands, or another audio approach.pause(duration).radially_sorted_grid helper. This returns an \(N^2 \times 2\) list of [r, c] pairs in the desired order.gridList and, for each (r,c):zoneLabel to your chosen explosion icon. otherwise, just leave the mine there.pause(duration) command within the animation loop.duration, the animation will seem slow. To increase the speed add an if statement that only pauses every 10 loops. MATLABโs mod command is a handy way to handle these skips.radially_sorted_grid
% Setup a minimal testing environment:
% Note: For testing, you may swap out any of the helpers below with the
% provided "key" versions.
rng(77,"twister");
g.settings = init_settings("easy");
g.state = init_state(g.settings.gridSize);
[g.gui, fig] = init_gui(g.settings);
g.state.isMine = get_mines(g, 4, 5);
g.state.minesNearBy = get_mineCounts(g);
g = update_zoneLabels(g);
guidata(fig, g);
% Example 1: Light the fuse...
g = explosion_animation(g, 7, 3);
init_clock \(^{๐}\)
timer object that periodically checks the gameโs time limit and updates the countdown display. This helper is part of the Tier 3 feature set, enabling time-limited games and automatic time-out behavior.
clock = init_clock(fig)
I:
|
fig |
\((1 \times 1)\) figure
Main Minesweeper figure window that stores the
game struct via guidata. The timer callback uses this handle to access and update game data.
|
O:
|
clock |
\((1 \times 1)\) timer
MATLAB timer used to periodically call
check_time_limit while the game is running.
|
clock.ExecutionMode = "fixedRate" so the callback runs at a constant frequency.clock.Period = 0.2 so check_time_limit is called 5 times per second.clock.TimerFcn = @(~,~) check_time_limit(fig) so each tick invokes your check_time_limit helper using the stored figure.clock.StopFcn = [] so the timer is not automatically deleted when stopped. This allows the same timer to be restarted on multiple runs.init_clock. It is initialized here, but it only begins running after the playerโs first successful click, where clicked_on_tile calls start(g.clock).game_over_screen should call stop(g.clock) to halt the countdown.g.settings and are interpreted by check_time_limit, which uses the elapsed time and settings.timeLimit to update g.gui.timeLabel and possibly trigger a time-out loss.% Minimal testing environment for the countdown clock.
rng(77,"twister");
g.settings = init_settings("test");
g.state = init_state(g.settings.gridSize);
[g.gui, fig] = init_gui(g.settings);
g.clock = init_clock(fig);
g.clock
% Returns something like:
% Timer Object: timer-7
%
% Timer Settings
% ExecutionMode: fixedRate
% Period: 0.2
% BusyMode: drop
% Running: off
%
% Callbacks
% TimerFcn: @(~,~)check_time_limit(fig)
% ErrorFcn: ''
% StartFcn: ''
% StopFcn: []
check_time_limit \(^{๐}\)
timer object created by init_clock.
check_time_limit(fig)
I:
|
fig |
\((1 \times 1)\) figure
|
O:
|
None |
g.state.gameOver is already true, simply stop the clock and return.
isinf(g.settings.timeLimit) == true), then there is no need to modify the timeLabel. Save g, and return.elapsed = toc(g.state.startTime) gives the elapsed time (seconds).timeLabel with the remaining time, but donโt allow it to display negative values.game_over_screen
game_over_screen
"test" and let the timer run down. Verify that:minesweeper (Full Game)
game.settingsgame.stategame.guigame.clock\(^{๐}\)
minesweeper(difficulty, seed)
I:
|
difficulty |
\((1 \times 1)\) string, optional
Selects the difficulty level.
|
seed |
\((1 \times 1)\) double, optional
Random number seed for reproducible gameplay.
|
|
O:
|
None |
None. However, this function constructs and displays (via helpers) a fully interactive Minesweeper game.
|
difficulty is NOT provided, set its default to "normal" .seed is provided, set the rng to this seed as usual.minesweeper is the entry point and overall driver of the project. It can be broken down into the following steps (mostly handled by helpers):
game.settings.game.state.game.gui.clock structure.\(^{๐}\)
clear game; removes existing game variables from the workspace.close all; closes all open figure windows.clicked_on_tile).clicked_on_tile, reset_game, or check_time_limit.% Start a reproducible test game:
minesweeper("test", 42)
% Start a normal game:
minesweeper()
% Start an easy game:
minesweeper("easy")
% Start a game with undefined difficulty (defaults to "brutal"):
minesweeper("tutorial")
% After running one of these, interact with the GUI:
% - Left-click to reveal tiles,
% - Right-click to toggle flags,
% - Click the reset icon to start a new run.