From 6ecce1e9ff2789b69fad23de9d8f228d1b8c84f1 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Thu, 16 Oct 2025 09:45:17 +0200 Subject: [PATCH] NEW: MIH MineSweeper Package pt1 --- .../assets/fonts/Mih_Icons.ttf | Bin 44128 -> 45564 bytes .../assets/fonts/style.css | 56 +- .../mih_package_components/mih_icons.dart | 41 +- .../mine_sweeper/components/board_square.dart | 13 + .../mine_sweeper/components/mine_tile.dart | 111 ++++ .../mine_sweeper/mih_mine_sweeper.dart | 58 +- .../package_tiles/mih_mine_sweeper_tile.dart | 44 ++ .../package_tools/mine_sweeper_game.dart | 596 ++++++++++++++++++ 8 files changed, 873 insertions(+), 46 deletions(-) create mode 100644 Frontend/lib/mih_packages/mine_sweeper/components/board_square.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/components/mine_tile.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart create mode 100644 Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart diff --git a/Frontend/lib/mih_components/mih_package_components/assets/fonts/Mih_Icons.ttf b/Frontend/lib/mih_components/mih_package_components/assets/fonts/Mih_Icons.ttf index 71c04e155aa0042fcb72d33ab638b33a0cfd01d5..a908997c66d80100c9048237b82601bb02359778 100644 GIT binary patch delta 2118 zcmZuyON<;x8Ln4%b$4}l^{c8M(=$CiJ-y@cvfGZwvxBjh!59<>4?}Dv;gFD(@k?aA z3pU6gqzRWOf*gof3Qo=l85<`-MuI~Q8wptmB9J11asY%BAwcB71qq2IOU-(@xm(rs z{r~s>^*_|5|IhEBop;d;KmY&(&jJh%ojTnd=7By^nm5#X`t17JX8hROHvoXSlFwXN zyRxZvPs#J$xbVz3&cF56Q$JPmH306sbMf5TmzExPUk2c{&nbT8qEgV`<9{gmc_sHR zu3x=&>Y_s6wI8d`6VGg%J+byf_Dur7>uQ1J^|fo8V3pia@)0F>FR!hid-)ObKT1BM zf;_jmapkH?R6RfW!<+{g|NF)5DfF+yV~ZbD8VeWzsTYFo-~HYH?(WWQ6$X14?!Frn zP1Mp+;v+zmyWjKT1h2MvF;63;@ z{Hr>Ah*TtPJk<-tjjAD2I4YpvsG2lzN(HA?gE?%pLYtxjayY1!EjR1N8czzQ9LA#p z(Rwx|;|9%5XhFDE)eWAK292jE795HK2~OsAjX9ngD#8@b*QmgXZ4igCpeg~gni>tQ zI2DC4Qb#K*JjEk*1PLeO0WI)IQ)!X82G=ScRw<#X9yc>>QfTwE>jo;fy&9k@VINaf zjxi}zJ+Pjl!Bm+N5p#0i9I5l>7IadeQK3;)qA_oRHL2!J7^&3m=h_gCRJLR?uS^9& zDju?Hn z(+)bFqFm}0oh)!HL#G~>X)cn(ODxS}!(~B|^pb#k4wYHE|3`1Ngjud(_&uUy#yBN9 zaecbe$CNtNmHKESyfzjv}#`52HFL)1>*C z=^JLWP{^DdsM8OjDDVr{(y)$IYp5eVMh$ERf;c)Oh7@gxDYqCqk$HN%?6nk6YD0sL zPD~@t9c=5uK)L}q_ftbomxo8Lid?S(#cX(dF`W%{lv9GPqy?g zXguy}iz0$C5?LvmX|>$#TankqavJuFNVG!xsNZU5M@!jpgU^%)T4hfk1jBCpaF|BD zA}aDv2&7@gxs0M#+4*Ey_Hr3|2GQ-=6rn0IHLGH_gUA3vz7U>B)8WCvQl9#*OUWV3 zWl#3%y2#W832jR4FqLt3pi@OFG0hLJw}LUYshqL$1?-hKycuZ)sjSo`MO)T zF=1S)o<<}mVP}-M=ulzJ>iBUh?ZrW-Yg3o^)3N#=%?~3h5W3FX6f@IScTg80>r;Q= zIbL|Aj||=oLy^fkLCfw?eqQ*}wGff6aQw3FB@r{b*kq=s*%)k!w z7KvQXNuz@WKS?n`*jEvFwp95RzN%r5X~gLphICa$mhQDff(bVXaWzC!BpnJ*B9n28 z7%Wo%``tI;jbnG6mu`exFRo>GudKfEL^Yph>iO+goQJ>2kN*p>`D6j$FTpwY|NGW2 ze>8#e`mHlt-CJa3kG4PrI%vmu#J=hMTqdnwb??=09K7BSY=I1XXFisQ zsWh%)?qj6zg?)?_Ufst;;cw0HSUG4w&gbBsv#y9o_pt?zfFE2syRp8paT#0!XTb(o dS8D@Y-nw+VJorH7fy%Az+d@2;`RDD;{{di8BliFR delta 691 zcmaKpO=uHQ9K>g{o1{rGmBgkcR*g{{PaGfY@;Y=nb+&Y-AZu8yhXA3EdNwcX8tZQADr-kxUCi~`#-35%0G{+IS$Q@* z5qJ$eea!rXLc_T&ex-g-eOM_}7ABG;teIU>EoIKg>1)fEXqa}mATMZ$NnCKPN*yf9 zh3v{o_#X8GZgO8M=@lN7-}(ra=- zIktiST4?U{Nd7nemt4!dK8&0YuU&E8jn-B#Zp|2tP@s0;+*RKpGi39Pc^{^_Vn5I+ znWORf=C}TT)u?Qo6uOP|jpSe}b7K$o+f~=AUGIEDz2EnJ34J&k=-(QUB9~7`hPOvQ zT{s&*mGrds?KXy 0) { + // Display bomb count + return Center( + child: Text( + '${square.bombsAround}', + style: TextStyle( + fontWeight: FontWeight.bold, + color: _getTileColor(square.bombsAround, context), + ), + ), + ); + } else { + // Opened, but no bomb count (empty square) + return const SizedBox.shrink(); + } + } + + // Default: Unopened tile + return const SizedBox.shrink(); + } + + Color _getTileColor(int bombsAround, BuildContext context) { + // Choose colors based on standard Minesweeper appearance + switch (bombsAround) { + case 1: + return MihColors.getBluishPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.blue; + case 2: + return MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.green; + case 3: + return MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.red; + case 4: + return MihColors.getPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.purple; + case 5: + return MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode != "Dark", + ); + // return Colors.brown; + default: + // return MihColors.getBluishPurpleColor( + // MzansiInnovationHub.of(context)!.theme.mode == "Dark", + // ); + return Colors.black; + } + } + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(1.0), + child: MihButton( + onPressed: onTap, + onLongPressed: onLongPress, + buttonColor: square.isOpened + ? MihColors.getGreyColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ) + : MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ), + width: 50, + height: 50, + borderRadius: 3, + child: _getTileContent(context), + ), + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart index 98fd163f..b0659619 100644 --- a/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart +++ b/Frontend/lib/mih_packages/mine_sweeper/mih_mine_sweeper.dart @@ -1,4 +1,12 @@ import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_action.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tools.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart'; +import 'package:provider/provider.dart'; class MihMineSweeper extends StatefulWidget { const MihMineSweeper({super.key}); @@ -10,6 +18,54 @@ class MihMineSweeper extends StatefulWidget { class _MihMineSweeperState extends State { @override Widget build(BuildContext context) { - return const Placeholder(); + return MihPackage( + appActionButton: getAction(), + appTools: getTools(), + appToolTitles: getToolTitle(), + appBody: getToolBody(), + selectedbodyIndex: context.watch().toolIndex, + onIndexChange: (newIndex) { + context.read().setToolIndex(newIndex); + }, + ); + } + + MihPackageAction getAction() { + return MihPackageAction( + icon: const Icon(Icons.arrow_back), + iconSize: 35, + onTap: () { + context.goNamed( + 'mihHome', + extra: true, + ); + FocusScope.of(context).unfocus(); + }, + ); + } + + MihPackageTools getTools() { + Map temp = {}; + temp[const Icon(FontAwesomeIcons.bomb)] = () { + context.read().setToolIndex(0); + }; + return MihPackageTools( + tools: temp, + selcetedIndex: context.watch().toolIndex, + ); + } + + List getToolTitle() { + List toolTitles = [ + "MineSweeper", + ]; + return toolTitles; + } + + List getToolBody() { + List toolBodies = [ + const MineSweeperGame(), + ]; + return toolBodies; } } diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart new file mode 100644 index 00000000..81cab8fc --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tiles/mih_mine_sweeper_tile.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_tile.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; + +class MihMineSweeperTile extends StatefulWidget { + final bool personalSelected; + final double packageSize; + const MihMineSweeperTile({ + super.key, + required this.personalSelected, + required this.packageSize, + }); + + @override + State createState() => _MihMineSweeperTileState(); +} + +class _MihMineSweeperTileState extends State { + @override + Widget build(BuildContext context) { + return MihPackageTile( + onTap: () { + context.goNamed( + "mihMineSweeper", + ); + }, + appName: "MineSweeper", + appIcon: Icon( + MihIcons.mineSweeper, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // size: widget.packageSize, + ), + iconSize: widget.packageSize, + primaryColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + secondaryColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + } +} diff --git a/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart new file mode 100644 index 00000000..be21f407 --- /dev/null +++ b/Frontend/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -0,0 +1,596 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_dropdwn_field.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_floating_menu.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_form.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_alert.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_package_components/mih_single_child_scroll.dart'; +import 'package:mzansi_innovation_hub/mih_components/mih_providers/mih_mine_sweeper_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/board_square.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mine_sweeper/components/mine_tile.dart'; +import 'package:provider/provider.dart'; + +class MineSweeperGame extends StatefulWidget { + const MineSweeperGame({super.key}); + + @override + State createState() => _MineSweeperGameState(); +} + +class _MineSweeperGameState extends State { + TextEditingController modeController = TextEditingController(); + final _formKey = GlobalKey(); + List> board = []; + bool isGameOver = false; + bool isGameWon = false; + int squaresLeft = -1; + bool _isFirstLoad = true; + + void showStartGameWindow(MihMineSweeperProvider mihMineSweeperProvider) { + showDialog( + context: context, + builder: (context) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "New Game Settings", + onWindowTapClose: () { + context.pop(); + }, + windowBody: Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + MihDropdownField( + controller: modeController, + hintText: "Difficulty", + dropdownOptions: ["Easy", "Normal", "Hard"], + requiredText: true, + editable: true, + enableSearch: false, + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + setState( + () => initializeBoard(mihMineSweeperProvider)); + Navigator.of(context).pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Start Game", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ], + ), + ); + }); + } + +// --- GAME INITIALIZATION LOGIC --- + void initializeBoard(MihMineSweeperProvider mihMineSweeperProvider) { + // 1. Create a board of empty squares + board = List.generate( + mihMineSweeperProvider.rowCount, + (i) => List.generate( + mihMineSweeperProvider.columnCount, + (j) => BoardSquare(), + ), + ); + // 2. Place bombs randomly + placeBombs(mihMineSweeperProvider); + // 3. Calculate the number of bombs around each non-mine square + calculateBombsAround(mihMineSweeperProvider); + // Reset state variables + squaresLeft = + mihMineSweeperProvider.rowCount * mihMineSweeperProvider.columnCount; + isGameOver = false; + isGameWon = false; + // You'd typically add a call to setState here, but it's in initState. + } + + void placeBombs(MihMineSweeperProvider mihMineSweeperProvider) { + final Random random = Random(); + int bombsPlaced = 0; + + while (bombsPlaced < mihMineSweeperProvider.totalMines) { + int r = random.nextInt(mihMineSweeperProvider.rowCount); + int c = random.nextInt(mihMineSweeperProvider.columnCount); + + if (!board[r][c].hasBomb) { + board[r][c].hasBomb = true; + bombsPlaced++; + } + } + } + + void calculateBombsAround(MihMineSweeperProvider mihMineSweeperProvider) { + for (int r = 0; r < mihMineSweeperProvider.rowCount; r++) { + for (int c = 0; c < mihMineSweeperProvider.columnCount; c++) { + if (!board[r][c].hasBomb) { + int count = 0; + + // Check the 8 neighbors + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + if (i == 0 && j == 0) continue; // Skip the current square + + int neighborR = r + i; + int neighborC = c + j; + + // Check if neighbor is within bounds + if (neighborR >= 0 && + neighborR < mihMineSweeperProvider.rowCount && + neighborC >= 0 && + neighborC < mihMineSweeperProvider.columnCount) { + if (board[neighborR][neighborC].hasBomb) { + count++; + } + } + } + } + board[r][c].bombsAround = count; + } + } + } + } + + // Handles recursive opening of zero-squares + void _expandZeros( + MihMineSweeperProvider mihMineSweeperProvider, int r, int c) { + if (r < 0 || + r >= mihMineSweeperProvider.rowCount || + c < 0 || + c >= mihMineSweeperProvider.columnCount || + board[r][c].isOpened) { + return; + } + + BoardSquare square = board[r][c]; + + // Open the current square + square.isOpened = true; + squaresLeft--; + + // If it's a zero square, recursively call for neighbors + if (square.bombsAround == 0) { + // Check all 8 neighbors (not just 4 sides, for standard Minesweeper expansion) + for (int i = -1; i <= 1; i++) { + for (int j = -1; j <= 1; j++) { + _expandZeros(mihMineSweeperProvider, r + i, c + j); + } + } + } + } + + void handleTap(MihMineSweeperProvider mihMineSweeperProvider, int r, int c) { + if (isGameOver || board[r][c].isOpened || board[r][c].isFlagged) { + return; + } + // 1. Check for bomb (LOSS) + if (board[r][c].hasBomb) { + setState(() { + board[r][c].isOpened = true; + isGameOver = true; + // lose alert + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + FontAwesomeIcons.bomb, + color: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + size: 100, + ), + alertTitle: "Better Luck Next Time", + alertBody: Column( + children: [ + Text( + "Your lost this game of MIH MineSweeper!!!", + style: TextStyle( + fontSize: 15, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + const SizedBox(height: 20), + Wrap( + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + setState( + () => initializeBoard(mihMineSweeperProvider)); + Navigator.of(context).pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "New Game", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ], + ), + alertColour: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + ); + }); + return; + } + // 2. Open square and handle expansion (RECURSION) + if (board[r][c].bombsAround == 0) { + // Start recursive expansion + _expandZeros(mihMineSweeperProvider, r, c); + } else { + // Just open the single square + board[r][c].isOpened = true; + squaresLeft--; + } + // 3. Check for win + _checkWinCondition(mihMineSweeperProvider); + // Update the UI + setState(() {}); + } + + void handleLongPress(int r, int c) { + if (isGameOver || board[r][c].isOpened) { + return; + } + setState(() { + // Toggle the flag status + board[r][c].isFlagged = !board[r][c].isFlagged; + }); + } + + // --- GAME ACTION LOGIC --- + void _checkWinCondition(MihMineSweeperProvider mihMineSweeperProvider) { + // Game is won if all non-mine squares are opened. + if (squaresLeft <= mihMineSweeperProvider.totalMines) { + isGameWon = true; + isGameOver = true; + // win alert + showDialog( + context: context, + builder: (context) { + return MihPackageAlert( + alertIcon: Icon( + Icons.celebration, + color: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + size: 100, + ), + alertTitle: "Congradulations", + alertBody: Column( + children: [ + Text( + "Your won this game of MIH MineSweeper!!!", + style: TextStyle( + fontSize: 15, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + ), + const SizedBox(height: 20), + Wrap( + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 10, + runSpacing: 10, + children: [ + MihButton( + onPressed: () { + setState(() => initializeBoard(mihMineSweeperProvider)); + Navigator.of(context).pop(); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "New Game", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + ], + ), + alertColour: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + }, + ); + } + } + + Color? getDifficultyColor() { + String mode = modeController.text; + switch (mode) { + case "Easy": + return MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ); + case "Normal": + return MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ); + case "Hard": + return MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark", + ); + default: + return null; + } + } + + @override + void initState() { + super.initState(); + modeController.text = "Easy"; + // showStartGameWindow(context.read()); + // initializeBoard(); + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // This method is safe for calling showDialog or reading provider values. + if (_isFirstLoad) { + // 1. Get the provider safely. + WidgetsBinding.instance.addPostFrameCallback((_) { + final mihMineSweeperProvider = context.read(); + // board = List.generate( + // mihMineSweeperProvider.rowCount, + // (i) => List.generate( + // mihMineSweeperProvider.columnCount, + // (j) => BoardSquare(), + // ), + // ); + // 2. Show the dialog to get initial game settings. + // The user selection in the dialog will call initializeBoard(). + showStartGameWindow(mihMineSweeperProvider); + }); + // 3. Set flag to prevent showing the dialog on subsequent dependency changes + _isFirstLoad = false; + } + } + + @override + Widget build(BuildContext context) { + return Consumer( + builder: (BuildContext context, + MihMineSweeperProvider mihMineSweeperProvider, Widget? child) { + return Stack( + alignment: Alignment.topCenter, + children: [ + MihSingleChildScroll( + child: board.isEmpty && squaresLeft < 0 + // Start Up Message before setting up game + ? Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox(height: 50), + Icon( + MihIcons.mineSweeper, + size: 165, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + const SizedBox(height: 10), + Text( + "Welcom to MIH MineSweeper, the first game of MIH.", + textAlign: TextAlign.center, + overflow: TextOverflow.visible, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), + const SizedBox(height: 25), + Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: TextStyle( + fontSize: 20, + fontWeight: FontWeight.normal, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + children: [ + TextSpan(text: "Press "), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + Icons.menu, + size: 20, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + TextSpan(text: " to start a new game."), + ], + ), + ), + ), + ], + ), + ) + // Display Game Board when game started + : Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + // Display game status + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + 'Mines: ${mihMineSweeperProvider.totalMines}', + textAlign: TextAlign.left, + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold), + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(10.0), + child: Text( + modeController.text, + textAlign: TextAlign.right, + style: TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: getDifficultyColor(), + ), + ), + ), + ), + ], + ), + // const SizedBox( + // height: 30, + // ), + // The Board Grid + SizedBox( + width: mihMineSweeperProvider.columnCount * + 40.0, // Control size based on columns + height: mihMineSweeperProvider.rowCount * + 40.0, // Control size based on rows + child: GridView.builder( + physics: + const NeverScrollableScrollPhysics(), // Prevent scrolling + gridDelegate: + SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: + mihMineSweeperProvider.columnCount, + crossAxisSpacing: 0, + mainAxisSpacing: 0, + ), + itemCount: mihMineSweeperProvider.rowCount * + mihMineSweeperProvider.columnCount, + itemBuilder: (context, index) { + int r = index ~/ + mihMineSweeperProvider + .columnCount; // Integer division for row + int c = index % + mihMineSweeperProvider + .columnCount; // Remainder for column + + return MineTile( + square: board[r][c], + onTap: () => + handleTap(mihMineSweeperProvider, r, c), + onLongPress: () => handleLongPress(r, c), + ); + }, + ), + ), + ], + ), + ), + Positioned( + right: 10, + bottom: 10, + child: MihFloatingMenu( + animatedIcon: AnimatedIcons.menu_close, + children: [ + SpeedDialChild( + child: Icon( + Icons.add, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + label: board.isEmpty && squaresLeft < 0 + ? "Start Game" + : "Reset Game", + labelBackgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + labelStyle: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontWeight: FontWeight.bold, + ), + backgroundColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onTap: () { + showStartGameWindow(mihMineSweeperProvider); + }, + ) + ]), + ) + ], + ); + }, + ); + } +}