├── .gitattributes ├── .gitignore ├── LICENSE ├── Minesweeper.Win32 ├── MainWindow.cpp ├── MainWindow.h ├── Minesweeper.Win32.vcxproj ├── Minesweeper.Win32.vcxproj.filters ├── main.cpp ├── packages.config ├── pch.cpp └── pch.h ├── Minesweeper.sln ├── Minesweeper ├── Assets │ ├── LockScreenLogo.scale-200.png │ ├── LockScreenLogo.targetsize-48.png │ ├── Logo.scale-200.png │ ├── SplashScreen.scale-200.png │ ├── Square150x150Logo.scale-200.png │ ├── Square44x44Logo.png │ ├── StoreLogo.png │ └── Wide310x150Logo.scale-200.png ├── Minesweeper.vcxproj ├── Minesweeper.vcxproj.filters ├── Package.appxmanifest ├── main.cpp ├── packages.config ├── pch.cpp └── pch.h ├── README.md └── msweepcore ├── CompAssets.cpp ├── CompAssets.h ├── CompUI.cpp ├── CompUI.h ├── IndexHelper.h ├── Minesweeper.cpp ├── Minesweeper.h ├── VisualGrid.cpp ├── VisualGrid.h ├── include └── msweepcore.h ├── msweepcore.vcxproj ├── msweepcore.vcxproj.filters ├── packages.config ├── pch.cpp └── pch.h /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc 262 | 263 | Generated Files/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Robert Mikhayelyan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Minesweeper.Win32/MainWindow.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "msweepcore.h" 3 | #include "MainWindow.h" 4 | #include 5 | 6 | namespace winrt 7 | { 8 | using namespace Windows::Foundation; 9 | using namespace Windows::Foundation::Numerics; 10 | using namespace Windows::Graphics; 11 | } 12 | 13 | const std::wstring MainWindow::ClassName = L"Minesweeper.Win32.MainWindow"; 14 | 15 | void MainWindow::RegisterWindowClass() 16 | { 17 | auto instance = winrt::check_pointer(GetModuleHandleW(nullptr)); 18 | WNDCLASSEX wcex = { sizeof(wcex) }; 19 | wcex.style = CS_HREDRAW | CS_VREDRAW; 20 | wcex.lpfnWndProc = WndProc; 21 | wcex.hInstance = instance; 22 | wcex.hIcon = LoadIconW(instance, IDI_APPLICATION); 23 | wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); 24 | wcex.hbrBackground = nullptr; 25 | wcex.lpszClassName = ClassName.c_str(); 26 | wcex.hIconSm = LoadIconW(instance, IDI_APPLICATION); 27 | winrt::check_bool(RegisterClassExW(&wcex)); 28 | } 29 | 30 | MainWindow::MainWindow( 31 | std::wstring const& titleString, 32 | std::shared_ptr const& game, 33 | winrt::Windows::Graphics::SizeInt32 const& windowSize) 34 | { 35 | auto instance = winrt::check_pointer(GetModuleHandleW(nullptr)); 36 | m_game = game; 37 | 38 | winrt::check_bool(CreateWindowExW(WS_EX_NOREDIRECTIONBITMAP, ClassName.c_str(), titleString.c_str(), WS_OVERLAPPEDWINDOW, 39 | CW_USEDEFAULT, CW_USEDEFAULT, windowSize.Width, windowSize.Height, nullptr, nullptr, instance, this)); 40 | WINRT_ASSERT(m_window); 41 | 42 | ShowWindow(m_window, SW_SHOWDEFAULT); 43 | UpdateWindow(m_window); 44 | } 45 | 46 | LRESULT MainWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) 47 | { 48 | if (WM_DESTROY == message) 49 | { 50 | PostQuitMessage(0); 51 | return 0; 52 | } 53 | 54 | switch (message) 55 | { 56 | case WM_MOUSEMOVE: 57 | { 58 | auto rawX = GET_X_LPARAM(lparam); 59 | auto rawY = GET_Y_LPARAM(lparam); 60 | winrt::float2 point = { (float)rawX, (float)rawY }; 61 | m_game->OnPointerMoved(point); 62 | } 63 | break; 64 | case WM_SIZE: 65 | case WM_SIZING: 66 | { 67 | auto windowSize = GetWindowSize(); 68 | m_game->OnParentSizeChanged({ (float)windowSize.Width, (float)windowSize.Height }); 69 | } 70 | break; 71 | case WM_LBUTTONDOWN: 72 | m_game->OnPointerPressed(false, false); 73 | break; 74 | case WM_RBUTTONDOWN: 75 | m_game->OnPointerPressed(true, false); 76 | break; 77 | } 78 | 79 | return base_type::MessageHandler(message, wparam, lparam); 80 | } 81 | 82 | winrt::Windows::Graphics::SizeInt32 MainWindow::GetWindowSize() 83 | { 84 | RECT rect = {}; 85 | winrt::check_bool(GetClientRect(m_window, &rect)); 86 | auto windowWidth = rect.right - rect.left; 87 | auto windowHeight = rect.bottom - rect.top; 88 | winrt::SizeInt32 windowSize = { windowWidth, windowHeight }; 89 | return windowSize; 90 | } -------------------------------------------------------------------------------- /Minesweeper.Win32/MainWindow.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | struct MainWindow : robmikh::common::desktop::DesktopWindow 5 | { 6 | static const std::wstring ClassName; 7 | static void RegisterWindowClass(); 8 | MainWindow( 9 | std::wstring const& titleString, 10 | std::shared_ptr const& game, 11 | winrt::Windows::Graphics::SizeInt32 const& windowSize); 12 | LRESULT MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam); 13 | 14 | private: 15 | winrt::Windows::Graphics::SizeInt32 GetWindowSize(); 16 | 17 | private: 18 | std::shared_ptr m_game; 19 | }; -------------------------------------------------------------------------------- /Minesweeper.Win32/Minesweeper.Win32.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | ARM 8 | 9 | 10 | Debug 11 | ARM64 12 | 13 | 14 | Debug 15 | Win32 16 | 17 | 18 | Release 19 | ARM 20 | 21 | 22 | Release 23 | ARM64 24 | 25 | 26 | Release 27 | Win32 28 | 29 | 30 | Debug 31 | x64 32 | 33 | 34 | Release 35 | x64 36 | 37 | 38 | 39 | 16.0 40 | {855940A1-6D41-49F3-9421-C0D813B23C7B} 41 | MinesweeperWin32 42 | 10.0 43 | 44 | 45 | 46 | Application 47 | true 48 | v142 49 | Unicode 50 | 51 | 52 | Application 53 | false 54 | v142 55 | true 56 | Unicode 57 | 58 | 59 | Application 60 | true 61 | v142 62 | Unicode 63 | 64 | 65 | Application 66 | true 67 | v142 68 | Unicode 69 | 70 | 71 | Application 72 | true 73 | v142 74 | Unicode 75 | 76 | 77 | Application 78 | false 79 | v142 80 | true 81 | Unicode 82 | 83 | 84 | Application 85 | false 86 | v142 87 | true 88 | Unicode 89 | 90 | 91 | Application 92 | false 93 | v142 94 | true 95 | Unicode 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | Level3 131 | Disabled 132 | true 133 | false 134 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 135 | 136 | 137 | Windows 138 | windowsapp.lib;$(SolutionDir)$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 139 | 140 | 141 | false 142 | 143 | 144 | 145 | 146 | Level3 147 | Disabled 148 | true 149 | false 150 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 151 | 152 | 153 | Windows 154 | windowsapp.lib;$(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 155 | 156 | 157 | false 158 | 159 | 160 | 161 | 162 | Level3 163 | Disabled 164 | true 165 | false 166 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 167 | 168 | 169 | Windows 170 | windowsapp.lib;$(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 171 | 172 | 173 | false 174 | 175 | 176 | 177 | 178 | Level3 179 | Disabled 180 | true 181 | false 182 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 183 | 184 | 185 | Windows 186 | windowsapp.lib;$(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 187 | 188 | 189 | false 190 | 191 | 192 | 193 | 194 | Level3 195 | MaxSpeed 196 | true 197 | true 198 | true 199 | false 200 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 201 | 202 | 203 | Windows 204 | true 205 | true 206 | windowsapp.lib;$(SolutionDir)$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 207 | 208 | 209 | false 210 | 211 | 212 | 213 | 214 | Level3 215 | MaxSpeed 216 | true 217 | true 218 | true 219 | false 220 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 221 | 222 | 223 | Windows 224 | true 225 | true 226 | windowsapp.lib;$(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 227 | 228 | 229 | false 230 | 231 | 232 | 233 | 234 | Level3 235 | MaxSpeed 236 | true 237 | true 238 | true 239 | false 240 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 241 | 242 | 243 | Windows 244 | true 245 | true 246 | windowsapp.lib;$(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 247 | 248 | 249 | false 250 | 251 | 252 | 253 | 254 | Level3 255 | MaxSpeed 256 | true 257 | true 258 | true 259 | false 260 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 261 | 262 | 263 | Windows 264 | true 265 | true 266 | windowsapp.lib;$(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 267 | 268 | 269 | false 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 293 | 294 | 295 | 296 | 297 | 298 | 299 | -------------------------------------------------------------------------------- /Minesweeper.Win32/Minesweeper.Win32.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Minesweeper.Win32/main.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "msweepcore.h" 3 | #include "MainWindow.h" 4 | 5 | namespace winrt 6 | { 7 | using namespace Windows::Foundation; 8 | using namespace Windows::Foundation::Numerics; 9 | using namespace Windows::UI; 10 | using namespace Windows::UI::Composition; 11 | using namespace Windows::UI::Composition::Desktop; 12 | using namespace Windows::Graphics; 13 | } 14 | 15 | namespace util 16 | { 17 | using namespace robmikh::common::desktop; 18 | } 19 | 20 | int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int) 21 | { 22 | winrt::init_apartment(); 23 | 24 | MainWindow::RegisterWindowClass(); 25 | 26 | // Create the DispatcherQueue that the compositor needs to run 27 | auto controller = util::CreateDispatcherQueueControllerForCurrentThread(); 28 | 29 | // Initialize Composition 30 | auto compositor = winrt::Compositor(); 31 | auto root = compositor.CreateContainerVisual(); 32 | root.RelativeSizeAdjustment({ 1.0f, 1.0f }); 33 | 34 | // Create our game 35 | winrt::SizeInt32 windowSize = { 800, 600 }; 36 | auto game = CreateMinesweeper(root, winrt::float2{ (float)windowSize.Width, (float)windowSize.Height }); 37 | 38 | // Create our main window 39 | auto window = MainWindow(L"Minesweeper.Win32", game, windowSize); 40 | 41 | // Hookup our visual tree to the window 42 | auto target = window.CreateWindowTarget(compositor); 43 | target.Root(root); 44 | 45 | // Message pump 46 | MSG msg; 47 | while (GetMessage(&msg, NULL, 0, 0)) 48 | { 49 | TranslateMessage(&msg); 50 | DispatchMessage(&msg); 51 | } 52 | 53 | return static_cast(msg.wParam); 54 | } -------------------------------------------------------------------------------- /Minesweeper.Win32/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Minesweeper.Win32/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" -------------------------------------------------------------------------------- /Minesweeper.Win32/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | // WinRT 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | // STL 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | // WIL 31 | #include 32 | 33 | // D3D 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | // Helpers 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include -------------------------------------------------------------------------------- /Minesweeper.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.28803.352 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Minesweeper", "Minesweeper\Minesweeper.vcxproj", "{93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02} = {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msweepcore", "msweepcore\msweepcore.vcxproj", "{9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}" 12 | EndProject 13 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Minesweeper.Win32", "Minesweeper.Win32\Minesweeper.Win32.vcxproj", "{855940A1-6D41-49F3-9421-C0D813B23C7B}" 14 | ProjectSection(ProjectDependencies) = postProject 15 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02} = {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02} 16 | EndProjectSection 17 | EndProject 18 | Global 19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 20 | Debug|ARM = Debug|ARM 21 | Debug|ARM64 = Debug|ARM64 22 | Debug|x64 = Debug|x64 23 | Debug|x86 = Debug|x86 24 | Release|ARM = Release|ARM 25 | Release|ARM64 = Release|ARM64 26 | Release|x64 = Release|x64 27 | Release|x86 = Release|x86 28 | EndGlobalSection 29 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 30 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|ARM.ActiveCfg = Debug|ARM 31 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|ARM.Build.0 = Debug|ARM 32 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|ARM.Deploy.0 = Debug|ARM 33 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|ARM64.ActiveCfg = Debug|ARM64 34 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|ARM64.Build.0 = Debug|ARM64 35 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|ARM64.Deploy.0 = Debug|ARM64 36 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|x64.ActiveCfg = Debug|x64 37 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|x64.Build.0 = Debug|x64 38 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|x64.Deploy.0 = Debug|x64 39 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|x86.ActiveCfg = Debug|Win32 40 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|x86.Build.0 = Debug|Win32 41 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Debug|x86.Deploy.0 = Debug|Win32 42 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|ARM.ActiveCfg = Release|ARM 43 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|ARM.Build.0 = Release|ARM 44 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|ARM.Deploy.0 = Release|ARM 45 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|ARM64.ActiveCfg = Release|ARM64 46 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|ARM64.Build.0 = Release|ARM64 47 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|ARM64.Deploy.0 = Release|ARM64 48 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|x64.ActiveCfg = Release|x64 49 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|x64.Build.0 = Release|x64 50 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|x64.Deploy.0 = Release|x64 51 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|x86.ActiveCfg = Release|Win32 52 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|x86.Build.0 = Release|Win32 53 | {93E6CAC0-A654-47B9-BFCF-B7474D7FA7C2}.Release|x86.Deploy.0 = Release|Win32 54 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Debug|ARM.ActiveCfg = Debug|ARM 55 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Debug|ARM.Build.0 = Debug|ARM 56 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Debug|ARM64.ActiveCfg = Debug|ARM64 57 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Debug|ARM64.Build.0 = Debug|ARM64 58 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Debug|x64.ActiveCfg = Debug|x64 59 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Debug|x64.Build.0 = Debug|x64 60 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Debug|x86.ActiveCfg = Debug|Win32 61 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Debug|x86.Build.0 = Debug|Win32 62 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Release|ARM.ActiveCfg = Release|ARM 63 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Release|ARM.Build.0 = Release|ARM 64 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Release|ARM64.ActiveCfg = Release|ARM64 65 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Release|ARM64.Build.0 = Release|ARM64 66 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Release|x64.ActiveCfg = Release|x64 67 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Release|x64.Build.0 = Release|x64 68 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Release|x86.ActiveCfg = Release|Win32 69 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02}.Release|x86.Build.0 = Release|Win32 70 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Debug|ARM.ActiveCfg = Debug|ARM 71 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Debug|ARM.Build.0 = Debug|ARM 72 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Debug|ARM64.ActiveCfg = Debug|ARM64 73 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Debug|ARM64.Build.0 = Debug|ARM64 74 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Debug|x64.ActiveCfg = Debug|x64 75 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Debug|x64.Build.0 = Debug|x64 76 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Debug|x86.ActiveCfg = Debug|Win32 77 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Debug|x86.Build.0 = Debug|Win32 78 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Release|ARM.ActiveCfg = Release|ARM 79 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Release|ARM.Build.0 = Release|ARM 80 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Release|ARM64.ActiveCfg = Release|ARM64 81 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Release|ARM64.Build.0 = Release|ARM64 82 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Release|x64.ActiveCfg = Release|x64 83 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Release|x64.Build.0 = Release|x64 84 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Release|x86.ActiveCfg = Release|Win32 85 | {855940A1-6D41-49F3-9421-C0D813B23C7B}.Release|x86.Build.0 = Release|Win32 86 | EndGlobalSection 87 | GlobalSection(SolutionProperties) = preSolution 88 | HideSolutionNode = FALSE 89 | EndGlobalSection 90 | GlobalSection(ExtensibilityGlobals) = postSolution 91 | SolutionGuid = {D97A7463-22D0-4BB1-ABE6-E192CA644E15} 92 | EndGlobalSection 93 | EndGlobal 94 | -------------------------------------------------------------------------------- /Minesweeper/Assets/LockScreenLogo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robmikh/Minesweeper/4e19fa34189099f069a35e138ba42ceb1e27080a/Minesweeper/Assets/LockScreenLogo.scale-200.png -------------------------------------------------------------------------------- /Minesweeper/Assets/LockScreenLogo.targetsize-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robmikh/Minesweeper/4e19fa34189099f069a35e138ba42ceb1e27080a/Minesweeper/Assets/LockScreenLogo.targetsize-48.png -------------------------------------------------------------------------------- /Minesweeper/Assets/Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robmikh/Minesweeper/4e19fa34189099f069a35e138ba42ceb1e27080a/Minesweeper/Assets/Logo.scale-200.png -------------------------------------------------------------------------------- /Minesweeper/Assets/SplashScreen.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robmikh/Minesweeper/4e19fa34189099f069a35e138ba42ceb1e27080a/Minesweeper/Assets/SplashScreen.scale-200.png -------------------------------------------------------------------------------- /Minesweeper/Assets/Square150x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robmikh/Minesweeper/4e19fa34189099f069a35e138ba42ceb1e27080a/Minesweeper/Assets/Square150x150Logo.scale-200.png -------------------------------------------------------------------------------- /Minesweeper/Assets/Square44x44Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robmikh/Minesweeper/4e19fa34189099f069a35e138ba42ceb1e27080a/Minesweeper/Assets/Square44x44Logo.png -------------------------------------------------------------------------------- /Minesweeper/Assets/StoreLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robmikh/Minesweeper/4e19fa34189099f069a35e138ba42ceb1e27080a/Minesweeper/Assets/StoreLogo.png -------------------------------------------------------------------------------- /Minesweeper/Assets/Wide310x150Logo.scale-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robmikh/Minesweeper/4e19fa34189099f069a35e138ba42ceb1e27080a/Minesweeper/Assets/Wide310x150Logo.scale-200.png -------------------------------------------------------------------------------- /Minesweeper/Minesweeper.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | true 6 | $(RequiredBundles);Microsoft.Windows.CppWinRT 7 | true 8 | {93e6cac0-a654-47b9-bfcf-b7474d7fa7c2} 9 | Minesweeper 10 | Minesweeper 11 | en-US 12 | 15.0 13 | true 14 | Windows Store 15 | 10.0 16 | 10.0.18362.0 17 | 10.0.18362.0 18 | 19 | 20 | 21 | 22 | Debug 23 | ARM 24 | 25 | 26 | Debug 27 | ARM64 28 | 29 | 30 | Debug 31 | Win32 32 | 33 | 34 | Debug 35 | x64 36 | 37 | 38 | Release 39 | ARM 40 | 41 | 42 | Release 43 | ARM64 44 | 45 | 46 | Release 47 | Win32 48 | 49 | 50 | Release 51 | x64 52 | 53 | 54 | 55 | Application 56 | v142 57 | Unicode 58 | 59 | 60 | true 61 | true 62 | 63 | 64 | false 65 | true 66 | false 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | False 76 | True 77 | Minesweeper_TemporaryKey.pfx 78 | SHA256 79 | True 80 | True 81 | Always 82 | x86|x64|arm|arm64 83 | 0 84 | 85 | 86 | 87 | Use 88 | pch.h 89 | $(IntDir)pch.pch 90 | Level4 91 | %(AdditionalOptions) /bigobj 92 | 4453;28204 93 | stdcpp17 94 | stdcpp17 95 | stdcpp17 96 | stdcpp17 97 | stdcpp17 98 | stdcpp17 99 | stdcpp17 100 | stdcpp17 101 | false 102 | false 103 | false 104 | false 105 | false 106 | false 107 | false 108 | false 109 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 110 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 111 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 112 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 113 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 114 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 115 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 116 | ..\msweepcore\include\;%(AdditionalIncludeDirectories) 117 | 118 | 119 | false 120 | $(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 121 | $(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 122 | $(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 123 | $(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 124 | $(SolutionDir)$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 125 | $(SolutionDir)$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 126 | $(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 127 | $(SolutionDir)$(Platform)\$(Configuration)\msweepcore\msweepcore.lib;%(AdditionalDependencies) 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | Designer 136 | 137 | 138 | 139 | 140 | 141 | Create 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | true 151 | 152 | 153 | true 154 | 155 | 156 | true 157 | 158 | 159 | true 160 | 161 | 162 | true 163 | 164 | 165 | 166 | 167 | true 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 177 | 178 | 179 | 180 | 181 | -------------------------------------------------------------------------------- /Minesweeper/Minesweeper.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {db9086fe-bacc-4437-8272-1aa6642082db} 20 | 21 | 22 | 23 | 24 | Assets 25 | 26 | 27 | Assets 28 | 29 | 30 | Assets 31 | 32 | 33 | Assets 34 | 35 | 36 | Assets 37 | 38 | 39 | Assets 40 | 41 | 42 | Assets 43 | 44 | 45 | Assets 46 | 47 | 48 | -------------------------------------------------------------------------------- /Minesweeper/Package.appxmanifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 7 | 8 | 9 | Minesweeper 10 | robmi 11 | Assets\StoreLogo.png 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Minesweeper/main.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "msweepcore.h" 3 | 4 | using namespace winrt; 5 | 6 | using namespace Windows::ApplicationModel::Core; 7 | using namespace Windows::Foundation; 8 | using namespace Windows::Foundation::Numerics; 9 | using namespace Windows::UI::Core; 10 | using namespace Windows::UI::Composition; 11 | using namespace Windows::System; 12 | using namespace Windows::UI; 13 | using namespace Windows::Graphics::Display; 14 | using namespace Windows::Foundation::Metadata; 15 | 16 | struct App : implements 17 | { 18 | IFrameworkView CreateView() 19 | { 20 | return *this; 21 | } 22 | 23 | void Initialize(CoreApplicationView const & view) 24 | { 25 | m_view = view; 26 | } 27 | 28 | void Load(hstring const&) 29 | { 30 | } 31 | 32 | void Uninitialize() 33 | { 34 | m_sizeChanged.revoke(); 35 | m_pointerMoved.revoke(); 36 | m_pointerPressed.revoke(); 37 | } 38 | 39 | void Run() 40 | { 41 | m_compositor = Compositor(); 42 | m_windowRoot = m_compositor.CreateContainerVisual(); 43 | m_windowRoot.RelativeSizeAdjustment({ 1.0f, 1.0f }); 44 | m_target = m_compositor.CreateTargetForCurrentView(); 45 | m_target.Root(m_windowRoot); 46 | 47 | m_minesweeper = CreateMinesweeper(m_windowRoot, GetWindowSize()); 48 | 49 | m_sizeChanged = m_window.SizeChanged(auto_revoke, { this, &App::OnSizeChanged }); 50 | m_pointerMoved = m_window.PointerMoved(auto_revoke, { this, &App::OnPointerMoved }); 51 | m_pointerPressed = m_window.PointerPressed(auto_revoke, { this, &App::OnPointerPressed }); 52 | 53 | m_window.Activate(); 54 | 55 | CoreDispatcher dispatcher = m_window.Dispatcher(); 56 | dispatcher.ProcessEvents(CoreProcessEventsOption::ProcessUntilQuit); 57 | } 58 | 59 | void SetWindow(CoreWindow const & window) 60 | { 61 | m_window = window; 62 | } 63 | 64 | void OnSizeChanged(CoreWindow const & window, WindowSizeChangedEventArgs const & args) 65 | { 66 | auto windowSize = float2(args.Size()); 67 | m_minesweeper->OnParentSizeChanged(windowSize); 68 | } 69 | 70 | float2 GetWindowSize() 71 | { 72 | return { m_window.Bounds().Width, m_window.Bounds().Height }; 73 | } 74 | 75 | void OnPointerMoved(IInspectable const & window, PointerEventArgs const & args) 76 | { 77 | float2 point = args.CurrentPoint().Position(); 78 | m_minesweeper->OnPointerMoved(point); 79 | } 80 | 81 | void OnPointerPressed(IInspectable const & window, PointerEventArgs const & args) 82 | { 83 | m_minesweeper->OnPointerPressed( 84 | args.CurrentPoint().Properties().IsRightButtonPressed(), 85 | args.CurrentPoint().Properties().IsEraser()); 86 | } 87 | 88 | CoreApplicationView m_view{ nullptr }; 89 | CoreWindow m_window{ nullptr }; 90 | 91 | Compositor m_compositor{ nullptr }; 92 | CompositionTarget m_target{ nullptr }; 93 | ContainerVisual m_windowRoot{ nullptr }; 94 | 95 | std::shared_ptr m_minesweeper{ nullptr }; 96 | 97 | CoreWindow::SizeChanged_revoker m_sizeChanged; 98 | CoreWindow::PointerMoved_revoker m_pointerMoved; 99 | CoreWindow::PointerPressed_revoker m_pointerPressed; 100 | }; 101 | 102 | int __stdcall wWinMain(HINSTANCE, HINSTANCE, PWSTR, int) 103 | { 104 | CoreApplication::Run(make()); 105 | } -------------------------------------------------------------------------------- /Minesweeper/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Minesweeper/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | -------------------------------------------------------------------------------- /Minesweeper/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | #include 22 | #include -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minesweeper 2 | A C++ implementation of Minesweeper using Windows.UI.Composition. 3 | -------------------------------------------------------------------------------- /msweepcore/CompAssets.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "CompAssets.h" 3 | 4 | using namespace winrt; 5 | 6 | using namespace Windows::Foundation; 7 | using namespace Windows::Foundation::Numerics; 8 | using namespace Windows::Graphics; 9 | using namespace Windows::UI; 10 | using namespace Windows::UI::Composition; 11 | 12 | CompositionSpriteShape GetDotShape( 13 | Compositor const& compositor, 14 | CompositionGeometry const& geometry, 15 | CompositionColorBrush const& brush, 16 | float2 offset) 17 | { 18 | auto shape = compositor.CreateSpriteShape(geometry); 19 | shape.FillBrush(brush); 20 | shape.Offset(offset); 21 | return shape; 22 | } 23 | 24 | CompAssets::CompAssets( 25 | Compositor const& compositor, 26 | float2 const& tileSize) 27 | { 28 | GenerateAssets(compositor, tileSize); 29 | } 30 | 31 | CompositionColorBrush CompAssets::GetColorBrushFromMineState(MineState state) 32 | { 33 | return m_mineStateBrushes.at(state); 34 | } 35 | 36 | CompositionColorBrush CompAssets::GetColorBrushFromMineCount(int count) 37 | { 38 | return m_mineCountBackgroundBrushes.at(count); 39 | } 40 | 41 | CompositionShape CompAssets::GetShapeFromMineCount(int count) 42 | { 43 | return m_mineCountShapes.at(count); 44 | } 45 | 46 | void CompAssets::GenerateAssets( 47 | Compositor const& compositor, 48 | float2 const& tileSize) 49 | { 50 | m_mineBrush = compositor.CreateColorBrush(Colors::Red()); 51 | 52 | m_mineStateBrushes.clear(); 53 | m_mineStateBrushes.insert({ MineState::Empty, compositor.CreateColorBrush(Colors::Blue()) }); 54 | m_mineStateBrushes.insert({ MineState::Flag, compositor.CreateColorBrush(Colors::Orange()) }); 55 | m_mineStateBrushes.insert({ MineState::Question, compositor.CreateColorBrush(Colors::LimeGreen()) }); 56 | 57 | m_mineCountBackgroundBrushes.clear(); 58 | m_mineCountBackgroundBrushes.insert({ 1, compositor.CreateColorBrush(Colors::LightBlue()) }); 59 | m_mineCountBackgroundBrushes.insert({ 2, compositor.CreateColorBrush(Colors::LightGreen()) }); 60 | m_mineCountBackgroundBrushes.insert({ 3, compositor.CreateColorBrush(Colors::LightSalmon()) }); 61 | m_mineCountBackgroundBrushes.insert({ 4, compositor.CreateColorBrush(Colors::LightSteelBlue()) }); 62 | m_mineCountBackgroundBrushes.insert({ 5, compositor.CreateColorBrush(Colors::MediumPurple()) }); 63 | m_mineCountBackgroundBrushes.insert({ 6, compositor.CreateColorBrush(Colors::LightCyan()) }); 64 | m_mineCountBackgroundBrushes.insert({ 7, compositor.CreateColorBrush(Colors::Maroon()) }); 65 | m_mineCountBackgroundBrushes.insert({ 8, compositor.CreateColorBrush(Colors::DarkSeaGreen()) }); 66 | m_mineCountBackgroundBrushes.insert({ 0, compositor.CreateColorBrush(Colors::WhiteSmoke()) }); 67 | 68 | m_mineCountShapes.clear(); 69 | { 70 | auto circleGeometry = compositor.CreateEllipseGeometry(); 71 | circleGeometry.Radius(tileSize / 12.0f); 72 | auto dotBrush = compositor.CreateColorBrush(Colors::Black()); 73 | 74 | // 1 75 | { 76 | auto containerShape = compositor.CreateContainerShape(); 77 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, tileSize / 2.0f)); 78 | m_mineCountShapes.insert({ 1, containerShape }); 79 | } 80 | 81 | // 2 82 | { 83 | auto containerShape = compositor.CreateContainerShape(); 84 | auto thirdX = tileSize.x / 3.0f; 85 | auto halfY = tileSize.y / 2.0f; 86 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { thirdX , halfY })); 87 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { thirdX * 2.0f , halfY })); 88 | m_mineCountShapes.insert({ 2, containerShape }); 89 | } 90 | 91 | // 3 92 | { 93 | auto containerShape = compositor.CreateContainerShape(); 94 | auto fourthX = tileSize.x / 4.0f; 95 | auto fourthY = tileSize.y / 4.0f; 96 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, tileSize / 2.0f)); 97 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY * 3.0f })); 98 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY })); 99 | m_mineCountShapes.insert({ 3, containerShape }); 100 | } 101 | 102 | 103 | // 4 104 | { 105 | auto containerShape = compositor.CreateContainerShape(); 106 | auto thirdX = tileSize.x / 3.0f; 107 | auto thirdY = tileSize.y / 3.0f; 108 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { thirdX , thirdY })); 109 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { thirdX * 2.0f , thirdY })); 110 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { thirdX , thirdY * 2.0f })); 111 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { thirdX * 2.0f , thirdY * 2.0f })); 112 | m_mineCountShapes.insert({ 4, containerShape }); 113 | } 114 | 115 | // 5 116 | { 117 | auto containerShape = compositor.CreateContainerShape(); 118 | auto fourthX = tileSize.x / 4.0f; 119 | auto fourthY = tileSize.y / 4.0f; 120 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, tileSize / 2.0f)); 121 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY * 3.0f })); 122 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY })); 123 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY })); 124 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY * 3.0f })); 125 | m_mineCountShapes.insert({ 5, containerShape }); 126 | } 127 | 128 | // 6 129 | { 130 | auto containerShape = compositor.CreateContainerShape(); 131 | auto fourthX = tileSize.x / 4.0f; 132 | auto fourthY = tileSize.y / 4.0f; 133 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY * 2.0f })); 134 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY * 3.0f })); 135 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY })); 136 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY })); 137 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY * 3.0f })); 138 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY * 2.0f })); 139 | m_mineCountShapes.insert({ 6, containerShape }); 140 | } 141 | 142 | // 7 143 | { 144 | auto containerShape = compositor.CreateContainerShape(); 145 | auto fourthX = tileSize.x / 4.0f; 146 | auto fourthY = tileSize.y / 4.0f; 147 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY * 2.0f })); 148 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY * 3.0f })); 149 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY })); 150 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY })); 151 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY * 3.0f })); 152 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY * 2.0f })); 153 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, tileSize / 2.0f)); 154 | m_mineCountShapes.insert({ 7, containerShape }); 155 | } 156 | 157 | // 8 158 | { 159 | auto containerShape = compositor.CreateContainerShape(); 160 | auto fourthX = tileSize.x / 4.0f; 161 | auto fourthY = tileSize.y / 4.0f; 162 | auto halfX = tileSize.y / 2.0f; 163 | auto thirdY = tileSize.y / 3.0f; 164 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY * 2.0f })); 165 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY * 3.0f })); 166 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY })); 167 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX, fourthY })); 168 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY * 3.0f })); 169 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { fourthX * 3.0f, fourthY * 2.0f })); 170 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { halfX, thirdY })); 171 | containerShape.Shapes().Append(GetDotShape(compositor, circleGeometry, dotBrush, { halfX, thirdY * 2.0f })); 172 | m_mineCountShapes.insert({ 8, containerShape }); 173 | } 174 | } 175 | } -------------------------------------------------------------------------------- /msweepcore/CompAssets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CompAssets 4 | { 5 | public: 6 | CompAssets( 7 | winrt::Windows::UI::Composition::Compositor const& compositor, 8 | winrt::Windows::Foundation::Numerics::float2 const& tileSize); 9 | ~CompAssets() {} 10 | 11 | winrt::Windows::UI::Composition::CompositionColorBrush GetMineBrush() { return m_mineBrush; } 12 | winrt::Windows::UI::Composition::CompositionColorBrush GetColorBrushFromMineState(MineState state); 13 | winrt::Windows::UI::Composition::CompositionColorBrush GetColorBrushFromMineCount(int count); 14 | winrt::Windows::UI::Composition::CompositionShape GetShapeFromMineCount(int count); 15 | 16 | private: 17 | void GenerateAssets( 18 | winrt::Windows::UI::Composition::Compositor const& compositor, 19 | winrt::Windows::Foundation::Numerics::float2 const& tileSize); 20 | 21 | private: 22 | winrt::Windows::UI::Composition::CompositionColorBrush m_mineBrush{ nullptr }; 23 | std::map m_mineStateBrushes; 24 | std::map m_mineCountBackgroundBrushes; 25 | std::map m_mineCountShapes; 26 | }; -------------------------------------------------------------------------------- /msweepcore/CompUI.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "VisualGrid.h" 3 | #include "CompAssets.h" 4 | #include "CompUI.h" 5 | 6 | using namespace winrt; 7 | 8 | using namespace Windows::Foundation; 9 | using namespace Windows::Foundation::Numerics; 10 | using namespace Windows::Graphics; 11 | using namespace Windows::UI; 12 | using namespace Windows::UI::Composition; 13 | 14 | CompUI::CompUI( 15 | ContainerVisual const& parentVisual, 16 | float2 const& parentSize, 17 | SizeInt32 const& gridSizeInTiles) 18 | { 19 | m_compositor = parentVisual.Compositor(); 20 | m_root = m_compositor.CreateSpriteVisual(); 21 | m_parentSize = parentSize; 22 | 23 | m_root.RelativeSizeAdjustment({ 1.0f, 1.0f }); 24 | m_root.Brush(m_compositor.CreateColorBrush(Colors::White())); 25 | m_root.BorderMode(CompositionBorderMode::Hard); 26 | parentVisual.Children().InsertAtTop(m_root); 27 | 28 | auto tileSize = float2{ 25, 25 }; 29 | m_gameBoard = std::make_unique( 30 | m_compositor, 31 | gridSizeInTiles, 32 | tileSize, 33 | float2{ 2.5f, 2.5f }); 34 | m_gameBoardMargin = { 100.0f, 100.0f }; 35 | 36 | auto gameBoardVisual = m_gameBoard->Root(); 37 | gameBoardVisual.RelativeOffsetAdjustment({ 0.5f, 0.5f, 0 }); 38 | gameBoardVisual.AnchorPoint({ 0.5f, 0.5f }); 39 | m_root.Children().InsertAtTop(gameBoardVisual); 40 | 41 | auto selectionVisual = m_gameBoard->SelectionVisual(); 42 | m_root.Children().InsertAtTop(selectionVisual); 43 | 44 | m_assets = std::make_unique(m_compositor, tileSize); 45 | } 46 | 47 | void CompUI::SelectTile(std::optional tileCoordinate) { m_gameBoard->SelectTile(tileCoordinate); } 48 | std::optional CompUI::CurrentSelectedTile() { return m_gameBoard->CurrentSelectedTile(); } 49 | 50 | void CompUI::Resize(float2 const& newSize) 51 | { 52 | m_parentSize = newSize; 53 | UpdateBoardScale(newSize); 54 | } 55 | 56 | std::optional CompUI::HitTest(float2 const& point) 57 | { 58 | auto windowSize = m_parentSize; 59 | auto scale = ComputeScaleFactor(); 60 | auto realBoardSize = m_gameBoard->Size() * scale; 61 | auto realOffset = (windowSize - realBoardSize) / 2.0f; 62 | 63 | return m_gameBoard->HitTest((point - realOffset) / scale); 64 | } 65 | 66 | void CompUI::UpdateBoardScale(float2 windowSize) 67 | { 68 | float scaleFactor = ComputeScaleFactor(windowSize); 69 | m_gameBoard->Root().Scale({ scaleFactor, scaleFactor, 1.0f }); 70 | } 71 | 72 | float CompUI::ComputeScaleFactor() 73 | { 74 | return ComputeScaleFactor(m_parentSize); 75 | } 76 | 77 | float CompUI::ComputeScaleFactor(float2 windowSize) 78 | { 79 | auto boardSize = m_gameBoard->Size() + m_gameBoardMargin; 80 | 81 | auto windowRatio = windowSize.x / windowSize.y; 82 | auto boardRatio = boardSize.x / boardSize.y; 83 | 84 | auto scaleFactor = windowSize.x / boardSize.x; 85 | if (windowRatio > boardRatio) 86 | { 87 | scaleFactor = windowSize.y / boardSize.y; 88 | } 89 | return scaleFactor; 90 | } 91 | 92 | void CompUI::UpdateTileWithState(TileCoordinate const& tileCoordinate, MineState mineState) 93 | { 94 | auto visual = m_gameBoard->GetTile(tileCoordinate.x, tileCoordinate.y); 95 | visual.Brush(m_assets->GetColorBrushFromMineState(mineState)); 96 | } 97 | 98 | void CompUI::Reset(SizeInt32 const& gridSizeInTiles) 99 | { 100 | m_gameBoard->Reset(gridSizeInTiles); 101 | m_indexHelper = std::make_unique(gridSizeInTiles.Width, gridSizeInTiles.Height); 102 | 103 | for (auto& visual : m_gameBoard->Tiles()) 104 | { 105 | visual.Brush(m_assets->GetColorBrushFromMineState(MineState::Empty)); 106 | } 107 | 108 | UpdateBoardScale(m_parentSize); 109 | m_mineAnimationPlaying = false; 110 | } 111 | 112 | void CompUI::UpdateTileAsMine(TileCoordinate const& tileCoordinate) 113 | { 114 | auto visual = m_gameBoard->GetTile(tileCoordinate.x, tileCoordinate.y); 115 | visual.Brush(m_assets->GetMineBrush()); 116 | } 117 | 118 | void CompUI::UpdateTileWithMineCount(TileCoordinate const& tileCoordinate, int numMines) 119 | { 120 | auto visual = m_gameBoard->GetTile(tileCoordinate.x, tileCoordinate.y); 121 | visual.Brush(m_assets->GetColorBrushFromMineCount(numMines)); 122 | 123 | if (numMines > 0) 124 | { 125 | auto shape = m_assets->GetShapeFromMineCount(numMines); 126 | auto shapeVisual = m_compositor.CreateShapeVisual(); 127 | shapeVisual.RelativeSizeAdjustment({ 1, 1 }); 128 | shapeVisual.Shapes().Append(shape); 129 | shapeVisual.BorderMode(CompositionBorderMode::Soft); 130 | visual.Children().InsertAtTop(shapeVisual); 131 | } 132 | } 133 | 134 | void CompUI::PlayMineAnimations(std::queue mineIndices, std::queue minesPerRing) 135 | { 136 | // Create an animation batch so that we can know when the animations complete. 137 | auto batch = m_compositor.CreateScopedBatch(CompositionBatchTypes::Animation); 138 | 139 | // Iterate and animate each mine 140 | auto animationDelayStep = std::chrono::milliseconds(100); 141 | auto currentDelay = std::chrono::milliseconds(0); 142 | auto currentMinesCount = 0; 143 | while (!mineIndices.empty()) 144 | { 145 | auto mineIndex = mineIndices.front(); 146 | PlayMineAnimation(mineIndex, currentDelay); 147 | currentMinesCount++; 148 | 149 | auto minesOnCurrentLevel = minesPerRing.front(); 150 | if (currentMinesCount == minesOnCurrentLevel) 151 | { 152 | currentMinesCount = 0; 153 | minesPerRing.pop(); 154 | currentDelay += animationDelayStep; 155 | } 156 | mineIndices.pop(); 157 | } 158 | 159 | // Subscribe to the completion event and complete the batch 160 | batch.Completed([=](auto&, auto&) 161 | { 162 | m_mineAnimationPlaying = false; 163 | }); 164 | batch.End(); 165 | 166 | m_mineAnimationPlaying = true; 167 | } 168 | 169 | void CompUI::PlayMineAnimation(int index, TimeSpan const& delay) 170 | { 171 | auto visual = m_gameBoard->GetTile(m_indexHelper->ComputeXFromIndex(index), m_indexHelper->ComputeYFromIndex(index)); 172 | // First, we need to promote the visual to the top. 173 | auto parentChildren = visual.Parent().Children(); 174 | parentChildren.Remove(visual); 175 | parentChildren.InsertAtTop(visual); 176 | // Make sure the visual has the mine brush 177 | visual.Brush(m_assets->GetMineBrush()); 178 | // Play the animation 179 | auto animation = m_compositor.CreateVector3KeyFrameAnimation(); 180 | animation.InsertKeyFrame(0.0f, { 1.0f, 1.0f, 1.0f }); 181 | animation.InsertKeyFrame(0.7f, { 2.0f, 2.0f, 1.0f }); 182 | animation.InsertKeyFrame(1.0f, { 1.0f, 1.0f, 1.0f }); 183 | animation.Duration(std::chrono::milliseconds(600)); 184 | animation.DelayTime(delay); 185 | animation.IterationBehavior(AnimationIterationBehavior::Count); 186 | animation.IterationCount(1); 187 | visual.StartAnimation(L"Scale", animation); 188 | } -------------------------------------------------------------------------------- /msweepcore/CompUI.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CompAssets; 4 | class VisualGrid; 5 | struct TileCoordinate; 6 | 7 | class CompUI 8 | { 9 | public: 10 | CompUI( 11 | winrt::Windows::UI::Composition::ContainerVisual const& parentVisual, 12 | winrt::Windows::Foundation::Numerics::float2 const& parentSize, 13 | winrt::Windows::Graphics::SizeInt32 const& gridSizeInTiles); 14 | ~CompUI() {} 15 | 16 | void Resize(winrt::Windows::Foundation::Numerics::float2 const& newSize); 17 | std::optional HitTest(winrt::Windows::Foundation::Numerics::float2 const& point); 18 | void SelectTile(std::optional tileCoordinate); 19 | std::optional CurrentSelectedTile(); 20 | void UpdateTileWithState(TileCoordinate const& tileCoordinate, MineState mineState); 21 | void Reset(winrt::Windows::Graphics::SizeInt32 const& gridSizeInTiles); 22 | void UpdateTileAsMine(TileCoordinate const& tileCoordinate); 23 | void UpdateTileWithMineCount(TileCoordinate const& tileCoordinate, int numMines); 24 | void PlayMineAnimations(std::queue mineIndices, std::queue minesPerRing); 25 | bool IsAnimationPlaying() { return m_mineAnimationPlaying; } 26 | 27 | private: 28 | float ComputeScaleFactor(winrt::Windows::Foundation::Numerics::float2 windowSize); 29 | float ComputeScaleFactor(); 30 | void UpdateBoardScale(winrt::Windows::Foundation::Numerics::float2 windowSize); 31 | void PlayMineAnimation(int index, winrt::Windows::Foundation::TimeSpan const& delay); 32 | 33 | private: 34 | winrt::Windows::UI::Composition::Compositor m_compositor{ nullptr }; 35 | winrt::Windows::UI::Composition::SpriteVisual m_root{ nullptr }; 36 | 37 | winrt::Windows::Foundation::Numerics::float2 m_parentSize; 38 | winrt::Windows::Foundation::Numerics::float2 m_gameBoardMargin; 39 | std::unique_ptr m_indexHelper; 40 | 41 | std::unique_ptr m_gameBoard; 42 | std::unique_ptr m_assets; 43 | 44 | bool m_mineAnimationPlaying = false; 45 | }; -------------------------------------------------------------------------------- /msweepcore/IndexHelper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | struct IndexHelper 3 | { 4 | int width; 5 | int height; 6 | 7 | IndexHelper(int width, int height) 8 | { 9 | this->width = width; 10 | this->height = height; 11 | } 12 | 13 | int ComputeIndex(int x, int y) 14 | { 15 | return x * height + y; 16 | } 17 | 18 | int ComputeXFromIndex(int index) 19 | { 20 | return index / height; 21 | } 22 | 23 | int ComputeYFromIndex(int index) 24 | { 25 | return index % height; 26 | } 27 | 28 | bool IsInBounds(int x, int y) 29 | { 30 | return (x >= 0 && x < width) && (y >= 0 && y < height); 31 | } 32 | }; -------------------------------------------------------------------------------- /msweepcore/Minesweeper.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "CompUI.h" 3 | #include "VisualGrid.h" 4 | #include "CompAssets.h" 5 | #include "Minesweeper.h" 6 | 7 | using namespace winrt; 8 | 9 | using namespace Windows::Foundation; 10 | using namespace Windows::Foundation::Numerics; 11 | using namespace Windows::Graphics; 12 | using namespace Windows::UI; 13 | using namespace Windows::UI::Composition; 14 | 15 | std::shared_ptr CreateMinesweeper( 16 | ContainerVisual parentVisual, 17 | float2 parentSize) 18 | { 19 | return std::make_shared(parentVisual, parentSize); 20 | } 21 | 22 | MineState CycleMineState(MineState const& mineState) 23 | { 24 | switch (mineState) 25 | { 26 | case MineState::Empty: 27 | return MineState::Flag; 28 | case MineState::Flag: 29 | return MineState::Question; 30 | case MineState::Question: 31 | return MineState::Empty; 32 | case MineState::Revealed: 33 | throw std::runtime_error("We shouldn't be cycling a revealed tile!"); 34 | } 35 | } 36 | 37 | Minesweeper::Minesweeper( 38 | ContainerVisual const& parentVisual, 39 | float2 parentSize) 40 | { 41 | auto boardSizeInTiles = SizeInt32{ 16, 16 }; 42 | m_ui = std::make_unique(parentVisual, parentSize, boardSizeInTiles); 43 | 44 | NewGame(boardSizeInTiles.Width, boardSizeInTiles.Height, 40); 45 | OnParentSizeChanged(parentSize); 46 | } 47 | 48 | void Minesweeper::OnPointerMoved(float2 point) 49 | { 50 | if (m_gameOver || m_ui->IsAnimationPlaying()) 51 | { 52 | return; 53 | } 54 | 55 | std::optional selectedTile = std::nullopt; 56 | if (auto tile = m_ui->HitTest(point)) 57 | { 58 | if (m_mineStates[m_indexHelper->ComputeIndex(tile->x, tile->y)] != MineState::Revealed) 59 | { 60 | selectedTile.swap(std::optional(tile)); 61 | } 62 | } 63 | m_ui->SelectTile(selectedTile); 64 | } 65 | 66 | void Minesweeper::OnParentSizeChanged(float2 newSize) 67 | { 68 | m_ui->Resize(newSize); 69 | } 70 | 71 | void Minesweeper::OnPointerPressed( 72 | bool isRightButton, 73 | bool isEraser) 74 | { 75 | if (m_gameOver && !m_ui->IsAnimationPlaying()) 76 | { 77 | NewGame(m_gameBoardWidth, m_gameBoardWidth, m_numMines); 78 | } 79 | 80 | if (auto currentSelection = m_ui->CurrentSelectedTile()) 81 | { 82 | int index = m_indexHelper->ComputeIndex(currentSelection->x, currentSelection->y); 83 | 84 | if (m_mineStates[index] != MineState::Revealed) 85 | { 86 | if (isRightButton || isEraser) 87 | { 88 | auto state = CycleMineState(m_mineStates[index]); 89 | m_mineStates[index] = state; 90 | m_ui->UpdateTileWithState(*currentSelection, state); 91 | } 92 | else if (m_mineStates[index] == MineState::Empty) 93 | { 94 | if (Sweep(currentSelection->x, currentSelection->y)) 95 | { 96 | // We hit a mine! Setup and play an animation while locking any input. 97 | auto hitX = currentSelection->x; 98 | auto hitY = currentSelection->y; 99 | 100 | // First, hide the selection visual and reset the selection 101 | m_ui->SelectTile(std::nullopt); 102 | 103 | PlayAnimationOnAllMines(hitX, hitY); 104 | 105 | m_gameOver = true; 106 | } 107 | else if (CheckIfWon()) 108 | { 109 | m_ui->SelectTile(std::nullopt); 110 | // TODO: Play a win animation 111 | m_gameOver = true; 112 | } 113 | } 114 | } 115 | } 116 | } 117 | 118 | void Minesweeper::NewGame(int boardWidth, int boardHeight, int mines) 119 | { 120 | m_gameBoardWidth = boardWidth; 121 | m_gameBoardHeight = boardHeight; 122 | m_indexHelper = std::make_unique(boardWidth, boardHeight); 123 | 124 | m_ui->Reset({ boardWidth, boardHeight }); 125 | m_mineStates.clear(); 126 | 127 | for (auto i = 0; i < boardWidth * boardHeight; i++) 128 | { 129 | m_mineStates.push_back(MineState::Empty); 130 | } 131 | 132 | m_gameOver = false; 133 | m_mineGenerationState = MineGenerationState::Deferred; 134 | m_numMines = mines; 135 | } 136 | 137 | bool Minesweeper::Sweep(int x, int y) 138 | { 139 | if (m_mineGenerationState == MineGenerationState::Deferred) 140 | { 141 | // We don't want the first thing that the user clicks to be a mine. 142 | // Generate mines but avoid putting it where the user clicked. 143 | GenerateMines(m_numMines, x, y); 144 | m_mineGenerationState = MineGenerationState::Generated; 145 | } 146 | 147 | bool hitMine = false; 148 | std::queue sweeps; 149 | sweeps.push(m_indexHelper->ComputeIndex(x, y)); 150 | Reveal(sweeps.front()); 151 | 152 | while (!sweeps.empty()) 153 | { 154 | int index = sweeps.front(); 155 | int currentx = m_indexHelper->ComputeXFromIndex(index); 156 | int currenty = m_indexHelper->ComputeYFromIndex(index); 157 | 158 | if (m_mines[index]) 159 | { 160 | // We hit a mine, game over 161 | hitMine = true; 162 | break; 163 | } 164 | 165 | if (m_neighborCounts[index] == 0) 166 | { 167 | PushIfUnmarked(sweeps, currentx - 1, currenty - 1); 168 | PushIfUnmarked(sweeps, currentx, currenty - 1); 169 | PushIfUnmarked(sweeps, currentx + 1, currenty - 1); 170 | PushIfUnmarked(sweeps, currentx + 1, currenty); 171 | PushIfUnmarked(sweeps, currentx + 1, currenty + 1); 172 | PushIfUnmarked(sweeps, currentx, currenty + 1); 173 | PushIfUnmarked(sweeps, currentx - 1, currenty + 1); 174 | PushIfUnmarked(sweeps, currentx - 1, currenty); 175 | } 176 | 177 | sweeps.pop(); 178 | } 179 | 180 | return hitMine; 181 | } 182 | 183 | void Minesweeper::Reveal(int index) 184 | { 185 | auto tileCoordinate = TileCoordinate{ m_indexHelper->ComputeXFromIndex(index), m_indexHelper->ComputeYFromIndex(index) }; 186 | 187 | if (m_mines[index]) 188 | { 189 | m_ui->UpdateTileAsMine(tileCoordinate); 190 | } 191 | else 192 | { 193 | int count = m_neighborCounts[index]; 194 | m_ui->UpdateTileWithMineCount(tileCoordinate, count); 195 | } 196 | 197 | m_mineStates[index] = MineState::Revealed; 198 | } 199 | 200 | bool Minesweeper::IsInBoundsAndUnmarked(int x, int y) 201 | { 202 | int index = m_indexHelper->ComputeIndex(x, y); 203 | return m_indexHelper->IsInBounds(x, y) && m_mineStates[index] == MineState::Empty; 204 | } 205 | 206 | void Minesweeper::PushIfUnmarked(std::queue & sweeps, int x, int y) 207 | { 208 | if (IsInBoundsAndUnmarked(x, y)) 209 | { 210 | int index = m_indexHelper->ComputeIndex(x, y); 211 | Reveal(index); 212 | sweeps.push(index); 213 | } 214 | } 215 | 216 | void Minesweeper::GenerateMines(int numMines, int excludeX, int excludeY) 217 | { 218 | m_mines.clear(); 219 | for (int x = 0; x < m_gameBoardWidth; x++) 220 | { 221 | for (int y = 0; y < m_gameBoardHeight; y++) 222 | { 223 | m_mines.push_back(false); 224 | } 225 | } 226 | 227 | srand(time(0)); 228 | for (int i = 0; i < numMines; i++) 229 | { 230 | int index = -1; 231 | auto excludeIndex = m_indexHelper->ComputeIndex(excludeX, excludeY); 232 | do 233 | { 234 | index = GenerateIndex(0, m_gameBoardWidth * m_gameBoardHeight - 1); 235 | } while (index == excludeIndex || m_mines[index]); 236 | 237 | m_mines[index] = true; 238 | } 239 | 240 | m_neighborCounts.clear(); 241 | for (int i = 0; i < m_mines.size(); i++) 242 | { 243 | int x = m_indexHelper->ComputeXFromIndex(i); 244 | int y = m_indexHelper->ComputeYFromIndex(i); 245 | 246 | if (m_mines[i]) 247 | { 248 | // -1 means a mine 249 | m_neighborCounts.push_back(-1); 250 | // DEBUG 251 | #if SHOW_MINES 252 | m_ui->UpdateTileWithState({ x, y }, MineState::Question); 253 | #endif 254 | } 255 | else 256 | { 257 | int count = GetSurroundingMineCount(x, y); 258 | m_neighborCounts.push_back(count); 259 | } 260 | } 261 | } 262 | 263 | int Minesweeper::GenerateIndex(int min, int max) 264 | { 265 | return min + (rand() % static_cast(max - min + 1)); 266 | } 267 | 268 | bool Minesweeper::TestSpot(int x, int y) 269 | { 270 | return m_indexHelper->IsInBounds(x, y) && m_mines[m_indexHelper->ComputeIndex(x, y)]; 271 | } 272 | 273 | int Minesweeper::GetSurroundingMineCount(int x, int y) 274 | { 275 | int count = 0; 276 | 277 | if (TestSpot(x + 1, y)) 278 | { 279 | count++; 280 | } 281 | 282 | if (TestSpot(x - 1, y)) 283 | { 284 | count++; 285 | } 286 | 287 | if (TestSpot(x, y + 1)) 288 | { 289 | count++; 290 | } 291 | 292 | if (TestSpot(x, y - 1)) 293 | { 294 | count++; 295 | } 296 | 297 | if (TestSpot(x + 1, y + 1)) 298 | { 299 | count++; 300 | } 301 | 302 | if (TestSpot(x - 1, y - 1)) 303 | { 304 | count++; 305 | } 306 | 307 | if (TestSpot(x - 1, y + 1)) 308 | { 309 | count++; 310 | } 311 | 312 | if (TestSpot(x + 1, y - 1)) 313 | { 314 | count++; 315 | } 316 | 317 | return count; 318 | } 319 | 320 | void Minesweeper::CheckTileForMineForAnimation(int x, int y, std::queue& mineIndices, int& visitedTiles, int& minesInRing) 321 | { 322 | if (m_indexHelper->IsInBounds(x, y)) 323 | { 324 | auto tileIndex = m_indexHelper->ComputeIndex(x, y); 325 | if (m_mines[tileIndex]) 326 | { 327 | mineIndices.push(tileIndex); 328 | minesInRing++; 329 | } 330 | visitedTiles++; 331 | } 332 | } 333 | 334 | void Minesweeper::PlayAnimationOnAllMines(int centerX, int centerY) 335 | { 336 | // Build a queue that contains the indices of the mines in a spiral starting from the clicked mine. 337 | std::queue mineIndices; 338 | std::queue minesPerRing; 339 | int visitedTiles = 0; 340 | int ringLevel = 0; 341 | while (visitedTiles < (m_gameBoardWidth * m_gameBoardHeight)) 342 | { 343 | if (ringLevel == 0) 344 | { 345 | auto hitMineIndex = m_indexHelper->ComputeIndex(centerX, centerY); 346 | mineIndices.push(hitMineIndex); 347 | minesPerRing.push(1); 348 | visitedTiles++; 349 | } 350 | else 351 | { 352 | auto currentMinesInRing = 0; 353 | 354 | // Check the top side 355 | for (auto x = centerX - ringLevel; x <= (centerX + ringLevel); x++) 356 | { 357 | auto y = centerY - ringLevel; 358 | CheckTileForMineForAnimation(x, y, mineIndices, visitedTiles, currentMinesInRing); 359 | } 360 | 361 | // Check the right side 362 | for (auto y = centerY - ringLevel + 1; y <= (centerY + ringLevel); y++) 363 | { 364 | auto x = centerX + ringLevel; 365 | CheckTileForMineForAnimation(x, y, mineIndices, visitedTiles, currentMinesInRing); 366 | } 367 | 368 | // Check the bottom side 369 | for (auto x = centerX - ringLevel; x < (centerX + ringLevel); x++) 370 | { 371 | auto y = centerY + ringLevel; 372 | CheckTileForMineForAnimation(x, y, mineIndices, visitedTiles, currentMinesInRing); 373 | } 374 | 375 | // Check the left side 376 | for (auto y = centerY - ringLevel + 1; y < (centerY + ringLevel); y++) 377 | { 378 | auto x = centerX - ringLevel; 379 | CheckTileForMineForAnimation(x, y, mineIndices, visitedTiles, currentMinesInRing); 380 | } 381 | 382 | if (currentMinesInRing > 0) 383 | { 384 | minesPerRing.push(currentMinesInRing); 385 | } 386 | } 387 | ringLevel++; 388 | } 389 | 390 | // Iterate and animate each mine 391 | m_ui->PlayMineAnimations(mineIndices, minesPerRing); 392 | } 393 | 394 | bool Minesweeper::CheckIfWon() 395 | { 396 | // Get the number of non-revealed tiles 397 | auto nonRevealedTiles = 0; 398 | for (auto& state : m_mineStates) 399 | { 400 | if (state != MineState::Revealed) 401 | { 402 | nonRevealedTiles += 1; 403 | } 404 | } 405 | 406 | return nonRevealedTiles == m_numMines; 407 | } 408 | -------------------------------------------------------------------------------- /msweepcore/Minesweeper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class CompUI; 3 | 4 | class Minesweeper : public IMinesweeper 5 | { 6 | public: 7 | Minesweeper( 8 | winrt::Windows::UI::Composition::ContainerVisual const& parentVisual, 9 | winrt::Windows::Foundation::Numerics::float2 parentSize); 10 | ~Minesweeper() override {} 11 | 12 | void OnPointerMoved(winrt::Windows::Foundation::Numerics::float2 point) override; 13 | void OnParentSizeChanged(winrt::Windows::Foundation::Numerics::float2 newSize) override; 14 | void OnPointerPressed( 15 | bool isRightButton, 16 | bool isEraser) override; 17 | 18 | private: 19 | void NewGame(int boardWidth, int boardHeight, int mines); 20 | bool Sweep(int x, int y); 21 | void Reveal(int index); 22 | bool IsInBoundsAndUnmarked(int x, int y); 23 | void PushIfUnmarked(std::queue& sweeps, int x, int y); 24 | void GenerateMines(int numMines, int excludeX, int excludeY); 25 | int GenerateIndex(int min, int max); 26 | bool TestSpot(int x, int y); 27 | int GetSurroundingMineCount(int x, int y); 28 | void CheckTileForMineForAnimation(int x, int y, std::queue& mineIndices, int& visitedTiles, int& minesInRing); 29 | void PlayAnimationOnAllMines(int centerX, int centerY); 30 | winrt::Windows::UI::Composition::CompositionShape GetShapeFromMineCount(int count); 31 | winrt::Windows::UI::Composition::CompositionSpriteShape GetDotShape( 32 | winrt::Windows::UI::Composition::CompositionGeometry const& geometry, 33 | winrt::Windows::UI::Composition::CompositionColorBrush const& brush, 34 | winrt::Windows::Foundation::Numerics::float2 offset); 35 | bool CheckIfWon(); 36 | 37 | private: 38 | std::unique_ptr m_ui; 39 | 40 | int m_gameBoardWidth; 41 | int m_gameBoardHeight; 42 | std::unique_ptr m_indexHelper; 43 | 44 | std::vector m_mineStates; 45 | std::vector m_mines; 46 | std::vector m_neighborCounts; 47 | MineGenerationState m_mineGenerationState = MineGenerationState::Deferred; 48 | int m_numMines = 0; 49 | 50 | bool m_gameOver = false; 51 | }; -------------------------------------------------------------------------------- /msweepcore/VisualGrid.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "VisualGrid.h" 3 | 4 | using namespace winrt; 5 | 6 | using namespace Windows::Foundation; 7 | using namespace Windows::Foundation::Numerics; 8 | using namespace Windows::Graphics; 9 | using namespace Windows::UI; 10 | using namespace Windows::UI::Composition; 11 | 12 | VisualGrid::VisualGrid( 13 | Compositor const& compositor, 14 | SizeInt32 const& gridSizeInTiles, 15 | float2 const& tileSize, 16 | float2 const& margin) 17 | { 18 | m_compositor = compositor; 19 | m_root = m_compositor.CreateSpriteVisual(); 20 | 21 | m_tileSize = tileSize; 22 | m_margin = margin; 23 | 24 | m_selectionVisual = m_compositor.CreateSpriteVisual(); 25 | auto colorBrush = m_compositor.CreateColorBrush(Colors::Red()); 26 | auto nineGridBrush = m_compositor.CreateNineGridBrush(); 27 | nineGridBrush.SetInsets(m_margin.x, m_margin.y, m_margin.x, m_margin.y); 28 | nineGridBrush.IsCenterHollow(true); 29 | nineGridBrush.Source(colorBrush); 30 | m_selectionVisual.Brush(nineGridBrush); 31 | m_selectionVisual.Offset(float3(m_margin * -1.0f, 0)); 32 | m_selectionVisual.IsVisible(false); 33 | m_selectionVisual.Size(m_tileSize + m_margin * 2.0f); 34 | 35 | Reset(gridSizeInTiles); 36 | } 37 | 38 | void VisualGrid::Reset( 39 | SizeInt32 const& gridSizeInTiles) 40 | { 41 | m_gridWidthInTiles = gridSizeInTiles.Width; 42 | m_gridHeightInTiles = gridSizeInTiles.Height; 43 | 44 | m_root.Children().RemoveAll(); 45 | m_tiles.clear(); 46 | 47 | m_root.Size((m_tileSize + m_margin) * float2(m_gridWidthInTiles, m_gridHeightInTiles)); 48 | m_indexHelper = std::make_unique(m_gridWidthInTiles, m_gridHeightInTiles); 49 | 50 | for (int x = 0; x < m_gridWidthInTiles; x++) 51 | { 52 | for (int y = 0; y < m_gridHeightInTiles; y++) 53 | { 54 | auto visual = m_compositor.CreateSpriteVisual(); 55 | visual.Size(m_tileSize); 56 | visual.CenterPoint({ m_tileSize / 2.0f, 0.0f }); 57 | visual.Offset(float3((m_margin / 2.0f) + (float2(m_tileSize + m_margin) * float2(x, y)), 0.0f)); 58 | 59 | m_root.Children().InsertAtTop(visual); 60 | m_tiles.push_back(visual); 61 | } 62 | } 63 | } 64 | 65 | std::optional VisualGrid::HitTest(float2 const& point) 66 | { 67 | int x = point.x / (m_tileSize.x + m_margin.x); 68 | int y = point.y / (m_tileSize.y + m_margin.y); 69 | 70 | if (m_indexHelper->IsInBounds(x, y)) 71 | { 72 | return std::optional{ { x, y } }; 73 | } 74 | else 75 | { 76 | return std::nullopt; 77 | } 78 | } 79 | 80 | SpriteVisual VisualGrid::GetTile(int x, int y) 81 | { 82 | return m_tiles[m_indexHelper->ComputeIndex(x, y)]; 83 | } 84 | 85 | void VisualGrid::SelectTile(std::optional tileCoordinate) 86 | { 87 | m_currentSelection = tileCoordinate; 88 | if (auto selectedTileCoordinate = tileCoordinate) 89 | { 90 | auto visual = m_tiles[m_indexHelper->ComputeIndex(selectedTileCoordinate->x, selectedTileCoordinate->y)]; 91 | m_selectionVisual.ParentForTransform(visual); 92 | m_selectionVisual.IsVisible(true); 93 | } 94 | else 95 | { 96 | m_selectionVisual.IsVisible(false); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /msweepcore/VisualGrid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | struct TileCoordinate 3 | { 4 | int x; 5 | int y; 6 | }; 7 | 8 | class VisualGrid 9 | { 10 | public: 11 | VisualGrid( 12 | winrt::Windows::UI::Composition::Compositor const& compositor, 13 | winrt::Windows::Graphics::SizeInt32 const& gridSizeInTiles, 14 | winrt::Windows::Foundation::Numerics::float2 const& tileSize, 15 | winrt::Windows::Foundation::Numerics::float2 const& margin); 16 | ~VisualGrid() {} 17 | 18 | void Reset(winrt::Windows::Graphics::SizeInt32 const& gridSizeInTiles); 19 | 20 | winrt::Windows::UI::Composition::ContainerVisual Root() { return m_root; } 21 | winrt::Windows::UI::Composition::SpriteVisual SelectionVisual() { return m_selectionVisual; } 22 | winrt::Windows::Foundation::Numerics::float2 Size() { return m_root.Size(); } 23 | const std::vector& Tiles() const { return m_tiles; } 24 | std::optional HitTest(winrt::Windows::Foundation::Numerics::float2 const& point); 25 | winrt::Windows::UI::Composition::SpriteVisual GetTile(int x, int y); 26 | void SelectTile(std::optional tileCoordinate); 27 | std::optional CurrentSelectedTile() { return m_currentSelection; } 28 | 29 | private: 30 | winrt::Windows::UI::Composition::Compositor m_compositor{ nullptr }; 31 | winrt::Windows::UI::Composition::SpriteVisual m_root{ nullptr }; 32 | 33 | std::vector m_tiles; 34 | winrt::Windows::UI::Composition::SpriteVisual m_selectionVisual{ nullptr }; 35 | std::unique_ptr m_indexHelper; 36 | 37 | int m_gridWidthInTiles; 38 | int m_gridHeightInTiles; 39 | winrt::Windows::Foundation::Numerics::float2 m_tileSize; 40 | winrt::Windows::Foundation::Numerics::float2 m_margin; 41 | 42 | std::optional m_currentSelection = std::nullopt; 43 | }; -------------------------------------------------------------------------------- /msweepcore/include/msweepcore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | enum class MineState 3 | { 4 | Empty = 0, 5 | Flag = 1, 6 | Question = 2, 7 | Revealed = 3 8 | }; 9 | 10 | enum class MineGenerationState 11 | { 12 | Deferred, 13 | Generated, 14 | }; 15 | 16 | class IMinesweeper 17 | { 18 | public: 19 | virtual ~IMinesweeper() {} 20 | 21 | virtual void OnPointerMoved(winrt::Windows::Foundation::Numerics::float2 point) = 0; 22 | virtual void OnParentSizeChanged(winrt::Windows::Foundation::Numerics::float2 newSize) = 0; 23 | virtual void OnPointerPressed( 24 | bool isRightButton, 25 | bool isEraser) = 0; 26 | }; 27 | 28 | std::shared_ptr CreateMinesweeper( 29 | winrt::Windows::UI::Composition::ContainerVisual parentVisual, 30 | winrt::Windows::Foundation::Numerics::float2 parentSize); 31 | -------------------------------------------------------------------------------- /msweepcore/msweepcore.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | ARM 8 | 9 | 10 | Debug 11 | ARM64 12 | 13 | 14 | Debug 15 | Win32 16 | 17 | 18 | Release 19 | ARM 20 | 21 | 22 | Release 23 | ARM64 24 | 25 | 26 | Release 27 | Win32 28 | 29 | 30 | Debug 31 | x64 32 | 33 | 34 | Release 35 | x64 36 | 37 | 38 | 39 | 16.0 40 | {9CBCE764-E914-4EEF-8022-FA7FBE9F1F02} 41 | msweepcore 42 | 10.0 43 | 44 | 45 | 46 | StaticLibrary 47 | true 48 | v142 49 | Unicode 50 | 51 | 52 | StaticLibrary 53 | false 54 | v142 55 | true 56 | Unicode 57 | 58 | 59 | StaticLibrary 60 | true 61 | v142 62 | Unicode 63 | 64 | 65 | StaticLibrary 66 | true 67 | v142 68 | Unicode 69 | 70 | 71 | StaticLibrary 72 | true 73 | v142 74 | Unicode 75 | 76 | 77 | StaticLibrary 78 | false 79 | v142 80 | true 81 | Unicode 82 | 83 | 84 | StaticLibrary 85 | false 86 | v142 87 | true 88 | Unicode 89 | 90 | 91 | StaticLibrary 92 | false 93 | v142 94 | true 95 | Unicode 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | $(SolutionDir)$(Configuration)\$(ProjectName)\ 129 | 130 | 131 | $(SolutionDir)$(Configuration)\$(ProjectName)\ 132 | 133 | 134 | $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ 135 | 136 | 137 | $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ 138 | 139 | 140 | $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ 141 | 142 | 143 | $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ 144 | 145 | 146 | $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ 147 | 148 | 149 | $(SolutionDir)$(Platform)\$(Configuration)\$(ProjectName)\ 150 | 151 | 152 | 153 | Level3 154 | Disabled 155 | true 156 | false 157 | stdcpp17 158 | include\;%(AdditionalIncludeDirectories) 159 | 160 | 161 | Console 162 | windowsapp.lib;%(AdditionalDependencies) 163 | 164 | 165 | 166 | 167 | Level3 168 | Disabled 169 | true 170 | false 171 | stdcpp17 172 | include\;%(AdditionalIncludeDirectories) 173 | 174 | 175 | Console 176 | windowsapp.lib;%(AdditionalDependencies) 177 | 178 | 179 | 180 | 181 | Level3 182 | Disabled 183 | true 184 | false 185 | stdcpp17 186 | include\;%(AdditionalIncludeDirectories) 187 | 188 | 189 | Console 190 | windowsapp.lib;%(AdditionalDependencies) 191 | 192 | 193 | 194 | 195 | Level3 196 | Disabled 197 | true 198 | false 199 | stdcpp17 200 | include\;%(AdditionalIncludeDirectories) 201 | 202 | 203 | Console 204 | windowsapp.lib;%(AdditionalDependencies) 205 | 206 | 207 | 208 | 209 | Level3 210 | MaxSpeed 211 | true 212 | true 213 | true 214 | false 215 | stdcpp17 216 | include\;%(AdditionalIncludeDirectories) 217 | 218 | 219 | Console 220 | true 221 | true 222 | windowsapp.lib;%(AdditionalDependencies) 223 | 224 | 225 | 226 | 227 | Level3 228 | MaxSpeed 229 | true 230 | true 231 | true 232 | false 233 | stdcpp17 234 | include\;%(AdditionalIncludeDirectories) 235 | 236 | 237 | Console 238 | true 239 | true 240 | windowsapp.lib;%(AdditionalDependencies) 241 | 242 | 243 | 244 | 245 | Level3 246 | MaxSpeed 247 | true 248 | true 249 | true 250 | false 251 | stdcpp17 252 | include\;%(AdditionalIncludeDirectories) 253 | 254 | 255 | Console 256 | true 257 | true 258 | windowsapp.lib;%(AdditionalDependencies) 259 | 260 | 261 | 262 | 263 | Level3 264 | MaxSpeed 265 | true 266 | true 267 | true 268 | false 269 | stdcpp17 270 | include\;%(AdditionalIncludeDirectories) 271 | 272 | 273 | Console 274 | true 275 | true 276 | windowsapp.lib;%(AdditionalDependencies) 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | false 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 307 | 308 | 309 | 310 | 311 | -------------------------------------------------------------------------------- /msweepcore/msweepcore.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /msweepcore/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /msweepcore/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" -------------------------------------------------------------------------------- /msweepcore/pch.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | // Minesweeper 18 | #include "msweepcore.h" 19 | 20 | #include "IndexHelper.h" 21 | 22 | #define SHOW_MINES 0 --------------------------------------------------------------------------------